mirror of
https://github.com/corda/corda.git
synced 2025-01-17 02:09:50 +00:00
Add AnonymousParty superclass of Party
Add AnonymousParty superclass of Party in preparation for anonymising parties stored in contract states. Signed-off-by: Ross Nicoll <ross.nicoll@r3.com>
This commit is contained in:
parent
35253e53b8
commit
a9d9441411
@ -1,6 +1,7 @@
|
|||||||
package net.corda.core.contracts
|
package net.corda.core.contracts
|
||||||
|
|
||||||
import net.corda.core.contracts.clauses.Clause
|
import net.corda.core.contracts.clauses.Clause
|
||||||
|
import net.corda.core.crypto.AnonymousParty
|
||||||
import net.corda.core.crypto.CompositeKey
|
import net.corda.core.crypto.CompositeKey
|
||||||
import net.corda.core.crypto.Party
|
import net.corda.core.crypto.Party
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
@ -349,8 +350,8 @@ inline fun <reified T : ContractState> Iterable<StateAndRef<ContractState>>.filt
|
|||||||
* Reference to something being stored or issued by a party e.g. in a vault or (more likely) on their normal
|
* Reference to something being stored or issued by a party e.g. in a vault or (more likely) on their normal
|
||||||
* ledger. The reference is intended to be encrypted so it's meaningless to anyone other than the party.
|
* ledger. The reference is intended to be encrypted so it's meaningless to anyone other than the party.
|
||||||
*/
|
*/
|
||||||
data class PartyAndReference(val party: Party, val reference: OpaqueBytes) {
|
data class PartyAndReference(val party: AnonymousParty, val reference: OpaqueBytes) {
|
||||||
override fun toString() = "${party.name}$reference"
|
override fun toString() = "${party}$reference"
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Marker interface for classes that represent commands */
|
/** Marker interface for classes that represent commands */
|
||||||
|
24
core/src/main/kotlin/net/corda/core/crypto/AnonymousParty.kt
Normal file
24
core/src/main/kotlin/net/corda/core/crypto/AnonymousParty.kt
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
package net.corda.core.crypto
|
||||||
|
|
||||||
|
import net.corda.core.contracts.PartyAndReference
|
||||||
|
import net.corda.core.serialization.OpaqueBytes
|
||||||
|
import java.security.PublicKey
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The [AnonymousParty] class contains enough information to uniquely identify a [Party] while excluding private
|
||||||
|
* information such as name. It is intended to represent a party on the distributed ledger.
|
||||||
|
*/
|
||||||
|
open class AnonymousParty(val owningKey: CompositeKey) {
|
||||||
|
/** A helper constructor that converts the given [PublicKey] in to a [CompositeKey] with a single node */
|
||||||
|
constructor(owningKey: PublicKey) : this(owningKey.composite)
|
||||||
|
|
||||||
|
/** Anonymised parties do not include any detail apart from owning key, so equality is dependent solely on the key */
|
||||||
|
override fun equals(other: Any?): Boolean = other is AnonymousParty && this.owningKey == other.owningKey
|
||||||
|
override fun hashCode(): Int = owningKey.hashCode()
|
||||||
|
// Use the key as the bulk of the toString(), but include a human readable identifier as well, so that [Party]
|
||||||
|
// can put in the key and actual name
|
||||||
|
override fun toString() = "${owningKey.toBase58String()} <Anonymous>"
|
||||||
|
|
||||||
|
fun ref(bytes: OpaqueBytes) = PartyAndReference(this, bytes)
|
||||||
|
fun ref(vararg bytes: Byte) = ref(OpaqueBytes.of(*bytes))
|
||||||
|
}
|
@ -1,7 +1,5 @@
|
|||||||
package net.corda.core.crypto
|
package net.corda.core.crypto
|
||||||
|
|
||||||
import net.corda.core.contracts.PartyAndReference
|
|
||||||
import net.corda.core.serialization.OpaqueBytes
|
|
||||||
import java.security.PublicKey
|
import java.security.PublicKey
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -22,15 +20,8 @@ import java.security.PublicKey
|
|||||||
*
|
*
|
||||||
* @see CompositeKey
|
* @see CompositeKey
|
||||||
*/
|
*/
|
||||||
class Party(val name: String, val owningKey: CompositeKey) {
|
class Party(val name: String, owningKey: CompositeKey) : AnonymousParty(owningKey) {
|
||||||
/** A helper constructor that converts the given [PublicKey] in to a [CompositeKey] with a single node */
|
/** A helper constructor that converts the given [PublicKey] in to a [CompositeKey] with a single node */
|
||||||
constructor(name: String, owningKey: PublicKey) : this(name, owningKey.composite)
|
constructor(name: String, owningKey: PublicKey) : this(name, owningKey.composite)
|
||||||
|
override fun toString() = "${owningKey.toBase58String()} (name)"
|
||||||
/** Anonymised parties do not include any detail apart from owning key, so equality is dependent solely on the key */
|
|
||||||
override fun equals(other: Any?): Boolean = other is Party && this.owningKey == other.owningKey
|
|
||||||
override fun hashCode(): Int = owningKey.hashCode()
|
|
||||||
override fun toString() = name
|
|
||||||
|
|
||||||
fun ref(bytes: OpaqueBytes) = PartyAndReference(this, bytes)
|
|
||||||
fun ref(vararg bytes: Byte) = ref(OpaqueBytes.of(*bytes))
|
|
||||||
}
|
}
|
@ -1,5 +1,7 @@
|
|||||||
package net.corda.core.node.services
|
package net.corda.core.node.services
|
||||||
|
|
||||||
|
import net.corda.core.contracts.PartyAndReference
|
||||||
|
import net.corda.core.crypto.AnonymousParty
|
||||||
import net.corda.core.crypto.CompositeKey
|
import net.corda.core.crypto.CompositeKey
|
||||||
import net.corda.core.crypto.Party
|
import net.corda.core.crypto.Party
|
||||||
|
|
||||||
@ -10,6 +12,7 @@ import net.corda.core.crypto.Party
|
|||||||
*/
|
*/
|
||||||
interface IdentityService {
|
interface IdentityService {
|
||||||
fun registerIdentity(party: Party)
|
fun registerIdentity(party: Party)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all identities known to the service. This is expensive, and [partyFromKey] or [partyFromName] should be
|
* Get all identities known to the service. This is expensive, and [partyFromKey] or [partyFromName] should be
|
||||||
* used in preference where possible.
|
* used in preference where possible.
|
||||||
@ -22,4 +25,7 @@ interface IdentityService {
|
|||||||
|
|
||||||
fun partyFromKey(key: CompositeKey): Party?
|
fun partyFromKey(key: CompositeKey): Party?
|
||||||
fun partyFromName(name: String): Party?
|
fun partyFromName(name: String): Party?
|
||||||
|
|
||||||
|
fun partyFromAnonymous(party: AnonymousParty): Party?
|
||||||
|
fun partyFromAnonymous(partyRef: PartyAndReference) = partyFromAnonymous(partyRef.party)
|
||||||
}
|
}
|
||||||
|
@ -2,10 +2,7 @@ package net.corda.core.node.services
|
|||||||
|
|
||||||
import com.google.common.util.concurrent.ListenableFuture
|
import com.google.common.util.concurrent.ListenableFuture
|
||||||
import net.corda.core.contracts.*
|
import net.corda.core.contracts.*
|
||||||
import net.corda.core.crypto.CompositeKey
|
import net.corda.core.crypto.*
|
||||||
import net.corda.core.crypto.Party
|
|
||||||
import net.corda.core.crypto.SecureHash
|
|
||||||
import net.corda.core.crypto.toStringShort
|
|
||||||
import net.corda.core.toFuture
|
import net.corda.core.toFuture
|
||||||
import net.corda.core.transactions.TransactionBuilder
|
import net.corda.core.transactions.TransactionBuilder
|
||||||
import net.corda.core.transactions.WireTransaction
|
import net.corda.core.transactions.WireTransaction
|
||||||
@ -198,7 +195,7 @@ interface VaultService {
|
|||||||
fun generateSpend(tx: TransactionBuilder,
|
fun generateSpend(tx: TransactionBuilder,
|
||||||
amount: Amount<Currency>,
|
amount: Amount<Currency>,
|
||||||
to: CompositeKey,
|
to: CompositeKey,
|
||||||
onlyFromParties: Set<Party>? = null): Pair<TransactionBuilder, List<CompositeKey>>
|
onlyFromParties: Set<AnonymousParty>? = null): Pair<TransactionBuilder, List<CompositeKey>>
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun <reified T : LinearState> VaultService.linearHeadsOfType() = linearHeadsOfType_(T::class.java)
|
inline fun <reified T : LinearState> VaultService.linearHeadsOfType() = linearHeadsOfType_(T::class.java)
|
||||||
|
Binary file not shown.
20
core/src/test/kotlin/net/corda/core/crypto/PartyTest.kt
Normal file
20
core/src/test/kotlin/net/corda/core/crypto/PartyTest.kt
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
package net.corda.core.crypto
|
||||||
|
|
||||||
|
import org.junit.Test
|
||||||
|
import java.math.BigInteger
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.test.assertNotEquals
|
||||||
|
|
||||||
|
class PartyTest {
|
||||||
|
@Test
|
||||||
|
fun `equality`() {
|
||||||
|
val key = entropyToKeyPair(BigInteger.valueOf(20170207L)).public.composite
|
||||||
|
val differentKey = entropyToKeyPair(BigInteger.valueOf(7201702L)).public.composite
|
||||||
|
val anonymousParty = AnonymousParty(key)
|
||||||
|
val party = Party("test key", key)
|
||||||
|
assertEquals(party, anonymousParty)
|
||||||
|
assertEquals(anonymousParty, party)
|
||||||
|
assertNotEquals(AnonymousParty(differentKey), anonymousParty)
|
||||||
|
assertNotEquals(AnonymousParty(differentKey), party)
|
||||||
|
}
|
||||||
|
}
|
@ -87,14 +87,15 @@ Party and CompositeKey
|
|||||||
Entities using the network are called *parties*. Parties can sign structures using keys, and a party may have many
|
Entities using the network are called *parties*. Parties can sign structures using keys, and a party may have many
|
||||||
keys under their control.
|
keys under their control.
|
||||||
|
|
||||||
Parties may sometimes be identified pseudonymously. For example, in a transaction sent to your node as part of a
|
Parties can be represented either in full (including name) or pseudonymously, using the ``Party`` or ``AnonymousParty``
|
||||||
chain of custody it is important you can convince yourself of the transaction's validity, but equally important that
|
classes respectively. For example, in a transaction sent to your node as part of a chain of custody it is important you
|
||||||
you don't learn anything about who was involved in that transaction. In these cases a public key may be present
|
can convince yourself of the transaction's validity, but equally important that you don't learn anything about who was
|
||||||
without any identifying information about who owns it.
|
involved in that transaction. In these cases ``AnonymousParty`` should be used, which contains a composite public key
|
||||||
|
without any identifying information about who owns it. In contrast, for internal processing where extended details of
|
||||||
|
a party are required, the ``Party`` class should be used. The identity service provides functionality for resolving
|
||||||
|
anonymous parties to full parties.
|
||||||
|
|
||||||
Identities of parties involved in signing a transaction can be represented simply by a ``CompositeKey``, or by further
|
An ``AuthenticatedObject`` represents an object (like a command) that has been signed by a set of parties.
|
||||||
information (such as name) using the ``Party`` class. An ``AuthenticatedObject`` represents an object (like a command)
|
|
||||||
that has been signed by a set of parties.
|
|
||||||
|
|
||||||
.. note:: These types are provisional and will change significantly in future as the identity framework becomes more fleshed out.
|
.. note:: These types are provisional and will change significantly in future as the identity framework becomes more fleshed out.
|
||||||
|
|
||||||
|
@ -3,6 +3,13 @@ Release notes
|
|||||||
|
|
||||||
Here are brief summaries of what's changed between each snapshot release.
|
Here are brief summaries of what's changed between each snapshot release.
|
||||||
|
|
||||||
|
Milestone 9
|
||||||
|
-----------
|
||||||
|
|
||||||
|
* API:
|
||||||
|
|
||||||
|
* Pseudonymous ``AnonymousParty`` class added as a superclass of ``Party``.
|
||||||
|
|
||||||
Milestone 8
|
Milestone 8
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
|
@ -192,12 +192,12 @@ fun Iterable<ContractState>.sumCashOrZero(currency: Issued<Currency>): Amount<Is
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun Cash.State.ownedBy(owner: CompositeKey) = copy(owner = owner)
|
fun Cash.State.ownedBy(owner: CompositeKey) = copy(owner = owner)
|
||||||
fun Cash.State.issuedBy(party: Party) = copy(amount = Amount(amount.quantity, amount.token.copy(issuer = amount.token.issuer.copy(party = party))))
|
fun Cash.State.issuedBy(party: AnonymousParty) = copy(amount = Amount(amount.quantity, amount.token.copy(issuer = amount.token.issuer.copy(party = party))))
|
||||||
fun Cash.State.issuedBy(deposit: PartyAndReference) = copy(amount = Amount(amount.quantity, amount.token.copy(issuer = deposit)))
|
fun Cash.State.issuedBy(deposit: PartyAndReference) = copy(amount = Amount(amount.quantity, amount.token.copy(issuer = deposit)))
|
||||||
fun Cash.State.withDeposit(deposit: PartyAndReference): Cash.State = copy(amount = amount.copy(token = amount.token.copy(issuer = deposit)))
|
fun Cash.State.withDeposit(deposit: PartyAndReference): Cash.State = copy(amount = amount.copy(token = amount.token.copy(issuer = deposit)))
|
||||||
|
|
||||||
infix fun Cash.State.`owned by`(owner: CompositeKey) = ownedBy(owner)
|
infix fun Cash.State.`owned by`(owner: CompositeKey) = ownedBy(owner)
|
||||||
infix fun Cash.State.`issued by`(party: Party) = issuedBy(party)
|
infix fun Cash.State.`issued by`(party: AnonymousParty) = issuedBy(party)
|
||||||
infix fun Cash.State.`issued by`(deposit: PartyAndReference) = issuedBy(deposit)
|
infix fun Cash.State.`issued by`(deposit: PartyAndReference) = issuedBy(deposit)
|
||||||
infix fun Cash.State.`with deposit`(deposit: PartyAndReference): Cash.State = withDeposit(deposit)
|
infix fun Cash.State.`with deposit`(deposit: PartyAndReference): Cash.State = withDeposit(deposit)
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ package net.corda.flows
|
|||||||
import co.paralleluniverse.fibers.Suspendable
|
import co.paralleluniverse.fibers.Suspendable
|
||||||
import net.corda.contracts.asset.Cash
|
import net.corda.contracts.asset.Cash
|
||||||
import net.corda.core.contracts.*
|
import net.corda.core.contracts.*
|
||||||
|
import net.corda.core.crypto.AnonymousParty
|
||||||
import net.corda.core.crypto.Party
|
import net.corda.core.crypto.Party
|
||||||
import net.corda.core.crypto.keys
|
import net.corda.core.crypto.keys
|
||||||
import net.corda.core.crypto.toStringShort
|
import net.corda.core.crypto.toStringShort
|
||||||
|
@ -12,7 +12,6 @@ import net.corda.core.map
|
|||||||
import net.corda.core.serialization.OpaqueBytes
|
import net.corda.core.serialization.OpaqueBytes
|
||||||
import net.corda.core.transactions.SignedTransaction
|
import net.corda.core.transactions.SignedTransaction
|
||||||
import net.corda.core.utilities.DUMMY_NOTARY
|
import net.corda.core.utilities.DUMMY_NOTARY
|
||||||
import net.corda.core.utilities.DUMMY_NOTARY_KEY
|
|
||||||
import net.corda.flows.IssuerFlow.IssuanceRequester
|
import net.corda.flows.IssuerFlow.IssuanceRequester
|
||||||
import net.corda.testing.*
|
import net.corda.testing.*
|
||||||
import net.corda.testing.node.MockNetwork
|
import net.corda.testing.node.MockNetwork
|
||||||
@ -54,11 +53,12 @@ class IssuerFlowTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun runIssuerAndIssueRequester(amount: Amount<Currency>, issueToPartyAndRef: PartyAndReference) : RunResult {
|
private fun runIssuerAndIssueRequester(amount: Amount<Currency>, issueToPartyAndRef: PartyAndReference) : RunResult {
|
||||||
|
val resolvedIssuerParty = bankOfCordaNode.services.identityService.partyFromAnonymous(issueToPartyAndRef) ?: throw IllegalStateException()
|
||||||
val issuerFuture = bankOfCordaNode.initiateSingleShotFlow(IssuerFlow.IssuanceRequester::class) {
|
val issuerFuture = bankOfCordaNode.initiateSingleShotFlow(IssuerFlow.IssuanceRequester::class) {
|
||||||
otherParty -> IssuerFlow.Issuer(issueToPartyAndRef.party)
|
otherParty -> IssuerFlow.Issuer(resolvedIssuerParty)
|
||||||
}.map { it.stateMachine }
|
}.map { it.stateMachine }
|
||||||
|
|
||||||
val issueRequest = IssuanceRequester(amount, issueToPartyAndRef.party, issueToPartyAndRef.reference, bankOfCordaNode.info.legalIdentity)
|
val issueRequest = IssuanceRequester(amount, resolvedIssuerParty, issueToPartyAndRef.reference, bankOfCordaNode.info.legalIdentity)
|
||||||
val issueRequestResultFuture = bankClientNode.services.startFlow(issueRequest).resultFuture
|
val issueRequestResultFuture = bankClientNode.services.startFlow(issueRequest).resultFuture
|
||||||
|
|
||||||
return IssuerFlowTest.RunResult(issuerFuture, issueRequestResultFuture)
|
return IssuerFlowTest.RunResult(issuerFuture, issueRequestResultFuture)
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package net.corda.node.services.identity
|
package net.corda.node.services.identity
|
||||||
|
|
||||||
|
import net.corda.core.contracts.PartyAndReference
|
||||||
|
import net.corda.core.crypto.AnonymousParty
|
||||||
import net.corda.core.crypto.CompositeKey
|
import net.corda.core.crypto.CompositeKey
|
||||||
import net.corda.core.crypto.Party
|
import net.corda.core.crypto.Party
|
||||||
import net.corda.core.node.services.IdentityService
|
import net.corda.core.node.services.IdentityService
|
||||||
@ -26,4 +28,11 @@ class InMemoryIdentityService() : SingletonSerializeAsToken(), IdentityService {
|
|||||||
|
|
||||||
override fun partyFromKey(key: CompositeKey): Party? = keyToParties[key]
|
override fun partyFromKey(key: CompositeKey): Party? = keyToParties[key]
|
||||||
override fun partyFromName(name: String): Party? = nameToParties[name]
|
override fun partyFromName(name: String): Party? = nameToParties[name]
|
||||||
|
override fun partyFromAnonymous(party: AnonymousParty): Party? {
|
||||||
|
return if (party is Party)
|
||||||
|
party
|
||||||
|
else
|
||||||
|
partyFromKey(party.owningKey)
|
||||||
|
}
|
||||||
|
override fun partyFromAnonymous(partyRef: PartyAndReference) = partyFromAnonymous(partyRef.party)
|
||||||
}
|
}
|
||||||
|
@ -5,8 +5,8 @@ import net.corda.contracts.asset.Cash
|
|||||||
import net.corda.core.ThreadBox
|
import net.corda.core.ThreadBox
|
||||||
import net.corda.core.bufferUntilSubscribed
|
import net.corda.core.bufferUntilSubscribed
|
||||||
import net.corda.core.contracts.*
|
import net.corda.core.contracts.*
|
||||||
|
import net.corda.core.crypto.AnonymousParty
|
||||||
import net.corda.core.crypto.CompositeKey
|
import net.corda.core.crypto.CompositeKey
|
||||||
import net.corda.core.crypto.Party
|
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.node.ServiceHub
|
import net.corda.core.node.ServiceHub
|
||||||
import net.corda.core.node.services.Vault
|
import net.corda.core.node.services.Vault
|
||||||
@ -198,7 +198,7 @@ class NodeVaultService(private val services: ServiceHub) : SingletonSerializeAsT
|
|||||||
override fun generateSpend(tx: TransactionBuilder,
|
override fun generateSpend(tx: TransactionBuilder,
|
||||||
amount: Amount<Currency>,
|
amount: Amount<Currency>,
|
||||||
to: CompositeKey,
|
to: CompositeKey,
|
||||||
onlyFromParties: Set<Party>?): Pair<TransactionBuilder, List<CompositeKey>> {
|
onlyFromParties: Set<AnonymousParty>?): Pair<TransactionBuilder, List<CompositeKey>> {
|
||||||
// Discussion
|
// Discussion
|
||||||
//
|
//
|
||||||
// This code is analogous to the Wallet.send() set of methods in bitcoinj, and has the same general outline.
|
// This code is analogous to the Wallet.send() set of methods in bitcoinj, and has the same general outline.
|
||||||
|
@ -4,10 +4,7 @@ import net.corda.contracts.CommercialPaper
|
|||||||
import net.corda.contracts.asset.*
|
import net.corda.contracts.asset.*
|
||||||
import net.corda.contracts.testing.fillWithSomeTestCash
|
import net.corda.contracts.testing.fillWithSomeTestCash
|
||||||
import net.corda.core.contracts.*
|
import net.corda.core.contracts.*
|
||||||
import net.corda.core.crypto.CompositeKey
|
import net.corda.core.crypto.*
|
||||||
import net.corda.core.crypto.Party
|
|
||||||
import net.corda.core.crypto.SecureHash
|
|
||||||
import net.corda.core.crypto.composite
|
|
||||||
import net.corda.core.days
|
import net.corda.core.days
|
||||||
import net.corda.core.flows.FlowStateMachine
|
import net.corda.core.flows.FlowStateMachine
|
||||||
import net.corda.core.flows.StateMachineRunId
|
import net.corda.core.flows.StateMachineRunId
|
||||||
@ -490,7 +487,7 @@ class TwoPartyTradeFlowTests {
|
|||||||
private fun LedgerDSL<TestTransactionDSLInterpreter, TestLedgerDSLInterpreter>.fillUpForBuyer(
|
private fun LedgerDSL<TestTransactionDSLInterpreter, TestLedgerDSLInterpreter>.fillUpForBuyer(
|
||||||
withError: Boolean,
|
withError: Boolean,
|
||||||
owner: CompositeKey,
|
owner: CompositeKey,
|
||||||
issuer: Party,
|
issuer: AnonymousParty,
|
||||||
notary: Party): Pair<Vault, List<WireTransaction>> {
|
notary: Party): Pair<Vault, List<WireTransaction>> {
|
||||||
val interimOwnerKey = MEGA_CORP_PUBKEY
|
val interimOwnerKey = MEGA_CORP_PUBKEY
|
||||||
// Bob (Buyer) has some cash he got from the Bank of Elbonia, Alice (Seller) has some commercial paper she
|
// Bob (Buyer) has some cash he got from the Bank of Elbonia, Alice (Seller) has some commercial paper she
|
||||||
|
@ -2,6 +2,7 @@ package net.corda.testing.node
|
|||||||
|
|
||||||
import kotlinx.support.jdk8.collections.putIfAbsent
|
import kotlinx.support.jdk8.collections.putIfAbsent
|
||||||
import net.corda.core.contracts.Attachment
|
import net.corda.core.contracts.Attachment
|
||||||
|
import net.corda.core.contracts.PartyAndReference
|
||||||
import net.corda.core.crypto.*
|
import net.corda.core.crypto.*
|
||||||
import net.corda.core.flows.FlowLogic
|
import net.corda.core.flows.FlowLogic
|
||||||
import net.corda.core.flows.FlowStateMachine
|
import net.corda.core.flows.FlowStateMachine
|
||||||
@ -73,6 +74,8 @@ class MockIdentityService(val identities: List<Party>) : IdentityService, Single
|
|||||||
|
|
||||||
override fun registerIdentity(party: Party) { throw UnsupportedOperationException() }
|
override fun registerIdentity(party: Party) { throw UnsupportedOperationException() }
|
||||||
override fun getAllIdentities(): Iterable<Party> = ArrayList(keyToParties.values)
|
override fun getAllIdentities(): Iterable<Party> = ArrayList(keyToParties.values)
|
||||||
|
override fun partyFromAnonymous(party: AnonymousParty): Party? = keyToParties[party.owningKey]
|
||||||
|
override fun partyFromAnonymous(partyRef: PartyAndReference): Party? = partyFromAnonymous(partyRef.party)
|
||||||
override fun partyFromKey(key: CompositeKey): Party? = keyToParties[key]
|
override fun partyFromKey(key: CompositeKey): Party? = keyToParties[key]
|
||||||
override fun partyFromName(name: String): Party? = nameToParties[name]
|
override fun partyFromName(name: String): Party? = nameToParties[name]
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@ import net.corda.contracts.asset.Cash
|
|||||||
import net.corda.core.contracts.Amount
|
import net.corda.core.contracts.Amount
|
||||||
import net.corda.core.contracts.StateAndRef
|
import net.corda.core.contracts.StateAndRef
|
||||||
import net.corda.core.contracts.withoutIssuer
|
import net.corda.core.contracts.withoutIssuer
|
||||||
|
import net.corda.core.crypto.AnonymousParty
|
||||||
import net.corda.core.crypto.Party
|
import net.corda.core.crypto.Party
|
||||||
import net.corda.explorer.formatters.AmountFormatter
|
import net.corda.explorer.formatters.AmountFormatter
|
||||||
import net.corda.explorer.identicon.identicon
|
import net.corda.explorer.identicon.identicon
|
||||||
@ -84,7 +85,7 @@ class CashViewer : CordaView("Cash") {
|
|||||||
*/
|
*/
|
||||||
sealed class ViewerNode(val equivAmount: ObservableValue<out Amount<Currency>>,
|
sealed class ViewerNode(val equivAmount: ObservableValue<out Amount<Currency>>,
|
||||||
val states: ObservableList<StateAndRef<Cash.State>>) {
|
val states: ObservableList<StateAndRef<Cash.State>>) {
|
||||||
class IssuerNode(val issuer: Party,
|
class IssuerNode(val issuer: AnonymousParty,
|
||||||
sumEquivAmount: ObservableValue<out Amount<Currency>>,
|
sumEquivAmount: ObservableValue<out Amount<Currency>>,
|
||||||
states: ObservableList<StateAndRef<Cash.State>>) : ViewerNode(sumEquivAmount, states)
|
states: ObservableList<StateAndRef<Cash.State>>) : ViewerNode(sumEquivAmount, states)
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ import net.corda.contracts.asset.Cash
|
|||||||
import net.corda.core.contracts.Issued
|
import net.corda.core.contracts.Issued
|
||||||
import net.corda.core.contracts.PartyAndReference
|
import net.corda.core.contracts.PartyAndReference
|
||||||
import net.corda.core.contracts.USD
|
import net.corda.core.contracts.USD
|
||||||
|
import net.corda.core.crypto.AnonymousParty
|
||||||
import net.corda.core.crypto.Party
|
import net.corda.core.crypto.Party
|
||||||
import net.corda.core.flows.FlowException
|
import net.corda.core.flows.FlowException
|
||||||
import net.corda.core.getOrThrow
|
import net.corda.core.getOrThrow
|
||||||
@ -49,7 +50,7 @@ data class CrossCashCommand(
|
|||||||
* Map from node to (map from issuer to USD quantity)
|
* Map from node to (map from issuer to USD quantity)
|
||||||
*/
|
*/
|
||||||
data class CrossCashState(
|
data class CrossCashState(
|
||||||
val nodeVaults: Map<Party, Map<Party, Long>>,
|
val nodeVaults: Map<AnonymousParty, Map<AnonymousParty, Long>>,
|
||||||
|
|
||||||
// node -> (notifying node -> [(issuer, amount)])
|
// node -> (notifying node -> [(issuer, amount)])
|
||||||
// This map holds the queues that encode the non-determinism of how tx notifications arrive in the background.
|
// This map holds the queues that encode the non-determinism of how tx notifications arrive in the background.
|
||||||
@ -67,20 +68,20 @@ data class CrossCashState(
|
|||||||
// requires more concurrent code which is conceptually also more complex than the current design.
|
// requires more concurrent code which is conceptually also more complex than the current design.
|
||||||
// TODO: Alternative: We may possibly reduce the complexity of the search even further using some form of
|
// TODO: Alternative: We may possibly reduce the complexity of the search even further using some form of
|
||||||
// knapsack instead of the naive search
|
// knapsack instead of the naive search
|
||||||
val diffQueues: Map<Party, Map<Party, List<Pair<Party, Long>>>>
|
val diffQueues: Map<AnonymousParty, Map<AnonymousParty, List<Pair<AnonymousParty, Long>>>>
|
||||||
) {
|
) {
|
||||||
fun copyVaults(): HashMap<Party, HashMap<Party, Long>> {
|
fun copyVaults(): HashMap<AnonymousParty, HashMap<AnonymousParty, Long>> {
|
||||||
val newNodeVaults = HashMap<Party, HashMap<Party, Long>>()
|
val newNodeVaults = HashMap<AnonymousParty, HashMap<AnonymousParty, Long>>()
|
||||||
for ((key, value) in nodeVaults) {
|
for ((key, value) in nodeVaults) {
|
||||||
newNodeVaults[key] = HashMap(value)
|
newNodeVaults[key] = HashMap(value)
|
||||||
}
|
}
|
||||||
return newNodeVaults
|
return newNodeVaults
|
||||||
}
|
}
|
||||||
|
|
||||||
fun copyQueues(): HashMap<Party, HashMap<Party, ArrayList<Pair<Party, Long>>>> {
|
fun copyQueues(): HashMap<AnonymousParty, HashMap<AnonymousParty, ArrayList<Pair<AnonymousParty, Long>>>> {
|
||||||
val newDiffQueues = HashMap<Party, HashMap<Party, ArrayList<Pair<Party, Long>>>>()
|
val newDiffQueues = HashMap<AnonymousParty, HashMap<AnonymousParty, ArrayList<Pair<AnonymousParty, Long>>>>()
|
||||||
for ((node, queues) in diffQueues) {
|
for ((node, queues) in diffQueues) {
|
||||||
val newQueues = HashMap<Party, ArrayList<Pair<Party, Long>>>()
|
val newQueues = HashMap<AnonymousParty, ArrayList<Pair<AnonymousParty, Long>>>()
|
||||||
for ((sender, value) in queues) {
|
for ((sender, value) in queues) {
|
||||||
newQueues[sender] = ArrayList(value)
|
newQueues[sender] = ArrayList(value)
|
||||||
}
|
}
|
||||||
@ -216,9 +217,9 @@ val crossCashTest = LoadTest<CrossCashCommand, CrossCashState>(
|
|||||||
|
|
||||||
gatherRemoteState = { previousState ->
|
gatherRemoteState = { previousState ->
|
||||||
log.info("Reifying state...")
|
log.info("Reifying state...")
|
||||||
val currentNodeVaults = HashMap<Party, HashMap<Party, Long>>()
|
val currentNodeVaults = HashMap<AnonymousParty, HashMap<AnonymousParty, Long>>()
|
||||||
simpleNodes.forEach {
|
simpleNodes.forEach {
|
||||||
val quantities = HashMap<Party, Long>()
|
val quantities = HashMap<AnonymousParty, Long>()
|
||||||
val vault = it.connection.proxy.vaultAndUpdates().first
|
val vault = it.connection.proxy.vaultAndUpdates().first
|
||||||
vault.forEach {
|
vault.forEach {
|
||||||
val state = it.state.data
|
val state = it.state.data
|
||||||
@ -230,7 +231,7 @@ val crossCashTest = LoadTest<CrossCashCommand, CrossCashState>(
|
|||||||
currentNodeVaults.put(it.info.legalIdentity, quantities)
|
currentNodeVaults.put(it.info.legalIdentity, quantities)
|
||||||
}
|
}
|
||||||
val (consistentVaults, diffQueues) = if (previousState == null) {
|
val (consistentVaults, diffQueues) = if (previousState == null) {
|
||||||
Pair(currentNodeVaults, mapOf<Party, Map<Party, List<Pair<Party, Long>>>>())
|
Pair(currentNodeVaults, mapOf<AnonymousParty, Map<AnonymousParty, List<Pair<AnonymousParty, Long>>>>())
|
||||||
} else {
|
} else {
|
||||||
log.info("${previousState.diffQueues.values.sumBy { it.values.sumBy { it.size } }} txs in limbo")
|
log.info("${previousState.diffQueues.values.sumBy { it.values.sumBy { it.size } }} txs in limbo")
|
||||||
val newDiffQueues = previousState.copyQueues()
|
val newDiffQueues = previousState.copyQueues()
|
||||||
@ -248,12 +249,12 @@ val crossCashTest = LoadTest<CrossCashCommand, CrossCashState>(
|
|||||||
"\nActual gathered state:\n${CrossCashState(currentNodeVaults, mapOf())}"
|
"\nActual gathered state:\n${CrossCashState(currentNodeVaults, mapOf())}"
|
||||||
)
|
)
|
||||||
// TODO We should terminate here with an exception, we cannot carry on as we have an inconsistent model. We carry on currently because we always diverge due to notarisation failures
|
// TODO We should terminate here with an exception, we cannot carry on as we have an inconsistent model. We carry on currently because we always diverge due to notarisation failures
|
||||||
return@LoadTest CrossCashState(currentNodeVaults, mapOf<Party, Map<Party, List<Pair<Party, Long>>>>())
|
return@LoadTest CrossCashState(currentNodeVaults, mapOf<AnonymousParty, Map<AnonymousParty, List<Pair<AnonymousParty, Long>>>>())
|
||||||
}
|
}
|
||||||
if (matches.size > 1) {
|
if (matches.size > 1) {
|
||||||
log.warn("Multiple predicted states match the remote state")
|
log.warn("Multiple predicted states match the remote state")
|
||||||
}
|
}
|
||||||
val minimumMatches = matches.fold<Map<Party, Int>, HashMap<Party, Int>?>(null) { minimum, next ->
|
val minimumMatches = matches.fold<Map<AnonymousParty, Int>, HashMap<AnonymousParty, Int>?>(null) { minimum, next ->
|
||||||
if (minimum == null) {
|
if (minimum == null) {
|
||||||
HashMap(next)
|
HashMap(next)
|
||||||
} else {
|
} else {
|
||||||
|
@ -5,6 +5,7 @@ import net.corda.client.mock.generateAmount
|
|||||||
import net.corda.client.mock.pickOne
|
import net.corda.client.mock.pickOne
|
||||||
import net.corda.core.contracts.Issued
|
import net.corda.core.contracts.Issued
|
||||||
import net.corda.core.contracts.PartyAndReference
|
import net.corda.core.contracts.PartyAndReference
|
||||||
|
import net.corda.core.crypto.AnonymousParty
|
||||||
import net.corda.core.crypto.Party
|
import net.corda.core.crypto.Party
|
||||||
import net.corda.core.serialization.OpaqueBytes
|
import net.corda.core.serialization.OpaqueBytes
|
||||||
import net.corda.flows.CashCommand
|
import net.corda.flows.CashCommand
|
||||||
@ -27,7 +28,7 @@ fun generateIssue(
|
|||||||
fun generateMove(
|
fun generateMove(
|
||||||
max: Long,
|
max: Long,
|
||||||
currency: Currency,
|
currency: Currency,
|
||||||
issuer: Party,
|
issuer: AnonymousParty,
|
||||||
possibleRecipients: List<Party>
|
possibleRecipients: List<Party>
|
||||||
): Generator<CashCommand.PayCash> {
|
): Generator<CashCommand.PayCash> {
|
||||||
return generateAmount(1, max, Generator.pure(Issued(PartyAndReference(issuer, OpaqueBytes.of(0)), currency))).combine(
|
return generateAmount(1, max, Generator.pure(Issued(PartyAndReference(issuer, OpaqueBytes.of(0)), currency))).combine(
|
||||||
|
@ -6,6 +6,7 @@ import net.corda.client.mock.pickOne
|
|||||||
import net.corda.client.mock.replicatePoisson
|
import net.corda.client.mock.replicatePoisson
|
||||||
import net.corda.contracts.asset.Cash
|
import net.corda.contracts.asset.Cash
|
||||||
import net.corda.core.contracts.USD
|
import net.corda.core.contracts.USD
|
||||||
|
import net.corda.core.crypto.AnonymousParty
|
||||||
import net.corda.core.crypto.Party
|
import net.corda.core.crypto.Party
|
||||||
import net.corda.core.flows.FlowException
|
import net.corda.core.flows.FlowException
|
||||||
import net.corda.core.getOrThrow
|
import net.corda.core.getOrThrow
|
||||||
@ -26,9 +27,9 @@ data class SelfIssueCommand(
|
|||||||
)
|
)
|
||||||
|
|
||||||
data class SelfIssueState(
|
data class SelfIssueState(
|
||||||
val vaultsSelfIssued: Map<Party, Long>
|
val vaultsSelfIssued: Map<AnonymousParty, Long>
|
||||||
) {
|
) {
|
||||||
fun copyVaults(): HashMap<Party, Long> {
|
fun copyVaults(): HashMap<AnonymousParty, Long> {
|
||||||
return HashMap(vaultsSelfIssued)
|
return HashMap(vaultsSelfIssued)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -70,7 +71,7 @@ val selfIssueTest = LoadTest<SelfIssueCommand, SelfIssueState>(
|
|||||||
},
|
},
|
||||||
|
|
||||||
gatherRemoteState = { previousState ->
|
gatherRemoteState = { previousState ->
|
||||||
val selfIssueVaults = HashMap<Party, Long>()
|
val selfIssueVaults = HashMap<AnonymousParty, Long>()
|
||||||
simpleNodes.forEach { node ->
|
simpleNodes.forEach { node ->
|
||||||
val vault = node.connection.proxy.vaultAndUpdates().first
|
val vault = node.connection.proxy.vaultAndUpdates().first
|
||||||
vault.forEach {
|
vault.forEach {
|
||||||
|
Loading…
Reference in New Issue
Block a user