How state sync works
State transfer from Ethereum to Bor happens through a system call:- A contract on Ethereum calls
syncStateon theStateSender.solcontract, emitting aStateSyncedevent. - Heimdall validators listen for
StateSyncedevents. One validator sends a state-sync transaction to Heimdall. - Once the transaction is included in a Heimdall block, it is added to the pending state-sync list.
- After every sprint on Bor (currently 16 blocks), the Bor node fetches pending state-sync records from Heimdall via API.
- Bor commits these records at the start of each sprint by calling
onStateReceiveon the target contract. This is a system call from address2^160-2.
IStateReceiver. The onStateReceive function can only be called by StateReceiver.sol at address 0x0000000000000000000000000000000000001001.
State sender contract
Source: StateSender.sol TheStateSender contract on Ethereum exposes a syncState function:
syncState emits the following event:
StateSynced event is emitted, Heimdall listens for it. After 2/3+ validators agree, the state-sync record is added to Heimdall state. Bor fetches and applies it at the start of the next sprint.
State receiver interface on Bor
The target contract on Bor must implement the following interface:StateReceiver.sol at address 0x0000000000000000000000000000000000001001 is permitted to call onStateReceive on target contracts.
System calls
The state sync commit on Bor uses a system call. Only the system address2^160-2 can make a system call. Bor calls it internally with the system address as msg.sender, which changes contract state and updates the state root for the block, without requiring a user-initiated transaction. This is inspired by EIP-210.
State-sync logs and Bor block receipts
Events emitted by system calls are handled differently from normal logs. Bor produces a synthetic transaction and receipt for each state-sync event, so clients can query these events through standard Ethereum JSON-RPC methods. The transaction hash is derived from:eth_getBlockByNumber, eth_getTransactionReceipt, and eth_getLogs include state-sync logs from the derived transaction. Note that the block bloom filter does not include state-sync log entries, and the derived transaction is not included in transactionRoot or receiptRoot.