CorDapp使用Linearstate演示CompositeKey用法:Flow抛出异常“无法找到匿名派对(DLDHEGSYz ...)”

时间:2018-06-19 08:52:37

标签: corda

我正在尝试使用复合键功能来显示如何使用复合键控制分类帐上的资产。我的流程代码中出现以下错误:

java.lang.IllegalArgumentException: Could not find Party for Anonymous(DLHpGSdYSvv7vLRGJuuZSsTWQpk7ehkB7B1K1bzV68YmY7)

at net.corda.core.identity.IdentityUtils.groupAbstractPartyByWellKnownParty(IdentityUtils.kt:47)
at net.corda.core.identity.IdentityUtils.groupAbstractPartyByWellKnownParty(IdentityUtils.kt:63)
at net.corda.core.flows.FinalityFlow.getPartiesToSend(FinalityFlow.kt:96)
at net.corda.core.flows.FinalityFlow.call(FinalityFlow.kt:54)
at net.corda.core.flows.FinalityFlow.call(FinalityFlow.kt:28)
at net.corda.core.flows.FlowLogic.subFlow(FlowLogic.kt:290)
at com.example.flow.ExampleFlow$Initiator.call(ExampleFlow.kt:102)
at com.example.flow.ExampleFlow$Initiator.call(ExampleFlow.kt:34)

以下是我的州定义

data class LandState(val alice: Party, val bob: Party, override val linearId: UniqueIdentifier = UniqueIdentifier()): LinearState{

val owner: AbstractParty = AnonymousParty (CompositeKey.Builder().addKeys(alice.owningKey, bob.owningKey).build())
override val participants: List<AbstractParty> = listOf(owner)}

以下是我的合同代码

 override fun verify(tx: LedgerTransaction) {
    val command = tx.commands.requireSingleCommand<Commands.Create>()
    requireThat {

        "No inputs should be consumed when issuing an IOU." using (tx.inputs.isEmpty())
        "Only one output state should be created." using (tx.outputs.size == 1)
        val out = tx.outputsOfType<LandState>().single()
        "Command must be signed by the Composite key holder" using (command.signers.contains(out.owner.owningKey))


    }
}

以下是我的流程

object ExampleFlow {
@InitiatingFlow
@StartableByRPC
class Initiator( val alice: Party,
                val bob: Party) : FlowLogic<SignedTransaction>() {
    /**
     * The progress tracker checkpoints each stage of the flow and outputs the specified messages when each
     * checkpoint is reached in the code. See the 'progressTracker.currentStep' expressions within the call() function.
     */
    companion object {
        object GENERATING_TRANSACTION : Step("Generating transaction based on new IOU.")
        object VERIFYING_TRANSACTION : Step("Verifying contract constraints.")
        object SIGNING_TRANSACTION : Step("Signing transaction with our private key.")
        object GATHERING_SIGS : Step("Gathering the counterparty's signature.") {
            override fun childProgressTracker() = CollectSignaturesFlow.tracker()
        }

        object FINALISING_TRANSACTION : Step("Obtaining notary signature and recording transaction.") {
            override fun childProgressTracker() = FinalityFlow.tracker()
        }

        fun tracker() = ProgressTracker(
                GENERATING_TRANSACTION,
                VERIFYING_TRANSACTION,
                SIGNING_TRANSACTION,
                GATHERING_SIGS,
                FINALISING_TRANSACTION
        )
    }

    override val progressTracker = tracker()

    /**
     * The flow logic is encapsulated within the call() method.
     */
    @Suspendable
    override fun call(): SignedTransaction {
        // Obtain a reference to the notary we want to use.
        val notary = serviceHub.networkMapCache.notaryIdentities[0]

        // Stage 1.
        progressTracker.currentStep = GENERATING_TRANSACTION
        // Generate an unsigned transaction.
        val landState = LandState(alice, bob)
       // val iouState = IOUState(iouValue, serviceHub.myInfo.legalIdentities.first(), otherParty)

        val txCommand = Command(IOUContract.Commands.Create(), listOf(landState.owner.owningKey))
        val txBuilder = TransactionBuilder(notary)
                .addOutputState(landState, IOU_CONTRACT_ID)
                .addCommand(txCommand)

        // Stage 2.
        progressTracker.currentStep = VERIFYING_TRANSACTION
        // Verify that the transaction is valid.

        // Stage 3.
        progressTracker.currentStep = SIGNING_TRANSACTION
        // Sign the transaction.
        val partSignedTx = serviceHub.signInitialTransaction(txBuilder)

        // Stage 4.
        progressTracker.currentStep = GATHERING_SIGS
        // Send the state to the counterparty, and receive it back with their signature.
        val otherPartyFlow = initiateFlow(bob)
        val fullySignedTx = subFlow(CollectSignaturesFlow(partSignedTx, setOf(otherPartyFlow), GATHERING_SIGS.childProgressTracker()))

        txBuilder.verify(serviceHub)

        // Stage 5.
        progressTracker.currentStep = FINALISING_TRANSACTION
        // Notarise and record the transaction in both parties' vaults.
        return subFlow(FinalityFlow(fullySignedTx))
    }
}

@InitiatedBy(Initiator::class)
class Acceptor(val otherPartyFlow: FlowSession) : FlowLogic<SignedTransaction>() {
    @Suspendable
    override fun call(): SignedTransaction {
        val signTransactionFlow = object : SignTransactionFlow(otherPartyFlow) {
            override fun checkTransaction(stx: SignedTransaction) = requireThat {

            }
        }

        return subFlow(signTransactionFlow)
    }
}}

我错过了什么吗?上述状态中的owner字段的类型为AnonymousParty,因为复合键的类型为public key,而不是众所周知的证书。

1 个答案:

答案 0 :(得分:1)

您不能将CollectSignaturesFlowCompositeKey一起使用。您需要定义自己的自定义流程以收集所需的签名。

为什么?因为CollectSignaturesFlow可以根据命令中列出的各方来确定谁向谁请求签名。由于CompositeKey与特定方不对应,因此该节点不知道向谁请求签名并引发异常。