Is there any way a CorDapp can ask a Notary if a state has been consumed prior to using it in a Transaction?
Background:
I am testing FungibleToken’s that point to EvolvableTokenType’s. Eventually the EvolvableTokenType changes and holders of the tokens that are not Participants of the EvolvableTokenType end up with states in their vault that have been unknowingly consumed. When they try to execute a transaction involving these states the Notary will refuse to sign because it knows the states have been consumed.
I have written flows that will contact a Participant and request the missing state(s). However it would be more efficient if I could first ask the Notary if I need to do that (i.e. if the state hasn’t been consumed I don’t need to ask a participant for an update).
You could do this a couple ways.
For example, in your vault query, you could simply make sure to filter on StateStatus = UNCONSUMED. That's one way you can ensure this works the way you expect and you never get a state that won't fit your criteria.
check out this section of the docs on vaultQuery : https://docs.corda.net/docs/corda-os/4.7/api-vault-query.html#querycriteria-interface
The other way I'd recommend that might also work is just to include this filter in your contract verification for the transaction, but doing it at the flow level just catches the problem sooner rather than later.
Related
As I’m developing my first corDapp, I thought it might be useful to be able to reference a transaction’s initiator(flow starter) from the contract level. The reason being that although my contract is callable by any party, I don’t necessarily want to allow any party to call each command.
In my state, I have a list of what you might call admins. These admins should be the only ones that are able to issue commands on this list like RemoveAdmin() or AddAdmin().
Instead of being able to reject this command from contract level (which I think should done at this level because this is just another command constraint) based on a reference of who initiated it, I have to instead do it on the responder flow level.
Anyone else think an tx.initiator field might be useful for permission constraints like I described? If not, why is it better to do it at the responder flow level?
I think the conceptual issue is that, in Corda, transactions can be collaboratively constructed - eg if two parties are exchanging assets and the partial tx gets passed around so they can populate it with their respective inputs. So there isn’t always a proposer/initiator conceptually. So the concept doesn’t exist on Corda’s data model.
That being said, you can take three approaches:
Since you don't care about who proposed the transaction, rather that it was done by an admin you can configure the non-proposing admins only to sign a tx if they see it has been signed by another admin. So none of the non-proposers will sign it until the actual proposer has.
Make the proposer/initiator of the transaction part of your State object and check that this proposer/initiator is in your Admin list.
Throw an exception if the initiator of the flow is not in the admin list:
//make sure that the party running this flow is already an admin
if(ourIdentity !in AdminInputStateRef.state.data.participants){
throw IllegalArgumentException("The initiator of this flow must be a admin.")
}
The goal is to generate events on every participating node when a state is changed that includes the business action that caused the change. In our case, Business Action maps to the Transaction command and provides the business intent or what the user is doing in business terms. So in our case, where we are modelling the lifecycle of a loan, an action might be to "Close" the loan.
We model Event at a state level as follows: Each Event encapsulates a Transaction Command and is uniquely identified by a (TxnHash, OutputIndex) and a created/consumed status.
We would prefer a polling mechanism to generate events on demand, but an asynch approach to generate events on ledger changes would be acceptable. Either way our challenge is in getting the Command from the Transaction.
We considered querying the States using the Vault Query API vaultQueryBy() for the polling solution (or vaultTrackBy() for the asynch Obvservalble Stream solution). We were able to create a flow that gets the txn for a state. This had to be done in a flow, as Corda deprecated the function that would have allowed us to do this in our Springboot client. In the client we use vaultQueryBy() to get a list of States. Then we call a flow that iterates over the states, gets txHash from each StateRef and then calls serviceHub.validatedTransactions.getTransaction(txHash) to get signedTransaction from which we can ultimately retrieve the Command. Is this the best or recommended approach?
Alternatively, we have also thought of generating events of the Transaction by querying for transactions and then building the Event for each input and output state in the transaction. If we go this route what's the best way to query transactions from the vault? Is there an Observable Stream-based option?
I assume this mapping of states to command is a common requirement for observers of the ledger because it is standard to drive contract logic off the transaction command and quite natural to have the command map to the user intent.
What is the best way to generate events that encapsulate the transaction command for each state created or consumed on the ledger?
If I understand correctly you're attempting to get a notified when certain types of ledger updates occur (open, approved, closed, etc).
First: Asynchronous notifications are best practice in Corda, polling should be avoided due to the added weight it puts on the node for constant querying and delays. Corda provides several mechanisms for Observables which you can use: https://docs.corda.net/api/kotlin/corda/net.corda.core.messaging/-corda-r-p-c-ops/vault-track-by.html
Second: Avoid querying transactions from the database as these are intended to be internal to the node. See this answer for background on why to avoid transaction querying. In general only tables that begin with "VAULT_*" are intended to be queried.
One way to solve your use case would be a "status" field which reflects the command that was used to produce the current state. For example: if a "Close" command was used to produce the state it's status field could be "closed". This way you could use the above vaultTrackBy to look at each state's status field and infer the action that occured.
Just to finish up on my comment: While the approach met the requirements, The problem with this solution is that we have to add and maintain our own code across all relevant states to capture transaction-level information that is already tracked by the platform. I would think a better solution would be for the platform to provide consumers access to transaction-level information (selectively perhaps) just as it does for states. After all, the transaction is, in part, a business/functional construct that is meaningful at the client application level. For example, If I am "transferring" a loan, that may be a complex business transaction that involves many input and output states and may be an important construct/notion for the client application to manage.
I'm currently tying to make a CordApp That will be used for DVP, but I'm having trouble understanding some key concepts. For instance, I understand that Contracts apply to one type of state in particular. What I don't really get is if the contract validation logic should apply to only that state object or all the states that will be in the given transaction.
The typical example would be the issuance of a sell order :
The input of a transaction the state of the stock account of the issuer and the outputs are the sell Order and the modified stock account.
Basically my question is were do I do checks like : I don't sell more than I own, the sum of the number of stocks in the sell order and what is left in the account is equal to what was initially in the account, ... ?
I have followed the Corda tutorials but I'm still not clear on that logic.
It boils down to the Orchestration Layer (flows or APIs, what the user intends to do) vs the Ledger layer (what the user can do. IE - guaranteed shared logic).
Contract code absolutely must be adhered to, so in your case not being able to sell more than you own would be part of the explicit contract.
The CMN guide here helped me conceptualise.
Flows are better described as business logic, so anything can be achieved within a flow as long as it adheres to the contract.
A security consideration: Anybody may create a flow, and they are equally able to use any Asset (and thus it's state) within their third-party flow.
It is the relevant contract that ensures that your asset is used for the purpose you imagine, and that it isn't used malevolently.
I am using Corda and in one of our use-cases, we need to limit the transaction information shared among the nodes (e.g. 4 parties) in the network.
The transaction state will contain sensitive data of other nodes but we need to limit this data to be accessed by authorised parties only. e.g. party A should not see data of Party B in the transaction state.
I looked at the Corda documentation and tumbled upon Transaction tear-off but I could not find any concrete implementation of this.
I would be really grateful, if someone can give me an examples of transaction tear-off implementation or point me to right direction if there is better approach to limit transaction state sharing among parties than using transaction tear-off.
Thanks in advance
Transaction tear-offs are typically used in the use case where you're using an oracle to attest to a fact within your transaction.
The idea being, you want to strictly limit the oracle to viewing only what is required in order for it to attest, so you filter out all other parts of the transaction.
Take a look at the following tutorial https://docs.corda.net/tutorial-tear-offs.html it contains the steps required to create a filtered transaction.
You can also take a look at the samples on https://www.corda.net/samples that make use of an oracle. In particular, if you look at the Options sample, the OptionIssueFlow creates a filtered transaction for the oracle to sign.
One other approach - would it matter if Party A could see the data of Party B if it didn't know it was Party B? If not, you could look at using confidential identities https://docs.corda.net/api-identity.html#confidential-identities
In our use case, we need to define certain rules at run-time based on which a node will transact with other nodes in the network. For example, we want to define a rate at the front end and check that the transaction is happening with this rate only for that particular node. In other words, can we define the terms and conditions at run-time and would this still be called a smart contract or does a smart contract need to be always hard-coded. Is there any alternate way to look at this?
The contract itself is hard-coded. This is because every node needs to agree that a given transaction is valid according to the contract rules, forever. If they varied based on the node, some nodes would consider a transaction valid while another would consider the transaction invalid, leading to inconsistencies in their ledgers.
Instead, you'd have to impose this logic in the flow. Let's say you have a TradeOffer flow that proposes a trade. Each node could install their own response flow that is initiated by TradeOffer flow. Each node's response flow could impose different conditions. For example, one node might sign any transaction, while another one would check that the proposed rate is within specified bounds.
To extend Joel's comment, the contract is indeed hard-coded, but there's nothing wrong with putting meta logic in there as long as the code runs the same way every time (i.e. it's deterministic).
What do I mean by this? Well, you can put a String type in your state which contains an expression that can then be evaluated (if you refer to https://relayto.com/r3/FIjS0Jfy/VB8epyay73 you can see the inclusion of a very basic maths expression used in a smart contract). There's nothing wrong with making this String as complex as possible, but just be aware that any potential users of your application will start raising eyebrows if you remove a lot of the protection that Corda offers of validation if you start dumbing down the coded verification logic and putting it all into a String.