在Corda中,如何使用“ CompositeKey”作为必需的签名者?

时间:2018-08-15 16:25:52

标签: corda

在Corda中,交易所需的签名者可以是CompositeKey而不是常规的公共密钥。如何创建CompositeKey并使其成为交易中必需的签名者?以及如何收集相应的签名?

1 个答案:

答案 0 :(得分:1)

以下是创建CompositeKey,使其成为交易中必需的签名者并收集相应签名的流程:

object OurFlow {
    @InitiatingFlow
    @StartableByRPC
    class Initiator(val otherPartyA: Party, val otherPartyB: Party) : FlowLogic<Unit>() {

        @Suspendable
        override fun call() {
            // We create a composite key that requires signatures from ourselves
            // and one of the other parties (each weight is one and the threshold is 2)
            val compositeKey = CompositeKey.Builder()
                    .addKey(ourIdentity.owningKey, weight = 1)
                    .addKey(otherPartyA.owningKey, weight = 1)
                    .addKey(otherPartyB.owningKey, weight = 1)
                    .build(2)

            // We make the `CompositeKey` the required signer.
            val txBuilder = TransactionBuilder(serviceHub.networkMapCache.notaryIdentities[0])
                    .addCommand(OurContract.Commands.Create(), compositeKey)
                    .addOutputState(OurState(ourIdentity, otherPartyA, otherPartyB), OurContract.ID)

            val partStx = serviceHub.signInitialTransaction(txBuilder)

            // We gather the signatures. Note that we cannot use
            // `CollectSignaturesFlow` because:
            // * The `CompositeKey` does not correspond to a specific
            //   counterparty
            // * The counterparty may refuse to sign
            val sessions = listOf(otherPartyA, otherPartyB).map { initiateFlow(it) }
            // We filter out any responses that are not
            // `TransactionSignature`s (i.e. refusals to sign).
            val signatures = sessions
                    .map { it.sendAndReceive<Any>(partStx).unwrap { it } }
                    .filter { it is TransactionSignature }
                    as List<TransactionSignature>
            val fullStx = partStx.withAdditionalSignatures(signatures)

            subFlow(FinalityFlow(fullStx))
        }
    }

    @InitiatedBy(Initiator::class)
    class Acceptor(val otherPartySession: FlowSession) : FlowLogic<Unit>() {
        @Suspendable
        override fun call() {
            otherPartySession.receive<SignedTransaction>().unwrap { partStx ->
                // We return either a `TransactionSignature` (if we're willing
                // to sign) or `false`.
                val payload = if (CONDITION) {
                    serviceHub.createSignature(partStx)
                } else {
                    false
                }

                otherPartySession.send(payload)
            }
        }
    }
}

以下是合同,该合同断言所需的签署者为CompositeKey,并且具有两个和三个权重为1的子级的阈值,对应于交易输出状态中列出的各方:

class OurContract : Contract {
    companion object {
        @JvmStatic
        val ID = "com.example.contract.OurContract"
    }

    override fun verify(tx: LedgerTransaction) {
        requireThat {
            val command = tx.commands.requireSingleCommand<Commands.Create>()
            "There is only one required signer." using (command.signers.size == 1)
            "The required signer is a CompositeKey." using (command.signers[0] is CompositeKey)
            val signer = command.signers[0] as CompositeKey
            "There are only three nodes and weights." using (signer.children.size == 3)
            "The threshold is two." using (signer.threshold == 2)
            "There is only one output." using (tx.outputStates.size == 1)
            "The output is of type OurState." using (tx.outputsOfType<OurState>().size == 1)
            val output = tx.outRefsOfType<OurState>().single().state.data
            val expectedNodesAndWeights = listOf(output.partyA, output.partyB, output.partyC).map {
                CompositeKey.NodeAndWeight(it.owningKey, 1)
            }
            "All three parties are children with weight 1." using (signer.children.containsAll(expectedNodesAndWeights))
        }
    }

    interface Commands : CommandData {
        class Create : Commands
    }
}

最后,这是我们的状态定义:

class OurState(val partyA: Party, val partyB: Party, val partyC: Party) : ContractState {
    override val participants = listOf(partyA, partyB, partyC)
}