Reputation: 177
I am getting an exception while executing my flow test
net.corda.core.contracts.TransactionVerificationException$ContractRejection: Contract verification failed: Required com.example.contract.InvoiceContract.Commands command, contract: com.example.contract.InvoiceContract
I have a txn which consumes 4 different types linear states, updates some fields and adds them to the output state. The txn has one command whose logic is defined in of the above state contracts. Below is my flow code:
object SubmitDocuments {
@InitiatingFlow
@StartableByRPC
class SubmitDocumentsToBank(val locState: StateAndRef<LOCState>, val invoiceState: StateAndRef<InvoiceState>, val packingListState: StateAndRef<PackingListState>, val bolState: StateAndRef<BillOfLadingState>, val updatedlocState: LOCState, val bank: Party) : FlowLogic<SignedTransaction>(){
companion object{
object CREATING_BUILDER : ProgressTracker.Step("Creating a Transaction builder")
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, 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 = ADDING_STATES
val newInvoiceState = invoiceState.state.data.copy(participants = listOf(invoiceState.state.data.seller, bank))
val newpackingListState = packingListState.state.data.copy(participants = listOf(invoiceState.state.data.seller, bank))
val newbolState = bolState.state.data.copy(owner = bank, participants = listOf(bank) )
buider.addInputState(invoiceState)
buider.addInputState(packingListState)
buider.addInputState(bolState)
buider.addInputState(locState)
buider.addOutputState(newInvoiceState, LOCContract.LOC_CONTRACT_ID)
buider.addOutputState(newpackingListState, LOCContract.LOC_CONTRACT_ID)
buider.addOutputState(newbolState, LOCContract.LOC_CONTRACT_ID)
buider.addOutputState(updatedlocState, LOCContract.LOC_CONTRACT_ID)
progressTracker.currentStep = ADDING_COMMAND
val verifyDocHashCommand = Command(LOCContract.Commands.VerifySubmittedDocuments(), listOf(serviceHub.myInfo.legalIdentities.first().owningKey))
buider.addCommand(verifyDocHashCommand)
progressTracker.currentStep = VERIFIYING_TX
buider.verify(serviceHub)
progressTracker.currentStep = SIGNING_TX
val stx = serviceHub.signInitialTransaction(buider)
progressTracker.currentStep = SENDING_TX
return subFlow(FinalityFlow(stx))
}
}
}
Below is my contract code which has the logic for command specified:
open class LOCContract: Contract {
companion object {
@JvmStatic
val LOC_CONTRACT_ID = "com.example.contract.LOCContract"
}
interface Commands: CommandData {
class IssueLoc(val referenceState: String): Commands
class VerifySubmittedDocuments: Commands
class EndorseDocuments(val caller: Party): Commands
class ReleaseDocuments: Commands
}
override fun verify(tx: LedgerTransaction) {
val time = Instant.now()
val command = tx.commands.requireSingleCommand<Commands>()
when (command.value) {
is LOCContract.Commands.VerifySubmittedDocuments -> {
val inputInvoiceState = tx.inputsOfType<InvoiceState>().single()
val inputplistState = tx.inputsOfType<PackingListState>().single()
val inputbolState = tx.inputsOfType<BillOfLadingState>().single()
val bolHash = inputbolState.props.billOfLadingAttachment.hash
val invoiceHash = inputInvoiceState.props.invoiceAttachmentHash.hash
val packinglistHash = inputplistState.props.packingListAttachment.hash
val nonContractAttachments:List<Attachment> = tx.attachments.filter { it !is ContractAttachment }
requireThat {
"Attachments are empty" using (nonContractAttachments.isNotEmpty())
var list: ImmutableList<SecureHash>? = null
nonContractAttachments.forEach((fun (data){
list!!.add(data.id)
}))
"transaction should have valid Bill of lading document hash" using (list!!.contains(bolHash))
"transaction should have valid Invoice document hash" using (list!!.contains(invoiceHash))
"transaction should have valid Packing List document hash" using (list!!.contains(packinglistHash))
}
}
}
}
}
Why is it complaining about => Required com.example.contract.InvoiceContract.Commands command, contract: com.example.contract.InvoiceContract, transaction: Am i missing anything while building the txn in the flow ?
Upvotes: 0
Views: 919
Reputation: 497
Error is valid : transaction required reference of com.example.contract.InvoiceContract.Commands
Inside a flow class, you are updating the InvoiceState
and but the transaction
didn't find reference to a command
of InvoiceContract
.
Fix should be:
InvoiceContract
contract class buider.addOutputState(newInvoiceState, InvoiceContract.INVOICE_CONTRACT_ID)
InvoiceContract
Command
to the transaction builder.Upvotes: 1
Reputation: 431
Seems Like your InvoiceContract
is inheriting from your LOCContract
, inside your InvoiceContract
at tx.commands.requireSingleCommand<Commands>()
is throwing this error.
Upvotes: 1