bug: transaction replay
Closely related to this:
A block is invalid if we've already seen a transaction. Txs can only be processed once.
There are two ways to implement this:
- unique tx ids + a "seen" tx cache per tip
- unique accounts.txs ids (aka account nonce) + a "account -> latest nonce" per tip
In bitcoin this is just called the UXTO set. We have a set of unspent tx outputs. It's quite big to store this in memory.
Funnily enough this doesn't need to occur in block validation.
Already the block validation logic is designed purely from the perspective of a sequencer - ie. solving the hashcash nakamoto puzzle means you get to be the proposer. The transactions don't necessarily need to be valid, they are literally just committing to a sequence, there is no state root in the block header.
So technically speaking, this is logic for the state machine
If we implement it in the state machine, all it needs to do is keep a cache of seen transactions / nonces to prevent reuse. I don't like the nonce idea because technically if you broadcast a tx with nonce 20 and your latest nonce is 19, and then a reorg happens and your latest nonce is now 10, someone could rebroadcast your nonce 20 tx.
So for example - the state machine ingests each tx, keeps a cache of "seen tx ids". I think a good anti-replay mechanism is to embed the latest [block, timestamp] into it, so it prevents reorging a tx according to a block and allows txs to come. This is what Solana does.
Transaction validity is defined with respect to two models:
- UXTO. Each UXTO can be used only once. Thus a transaction is invalid if all UXTO's are already used.
- Account-based. Each account has a nonce which must be n+1 of the previous nonce for a transaction to be valid.