Transaction verification
This proposal describes and discusses how transactions can be traced and proved to have taken place in the tagion system.
Motivation
Suppose we have three persons. Alice, Bob & Carol. Carol sets an item for sale which both Alice and Bob wants to buy. First person to buy it gets it. Alice sends the transaction to Carol, but Bob only says that he has already sent the money. Since only outputs are stored there is no way for Carol to veriy if it was Bob or Alice who sent it. Also as a twist Carol may choose to send the money directly after receiving them making it look like the money was never sent at all.
Based on the above it can be seen that there can be ways where providing the history is important. Especially one link back. The following describes a solution as to how we by saving hashes of contracts in the recorderchain, along with the previous recorderblock in the DART, are able to provide history as to how transactions took place in the system.
Requirements
One of the KVP's of Tagion is that the system is designed so that the nodes should perform the least amount of work as possible, and in theory only have the job of storing current distributed data that there is consensus on.
Storing only the UTXO set, rather than the full transaction history an already spent outputs, enhances efficiency by reducing the amount of data needed for transaction validation. This approach simplifies the validation process, minimizes storage requirements, and supports features that improve security and privacy, such as the creation of new addresses for change. Again it is important to remember that the nodes do not require spent UTXO's in order to validate a transaction and therefore according to the foundation of Tagion it should not be in the consensus data.
Proposed solution
Currently Tagion nodes maintains a opt-in recorder-chain, which stores all changes to the database. It has a list of inputs, as well as outputs that are going to be added and removed. The idea is to add the hash of the contracts that have been executed in the system into the recorderchain, in order to be able to lookup the transaction hash, prove that the tx has happened and the input was created at some point in time.
It is important to note that only the transaction hash is kept in the recorderchain, meaning that without the raw contract which can calculate the contract the information is not easily usable though not privacy enhancing.
As mentioned earlier, Tagion nodes are not currently required to keep the state of the recorderchain. But in order to create a hash-lock between the recorderchain and dart for faster proofs, the hash of the last RecorderBlock should be added to the epoch_chain in the DART. This makes proving that the recorderchain is correct much faster, since I can lookup an epoch in the DART and instantly verify if the recorderchain matches it.
Hash-trie for compressing contract hashes
Instead of storing all contract hashes raw in an array in the recorderchain it could be possible to create a data structure similar to the DART, which will hold the hashes in a trie-like structure. Zipping is not possible since hashes cannot really be compressed.
Simple proving of transaction with subscription.
In most cases the above will be quite overkill and a bit cumbersome for a node to perform. The simplest way is with the Subscription API proposal.
Client A sends his transaction to the network and also creates a subscribe event on the outputs of the contract against multiple nodes. When the transaction goes through he is returned the HiRPC's for the archive that he was trying to read with a signature from the node. He is then able to verify that the transaction did actually go through.
Note. This would require the returned HiRPC to include the epoch number that the database was read at. This would also help in a lot of other cases, so no matter what it is also something that must be added.
Merkle proof.
The simple proving does not actually prove directly that our data was in the system. Instead a new type of request could be added to the system which would allow clients to ask for a merkle-proof that the dartindex is actually located in the DART with the bullseye. The proof could be made with a simple merkle-path to the root from the archive which would give actual proof of membership or non-membership. The algorithm for calculating a merkle-proof / path is O(log n), which is acceptable for a node to do. Though is should be noted that it is not a "cheap" request to perform, and would be great for the mirror-nodes to do.
Example of merkle proof request:
{
"$@": "HiRPC",
"$msg": {
"method": "dartProof",
"params": {
"dart_indices": [
[
"*",
"@4c2LxGMUI7o7AnNQfKxgAEdjwizVRvdtV3j2ItiBwQM="
]
]
}
},
}
It would make sense to keep the same structure as for the other requests such as dartRead
etc though there should be a very well-defined limit as to how many archives can be requested proofs on.
The response would need to include all branches going up to the bullseye from the archive. A minimum proof of an archive in an empty rim 3. would therefore require (1 + 256) hashes. It should also include the epoch in which the proof was created in order for validators of the proof to verify that the epoch archive matches the same eye.