您好我在参与者列表中有两个实施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版
答案 0 :(得分:2)
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
s,但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 {