I have an contract which consumes an input of typeA to produce output of typeB and my contract looks similar as shown
override fun verify(tx: LedgerTransaction) {
val commandCreate = tx.commands.requireSingleCommand<Commands.Create>()
requireThat {
"One input state should be there for TypeB" using (tx.inputStates.size==1)
"One output states should be there for TypeB" using (tx.outputStates.size==1)
"Input State should be a TypeA" using (tx.getInput(0) is TypeAState)
"Output State should be a TypeB" using(tx.getOutput(0) is TypeBState)
"TypeA id Number should not be empty" using((tx.getInput(0) as TypeAState).idNumber.isNotEmpty())
}
and I get the following error while invoking the flow
java.util.concurrent.ExecutionException:
net.corda.core.contracts.TransactionVerificationException$ContractRejection:
Contract verification failed: Required
com.example.contract.PolicyContract.Commands.Create command, contract:
com.example.contract.PolicyContract, transaction:
B2AE49DEDFE882C9DDBA9ECB35740A689CFDC4F8ED78DD43D912FDC9DC5DC2C4
My flow looks something like this
val txCommand = Command(TypeBContract.Commands.Create(), listOf(me.owningKey))
val txBuilder = TransactionBuilder(notary)
.addInputState(typeARef)
.addOutputState(outputState, TYPEB_CREATION_CONTRACT_ID)
.addCommand(txCommand)
Where am I going wrong??
The problem is the requireSingleCommand. When you create a transaction with input states, the command that the input state was included within another transaction will load here as well.
To solve this use tx.commandsOfType<YourType>() or whatever the syntax is. This will not throw an exception. This solution is what you should use when there are inputs and outputs in a transaction.
The exception is due to single being called in requireSingleCommand.
Related
Scenario: running 2 Corda nodes (say, A and B) that are running within a larger zone. There is 1 notary node in the zone.
I have 2 different flows: the first flow f1 only runs on node A and only creates transactions that are stored locally (as in, no other nodes are involved). The second flow f2 also only runs on node A and creates a transaction that modifies the states inserted by flow f1 (s1, s2, ...) by adding an input-output pair to the transaction where the input states are the existing (s1, s2, ...) states and the output states are the modified states (s1', s2', ...). Flow f2 also creates an additional output state, therefore we have Sn input states and S(n+1) output states. The transaction created in flow f2 is shared with node B.
Flow f1 runs fine, but as soon as I run flow f2 I receive the following error in Node A:
net.corda.core.flows.UnexpectedFlowEndException: net.corda.core.flows.NotaryFlow$Client is not registered. In the logs of the notary I can see the same error, and when I check the logs for nodeB it says: net.corda.core.flows.UnexpectedFlowEndException: Counter-flow errored
I have local tests, using a mock network that is able to run fine. I currently have no clue on how to debug this issue or whether it is a mistake in the flow itself, or something else. I am running version 4.5.8
Below is the code snippet for creating the transaction in flow f2 (variables have been renamed):
val txBuilder = TransactionBuilder(notary)
.addOutputState(additionalState, CustomContract.ID)
.addCommand(
Command(
contract,
additionalState.participants.map { it.owningKey })
)
existingStates.forEach { txBuilder.addInputState(serviceHub.toStateAndRef<CustomState>(it.ref)) }
existingStatesModified.forEach { txBuilder.addOutputState(it, CustomContract.ID) }
// Stage 2.
progressTracker.currentStep = VERIFYING_TRANSACTION
// Verify that the transaction is valid.
txBuilder.verify(serviceHub)
// Stage 3.
progressTracker.currentStep = SIGNING_TRANSACTION
// Sign the transaction.
val partSignedTx = serviceHub.signInitialTransaction(txBuilder)
// Stage 4.
progressTracker.currentStep = GATHERING_SIGS
// Send the state to the counterparty, and receive it back with their signature.
val otherPartySessions = counterParties.map { initiateFlow(it!!) }
val fullySignedTx =
subFlow(CollectSignaturesFlow(partSignedTx, otherPartySessions, GATHERING_SIGS.childProgressTracker()))
// Stage 5.
progressTracker.currentStep = FINALISING_TRANSACTION
// Notarise and record the transaction in both parties' vaults.
require(insertEvent(insuranceEventState.fullEvent)) { "Unable to insert event data into the triple store." }
return subFlow(FinalityFlow(fullySignedTx, otherPartySessions, FINALISING_TRANSACTION.childProgressTracker()))```
Turns out this was caused by an incorrectly configured notary (which was out of my control).
Assume a node is given a filtered transaction containing a few states, while some have been excluded out. How can the node run the smart contract verify function on the states that included in the transaction? Am trying to achieve something similar to ledgerTransaction.verify()
As of Corda 3, you cannot run the remaining states' verify methods, since the verify method requires a LedgerTransaction.
Instead, you would have to retrieve the states from the FilteredTransaction, and provide your own checking logic. For example:
val inputStateRefs = filteredTransaction.inputs
val inputStateAndRefs = inputStateRefs.map { inputStateRef ->
serviceHub.toStateAndRef<TemplateState>(inputStateRef)
}
inputStateAndRefs.forEach { inputStateAndRef ->
val state = inputStateAndRef.state
// TODO: Checking...
}
Consider the following case:
node A builds and signs a TX which is sent to B for signing.
class FlowA(val otherParty: Party) : FlowLogic<SignedTransaction>() {
#Suspendable
override fun call(): SignedTransaction {
val notary = serviceHub.networkMapCache.getNotary()
val builder = TransactionBuilder(notary)
// ... add some commands and states
val stx = serviceHub.signInitialTransaction(builder)
val session = initiateFlow(otherParty)
subFlow(SendTransactionFlow(session, stx))
return session.sendAndReceive<SignedTransaction>(stx).unwrap {
it.id == stx.id // is it enough?
it
}
}
}
class FlowB(val session: FlowSession) : FlowLogic<Unit>() {
#Suspendable
override fun call() {
subFlow(ReceiveTransactionFlow(session, false))
val stx = session.receive<SignedTransaction>().unwrap {
val ledgerTx = it.toLedgerTransaction(serviceHub, false)
ledgerTx.commandsOfType<SomeContract.Commands.SomeCommand>().single()
ledgerTx.verify() // is it enough?
}
}
}
Is it secure to check only the id of the transaction from the sender side once we received the full signed transaction?
I've read in the doc that id is the root Merkle tree built by using transaction's components, so if the otherParty change something the id would be different, correct?
From the receiver side, is it secure to check which commands are present in the transaction so we are sure that the contract relative to that command is run by means of verify?
On receiving a transaction, you will be able to interrogate all the inputs, outputs and commands.
Typically, the interrogation would happen inside the contracts verify method.
Yes, if anything were to change the root ID would indeed change. Note that it's not possible to change anything within a transaction once it has been signed.
Other things you could look for is the presence of the transaction being notarised.
It depends on what your contract needs to do, but yes, you would check which commands are present within a transaction e.g. in the issuance of a security, you might check that only one issue command is present.
You can also check the commands have received the required counterparty signatures.
If you would like to discuss in person, feel free to join one of office hour sessions - https://www.corda.net/support/technical-office-hours/
I have some ContractState, and there are two commands that can 'delete' the state (mark it as historic, with no new state to replace it) - let's say 'Delete' and 'Revoke', which have different real-world consequences.
I can still see the historic states in the vault, right? How can I determine which command deleted the state? I suppose I could add some enum to the state: 'Active|Deleted|Revoked', and then move the state from S(Active) -> S(Deleted|Revoked) -> Historic. But that seems clunky.
In theory, you could determine which command was used to consume the state by checking the transaction that consumed the state.
However, there is currently no non-deprecated API for viewing the contents of the node's transaction storage as a node owner. This is because in a future version of Corda, we expect transaction resolution to occur within a secure guard extension (SGX). This will affect which transactions are visible, and Corda therefore cannot commit to a stable API for viewing the contents of the node's transaction storage.
If you're willing to use the deprecated internalVerifiedTransactionsSnapshot/internalVerifiedTransactionsFeed API, you could do something like:
val (_, vaultUpdates) = proxy.vaultTrackBy<ContractState>()
vaultUpdates.toBlocking().subscribe { update ->
update.produced.forEach { stateAndRef ->
val newStateTxId = stateAndRef.ref.txhash
val transactions = proxy.internalVerifiedTransactionsSnapshot()
val transaction = transactions.find { transaction -> transaction.id == newStateTxId }!!
val commands = transaction.tx.commands
}
}
An alternative would be to add a status field to the state, and updating the status field instead of marking it as consumed when "deleting" it. For example:
class MyState(val expired: Boolean): ContractState {
override val participants = TODO()
}
In Corda, is there a way to refer to an unspent state in a transaction without spending it? The aim is to allow the contract to use some of the information in the state being referred to as part of the verify method.
Reference states will be added to Corda Version 4 which will be released later this year. This solves the problem above. See:
https://github.com/corda/corda/blob/master/docs/source/design/reference-states/design.md
There is no built-in support for this pattern in Corda at this time, but it will be added in Corda 4 (see Roger's answer below). For now, you have several options:
Writing the states' contracts to allow this behaviour:
You can add a command to the contract which enforces the requirement that there is a matching output for each input of the state type you wish to reference. This guarantees that the transaction is only referencing the state, and not modifying it. Here is an example:
class MyContract : Contract {
override fun verify(tx: LedgerTransaction) {
val command = tx.commands.requireSingleCommand<MyContract.Commands>()
when (command.value) {
is Commands.Reference -> requireThat {
val inputs = tx.inputsOfType<MyState>()
val outputs = tx.outputsOfType<MyState>()
// Assuming `MyState.equals` has been overridden appropriately.
"There must be a matching output state for each input state" using
(inputs.toSet() == outputs.toSet())
}
}
}
interface Commands : CommandData {
class Reference: Commands
}
}
Referring the state as a field in an input state, output state or command:
You can include the reference state in the transaction as a field on an input state, output state or command. A command is likely to be the best fit:
interface Commands : CommandData {
class Reference(val referenceState: MyState): Commands
}
You can then check the contents of this state within the contract's verify method. For example:
class MyContract : Contract {
override fun verify(tx: LedgerTransaction) {
val command = tx.commands.requireSingleCommand<MyContract.Commands>()
when (command.value) {
is Commands.Reference -> requireThat {
val commandData = command.value as Commands.Reference
val referenceState = commandData.referenceStateAndRef.state.data
val inputs = tx.inputsOfType<MyState>()
"The input state contents must match the reference data" using
(inputs.all { it.contents == referenceState.contents })
}
}
}
interface Commands : CommandData {
class Reference(val referenceStateAndRef: StateAndRef<MyState>): Commands
}
}
With this approach, you also have to check in the flow that the reference state is identical to the state actually on the ledger (i.e. that the transaction's proposer hasn't added a fake state object as a reference). For example:
val referenceCommand = ledgerTransaction.commandsOfType<Reference>().single()
val referenceStateAndRef = referenceCommand.value.referenceStateAndRef
val actualStateAndRefFromVault = serviceHub.toStateAndRef<MyState>(referenceStateRef)
if (referenceStateAndRef != actualStateAndRefFromVault) {
throw FlowException("Referenced state does not match state in the vault.")
}