【问题标题】:Corda nodes generating different linear ids for the same stateCorda 节点为同一状态生成不同的线性 ID
【发布时间】:2018-05-15 14:53:46
【问题描述】:

您好,我有一个实施 LinearState 的状态,参与者列表中有两方。作为覆盖 linearid 的一部分,我将字符串数据传递给 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版

【问题讨论】:

  • 两个节点的输出:nodeA->abcdefg_e7ed6e2c-7fd0-4b8d-8da6-4c82d63b4aa5 nodeB->abcdefg_63502423-60e0-4973-8036-4af8bf6655ba
  • 已解决。在 PurchaseOrderState 类的构造函数中移动覆盖 val linearId : UniqueIdentifier = UniqueIdentifier(props.purchaseOrderID)。

标签: corda


【解决方案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。因此,这两个节点将看到不同的UniqueIdentifiers,尽管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 {

【讨论】:

    猜你喜欢
    • 2019-11-05
    • 1970-01-01
    • 2020-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-19
    • 1970-01-01
    • 2010-10-17
    相关资源
    最近更新 更多