At linux.conf.au I gave a last-minute talk previewing my work on pettycoin (video, slides), an experiment to shard a bitcoin-like network. The idea is to trade off some security and robustness in return for scale, but use it only for small amounts where fraud is less worthwhile. On the bitcoin network today this is already seen with zero-confirmation transactions, and this is the niche pettycoin seeks to fill.
There are numerous problems to be overcome (one being the time taken by my day job, of course). But segmenting the network and the blockchain is an interesting challenge: bitcoin's blockchain is already designed so that you can have partial knowledge (mainly so you can prune used outputs). But there's a clear divide between full nodes, and second-class partial nodes. I want a system where no one need know everything, and I'm getting closer to that goal.
Consider the simplest useful transaction in the bitcoin network, with one input (ie. a previous transaction's output) and one output. To verify this is a fairly simple process:
- Is the transaction well-formed?
- Find the transaction whose output this is spending.
- Does the signature match the address of that output?
- Has that output already been spent?
With bitcoin, you're expected to know every transaction with unspent outputs, so if you can't find the transaction at step 2, the verification fails. Even better, you can verify that previous transaction, too, all the way back to the creating of the coins involved. Your only worry is that the blockchain you have is the same as everyone else's, so they'll accept your transaction later.
If you don't expect to know everything, it's more difficult. You can use a merkle proof to show that a transaction was present in a block; it takes just log(N) hashes for an N-transaction block. So you could prove that all those previous transactions are in the blockchain (though that might be thousands of transactions) by providing me with each transaction and proof.
But this can't prove that there are not duplicate transactions in the blockchain itself. Only knowing the entire contents would do that. So we're relying on the rest of the network, each with a partial view, to check that didn't happen.
This leads to the two requirements for any aspect of the pettycoin system which a node can't verify by itself:
- The information to verify must be seen by some honest nodes.
- Each node must have an efficient way of reporting if it sees a problem.
The former is a bit tricky. Consensus is formed by the blockchain, but you don't want to see all of it. You might expect to see some fraction of it, but if you don't, how would you alert the network in a way that can't be faked? Imagine a miner holds back 5 transactions in the block, the miner might wait for your complaint message on one, then release that transaction making you look like the dishonest one. By making you cry wolf, they can ensure you are ignored.
The solution used in pettycoin is that miners have to prove that they know the transactions in the 10 previous blocks. They do this by hashing the transactions from the previous block into a merkle tree like normal, only they prefix each transaction with their payout address (this is called prev_merkle in the code). The only way to generate this hash is to know the contents of each transaction, and you can't make a valid block without it. Unfortunately, the only way to demonstrate that this hash is wrong (thus the block is invalid) is to also know the contents of each transaction in the block. Thus transactions are batched into groups of 4096; you only need send 4096 transactions to prove that one of the hashes in a block is wrong. Miners will insist on knowing the transactions for those blocks, knowing that if they fake it they'll likely be caught.
Reporting most other problems in a block is fairly:
- You can prove a duplicate spend in the block chain by showing both transactions and the merkle proofs that they are in each block. The second block is invalid.
- You can prove a malformed transaction by showing the transactions and the merkle proof it is in the block. That block is invalid.
- You can prove an overspend by showing the transactions used as inputs. That block is invalid.
But if a transaction in a block relies on an output of a transaction which never existed, you can't prove it. Even if you know every transaction which ever happened, you can't prove that to me (without sending me the whole blockchain). The initial design lived with such warts in the blockchain, instead insisting that you would have to show all the predecessors when you paid me (via a payment protocol). That predecessor tree quickly becomes unwieldy, however.
The new approach is that for each input of a transaction in the blockchain, the miner has to include the block and transaction number where it appeared. Now anyone who knows that previous transaction can check it, and if there's a problem it's easy for any node to prove by showing the transaction which is in that previous block (with merkle proof that it is).
This means that the blockchain can be trusted, if half the mining power can be trusted. This is a weaker guarantee that bitcoin, but sufficiently strong for pettycoin. If you send me a new transaction along with transactions it uses as inputs and merkle proofs that they are in the blockchain, I only need ensure that the new transaction isn't a double-spend. That's the same as the bitcoin network, with zero-confirmation transactions (though pettycoin has a special double-spend report message to expedite it a little).
Next post, I'll respond to the best criticism of pettycoin yet, the problem of gateways (by Jason Gi)...