第三方 签名服务_在只有一部分交易方是签名方的情况下保存交易

第三方 签名服务

我花了一段时间才想到一个标题,该标题可以概述本帖子的内容,而不会成为完整的句子。 我想我已经选择了清晰易读的东西。 无论哪种方式,让我澄清一下我实际上在说什么。

我已经看到几个人在Slack中提出类似以下的问题:

在该示例中,它显示了当运行响应者流的节点是必需签名者之一时的响应者流。 但是,当运行响应者流的节点不是必需的签名者(例如,与tx有关的状态的参与者之一)时,情况又如何呢? 我是否需要为此类节点编写响应者流程? 如果是这样,我应该如何编写响应者流程?

换一种说法:

我的州有一组参与者。 其中有些必须签署交易,有些则不能。 如何构造我的流程,尤其是响应者流程以应对呢?

由于响应者流程的工作方式,每个交易对手都在其中运行相同的响应者代码(除非被覆盖)。 样本中找到的简单代码无法处理让一组交易方做某事,而另一方做其他事。 需要构造您的流程以明确处理此问题。

执行此操作的代码相对简单,但是除非您已经使用Corda进行了一段时间的开发,否则它可能并不明显。

到目前为止,我对此问题有两种解决方案。 我很确定这些是当前可用的最佳解决方案,并且我想不出任何其他可行或值得追求的解决方案。 这些解决方案是:

  • 向交易对手发送标志以告知他们是否为签名人
  • 使用子流的@InitiatingFlow收集签名或保存交易

我将在以下各节中进行扩展。

在我接触他们之前,如果您不考虑签署人和参与者之间的差异,会发生什么? 典型的响应者流程将包括:

 @InitiatedBy (SendMessageFlow:: class )  class SendMessageResponder( private val session: FlowSession) : FlowLogic() { 
   @Suspendable 
   override fun call(): SignedTransaction { 
     subFlow(object : SignTransactionFlow(session) { 
       override fun checkTransaction(stx: SignedTransaction) { } 
     }) 
     return subFlow(ReceiveFinalityFlow(otherSideSession = session)) 
   }  } 

如果启动流触发此响应者进行非签名交易对手,则会发生错误:

 net.corda.core.flows.UnexpectedFlowEndException: Tried to access ended session SessionId(toLong= ) with empty buffer net.corda.core.flows.UnexpectedFlowEndException: Tried to access ended session SessionId(toLong= 3446769309292325575 net.corda.core.flows.UnexpectedFlowEndException: Tried to access ended session SessionId(toLong= 3446769309292325575 ) with empty buffer 
     at net.corda.node.services.statemachine.FlowStateMachineImpl.processEventsUntilFlowIsResumed(FlowStateMachineImpl.kt: 161 ) ~[corda-node- 4.0 .jar:?] 
     at net.corda.node.services.statemachine.FlowStateMachineImpl.suspend(FlowStateMachineImpl.kt: 407 ) ~[corda-node- 4.0 .jar:?] 
     at net.corda.node.services.statemachine.FlowSessionImpl.receive(FlowSessionImpl.kt: 67 ) ~[corda-node- 4.0 .jar:?] 
     at net.corda.node.services.statemachine.FlowSessionImpl.receive(FlowSessionImpl.kt: 71 ) ~[corda-node- 4.0 .jar:?] 
     at net.corda.core.flows.SignTransactionFlow.call(CollectSignaturesFlow.kt: 294 ) ~[corda-core- 4.0 .jar:?] 
     at net.corda.core.flows.SignTransactionFlow.call(CollectSignaturesFlow.kt: 198 ) ~[corda-core- 4.0 .jar:?] 
     at net.corda.node.services.statemachine.FlowStateMachineImpl.subFlow(FlowStateMachineImpl.kt: 290 ) ~[corda-node- 4.0 .jar:?] 
     at net.corda.core.flows.FlowLogic.subFlow(FlowLogic.kt: 314 ) ~[corda-core- 4.0 .jar:?] 
     at dev.lankydan.tutorial.flows.SendMessageResponder.call(SendMessageFlow.kt: 70 ) ~[main/:?] 
     at dev.lankydan.tutorial.flows.SendMessageResponder.call(SendMessageFlow.kt: 64 ) ~[main/:?] 

这是因为非签名者从未发送过交易以进行签名,但是,可惜的是,他们的代码正坐在那里等待对永远不会发生的交易进行签名。 多么难过。 我在这里是为了防止您的交易对手在这里感到悲伤。

这也是一个很好的教学时刻。 如果你看到类似上面的堆栈跟踪,这是最有可能是由于错放send S和receive秒。 它们的顺序错误,或者sendreceive丢失。 逐行运行代码,您应该应该能够查明不匹配的位置。

按标志区分

这种解决方案是我首先想到的,因为它更容易理解。

通知交易对手,告诉他们是否需要签署交易。 然后,他们的响应者流将执行SignTransactionFlow或跳过它,直接进入ReceiveFinalityFlow 。 这两个路径将始终接收该标志并调用ReceiveFinalityFlow

可以在下面找到一个示例:

 @InitiatingFlow  class SendMessageFlow( private val message: MessageState) : 
   FlowLogic() { 
   @Suspendable 
   override fun call(): SignedTransaction { 
     val spy = serviceHub.identityService.partiesFromName( "Spy" , false ).first() 
     val tx = verifyAndSign(transaction(spy)) 
     // initiate sessions with each party 
     val signingSession = initiateFlow(message.recipient) 
     val spySession = initiateFlow(spy) 
     // send signing flags to counterparties 
     signingSession.send( true ) 
     spySession.send( false ) 
     val stx = collectSignature(tx, listOf(signingSession)) 
     // tell everyone to save the transaction 
     return subFlow(FinalityFlow(stx, listOf(signingSession, spySession)) 
   } 
   private fun transaction(spy: Party) = 
     TransactionBuilder(notary()).apply { 
       // the spy is added to the messages participants 
       val spiedOnMessage = message.copy(participants = message.participants + spy) 
       addOutputState(spiedOnMessage, MessageContract.CONTRACT_ID) 
       addCommand(Command(Send(), listOf(message.recipient, message.sender).map(Party::owningKey))) 
     }  }  @InitiatedBy (SendMessageFlow:: class )  class SendMessageResponder( private val session: FlowSession) : FlowLogic() { 
   @Suspendable 
   override fun call(): SignedTransaction { 
     // receive the flag 
     val needsToSignTransaction = session.receive().unwrap { it } 
     // only sign if instructed to do so 
     if (needsToSignTransaction) { 
       subFlow(object : SignTransactionFlow(session) { 
         override fun checkTransaction(stx: SignedTransaction) { } 
       }) 
     } 
     // always save the transaction 
     return subFlow(ReceiveFinalityFlow(otherSideSession = session)) 
   }  } 

上面代码的重点:

  • spy (另一方)已添加到该州的participants列表中
  • 将标志发送给参与者,告诉他们是否签名
  • 响应者流receive s标志,如果告知,则跳过SignTransactionFlow
  • 调用ReceiveFinalityFlow ,等待启动程序调用FinalityFlow

我将在这里留下解释,因为没有太多要说的了。

通过额外的启动流程来分离逻辑

由于不同流相互混合而导致的间接性,因此该解决方案会涉及更多的内容。 在进行任何解释之前,确实需要阅读此解决方案:

 @InitiatingFlow  @StartableByRPC  class SendMessageWithExtraInitiatingFlowFlow( private val message: MessageState) : 
   FlowLogic() { 
   @Suspendable 
   override fun call(): SignedTransaction { 
     logger.info( "Started sending message ${message.contents}" ) 
     val spy = serviceHub.identityService.partiesFromName( "Spy" , false ).first() 
     val tx = verifyAndSign(transaction(spy)) 
     // collect signatures from the signer in a new session 
     val stx = subFlow(CollectSignaturesInitiatingFlow(tx, listOf(message.recipient))) 
     // initiate new sessions for all parties 
     val sessions = listOf(message.recipient, spy).map { initiateFlow(it) } 
     // tell everyone to save the transaction 
     return subFlow(FinalityFlow(stx, sessions)) 
   } 
   private fun transaction(spy: Party) = 
     TransactionBuilder(notary()).apply { 
       // the spy is added to the messages participants 
       val spiedOnMessage = message.copy(participants = message.participants + spy) 
       addOutputState(spiedOnMessage, MessageContract.CONTRACT_ID) 
       addCommand(Command(Send(), listOf(message.recipient, message.sender).map(Party::owningKey))) 
     }  }  @InitiatedBy (SendMessageWithExtraInitiatingFlowFlow:: class )  class SendMessageWithExtraInitiatingFlowResponder( private val session: FlowSession) : FlowLogic() { 
   @Suspendable 
   override fun call(): SignedTransaction { 
     // save the transaction and nothing else 
     return subFlow(ReceiveFinalityFlow(otherSideSession = session)) 
   }  }  @InitiatingFlow  class CollectSignaturesInitiatingFlow( 
   private val transaction: SignedTransaction, 
   private val signers: List  ) : FlowLogic() { 
   @Suspendable 
   override fun call(): SignedTransaction { 
     // create new sessions to signers and trigger the signing responder flow 
     val sessions = signers.map { initiateFlow(it) } 
     return subFlow(CollectSignaturesFlow(transaction, sessions)) 
   }  }  @InitiatedBy (CollectSignaturesInitiatingFlow:: class )  class CollectSignaturesResponder( private val session: FlowSession) : FlowLogic() { 
   @Suspendable 
   override fun call(): SignedTransaction { 
     // sign the transaction and nothing else 
     return subFlow(object : SignTransactionFlow(session) { 
       override fun checkTransaction(stx: SignedTransaction) { } 
     }) 
   }  } 

上面的代码流如下:

  • spy (另一方)已添加到该州的participants列表中
  • 通过调用CollectSignaturesInitiatingFlow收集签名者的签名
  • CollectSignaturesInitiatingFlow创建一个新会话并调用CollectSignaturesFlow
  • CollectSignaturesResponderCollectSignaturesInitiatingFlow发送的交易进行CollectSignaturesInitiatingFlow
  • 为每个参与者发起更多会话
  • 调用FinalityFlow会触发链接到原始/顶级流的SendMessageWithExtraInitiatingFlowResponder

上面的代码基于以下事实:使用@InitiatingFlow注释的任何流@InitiatingFlow将被路由到其@InitiatedBy合作伙伴,并且是在新会话中完成的 。 利用此功能,可以添加仅针对必需签名者触发的响应者流程。 仍为顶级流( SendMessageWithExtraInitiatingFlowFlow )创建会话,并在FinalityFlow中使用该FinalityFlow

幕后还发生了其他一些事情,但是本文不需要这些内容。

哪个更好?

目前很难说。 我将不得不做一些性能测试,然后再处理一些代码……

我目前的看法是, 额外的启动流程效果更好。 它消除了从发起方到每个交易对手的跨网络额外行程的需要。 它添加了一些附加的样板代码,但也从其余的响应者/交易方代码中提取了签名逻辑。

老实说,正如我在一分钟前说的那样,我真的需要使用它并提出更复杂的用例,然后才能给出一个好的答案。 我怀疑我是否会解决这个问题……;

结论

无论您选择哪条路线,或者即使您想出另一条路线,也可以在Corda中100%完成保存交易的交易,其中只有一部分交易方是签名人。 如果这不可能,我将非常失望。 只要你有一个过程以改变响应逻辑流程来处理不同的send S和receive s表示签约和非签约各方需要。 你应该很好。

如果您喜欢这篇文章或发现它有帮助(或两者都有),请随时在Twitter上@LankyDanDev关注我,并记住与可能对您有用的任何人分享!

翻译自: https://www.javacodegeeks.com/2019/08/saving-transactions-subset-parties-signers.html

第三方 签名服务

你可能感兴趣的:(python,java,区块链,设计模式,linux)