Skip to content

Commit acb50e4

Browse files
Updated account management and resolution functionality.
1 parent 0b096ed commit acb50e4

24 files changed

+282
-92
lines changed

build.gradle

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ buildscript {
1414
junit_version = '5.3.1'
1515

1616
onixlabs_group = 'io.onixlabs'
17-
onixlabs_corda_core_release_version = '3.2.0'
17+
onixlabs_corda_core_release_version = '4.0.0-rc1'
1818

1919
cordapp_platform_version = 10
2020
cordapp_contract_name = 'ONIXLabs Corda Identity Framework Contract'

gradle.properties

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name=onixlabs-corda-identity-framework
22
group=io.onixlabs
3-
version=3.3.0
3+
version=4.0.0-rc1
44
onixlabs.development.jarsign.keystore=../lib/onixlabs.development.pkcs12
55
onixlabs.development.jarsign.password=5891f47942424d2acbe108691fdb5ba258712fca7e4762be4327241ebf3dbfa3

onixlabs-corda-identity-framework-contract/src/main/kotlin/io/onixlabs/corda/identityframework/contract/accounts/AccountContract.kt

+16
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,12 @@ open class AccountContract : Contract {
6464
internal const val CONTRACT_RULE_OUTPUTS =
6565
"On account issuing, at least one account state must be created."
6666

67+
internal const val CONTRACT_RULE_OWNER_DELIMITER =
68+
"On account issuing, the account owner name must not contain an @ symbol."
69+
70+
internal const val CONTRACT_RULE_LINEAR_ID_DELIMITER =
71+
"On account issuing, the account linear ID must not contain an @ symbol."
72+
6773
internal const val CONTRACT_RULE_PARTICIPANTS =
6874
"On account issuing, the owner of each created account must be a participant."
6975

@@ -81,6 +87,12 @@ open class AccountContract : Contract {
8187
internal const val CONTRACT_RULE_OUTPUTS =
8288
"On account amending, at least one account state must be created."
8389

90+
internal const val CONTRACT_RULE_OWNER_DELIMITER =
91+
"On account amending, the account owner name must not contain an @ symbol."
92+
93+
internal const val CONTRACT_RULE_LINEAR_ID_DELIMITER =
94+
"On account amending, the account linear ID must not contain an @ symbol."
95+
8496
internal const val CONTRACT_RULE_PARTICIPANTS =
8597
"On account amending, the owner of each created account must be a participant."
8698

@@ -138,6 +150,8 @@ open class AccountContract : Contract {
138150

139151
Issue.CONTRACT_RULE_INPUTS using (accountInputs.isEmpty())
140152
Issue.CONTRACT_RULE_OUTPUTS using (accountOutputs.isNotEmpty())
153+
Issue.CONTRACT_RULE_OWNER_DELIMITER using (accountOutputs.all { AccountParty.DELIMITER !in it.owner.toString() })
154+
Issue.CONTRACT_RULE_LINEAR_ID_DELIMITER using (accountOutputs.all { AccountParty.DELIMITER !in it.linearId.toString() })
141155
Issue.CONTRACT_RULE_PARTICIPANTS using (accountOutputs.all { it.owner in it.participants })
142156
Issue.CONTRACT_RULE_SIGNERS using (accountOutputs.all { it.owner.owningKey in signers })
143157

@@ -156,6 +170,8 @@ open class AccountContract : Contract {
156170

157171
Amend.CONTRACT_RULE_INPUTS using (accountInputs.isNotEmpty())
158172
Amend.CONTRACT_RULE_OUTPUTS using (accountOutputs.isNotEmpty())
173+
Amend.CONTRACT_RULE_OWNER_DELIMITER using (accountOutputs.all { AccountParty.DELIMITER !in it.owner.toString() })
174+
Amend.CONTRACT_RULE_LINEAR_ID_DELIMITER using (accountOutputs.all { AccountParty.DELIMITER !in it.linearId.toString() })
159175
Amend.CONTRACT_RULE_PARTICIPANTS using (accountOutputs.all { it.owner in it.participants })
160176
Amend.CONTRACT_RULE_SIGNERS using (accountOutputs.all { it.owner.owningKey in signers })
161177

onixlabs-corda-identity-framework-contract/src/main/kotlin/io/onixlabs/corda/identityframework/contract/accounts/AccountParty.kt

+10-4
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,16 @@ import java.util.*
3434
* @property accountLinearId The linear ID of the account associated with this party.
3535
* @property accountType The type of the account associated with this party.
3636
*/
37-
class AccountParty internal constructor(
37+
class AccountParty(
3838
val owner: AbstractParty,
3939
val accountLinearId: UniqueIdentifier,
4040
val accountType: Class<out Account>
4141
) : AbstractParty(owner.owningKey) {
4242

43+
companion object {
44+
const val DELIMITER = '@'
45+
}
46+
4347
/**
4448
* Gets an account resolver to resolve this [AccountParty] back to the associated [Account].
4549
*
@@ -90,8 +94,10 @@ class AccountParty internal constructor(
9094
* @return Returns true if the specified object is equal to the current object; otherwise, false.
9195
*/
9296
override fun equals(other: Any?): Boolean {
93-
return if (other !is AccountParty) super.equals(other)
94-
else other.owner == owner && other.accountLinearId == accountLinearId && other.accountType == accountType
97+
return this === other || (other is AccountParty
98+
&& other.owner == owner
99+
&& other.accountLinearId == accountLinearId
100+
&& other.accountType == accountType)
95101
}
96102

97103
/**
@@ -109,7 +115,7 @@ class AccountParty internal constructor(
109115
* @return Returns a string that represents the current object.
110116
*/
111117
override fun toString(): String {
112-
return "$accountLinearId@$owner"
118+
return "$accountLinearId$DELIMITER$owner"
113119
}
114120

115121
/**

onixlabs-corda-identity-framework-contract/src/main/kotlin/io/onixlabs/corda/identityframework/contract/attestations/Attestation.kt

+1-15
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ package io.onixlabs.corda.identityframework.contract.attestations
1818

1919
import io.onixlabs.corda.core.contract.ChainState
2020
import io.onixlabs.corda.core.contract.Hashable
21-
import io.onixlabs.corda.identityframework.contract.accountLinearId
2221
import io.onixlabs.corda.identityframework.contract.attestations.AttestationSchema.AttestationEntity
2322
import io.onixlabs.corda.identityframework.contract.attestations.AttestationSchema.AttestationSchemaV1
2423
import io.onixlabs.corda.identityframework.contract.toDataClassString
@@ -92,20 +91,7 @@ open class Attestation<T : ContractState>(
9291
* @return Returns a persistent state entity.
9392
*/
9493
override fun generateMappedObject(schema: MappedSchema): PersistentState = when (schema) {
95-
is AttestationSchemaV1 -> AttestationEntity(
96-
linearId = linearId.id,
97-
externalId = linearId.externalId,
98-
attestor = attestor,
99-
attestorAccountLinearId = attestor.accountLinearId?.id,
100-
attestorAccountExternalId = attestor.accountLinearId?.externalId,
101-
pointer = pointer.statePointer.toString(),
102-
pointerStateType = pointer.stateType.canonicalName,
103-
pointerHash = pointer.hash.toString(),
104-
status = status,
105-
previousStateRef = previousStateRef?.toString(),
106-
hash = hash.toString(),
107-
attestationType = javaClass.canonicalName
108-
)
94+
is AttestationSchemaV1 -> AttestationEntity(this)
10995
else -> throw IllegalArgumentException("Unrecognised schema: $schema.")
11096
}
11197

onixlabs-corda-identity-framework-contract/src/main/kotlin/io/onixlabs/corda/identityframework/contract/attestations/AttestationSchema.kt

+17-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package io.onixlabs.corda.identityframework.contract.attestations
1818

19+
import io.onixlabs.corda.identityframework.contract.accountLinearId
1920
import net.corda.core.crypto.NullKeys.NULL_PARTY
2021
import net.corda.core.identity.AbstractParty
2122
import net.corda.core.schemas.MappedSchema
@@ -68,5 +69,20 @@ object AttestationSchema {
6869

6970
@Column(name = "attestation_type", nullable = false)
7071
val attestationType: String = ""
71-
) : PersistentState()
72+
) : PersistentState() {
73+
internal constructor(attestation: Attestation<*>) : this(
74+
linearId = attestation.linearId.id,
75+
externalId = attestation.linearId.externalId,
76+
attestor = attestation.attestor,
77+
attestorAccountLinearId = attestation.attestor.accountLinearId?.id,
78+
attestorAccountExternalId = attestation.attestor.accountLinearId?.externalId,
79+
pointer = attestation.pointer.statePointer.toString(),
80+
pointerStateType = attestation.pointer.stateType.canonicalName,
81+
pointerHash = attestation.pointer.hash.toString(),
82+
status = attestation.status,
83+
previousStateRef = attestation.previousStateRef?.toString(),
84+
hash = attestation.hash.toString(),
85+
attestationType = attestation.javaClass.canonicalName
86+
)
87+
}
7288
}

onixlabs-corda-identity-framework-contract/src/main/kotlin/io/onixlabs/corda/identityframework/contract/claims/CordaClaim.kt

+1-18
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ package io.onixlabs.corda.identityframework.contract.claims
1818

1919
import io.onixlabs.corda.core.contract.ChainState
2020
import io.onixlabs.corda.core.contract.Hashable
21-
import io.onixlabs.corda.identityframework.contract.accountLinearId
2221
import io.onixlabs.corda.identityframework.contract.claims.CordaClaimSchema.CordaClaimEntity
2322
import io.onixlabs.corda.identityframework.contract.claims.CordaClaimSchema.CordaClaimSchemaV1
2423
import net.corda.core.contracts.BelongsToContract
@@ -98,23 +97,7 @@ open class CordaClaim<T : Any>(
9897
* @return Returns a persistent state entity.
9998
*/
10099
override fun generateMappedObject(schema: MappedSchema): PersistentState = when (schema) {
101-
is CordaClaimSchemaV1 -> CordaClaimEntity(
102-
linearId = linearId.id,
103-
externalId = linearId.externalId,
104-
issuer = issuer,
105-
issuerAccountLinearId = issuer.accountLinearId?.id,
106-
issuerAccountExternalId = issuer.accountLinearId?.externalId,
107-
holder = holder,
108-
holderAccountLinearId = holder.accountLinearId?.id,
109-
holderAccountExternalId = holder.accountLinearId?.externalId,
110-
property = property,
111-
value = value.toString(),
112-
valueType = value.javaClass.canonicalName,
113-
previousStateRef = previousStateRef?.toString(),
114-
isSelfIssued = isSelfIssued,
115-
hash = hash.toString(),
116-
claimType = javaClass.canonicalName
117-
)
100+
is CordaClaimSchemaV1 -> CordaClaimEntity(this)
118101
else -> throw IllegalArgumentException("Unrecognised schema: $schema.")
119102
}
120103

onixlabs-corda-identity-framework-contract/src/main/kotlin/io/onixlabs/corda/identityframework/contract/claims/CordaClaimSchema.kt

+20-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package io.onixlabs.corda.identityframework.contract.claims
1818

19+
import io.onixlabs.corda.identityframework.contract.accountLinearId
1920
import net.corda.core.crypto.NullKeys.NULL_PARTY
2021
import net.corda.core.identity.AbstractParty
2122
import net.corda.core.schemas.MappedSchema
@@ -78,5 +79,23 @@ object CordaClaimSchema {
7879

7980
@Column(name = "claim_type", nullable = false)
8081
val claimType: String = ""
81-
) : PersistentState()
82+
) : PersistentState() {
83+
internal constructor(claim: CordaClaim<*>) : this(
84+
linearId = claim.linearId.id,
85+
externalId = claim.linearId.externalId,
86+
issuer = claim.issuer,
87+
issuerAccountLinearId = claim.issuer.accountLinearId?.id,
88+
issuerAccountExternalId = claim.issuer.accountLinearId?.externalId,
89+
holder = claim.holder,
90+
holderAccountLinearId = claim.holder.accountLinearId?.id,
91+
holderAccountExternalId = claim.holder.accountLinearId?.externalId,
92+
property = claim.property,
93+
value = claim.value.toString(),
94+
valueType = claim.value.javaClass.canonicalName,
95+
previousStateRef = claim.previousStateRef?.toString(),
96+
isSelfIssued = claim.isSelfIssued,
97+
hash = claim.hash.toString(),
98+
claimType = claim.javaClass.canonicalName
99+
)
100+
}
82101
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* Copyright 2020-2021 ONIXLabs
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.onixlabs.corda.identityframework.workflow
18+
19+
import io.onixlabs.corda.identityframework.contract.accounts.Account
20+
import io.onixlabs.corda.identityframework.contract.accounts.AccountParty
21+
import net.corda.core.contracts.UniqueIdentifier
22+
import net.corda.core.identity.AbstractParty
23+
import net.corda.core.identity.AnonymousParty
24+
import net.corda.core.identity.CordaX500Name
25+
import net.corda.core.messaging.CordaRPCOps
26+
import net.corda.core.utilities.parsePublicKeyBase58
27+
28+
fun CordaRPCOps.ownsLegalIdentity(party: AbstractParty): Boolean {
29+
val partyToResolve = if (party is AccountParty) party.owner else party
30+
val wellKnownParty = wellKnownPartyFromAnonymous(partyToResolve)
31+
32+
return wellKnownParty in nodeInfo().legalIdentities
33+
}
34+
35+
fun CordaRPCOps.resolveParty(value: String, type: Class<out Account> = Account::class.java): AbstractParty {
36+
return if (AccountParty.DELIMITER in value) resolveAccountParty(value, type) else resolveAbstractParty(value)
37+
}
38+
39+
fun CordaRPCOps.resolveAbstractParty(value: String): AbstractParty {
40+
return try {
41+
val parsedCordaX500Name = CordaX500Name.parse(value)
42+
wellKnownPartyFromX500Name(parsedCordaX500Name)
43+
} catch (ex: Exception) {
44+
val parsedPublicKey = parsePublicKeyBase58(value)
45+
AnonymousParty(parsedPublicKey)
46+
} ?: throw IllegalArgumentException("Failed to resolve '$value' to party.")
47+
}
48+
49+
fun CordaRPCOps.resolveAccountParty(value: String, type: Class<out Account> = Account::class.java): AccountParty {
50+
val identityComponent = value.substringAfter(AccountParty.DELIMITER)
51+
val linearIdComponent = value.substringBefore(AccountParty.DELIMITER)
52+
53+
val identity = resolveAbstractParty(identityComponent)
54+
val linearId = UniqueIdentifier.fromString(linearIdComponent)
55+
56+
return AccountParty(identity, linearId, type)
57+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Copyright 2020-2021 ONIXLabs
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.onixlabs.corda.identityframework.workflow
18+
19+
import co.paralleluniverse.fibers.Suspendable
20+
import io.onixlabs.corda.core.workflow.checkSufficientSessions
21+
import io.onixlabs.corda.identityframework.contract.accounts.AccountParty
22+
import net.corda.core.contracts.ContractState
23+
import net.corda.core.flows.FlowLogic
24+
import net.corda.core.flows.FlowSession
25+
import net.corda.core.identity.AbstractParty
26+
import net.corda.core.transactions.TransactionBuilder
27+
28+
@Suspendable
29+
fun FlowLogic<*>.checkSufficientSessionsWithAccounts(sessions: Iterable<FlowSession>, states: Iterable<ContractState>) {
30+
checkSufficientSessions(sessions, states) { it.getAccountOwningPartyOrThis() }
31+
}
32+
33+
@Suspendable
34+
fun FlowLogic<*>.checkSufficientSessionsWithAccounts(sessions: Iterable<FlowSession>, vararg states: ContractState) {
35+
checkSufficientSessions(sessions, *states) { it.getAccountOwningPartyOrThis() }
36+
}
37+
38+
@Suspendable
39+
fun FlowLogic<*>.checkSufficientSessions(sessions: Iterable<FlowSession>, transaction: TransactionBuilder) {
40+
checkSufficientSessions(sessions, transaction) { it.getAccountOwningPartyOrThis() }
41+
}
42+
43+
private fun AbstractParty.getAccountOwningPartyOrThis(): AbstractParty {
44+
return if (this is AccountParty) owner else this
45+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* Copyright 2020-2021 ONIXLabs
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.onixlabs.corda.identityframework.workflow
18+
19+
import io.onixlabs.corda.identityframework.contract.accounts.Account
20+
import io.onixlabs.corda.identityframework.contract.accounts.AccountParty
21+
import net.corda.core.contracts.UniqueIdentifier
22+
import net.corda.core.identity.AbstractParty
23+
import net.corda.core.identity.AnonymousParty
24+
import net.corda.core.identity.CordaX500Name
25+
import net.corda.core.node.ServiceHub
26+
import net.corda.core.utilities.parsePublicKeyBase58
27+
28+
fun ServiceHub.ownsLegalIdentity(party: AbstractParty): Boolean {
29+
val partyToResolve = if (party is AccountParty) party.owner else party
30+
val wellKnownParty = identityService.wellKnownPartyFromAnonymous(partyToResolve)
31+
32+
return wellKnownParty in myInfo.legalIdentities
33+
}
34+
35+
fun ServiceHub.resolveParty(value: String, type: Class<out Account> = Account::class.java): AbstractParty {
36+
return if (AccountParty.DELIMITER in value) resolveAccountParty(value, type) else resolveAbstractParty(value)
37+
}
38+
39+
fun ServiceHub.resolveAbstractParty(value: String): AbstractParty {
40+
return try {
41+
val parsedCordaX500Name = CordaX500Name.parse(value)
42+
identityService.wellKnownPartyFromX500Name(parsedCordaX500Name)
43+
} catch (ex: Exception) {
44+
val parsedPublicKey = parsePublicKeyBase58(value)
45+
AnonymousParty(parsedPublicKey)
46+
} ?: throw IllegalArgumentException("Failed to resolve '$value' to party.")
47+
}
48+
49+
fun ServiceHub.resolveAccountParty(value: String, type: Class<out Account> = Account::class.java): AccountParty {
50+
val identityComponent = value.substringAfter(AccountParty.DELIMITER)
51+
val linearIdComponent = value.substringBefore(AccountParty.DELIMITER)
52+
53+
val identity = resolveAbstractParty(identityComponent)
54+
val linearId = UniqueIdentifier.fromString(linearIdComponent)
55+
56+
return AccountParty(identity, linearId, type)
57+
}

0 commit comments

Comments
 (0)