Execution Client & Sentinel
Sova’s Execution Engine and REVM Inspector
Customized REVM Inspector: Sova’s execution client (uses Reth as a EL library) introduces a custom EVM inspector (SovaInspector
) to enforce Bitcoin transaction finality rules within the EVM. The inspector hooks into the REVM execution cycle (via the Inspector
trait) to monitor and control state changes related to Bitcoin bridging. In practice, it intercepts calls to Sova’s Bitcoin precompile (a special contract at 0x...0999
used for BTC integration) and tracks any storage slots that are written as part of Bitcoin deposit/withdrawal logic. Before allowing a Bitcoin-related call (e.g. broadcasting a BTC transaction) to proceed, the inspector checks with the Sentinel service whether the involved contract storage slots are “locked” (i.e. tied to a pending Bitcoin tx). This is done via a gRPC API call in StorageSlotProvider
to the Sentinel, which returns the lock status of each slot.
Lock Enforcement and Reverts: If the Sentinel indicates a slot is already locked, it means a Bitcoin transaction is still awaiting confirmation for that slot. In that case, the inspector will revert the execution to prevent double-spending or inconsistent state. It uses an internal checkpoint in the EVM journal to roll back any tentative state changes if needed. Only one BTC-broadcast operation is allowed per transaction – the inspector enforces this by caching the first call and rejecting subsequent ones in the same EVM transaction. When a Bitcoin precompile call finishes, the inspector verifies it executed successfully; if not, it produces a revert (with a failure message). For a successful BTC broadcast, the inspector caches the resulting Bitcoin txid and current BTC block height (from the on-chain L1Block contract). These cached values are later used to lock the affected slots.
Integration with Execution Layer: After each transaction (and at end-of-block), Sova’s execution engine invokes the inspector to update the Sentinel with any new locks. The inspector’s update_sentinel_locks()
will batch-lock all storage slots that were written during a Bitcoin-related operation, tying them to the specific BTC txid and the Sova block number. This call notifies the Sentinel to record (in its database) that those slots are now immutable until the Bitcoin transaction confirms or is finalized. In essence, the execution layer defers finalizing certain state changes until the Bitcoin network consensus is reached. The inspector and Sentinel together implement an optimistic execution: state is updated on Sova immediately, but can be rolled back by the inspector later if the BTC tx fails to confirm. This design tightly couples Sova’s EVM execution with Bitcoin’s state, ensuring that smart contracts cannot double-mint or double-spend BTC-pegged assets. It effectively extends Ethereum’s execution model with a Bitcoin finality oracle.
Bitcoin Finality via the Sentinel API and Database
Sentinel Service & Slot Locks: The Sova Sentinel is an off-chain gRPC service (with a SQLite DB) dedicated to tracking Bitcoin transaction confirmations and locking contract storage until finality. Its core purpose is to prevent double-spend or replay attacks when minting or moving BTC-backed assets on Sova. The Sentinel maintains a record of each “slot lock,” which links a contract storage slot to a specific Bitcoin transaction (by txid) and the original value to revert to if needed. When the Sova node calls LockSlot
(or batch variant) during a Bitcoin-related transaction, the Sentinel records the current slot value and the intended new value in its DB, marking it as Locked. This means the contract state associated with that BTC tx should not be altered by any other transaction until confirmations are achieved. For example, when a user submits a Bitcoin transaction to mint sovaBTC (Sova’s BTC-pegged token), the slot that records that BTC deposit is locked as soon as the mint is initiated. This ensures the same Bitcoin TX cannot be reused to mint twice, and the data cannot be tampered with mid-confirmation.
Confirmation and Finalization: The Sentinel continuously monitors the Bitcoin blockchain (via an RPC Bitcoin node) to check the confirmation status of each tracked txid. By default it requires 6 confirmations (configurable) for finality, aligning with Bitcoin’s standard safety threshold. Each lock record stores the Bitcoin block height when the tx was first seen. When a Sova node later queries get_slot_status
(e.g. at the start of a new block or when a locked slot is accessed), the Sentinel compares the current Bitcoin tip to the saved height to determine confirmations. If the tx has reached the confirmation threshold, the Sentinel will mark the slot as Unlocked and allow state to be finalized. At that point, the previously tentative state change (e.g. minted tokens) becomes permanent. If the transaction is still unconfirmed and within the threshold, the slot remains Locked (further writes are rejected).
Reversion on Failure: If a Bitcoin transaction fails to confirm in a reasonable time (e.g. after a certain number of extra blocks, default is 18 blocks as per BITCOIN_REVERT_THRESHOLD
), the Sentinel can declare the slot Reverted. In a Reverted status, the Sentinel provides the original stored value and the current (tentative) value back to the execution client. The Sova inspector then uses this info to rollback the contract state to the revert value, effectively undoing the mint or state change as if the Bitcoin tx never happened. This mechanism is crucial: it protects Sova from a scenario where, for example, a user’s BTC deposit tx gets orphaned or double-spent on Bitcoin after sovaBTC was already minted on Sova. By reverting, the sovaBTC maintains a 1:1 backing. The Sentinel’s database keeps both the current_value
and revert_value
for each slot, so it can instruct the node exactly how to restore state. The inspector applies these reverts by injecting the prior values back into the EVM’s state journal for that contract slot.
L1 Block Anchoring: In addition to per-transaction locks, Sova adds a Bitcoin finality anchor in every block. Each new Sova block includes a system “deposit” transaction to the SovaL1Block
contract that records the latest Bitcoin block info. This setBitcoinBlockData(uint64 blockHeight, bytes32 blockHash)
call stores the current Bitcoin chain height and the hash of the block that is N blocks back (N = confirmation threshold, e.g. 6). Every block, Sova’s builder fetches Bitcoin’s tip height and the hash of tip−6 and injects that into the block’s first transactions. During block execution, the node validates this by querying a Bitcoin RPC: it checks that the provided block hash matches the actual hash at (height−6) on the Bitcoin node. If it doesn’t match (meaning an invalid or outdated anchor), the block is rejected. This design ensures Bitcoin-native confirmation and finalization at the chain level: a Sova block is only considered valid if it’s anchored to a recent Bitcoin block that eventually becomes deeply confirmed. In effect, Sova cannot finalize its state changes beyond 6 blocks without a corresponding final Bitcoin checkpoint. This provides strong finality guarantees – a Sova block can’t be reversed unless the referenced Bitcoin block (with 6 confirms) itself gets reorganized, which is extraordinarily unlikely.
Auditable Trail of Deposits: The architecture is intended to provide an end-to-end auditable trail of each BTC deposit and withdrawal. Each deposit’s details (BTC txid, amount, destination user) are captured on Sova – by an event log and a contract storage mapping. The Sentinel also keeps an off-chain record of every locked slot and associated txid. A third-party auditor (or a Sova full node operator) can correlate these records: for every sovaBTC minted, there should be a corresponding Bitcoin transaction in the Bitcoin ledger sending that exact amount to the sovaBTC contract address. By examining Sova’s on-chain state and events, one can list all BTC txids that led to sovaBTC mints and verify each tx on Bitcoin. Similarly, all sovaBTC burns (withdrawals) correspond to actual Bitcoin outputs sent out – and the precompile’s output includes the BTC txid, which could be logged or obtained by the user (the inspector returns the 32-byte txid on success). Because Sova’s L1Block contract regularly records the current Bitcoin block hash, one can also verify independently that the Sentinel is reporting confirmations correctly – the hash of the Bitcoin block at height H-6 is stored on-chain, so anyone running a Bitcoin node can confirm that any given Sova block was anchored to the correct Bitcoin state.
Independent Verification by Nodes: A third-party node operator could run their own Sentinel instance pointing to their Bitcoin node to cross-verify all locks. (In practice, all validators must agree on lock status, so the “official” Sentinel is a source of truth. However, because Bitcoin data is globally available, any discrepancy would be detectable by comparing to one’s own Bitcoin node.) This means the trail of BTC deposits -> sovaBTC and back is transparent: at any time, the total sovaBTC supply on Sova should equal the total BTC that was sent into the system minus BTC withdrawn. This design allows an auditor to track this total and even map individual transactions. For example, if 100 sovaBTC exist on Sova, an auditor can find exactly which Bitcoin transactions contributed to that 100 and confirm those transactions had 6 confirmations. If an inconsistency is found (e.g. sovaBTC supply that isn’t backed by confirmed BTC), it would imply a breach of protocol by the operators – something the design is meant to prevent.
Last updated