Imagine that the UTXO set was hashed into a Merkle tree every block and that the root hash was included in the block header (or coinbase TX). Delivering an SPV client the Merkle path from an unspent output to the root hash is proof that the output has not yet been spent in any confirmed transaction.
This suggestion was made ages ago on
bitcointalk forum, but never really worked on. The link is to a fairly long thread that meanders a little.
What is really cool is that a block can include the proof that the merkle tree was correctly updated too. I discussed this property
here.
For each transaction input, you include the proof that it is valid. This proof also allows you delete that input from the set.
Similarly, for each transaction output, you include the proof that it can be inserted. That proof allows you to delete the output from the set.
Basically, if I give you the merkle root of the UTXO set and proof that an input exists, you can verify that proof and then also compute the new merkle root. The new merkle root is for the exact same set, but with that output matching that input deleted.
Likewise, if I give you the current merkle root and the path to where it should be inserted, you can add an output into the set. You can prove that it is the valid location to add the output and you can work out the merkle root for the set that contains adding the output and also the path counts as proof that the addition is valid.
So, an expanded transaction would be
Code:
- tx header
- inputs
-- proof of existance for input 0
-- input 0
-- proof of existance for input 1
-- input 1
...
- output
-- insertion merkle path for output 0
-- output 0
-- insertion merkle path for output 0
-- output 0
...
A full node could convert a normal transaction into an expanded transaction by adding the paths.
It has a lot of bloat though
. A merkle path is needed for each proof. The number of utxos at the moment is around 64 million. That is 2^26 or 26 levels of a binary tree. The merkle branch would be 26 hashes long. At 32 bytes per hash, that is 832 bytes.
With a 2 input, 2 output transaction would increase from 250 bytes to 3578 bytes. This is a big increase in block size (14X) but means that each block could be verified independently.
You take a block and it says what the merkle root of the UTXO set is. You can then go through each transaction and update the merkle root for each input and output. At the end, you get the updated merkle root. That root is included in the block too.
This means that someone who has never seen any other block can verify that that block is valid and connects to its parent.
An invalid blockchain would have at least 1 block which was invalid.