nitesh solanki
nitesh solanki

Reputation: 177

net.corda.core.contracts.TransactionVerificationException$ContractRejection: Contract verification failed:

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

Answers (2)

balajimore
balajimore

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:

  1. Output state should refer to InvoiceContract contract class buider.addOutputState(newInvoiceState, InvoiceContract.INVOICE_CONTRACT_ID)
  2. Then create and add appropriate InvoiceContract Command to the transaction builder.

Upvotes: 1

Rickky13
Rickky13

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

Related Questions