mirror of
https://github.com/corda/corda.git
synced 2025-01-24 13:28:07 +00:00
Enable anonymisation (#1073)
* Enabled confidential identities in: ** IssuerFlow ** Trader demo ** Two party deal flows ** Two party trade flows ** Corda RPC tests ** Cash flows ** Integration testing tutorial ** Node monitor model tests ** CollectSignatureFlow * Relay local node's confidential identities to counterparties when requesting transaction signatures, so counterparties know where the inputs come from. * Require all identities are known in finality flow * Ensure all identities in FxTransactionBuildTutorial are known to each other * Add flow for syncing identities to a number of counterparties * Address PR comments * Disable anonymisation in example code * Revert unnecessary changes remaining from earlier rebases * Corrections after rebase * Remove unneeded identity registration Remove unneeded identity registrations from tests, which sometimes cause duplicated entries in the database * Revert accidental change in examples * Revert unneeded imports * Revert changes to CoreFlowHandlers.kt
This commit is contained in:
parent
330db73c5d
commit
65dcfe4abe
@ -133,8 +133,8 @@ class NodeMonitorModelTest : DriverBasedTest() {
|
||||
@Test
|
||||
fun `cash issue and move`() {
|
||||
val anonymous = false
|
||||
rpc.startFlow(::CashIssueFlow, 100.DOLLARS, OpaqueBytes.of(1), notaryNode.notaryIdentity).returnValue.getOrThrow()
|
||||
rpc.startFlow(::CashPaymentFlow, 100.DOLLARS, bobNode.legalIdentity, anonymous).returnValue.getOrThrow()
|
||||
val (_, issueIdentity) = rpc.startFlow(::CashIssueFlow, 100.DOLLARS, OpaqueBytes.of(1), notaryNode.notaryIdentity).returnValue.getOrThrow()
|
||||
val (_, paymentIdentity) = rpc.startFlow(::CashPaymentFlow, 100.DOLLARS, bobNode.legalIdentity).returnValue.getOrThrow()
|
||||
|
||||
var issueSmId: StateMachineRunId? = null
|
||||
var moveSmId: StateMachineRunId? = null
|
||||
@ -191,7 +191,7 @@ class NodeMonitorModelTest : DriverBasedTest() {
|
||||
require(stx.tx.outputs.size == 1)
|
||||
val signaturePubKeys = stx.sigs.map { it.by }.toSet()
|
||||
// Alice and Notary signed
|
||||
require(aliceNode.legalIdentity.owningKey.isFulfilledBy(signaturePubKeys))
|
||||
require(issueIdentity!!.owningKey.isFulfilledBy(signaturePubKeys))
|
||||
require(notaryNode.notaryIdentity.owningKey.isFulfilledBy(signaturePubKeys))
|
||||
moveTx = stx
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import net.corda.core.contracts.StateRef
|
||||
import net.corda.core.contracts.TransactionState
|
||||
import net.corda.core.crypto.isFulfilledBy
|
||||
import net.corda.core.identity.AbstractParty
|
||||
import net.corda.core.crypto.toStringShort
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.internal.ResolveTransactionsFlow
|
||||
import net.corda.core.node.ServiceHub
|
||||
@ -126,6 +127,12 @@ open class FinalityFlow(val transactions: Iterable<SignedTransaction>,
|
||||
// Calculate who is meant to see the results based on the participants involved.
|
||||
return extractParticipants(ltx)
|
||||
.map(this::partyFromAnonymous)
|
||||
.map { participant ->
|
||||
if (participant.wellKnown != null)
|
||||
participant
|
||||
else
|
||||
throw IllegalArgumentException("Could not resolve well known identity of participant ${participant.participant.owningKey.toStringShort()}")
|
||||
}
|
||||
.toSet()
|
||||
}
|
||||
|
||||
|
@ -9,8 +9,9 @@ import net.corda.core.utilities.ProgressTracker
|
||||
import net.corda.core.utilities.unwrap
|
||||
|
||||
/**
|
||||
* Very basic flow which exchanges transaction key and certificate paths between two parties in a transaction.
|
||||
* This is intended for use as a subflow of another flow.
|
||||
* Very basic flow which generates new confidential identities for parties in a transaction and exchanges the transaction
|
||||
* key and certificate paths between the parties. This is intended for use as a subflow of another flow which builds a
|
||||
* transaction.
|
||||
*/
|
||||
@StartableByRPC
|
||||
@InitiatingFlow
|
||||
|
@ -219,6 +219,7 @@ class ContractUpgradeFlowTest {
|
||||
val result = a.services.startFlow(CashIssueFlow(Amount(1000, USD), OpaqueBytes.of(1), notary)).resultFuture
|
||||
mockNet.runNetwork()
|
||||
val stx = result.getOrThrow().stx
|
||||
val anonymisedRecipient = result.get().recipient!!
|
||||
val stateAndRef = stx.tx.outRef<Cash.State>(0)
|
||||
val baseState = a.database.transaction { a.services.vaultQueryService.queryBy<ContractState>().states.single() }
|
||||
assertTrue(baseState.state.data is Cash.State, "Contract state is old version.")
|
||||
@ -230,7 +231,7 @@ class ContractUpgradeFlowTest {
|
||||
val firstState = a.database.transaction { a.services.vaultQueryService.queryBy<ContractState>().states.single() }
|
||||
assertTrue(firstState.state.data is CashV2.State, "Contract state is upgraded to the new version.")
|
||||
assertEquals(Amount(1000000, USD).`issued by`(a.info.legalIdentity.ref(1)), (firstState.state.data as CashV2.State).amount, "Upgraded cash contain the correct amount.")
|
||||
assertEquals<Collection<AbstractParty>>(listOf(a.info.legalIdentity), (firstState.state.data as CashV2.State).owners, "Upgraded cash belongs to the right owner.")
|
||||
assertEquals<Collection<AbstractParty>>(listOf(anonymisedRecipient), (firstState.state.data as CashV2.State).owners, "Upgraded cash belongs to the right owner.")
|
||||
}
|
||||
|
||||
class CashV2 : UpgradedContract<Cash.State, CashV2.State> {
|
||||
|
@ -7,12 +7,14 @@ import net.corda.core.transactions.TransactionBuilder
|
||||
import net.corda.core.utilities.getOrThrow
|
||||
import net.corda.finance.GBP
|
||||
import net.corda.finance.contracts.asset.Cash
|
||||
import net.corda.testing.ALICE
|
||||
import net.corda.testing.node.MockNetwork
|
||||
import net.corda.testing.node.MockServices
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFailsWith
|
||||
|
||||
class FinalityFlowTests {
|
||||
lateinit var mockNet: MockNetwork
|
||||
@ -53,4 +55,18 @@ class FinalityFlowTests {
|
||||
}
|
||||
assertEquals(notarisedTx, transactionSeenByB)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `reject a transaction with unknown parties`() {
|
||||
val amount = Amount(1000, Issued(nodeA.info.legalIdentity.ref(0), GBP))
|
||||
val fakeIdentity = ALICE // Alice isn't part of this network, so node A won't recognise them
|
||||
val builder = TransactionBuilder(notary)
|
||||
Cash().generateIssue(builder, amount, fakeIdentity, notary)
|
||||
val stx = nodeA.services.signInitialTransaction(builder)
|
||||
val flow = nodeA.services.startFlow(FinalityFlow(stx))
|
||||
mockNet.runNetwork()
|
||||
assertFailsWith<IllegalArgumentException> {
|
||||
flow.resultFuture.getOrThrow()
|
||||
}
|
||||
}
|
||||
}
|
@ -116,10 +116,10 @@ class CordaRPCOpsImplTest {
|
||||
)
|
||||
}
|
||||
|
||||
result.returnValue.getOrThrow()
|
||||
val anonymisedRecipient = result.returnValue.getOrThrow().recipient!!
|
||||
val expectedState = Cash.State(Amount(quantity,
|
||||
Issued(aliceNode.info.legalIdentity.ref(ref), GBP)),
|
||||
recipient)
|
||||
anonymisedRecipient)
|
||||
|
||||
// Query vault via RPC
|
||||
val cash = rpc.vaultQueryBy<Cash.State>()
|
||||
@ -141,7 +141,6 @@ class CordaRPCOpsImplTest {
|
||||
vaultTrackCash = rpc.vaultTrackBy<Cash.State>().updates
|
||||
}
|
||||
|
||||
val anonymous = false
|
||||
val result = rpc.startFlow(::CashIssueFlow,
|
||||
100.DOLLARS,
|
||||
OpaqueBytes(ByteArray(1, { 1 })),
|
||||
@ -150,7 +149,7 @@ class CordaRPCOpsImplTest {
|
||||
|
||||
mockNet.runNetwork()
|
||||
|
||||
rpc.startFlow(::CashPaymentFlow, 100.DOLLARS, aliceNode.info.legalIdentity, anonymous)
|
||||
rpc.startFlow(::CashPaymentFlow, 100.DOLLARS, aliceNode.info.legalIdentity)
|
||||
|
||||
mockNet.runNetwork()
|
||||
|
||||
@ -183,7 +182,7 @@ class CordaRPCOpsImplTest {
|
||||
require(stx.tx.inputs.isEmpty())
|
||||
require(stx.tx.outputs.size == 1)
|
||||
val signaturePubKeys = stx.sigs.map { it.by }.toSet()
|
||||
// Only Alice signed
|
||||
// Only Alice signed, as issuer
|
||||
val aliceKey = aliceNode.info.legalIdentity.owningKey
|
||||
require(signaturePubKeys.size <= aliceKey.keys.size)
|
||||
require(aliceKey.isFulfilledBy(signaturePubKeys))
|
||||
@ -194,7 +193,7 @@ class CordaRPCOpsImplTest {
|
||||
require(stx.tx.outputs.size == 1)
|
||||
val signaturePubKeys = stx.sigs.map { it.by }.toSet()
|
||||
// Alice and Notary signed
|
||||
require(aliceNode.info.legalIdentity.owningKey.isFulfilledBy(signaturePubKeys))
|
||||
require(aliceNode.services.keyManagementService.filterMyKeys(signaturePubKeys).toList().isNotEmpty())
|
||||
require(notaryNode.info.notaryIdentity.owningKey.isFulfilledBy(signaturePubKeys))
|
||||
}
|
||||
)
|
||||
|
@ -337,10 +337,10 @@ class FlowFrameworkTests {
|
||||
node1.services.startFlow(CashIssueFlow(
|
||||
2000.DOLLARS,
|
||||
OpaqueBytes.of(0x01),
|
||||
notary1.info.notaryIdentity))
|
||||
notary1.info.notaryIdentity)).resultFuture.getOrThrow()
|
||||
// We pay a couple of times, the notary picking should go round robin
|
||||
for (i in 1..3) {
|
||||
val flow = node1.services.startFlow(CashPaymentFlow(500.DOLLARS, node2.info.legalIdentity, anonymous = false))
|
||||
val flow = node1.services.startFlow(CashPaymentFlow(500.DOLLARS, node2.info.legalIdentity))
|
||||
mockNet.runNetwork()
|
||||
flow.resultFuture.getOrThrow()
|
||||
}
|
||||
|
@ -17,9 +17,8 @@ class BankOfCordaHttpAPITest {
|
||||
val bigCorpNodeFuture = startNode(providedName = BIGCORP_LEGAL_NAME)
|
||||
val nodeBankOfCordaFuture = startNode(providedName = BOC.name, advertisedServices = setOf(ServiceInfo(SimpleNotaryService.type)))
|
||||
val (nodeBankOfCorda) = listOf(nodeBankOfCordaFuture, bigCorpNodeFuture).map { it.getOrThrow() }
|
||||
val anonymous = false
|
||||
val nodeBankOfCordaApiAddr = startWebserver(nodeBankOfCorda).getOrThrow().listenAddress
|
||||
assertTrue(BankOfCordaClientApi(nodeBankOfCordaApiAddr).requestWebIssue(IssueRequestParams(1000, "USD", BIGCORP_LEGAL_NAME, "1", BOC.name, BOC.name, anonymous)))
|
||||
assertTrue(BankOfCordaClientApi(nodeBankOfCordaApiAddr).requestWebIssue(IssueRequestParams(1000, "USD", BIGCORP_LEGAL_NAME, "1", BOC.name, BOC.name)))
|
||||
}, isDebug = true)
|
||||
}
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ class BankOfCordaRPCClientTest {
|
||||
1000.DOLLARS, BIG_CORP_PARTY_REF,
|
||||
nodeBigCorporation.nodeInfo.legalIdentity,
|
||||
anonymous,
|
||||
nodeBankOfCorda.nodeInfo.notaryIdentity)
|
||||
nodeBankOfCorda.nodeInfo.notaryIdentity).returnValue.getOrThrow()
|
||||
|
||||
// Check Bank of Corda Vault Updates
|
||||
vaultUpdatesBoc.expectEvents {
|
||||
|
@ -55,8 +55,7 @@ private class BankOfCordaDriver {
|
||||
// The ISSUE_CASH will request some Cash from the ISSUER on behalf of Big Corporation node
|
||||
val role = options.valueOf(roleArg)!!
|
||||
|
||||
val anonymous = true
|
||||
val requestParams = IssueRequestParams(options.valueOf(quantity), options.valueOf(currency), BIGCORP_LEGAL_NAME, "1", BOC.name, DUMMY_NOTARY.name, anonymous)
|
||||
val requestParams = IssueRequestParams(options.valueOf(quantity), options.valueOf(currency), BIGCORP_LEGAL_NAME, "1", BOC.name, DUMMY_NOTARY.name)
|
||||
|
||||
try {
|
||||
when (role) {
|
||||
|
@ -46,9 +46,10 @@ class BankOfCordaClientApi(val hostAndPort: NetworkHostAndPort) {
|
||||
?: throw IllegalStateException("Unable to locate notary node in network map cache")
|
||||
|
||||
val amount = Amount(params.amount, Currency.getInstance(params.currency))
|
||||
val anonymous = true
|
||||
val issuerBankPartyRef = OpaqueBytes.of(params.issuerBankPartyRef.toByte())
|
||||
|
||||
return rpc.startFlow(::CashIssueAndPaymentFlow, amount, issuerBankPartyRef, issueToParty, params.anonymous, notaryNode.notaryIdentity)
|
||||
return rpc.startFlow(::CashIssueAndPaymentFlow, amount, issuerBankPartyRef, issueToParty, anonymous, notaryNode.notaryIdentity)
|
||||
.returnValue.getOrThrow().stx
|
||||
}
|
||||
}
|
||||
|
@ -20,8 +20,7 @@ class BankOfCordaWebApi(val rpc: CordaRPCOps) {
|
||||
data class IssueRequestParams(val amount: Long, val currency: String,
|
||||
val issueToPartyName: X500Name, val issuerBankPartyRef: String,
|
||||
val issuerBankName: X500Name,
|
||||
val notaryName: X500Name,
|
||||
val anonymous: Boolean)
|
||||
val notaryName: X500Name)
|
||||
|
||||
private companion object {
|
||||
val logger = loggerFor<BankOfCordaWebApi>()
|
||||
@ -51,12 +50,13 @@ class BankOfCordaWebApi(val rpc: CordaRPCOps) {
|
||||
?: return Response.status(Response.Status.FORBIDDEN).entity("Unable to locate $notaryParty in network map service").build()
|
||||
|
||||
val amount = Amount(params.amount, Currency.getInstance(params.currency))
|
||||
val anonymous = true
|
||||
val issuerBankPartyRef = OpaqueBytes.of(params.issuerBankPartyRef.toByte())
|
||||
|
||||
// invoke client side of Issuer Flow: IssuanceRequester
|
||||
// The line below blocks and waits for the future to resolve.
|
||||
return try {
|
||||
rpc.startFlow(::CashIssueAndPaymentFlow, amount, issuerBankPartyRef, issueToParty, params.anonymous, notaryNode.notaryIdentity).returnValue.getOrThrow()
|
||||
rpc.startFlow(::CashIssueAndPaymentFlow, amount, issuerBankPartyRef, issueToParty, anonymous, notaryNode.notaryIdentity).returnValue.getOrThrow()
|
||||
logger.info("Issue and payment request completed successfully: $params")
|
||||
Response.status(Response.Status.CREATED).build()
|
||||
} catch (e: Exception) {
|
||||
|
@ -56,7 +56,6 @@ class TraderDemoTest : NodeBasedTest() {
|
||||
val expectedBCash = clientB.cashCount + 1
|
||||
val expectedPaper = listOf(clientA.commercialPaperCount + 1, clientB.commercialPaperCount)
|
||||
|
||||
// TODO: Enable anonymisation
|
||||
clientBank.runIssuer(amount = 100.DOLLARS, buyerName = nodeA.info.legalIdentity.name, sellerName = nodeB.info.legalIdentity.name)
|
||||
clientB.runSeller(buyerName = nodeA.info.legalIdentity.name, amount = 5.DOLLARS)
|
||||
|
||||
|
@ -51,12 +51,11 @@ class TraderDemoClientApi(val rpc: CordaRPCOps) {
|
||||
val notaryNode = rpc.nodeIdentityFromParty(notaryLegalIdentity)
|
||||
?: throw IllegalStateException("Unable to locate notary node in network map cache")
|
||||
val amounts = calculateRandomlySizedAmounts(amount, 3, 10, Random())
|
||||
val anonymous = false
|
||||
rpc.startFlow(::CashIssueFlow, amount, OpaqueBytes.of(1), notaryNode.notaryIdentity).returnValue.getOrThrow()
|
||||
// Pay random amounts of currency up to the requested amount
|
||||
amounts.forEach { pennies ->
|
||||
// TODO This can't be done in parallel, perhaps due to soft-locking issues?
|
||||
rpc.startFlow(::CashPaymentFlow, amount.copy(quantity = pennies), buyer, anonymous).returnValue.getOrThrow()
|
||||
rpc.startFlow(::CashPaymentFlow, amount.copy(quantity = pennies), buyer).returnValue.getOrThrow()
|
||||
}
|
||||
println("Cash issued to buyer")
|
||||
|
||||
|
@ -149,8 +149,7 @@ class NewTransaction : Fragment() {
|
||||
dialogPane = root
|
||||
initOwner(window)
|
||||
setResultConverter {
|
||||
// TODO: Enable confidential identities
|
||||
val anonymous = false
|
||||
val anonymous = true
|
||||
val defaultRef = OpaqueBytes.of(1)
|
||||
val issueRef = if (issueRef.value != null) OpaqueBytes.of(issueRef.value) else defaultRef
|
||||
when (it) {
|
||||
|
@ -123,14 +123,13 @@ val crossCashTest = LoadTest<CrossCashCommand, CrossCashState>(
|
||||
|
||||
generate = { (nodeVaults), parallelism ->
|
||||
val nodeMap = simpleNodes.associateBy { it.info.legalIdentity }
|
||||
val anonymous = true
|
||||
Generator.pickN(parallelism, simpleNodes).flatMap { nodes ->
|
||||
Generator.sequence(
|
||||
nodes.map { node ->
|
||||
val quantities = nodeVaults[node.info.legalIdentity] ?: mapOf()
|
||||
val possibleRecipients = nodeMap.keys.toList()
|
||||
val moves = quantities.map {
|
||||
it.value.toDouble() / 1000 to generateMove(it.value, USD, node.info.legalIdentity, possibleRecipients, anonymous)
|
||||
it.value.toDouble() / 1000 to generateMove(it.value, USD, node.info.legalIdentity, possibleRecipients)
|
||||
}
|
||||
val exits = quantities.mapNotNull {
|
||||
if (it.key == node.info.legalIdentity) {
|
||||
@ -140,7 +139,7 @@ val crossCashTest = LoadTest<CrossCashCommand, CrossCashState>(
|
||||
}
|
||||
}
|
||||
val command = Generator.frequency(
|
||||
listOf(1.0 to generateIssue(10000, USD, notary.info.notaryIdentity, possibleRecipients, anonymous)) + moves + exits
|
||||
listOf(1.0 to generateIssue(10000, USD, notary.info.notaryIdentity, possibleRecipients)) + moves + exits
|
||||
)
|
||||
command.map { CrossCashCommand(it, nodeMap[node.info.legalIdentity]!!) }
|
||||
}
|
||||
|
@ -16,14 +16,13 @@ fun generateIssue(
|
||||
max: Long,
|
||||
currency: Currency,
|
||||
notary: Party,
|
||||
possibleRecipients: List<Party>,
|
||||
anonymous: Boolean
|
||||
possibleRecipients: List<Party>
|
||||
): Generator<IssueAndPaymentRequest> {
|
||||
return generateAmount(1, max, Generator.pure(currency)).combine(
|
||||
Generator.pure(OpaqueBytes.of(0)),
|
||||
Generator.pickOne(possibleRecipients)
|
||||
) { amount, ref, recipient ->
|
||||
IssueAndPaymentRequest(amount, ref, recipient, notary, anonymous)
|
||||
IssueAndPaymentRequest(amount, ref, recipient, notary, true)
|
||||
}
|
||||
}
|
||||
|
||||
@ -31,13 +30,12 @@ fun generateMove(
|
||||
max: Long,
|
||||
currency: Currency,
|
||||
issuer: Party,
|
||||
possibleRecipients: List<Party>,
|
||||
anonymous: Boolean
|
||||
possibleRecipients: List<Party>
|
||||
): Generator<PaymentRequest> {
|
||||
return generateAmount(1, max, Generator.pure(Issued(PartyAndReference(issuer, OpaqueBytes.of(0)), currency))).combine(
|
||||
Generator.pickOne(possibleRecipients)
|
||||
) { amount, recipient ->
|
||||
PaymentRequest(amount.withoutIssuer(), recipient, anonymous, setOf(issuer))
|
||||
PaymentRequest(amount.withoutIssuer(), recipient, true, setOf(issuer))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -38,7 +38,7 @@ val selfIssueTest = LoadTest<SelfIssueCommand, SelfIssueState>(
|
||||
|
||||
generate = { _, parallelism ->
|
||||
val generateIssue = Generator.pickOne(simpleNodes).flatMap { node ->
|
||||
generateIssue(1000, USD, notary.info.notaryIdentity, listOf(node.info.legalIdentity), anonymous = true).map {
|
||||
generateIssue(1000, USD, notary.info.notaryIdentity, listOf(node.info.legalIdentity)).map {
|
||||
SelfIssueCommand(it, node)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user