Maka
Maka

Reputation: 357

Observer node with confidential identities

I've started making some tests with the Observer node (https://docs.corda.net/tutorial-observer-nodes.html), and I just built the following simple scenario:

  1. Regulator issues 10.POUNDS to Bank A (CashIssueAndPaymentFlow)
  2. Bank A sends 4.POUNDS to Bank B using confidential identities (CashPaymentFlow, anonymous=true)
  3. In a subflow, Bank A syncs identities (IdentitySyncFlow) and reports the transaction (SendTransactionFlow) to the Regulator

When I query the Regulator vault, it can't identify Bank B as the owner of the 4.POUNDS, that is, it cannot resolve the identity using wellKnownPartyFromAnonymous():

6.00 GBP, owner=C=BR,L=Sao Paulo,O=BankA
4.00 GBP, owner=Anonymous(DLEg4Kqd7dwcGqkMrJEWoxugT61SoYKzxqpcMBKbMGXu3q)

Maybe I'm missing something?

Follow the code:

object TransferCashFlow {

    @InitiatingFlow
    @StartableByRPC
    class Initiator(val amount: Amount<Currency>, val otherParty: Party, val regulator: Party) : FlowLogic<SignedTransaction>() {

            @Suspendable
            override fun call(): SignedTransaction {
                val tx = subFlow(CashPaymentFlow(amount, otherParty, true)).stx
                subFlow(ReportFlow.Initiator(regulator, tx))
                return tx
            }
    }
}

object ReportFlow {

    @InitiatingFlow
    class Initiator(val regulator: Party, val tx: SignedTransaction) : FlowLogic<Unit>() {

        @Suspendable
        override fun call() {

            val regulatorSession = initiateFlow(regulator)
            subFlow(IdentitySyncFlow.Send(regulatorSession, tx.tx))
            subFlow(SendTransactionFlow(regulatorSession, tx))
        }
    }

    @InitiatedBy(Initiator::class)
    class Responder(private val otherPartySession: FlowSession) : FlowLogic<Unit>() {
        @Suspendable
        override fun call() {

            subFlow(IdentitySyncFlow.Receive(otherPartySession))
            subFlow(ReceiveTransactionFlow(otherPartySession, true, StatesToRecord.ALL_VISIBLE))
        }
    }
}

Upvotes: 2

Views: 261

Answers (1)

Joel
Joel

Reputation: 23140

By design, IdentitySyncFlow.Send will only send across the certificates for the confidential identities in the transaction that belong to the sending node. See the definition of extractOurConfidentialIdentities() in IdentitySyncFlow:

private fun extractOurConfidentialIdentities(): Map<AbstractParty, PartyAndCertificate?> {
    val states: List<ContractState> = (tx.inputs.map { serviceHub.loadState(it) }.requireNoNulls().map { it.data } + tx.outputs.map { it.data })
    val identities: Set<AbstractParty> = states.flatMap(ContractState::participants).toSet()
    // Filter participants down to the set of those not in the network map (are not well known)
    val confidentialIdentities = identities
        .filter { serviceHub.networkMapCache.getNodesByLegalIdentityKey(it.owningKey).isEmpty() }
        .toList()
    return confidentialIdentities
        .map { Pair(it, serviceHub.identityService.certificateFromKey(it.owningKey)) }
        // Filter down to confidential identities of our well known identity
        // TODO: Consider if this too restrictive - we perhaps should be checking the name on the signing certificate in the certificate path instead
        .filter { it.second?.name == ourIdentity.name }
        .toMap()
}

The penultimate line ensures that the node doesn't send any identity certificates that aren't its own. This is to prevent a node tricking a counterparty into sending it a bunch of confidential identities.

If you wanted to send all the confidential identities, you'd have to define your own flow, based on IdentitySyncFlow, which doesn't perform this filtering.

Upvotes: 2

Related Questions