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:
Ross Nicoll 2017-02-02 16:56:25 +00:00 committed by Chris Rankin
parent 35253e53b8
commit a9d9441411
20 changed files with 115 additions and 54 deletions

View File

@ -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 */

View 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))
}

View File

@ -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))
} }

View File

@ -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)
} }

View File

@ -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)

View 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)
}
}

View File

@ -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.

View File

@ -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
----------- -----------

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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)
} }

View File

@ -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.

View File

@ -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

View File

@ -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]
} }

View File

@ -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)

View File

@ -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 {

View File

@ -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(

View File

@ -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 {