Skip to content

Race condition in the Solana Wormhole gateway program #767

@lukasz-zimnoch

Description

@lukasz-zimnoch

Issue discovered by Karl and Kevin from the Wormhole team:

Sending tbtc can hit a race condition due to the way the Wormhole message account is derived. To bypass transaction simulation, see this failed transaction.

The core_message account's derivation depends on the wormhole gateway's emitter sequence account data. Every time wormhole publishes a message, it upticks this sequence. But because the sequence is used to derive this pubkey, there can be two folks trying to invoke the send_tbtc instruction, and only one of those guys will succeed.

For example, if Kevin and I both want to send tbtc, we both fetch the emitter sequence account to fetch the latest sequence number to drive the message PDA address. We both see 2 as the value. When we both send our transactions, either Kevin's transaction or my transaction may land first. If Kevin's lands first, mine will fail because the program during runtime will be trying to derive the message account using the value 3 instead of 2

What this means is there can be only one send_tbtc instruction per slot (unless someone can anticipate that his transaction lands after someone else's in the same slot, using sequence + 1 for his derivation... but that is unlikely)

There should be a new instruction that executes almost exactly the same way as send_tbtc (maybe call it send_tbtc_v2?) but the message account either uses a keypair generated off-chain or uses a PDA determined by another account called something like Payer Sequence, which uses a sequence number per transaction payer.
The latter way is safe to use because the payer is always tied to the transaction (lamports are sent from the payer to pay for the wormhole message fee, allocate accounts etc). So using web3, we can fetch this sequence reliably to derive the message PDA address

Using this type of account would solve the issue in a new instruction: link

The core message would then be derived this way: link

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions