我正在制作一个涉及两方的CorDapp-客户和保险人。我有两个主要流程,一个是IssuePolicy,另一个是PayoutPolicy。当我运行每个流程一次时,没有任何问题。当我再次运行IssuePolicy时,收到错误消息:The Initiator of CollectSignaturesFlow must pass in exactly the sessions required to sign the transaction.
我已经搜索了Stack Overflow并找到了该帖子:Flow Exception in CollectSignaturesFlow,但我相信我已经与一方签约并发起了与另一方的交流,所以我不确定该解决方案是否适用于我。任何帮助将不胜感激!
问题政策流程:
// Step 3. Building.
progressTracker.currentStep = BUILDING
val notary = serviceHub.networkMapCache.notaryIdentities[0]
val utx = TransactionBuilder(notary = notary)
.addOutputState(policy, INSUREFLIGHT_CONTRACT_ID)
.addCommand(InsureFlightContract.Commands.Issue(), policy.participants.map { it.owningKey })
.setTimeWindow(serviceHub.clock.instant(), 30.seconds)
// Stage 4. Get some cash from the vault and add a spend to our transaction builder.
// We pay cash to the underwriter's policy key.
val (_, cashSigningKeys) = Cash.generateSpend(serviceHub, utx, premium, underwriter)
check(cashSigningKeys == cashSigningKeys){
throw FlowException("")
}
// Step 5. Sign the transaction.
progressTracker.currentStep = SIGNING
val ptx = serviceHub.signInitialTransaction(utx, policy.client.owningKey)
// Step 6. Get the counter-party signature.
progressTracker.currentStep = COLLECTING
val otherpartySession = initiateFlow(underwriter)
val stx = subFlow(CollectSignaturesFlow(
ptx,
listOf(otherpartySession),
COLLECTING.childProgressTracker())
)
// Step 7. Finalize the transaction.
progressTracker.currentStep = FINALIZING
return subFlow(FinalityFlow(stx, FINALIZING.childProgressTracker()))
}
}
// Allows counterparty to respond.
@InitiatedBy(Initiator::class)
class IssuePolicyResponder(val otherPartySession: FlowSession) : FlowLogic<Unit>() {
@Suspendable
override fun call() {
val signTransactionFlow = object : SignTransactionFlow(otherPartySession, SignTransactionFlow.tracker()) {
override fun checkTransaction(stx: SignedTransaction) = requireThat {
}
}
subFlow(signTransactionFlow)
}
}
}
政策状态定义:
//Policy Class, includes premium, claim, client, underwriter, flight, and policyID
data class Policy(val premium: Amount<Currency>,
val claim: Amount<Currency>,
val client: Party,
val underwriter: Party,
val flight: String,
override val linearId: UniqueIdentifier = UniqueIdentifier()) : LinearState {
//Get clients and underwriters
override val participants: List<Party> get() = listOf(client, underwriter)
//Functions to update policy parameters
fun payPremium(amountToPay: Amount<Currency>) = copy(premium = premium + amountToPay)
fun payClaim(amountToPay: Amount<Currency>) = copy(claim = claim + amountToPay)
fun withNewClient(newClient: Party) = copy(client = newClient)
fun withNewUnderwriter(newUnderwriter: Party) = copy(underwriter = newUnderwriter)
fun withNewFlight(newFlight: String) = copy(flight = newFlight)
//Provides response
override fun toString(): String {
val clientString = (client as? Party)?.name?.organisation ?: client.owningKey.toBase58String()
val underwriterString = (underwriter as? Party)?.name?.organisation ?: underwriter.owningKey.toBase58String()
return "Policy($linearId): $clientString has paid a premium of $$premium for flight $flight, underwritten by $underwriterString with" +
"a claim amount of $$claim."
}
}
合同中的命令:
interface Commands : CommandData {
class Issue : TypeOnlyCommandData(), Commands
class Settle : TypeOnlyCommandData(), Commands
}
override fun verify(tx: LedgerTransaction): Unit {
val command = tx.commands.requireSingleCommand<Commands>()
val setOfSigners = command.signers.toSet()
when (command.value) {
is Commands.Issue -> verifyIssue(tx, setOfSigners)
is Commands.Settle -> verifySettle(tx, setOfSigners)
else -> throw IllegalArgumentException("Unrecognized command. You can only issue or settle.")
}
}
答案 0 :(得分:3)
并非您节点的保管库中的所有现金都将由您节点的主公钥拥有。这是因为当Cash.generateSpend
生成更改输出时,出于隐私原因,此更改将分配给新的机密身份而不是您节点的主要身份。
这是cashSigningKeys
返回的Cash.generateSpend
的目的。这是拥有Cash.generateSpend
添加到交易生成器中的所有现金的公共密钥的列表。
我猜您第一次运行IssuePolicy
/ PayoutPolicy
时,它会产生一些由新机密身份拥有的现金。您永远不会使用新的机密身份的密钥签署交易。实际上,当您致电CollectSignaturesFlow
时,正是这个机密身份的会话丢失了。
当然,使用此机密身份创建会话是没有意义的,因为它实际上对应于运行流的节点。相反,您需要使用cashSigningKeys
返回的Cash.generateSpend
,并在调用CollectSignaturesFlow
之前通过以下方法用它们对事务进行签名:
val ptx = serviceHub.signInitialTransaction(
utx,
cashSigningKeys + policy.client.owningKey)