Solana vs Ethereum for relaying transactions
Sometimes you want your backend to submit blockchain transaction so that your users don’t have to. This is called a relayer.
I already built this for Ethereum and EVM-based chains, and it definetely has it’s quirks. This post explores how transaction relaying works on Solana.
Transactions in EVM
In EVM, we can send lots of transactions by making sure we increment the nonce each time.
Transactions in EVM are always sequential. Transaction 3 can never go through before transaction 2 goes through. When building a relayer, this means that a single transaction failing can cause the whole pipeline to get clogged.
Does it work the same way in Solana?
How it works in Solana
To test this, I wrote a script using @solana/web3.js
that send tokens.
Sending one token transaction works nicely
Sending 50 token transactions in sequence one by one works nicely (but takes time)
What about trying to send tokens 50 times all at once? Something weird happens. All the transactions go through instantly, but they all become the same! It’s just one transaction hash. The system probably sees them as the same and prevents double spends in this way.
Making all the 50 transactions different (with a varying amount), makes it possible to submit them all at once and get 50 different transactions (super fast). Yay!
It seems that Solana is good at executing transactions in parallel. They don’t have the same troublesome nonce system as EVM.
But how do they prevent double spends?
Solana uses “Recent Blockhashes” to prevent double spends
When submitting a transaction, Solana checks if your signed transaction already exists on-chain. Since the size of the whole blockchain is huge (300TB), only the last 150 blocks are checked. If your transaction is already there, it gets discarded. If your transaction is older than 150 blocks, it also gets discarded.
This has two important side effects:
- Transaction expiration. 150 blocks takes around 80-90 seconds. This means that transactions that are not submitted and accepted on-chain during this time-frame are dead forever.
- Impossible to submit multiple equal transactions in short timeframes. Demonstrated by my testing above, submitting lots of completely equal transaction in a very short timeframe will make them duplicate and avoiding their execution.
Transaction expiration is actually great when creating a relayer system. It makes the system more reliable and simpler. It means that I can be sure that a transaction has failed and will never be seen on-chain after the time period. Transactions in EVM are different, they can fly in the air for days and then suddenly get accepted.
The second point about short timeframes isn’t a concern in most real-world applications, but worth keeping in mind. Who would submit a hundred completely equal transactions in the same sub-second? Doesn’t make sense.
PS: It’s worth noting that if you want long-lived transaction signatures, Solana has a solution for that called Durable Nonces. I imagine that can be useful for things like multi-sig transactions and scheduled transactions
Recap
- Transactions in solana are signed with a
recent_blockhash
instead of thenonce
in ethereum.
- If the
recent_blockhash
is too old, the transaction is discarded
- Solana doesn’t care about sequentiality, a transaction submitted now can arrive on chain before a transaction submitted 30 seconds ago
- In a relayer system, transactions can’t clog the pipeline in the same way as is common in EVM