Corda节点为同一状态生成不同的线性ID

  • 本文关键字:线性 ID 状态 节点 Corda corda
  • 更新时间 :
  • 英文 :


嗨,我有一个实现线性状态的状态,参与者列表中有两方。作为覆盖线性id的一部分,我将字符串数据传递给UniqueIdentifier构造函数。以下是状态定义:

data class PurchaseOrderState(
val buyer: Party,
val seller: Party,
val props: PurchaseOrderProperties,
val invoiceAssigned: Boolean
):LinearState{
override val participants = listOf(buyer, seller)
override val linearId : UniqueIdentifier = UniqueIdentifier(props.purchaseOrderID)
}
@CordaSerializable
data class PurchaseOrderProperties(
val purchaseOrderID: String,
val invoiceStateReference: StateRef?
)   
}

下面是我的流程,它具有构建事务的逻辑:

object PurchaseOrderFlow {

@InitiatingFlow
@StartableByRPC
class SendPurchaseOrder(val purchaseOrderState: PurchaseOrderState) : FlowLogic<SignedTransaction>(){
companion object{
object CREATING_BUILDER : ProgressTracker.Step("Creating a Transaction builder for the Purchase Order transaction")
object ISSUING_PURCHASE_ORDER : ProgressTracker.Step("Creating and signing a new Purchase order")
object ADDING_STATES : ProgressTracker.Step("Adding Purchase order State in the transation output")
object ADDING_COMMAND : ProgressTracker.Step("Adding a Create Command in the transaction")
object VERIFIYING_TX : ProgressTracker.Step("Verifying the txn")
object SIGNING_TX : ProgressTracker.Step("Signing the transaction")
object SENDING_TX : ProgressTracker.Step("Sending and committing the transaction")
fun tracker() = ProgressTracker(CREATING_BUILDER, ISSUING_PURCHASE_ORDER, ADDING_STATES, ADDING_COMMAND, SIGNING_TX, VERIFIYING_TX, SENDING_TX  )
}
override val progressTracker: ProgressTracker = tracker()
@Suspendable
override fun call(): SignedTransaction {
val notary = serviceHub.networkMapCache.notaryIdentities.first()
progressTracker.currentStep = CREATING_BUILDER
val buider = TransactionBuilder(notary)
buider.setTimeWindow(Instant.now(), Duration.ofSeconds(60))
progressTracker.currentStep = ISSUING_PURCHASE_ORDER
buider.addOutputState(purchaseOrderState, PurchaseOrderContract.PO_CONTRACT_ID)
logger.info("Linerid in PO"+" "+purchaseOrderState.linearId)
progressTracker.currentStep = ADDING_COMMAND
val command = Command(PurchaseOrderContract.Commands.Create(), listOf(purchaseOrderState.buyer.owningKey))
buider.addCommand(command)
// buider.addAttachment(purchaseOrderState.props.purchaseOrderAttachmentHash)
progressTracker.currentStep = VERIFIYING_TX
buider.verify(serviceHub)
progressTracker.currentStep = SIGNING_TX
val stx = serviceHub.signInitialTransaction(buider)
progressTracker.currentStep = SENDING_TX
return subFlow(FinalityFlow(stx))
}
}

}

以下是流程测试代码:

class PurchaseOrderFlowTests {
lateinit var network: MockNetwork
lateinit var a: StartedMockNode
lateinit var b: StartedMockNode
@Before
fun setup() {
network = MockNetwork(listOf("com.example.contract"))
a = network.createPartyNode()
b = network.createPartyNode()
// For real nodes this happens automatically, but we have to manually register the flow for tests.
// listOf(a, b).forEach{ it.registerInitiatedFlow(PurchaseOrderFlow.SendPurcahseOrder::class.java)}
network.runNetwork()
}
@After
fun tearDown() {
network.stopNodes()
}
@Test
fun `Create a puchase Order`() {
val importerCompany = TradeFinanceDataStructures.Company("Importer", "India", null, null)
val exporterCompany = TradeFinanceDataStructures.Company("Exporter", "EU", null, null)
val props = PurchaseOrderProperties("abcdefg", importerCompany, exporterCompany, LocalDate.of(2018, 5, 15), SecureHash.randomSHA256(), null, listOf(TradeFinanceDataStructures.Item("LedTv", "45424", "Led Tv by LG India", "gms", 5, 15000.0, 60000.0)))
val postate = PurchaseOrderState(a.services.myInfo.singleIdentity(), b.services.myInfo.singleIdentity(), props, false)
val flow = PurchaseOrderFlow.SendPurchaseOrder(postate)
val future = a.startFlow(flow)
network.runNetwork()
val signedTx = future.getOrThrow()
signedTx.verifySignaturesExcept(b.info.singleIdentity().owningKey)
listOf(a, b).forEach { node ->
val locStates = node.transaction {
print(node.services.vaultService.queryBy<PurchaseOrderState>().states.single().state.data.linearId) // **this was different on both the nodes**
}
}
}

在运行上述流程的单元测试后,我注意到两个节点在同一状态下具有不同的线性 id。上面的代码有什么问题吗?我正在使用 corda 版本 3.1

UniqueIdentifier具有以下构造函数:

data class UniqueIdentifier(
val externalId: String? = null, 
val id: UUID = UUID.randomUUID()
)

NodeA序列化一个PurchaseOrderState并将其发送到NodeB时,NodeB使用状态的构造函数重建状态。它使用以下逻辑重新创建状态的linearId属性:

override val linearId : UniqueIdentifier = 
UniqueIdentifier(props.purchaseOrderID)

由于未传递第二个构造函数字段,因此它默认为随机UUID。因此,两个节点将看到不同的UniqueIdentifier,尽管externalId相同。

若要避免这种情况,应将linearId传递到构造函数中,如下所示:

data class PurchaseOrderState(
val buyer: Party,
val seller: Party,
val props: PurchaseOrderProperties,
val invoiceAssigned: Boolean,
override val linearId : UniqueIdentifier = UniqueIdentifier(props.purchaseOrderID)): LinearState {

最新更新