在Corda中,交易所需的签名者可以是CompositeKey
而不是常规的公共密钥。如何创建CompositeKey
并使其成为交易中必需的签名者?以及如何收集相应的签名?
答案 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)
}