Broadcasting to other chains
The engine starts an event handler with a match
expression to perform operations for events including (but not limited to)
Keygen requests
Signing requests
Handover requests
Broadcast requests (assuming the current node is the
nominee
)
If broadcast requests fail, it sends an extrinsic to call transaction_signing_failure
to indicate that it failed on chain.
Additionally, the engine regularly sends heartbeat extrinsics to the state chain to ensure it knows the node is alive.
Replay protection
We inquiried Chainflip Labs about the possibility of a malicious broadcaster falsely invoking transaction_signing_failure
after successfully broadcasting a transaction, potentially causing an egress message to take effect multiple times. This specific aspect is handled by code that was not in the scope of this audit.
Chainflip Labs confirmed that egressing transactions are rebroadcast multiple times, and that in some cases the same transaction could also be signed multiple times (this is the case of Ethereum transactions). However, all outgoing transactions have some form of replay protection which adequately protects them from this potential attack.
Specifically, in the case of Ethereum transactions the replay protection is contained in the key nonce (KeyManager.sol↗ line 287), which is a unique hash. A message with an already-seen key nonce will be rejected. Even if the same transaction data could be signed multiple times, the nonce contained whithin the transaction data never changes, therefore preventing the same egress message from being replayed.
Polkadot uses the account nonce to avoid transaction replay: the chain will reject duplicate nonces.
Bitcoin transactions are natively immune from rebroadcasting issues, since input UTXOs cannot be spent multiple times.