Skip to content

Commit c15b578

Browse files
Added accounts implementation including contract, workflow and integration APIs and tests.
1 parent 250cabc commit c15b578

File tree

43 files changed

+2516
-11
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+2516
-11
lines changed

build.gradle

Lines changed: 1 addition & 1 deletion
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 = '2.1.1'
17+
onixlabs_corda_core_release_version = '2.1.2'
1818

1919
cordapp_platform_version = 10
2020
cordapp_contract_name = 'ONIXLabs Corda Identity Framework Contract'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
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.contract
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+
24+
/**
25+
* Gets the account linear ID from an [AccountParty], or null of this [AbstractParty] is not an [AccountParty].
26+
*/
27+
val AbstractParty.accountLinearId: UniqueIdentifier?
28+
get() = if (this is AccountParty) accountLinearId else null
29+
30+
/**
31+
* Gets the account type from an [AccountParty], or null of this [AbstractParty] is not an [AccountParty].
32+
*/
33+
val AbstractParty.accountType: Class<out Account>?
34+
get() = if (this is AccountParty) accountType else null
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
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.contract.accounts
18+
19+
import io.onixlabs.corda.identityframework.contract.accounts.AccountSchema.AccountEntity
20+
import io.onixlabs.corda.identityframework.contract.accounts.AccountSchema.AccountSchemaV1
21+
import io.onixlabs.corda.identityframework.contract.toDataClassString
22+
import net.corda.core.contracts.BelongsToContract
23+
import net.corda.core.contracts.LinearState
24+
import net.corda.core.contracts.UniqueIdentifier
25+
import net.corda.core.identity.AbstractParty
26+
import net.corda.core.schemas.MappedSchema
27+
import net.corda.core.schemas.PersistentState
28+
import net.corda.core.schemas.QueryableState
29+
import java.util.*
30+
31+
/**
32+
* Represents an account, which allows contract states to be partitioned within a single node.
33+
*
34+
* @property owner The owner of the account.
35+
* @property linearId The unique identifier of the account.
36+
* @property participants THe participants of this account; namely the owner.
37+
*/
38+
@BelongsToContract(AccountContract::class)
39+
open class Account(
40+
val owner: AbstractParty,
41+
override val linearId: UniqueIdentifier = UniqueIdentifier()
42+
) : LinearState, QueryableState {
43+
44+
override val participants: List<AbstractParty>
45+
get() = listOf(owner)
46+
47+
/**
48+
* Generates a persistent state entity from this contract state.
49+
*
50+
* @param schema The mapped schema from which to generate a persistent state entity.
51+
* @return Returns a persistent state entity.
52+
*/
53+
override fun generateMappedObject(schema: MappedSchema): PersistentState = when (schema) {
54+
is AccountSchemaV1 -> AccountEntity(
55+
linearId = linearId.id,
56+
externalId = linearId.externalId,
57+
owner = owner
58+
)
59+
else -> throw IllegalArgumentException("Unrecognised schema: $schema.")
60+
}
61+
62+
/**
63+
* Gets the supported schemas of this state.
64+
*
65+
* @return Returns the supported schemas of this state.
66+
*/
67+
override fun supportedSchemas(): Iterable<MappedSchema> {
68+
return listOf(AccountSchemaV1)
69+
}
70+
71+
/**
72+
* Determines whether the specified object is equal to the current object.
73+
*
74+
* @param other The object to compare with the current object.
75+
* @return Returns true if the specified object is equal to the current object; otherwise, false.
76+
*/
77+
override fun equals(other: Any?): Boolean {
78+
return this === other || (other is Account
79+
&& other.javaClass == javaClass
80+
&& other.owner == owner
81+
&& other.linearId == linearId)
82+
}
83+
84+
/**
85+
* Serves as the default hash function.
86+
*
87+
* @return Returns a hash code for the current object.
88+
*/
89+
override fun hashCode(): Int {
90+
return Objects.hash(owner, linearId, javaClass)
91+
}
92+
93+
/**
94+
* Returns a string that represents the current object.
95+
*
96+
* @return Returns a string that represents the current object.
97+
*/
98+
override fun toString(): String {
99+
return toDataClassString()
100+
}
101+
102+
/**
103+
* Creates an account party from this account.
104+
* @return Returns an account party that resolves this account.
105+
*/
106+
fun toAccountParty(): AccountParty {
107+
return AccountParty(owner, linearId, javaClass)
108+
}
109+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
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.contract.accounts
18+
19+
import io.onixlabs.corda.core.contract.ContractID
20+
import net.corda.core.contracts.CommandData
21+
import net.corda.core.contracts.Contract
22+
import net.corda.core.contracts.requireSingleCommand
23+
import net.corda.core.contracts.requireThat
24+
import net.corda.core.transactions.LedgerTransaction
25+
import java.security.PublicKey
26+
27+
/**
28+
* Represents the smart contract for accounts.
29+
*
30+
* This contract is open to allow developers to implement their own account contracts, however it has been designed
31+
* such that derived contracts will respect and not circumvent the underlying constraints in the parent contract.
32+
*/
33+
open class AccountContract : Contract {
34+
35+
companion object : ContractID
36+
37+
/**
38+
* Verifies a ledger transaction using a command from this contract.
39+
*
40+
* @param tx The ledger transaction to verify.
41+
*/
42+
final override fun verify(tx: LedgerTransaction) {
43+
val command = tx.commands.requireSingleCommand<AccountContractCommand>()
44+
when (command.value) {
45+
is Issue -> verifyIssue(tx, command.signers.toSet())
46+
is Amend -> verifyAmend(tx, command.signers.toSet())
47+
is Revoke -> verifyRevoke(tx, command.signers.toSet())
48+
else -> throw IllegalArgumentException("Unrecognised command: ${command.value}.")
49+
}
50+
}
51+
52+
/**
53+
* Defines the interface for corda claim contract commands.
54+
*/
55+
interface AccountContractCommand : CommandData
56+
57+
/**
58+
* Represents the command to issue accounts.
59+
*/
60+
object Issue : AccountContractCommand {
61+
internal const val CONTRACT_RULE_INPUTS =
62+
"On account issuing, zero account states must be consumed."
63+
64+
internal const val CONTRACT_RULE_OUTPUTS =
65+
"On account issuing, at least one account state must be created."
66+
67+
internal const val CONTRACT_RULE_PARTICIPANTS =
68+
"On account issuing, the owner of each created account must be a participant."
69+
70+
internal const val CONTRACT_RULE_SIGNERS =
71+
"On account issuing, the owner of each account must sign the transaction."
72+
}
73+
74+
/**
75+
* Represents the command to amend accounts.
76+
*/
77+
object Amend : AccountContractCommand {
78+
internal const val CONTRACT_RULE_INPUTS =
79+
"On account amending, at least one account state must be consumed."
80+
81+
internal const val CONTRACT_RULE_OUTPUTS =
82+
"On account amending, at least one account state must be created."
83+
84+
internal const val CONTRACT_RULE_PARTICIPANTS =
85+
"On account amending, the owner of each created account must be a participant."
86+
87+
internal const val CONTRACT_RULE_SIGNERS =
88+
"On account amending, the owner of each account must sign the transaction."
89+
}
90+
91+
/**
92+
* Represents the command to revoke accounts.
93+
*/
94+
object Revoke : AccountContractCommand {
95+
internal const val CONTRACT_RULE_INPUTS =
96+
"On account revoking, at least one account state must be consumed."
97+
98+
internal const val CONTRACT_RULE_OUTPUTS =
99+
"On account revoking, zero account states must be created."
100+
101+
internal const val CONTRACT_RULE_SIGNERS =
102+
"On account revoking, the owner of each account must sign the transaction."
103+
}
104+
105+
/**
106+
* Provides the ability to extend the rules for issuing accounts.
107+
*
108+
* @param transaction The ledger transaction to verify.
109+
* @param signers The signers of the transaction.
110+
*/
111+
protected open fun onVerifyIssue(transaction: LedgerTransaction, signers: Set<PublicKey>) = requireThat { }
112+
113+
/**
114+
* Provides the ability to extend the rules for amending accounts.
115+
*
116+
* @param transaction The ledger transaction to verify.
117+
* @param signers The signers of the transaction.
118+
*/
119+
protected open fun onVerifyAmend(transaction: LedgerTransaction, signers: Set<PublicKey>) = requireThat { }
120+
121+
/**
122+
* Provides the ability to extend the rules for revoking accounts.
123+
*
124+
* @param transaction The ledger transaction to verify.
125+
* @param signers The signers of the transaction.
126+
*/
127+
protected open fun onVerifyRevoke(transaction: LedgerTransaction, signers: Set<PublicKey>) = requireThat { }
128+
129+
/**
130+
* Verifies a ledger transaction using the Issue command.
131+
*
132+
* @param transaction The ledger transaction to verify.
133+
* @param signers The signers of the transaction.
134+
*/
135+
private fun verifyIssue(transaction: LedgerTransaction, signers: Set<PublicKey>) = requireThat {
136+
val accountInputs = transaction.inputsOfType<Account>()
137+
val accountOutputs = transaction.outputsOfType<Account>()
138+
139+
Issue.CONTRACT_RULE_INPUTS using (accountInputs.isEmpty())
140+
Issue.CONTRACT_RULE_OUTPUTS using (accountOutputs.isNotEmpty())
141+
Issue.CONTRACT_RULE_PARTICIPANTS using (accountOutputs.all { it.owner in it.participants })
142+
Issue.CONTRACT_RULE_SIGNERS using (accountOutputs.all { it.owner.owningKey in signers })
143+
144+
onVerifyIssue(transaction, signers)
145+
}
146+
147+
/**
148+
* Verifies a ledger transaction using the Amend command.
149+
*
150+
* @param transaction The ledger transaction to verify.
151+
* @param signers The signers of the transaction.
152+
*/
153+
private fun verifyAmend(transaction: LedgerTransaction, signers: Set<PublicKey>) = requireThat {
154+
val accountInputs = transaction.inputsOfType<Account>()
155+
val accountOutputs = transaction.outputsOfType<Account>()
156+
157+
Amend.CONTRACT_RULE_INPUTS using (accountInputs.isNotEmpty())
158+
Amend.CONTRACT_RULE_OUTPUTS using (accountOutputs.isNotEmpty())
159+
Amend.CONTRACT_RULE_PARTICIPANTS using (accountOutputs.all { it.owner in it.participants })
160+
Amend.CONTRACT_RULE_SIGNERS using (accountOutputs.all { it.owner.owningKey in signers })
161+
162+
onVerifyAmend(transaction, signers)
163+
}
164+
165+
/**
166+
* Verifies a ledger transaction using the Revoke command.
167+
*
168+
* @param transaction The ledger transaction to verify.
169+
* @param signers The signers of the transaction.
170+
*/
171+
private fun verifyRevoke(transaction: LedgerTransaction, signers: Set<PublicKey>) = requireThat {
172+
val accountInputs = transaction.inputsOfType<Account>()
173+
val accountOutputs = transaction.outputsOfType<Account>()
174+
175+
Revoke.CONTRACT_RULE_INPUTS using (accountInputs.isNotEmpty())
176+
Revoke.CONTRACT_RULE_OUTPUTS using (accountOutputs.isEmpty())
177+
Revoke.CONTRACT_RULE_SIGNERS using (accountInputs.all { it.owner.owningKey in signers })
178+
179+
onVerifyRevoke(transaction, signers)
180+
}
181+
}

0 commit comments

Comments
 (0)