Bitcoin Light Client

Serves as a smart contract based light client for Bitcoin. For each new Bitcoin block, the block hash and the witness root are written into this contract. This is done with a system transaction executed in the beginning of the first Citrea block that corresponds to the new Bitcoin block.

You can find this contract at address 0x31000...0001, here.

State Structure

uint256 public blockNumber;

Next block height to store block hash and witness root information for.


mapping(uint256 => bytes32) public blockHashes;

A block height: block hash mapping. It stores the block hash of the block for a given block height in Bitcoin.


mapping(bytes32 => bytes32) public witnessRoots;

A block hash: witness root mapping. It stores the witness root of the block corresponding to a given block hash in Bitcoin.

Access Control Structure

modifier onlySystem() 

This contract has only one access control modifier, and it is used to check the caller of a function against the hardcoded system caller address which is 0xdeaDDeADDEaDdeaDdEAddEADDEAdDeadDEADDEaD.

Functions

function initializeBlockNumber(uint256 _blockNumber) external onlySystem

Gets triggered in the first ever Citrea block, and it sets the block height of the Bitcoin block that corresponds to the first Citrea block. This function is called only once during the lifetime of the contract and it is called by the system caller.


function setBlockInfo(bytes32 _blockHash, bytes32 _witnessRoot) external onlySystem

Called by the system caller and it sets the block hash and witness root of the next Bitcoin block denoted by the blockNumber. It also increments the blockNumber by one.


function getBlockHash(uint256 _blockNumber) external view returns (bytes32)

Returns the block hash of the Bitcoin block corresponding to the given block height.


The following functions getWitnessRootByHash and getWitnessRootByNumber returning the zero value does NOT mean that there is no such a block recorded unlike the blockhash getters as it is possible for a valid witness root to be the zero value in the case of a Bitcoin block with one transaction. This happens as the wTXId of a coinbase transaction is the zero value and the Merkle root is the leaf itself in the case of one leaf.

function getWitnessRootByHash(bytes32 _blockHash) external view returns (bytes32)

Returns the witness root of the Bitcoin block corresponding to the given block hash.


function getWitnessRootByNumber(uint256 _blockNumber) external view returns (bytes32)

Returns the witness root of the Bitcoin block corresponding to the given block height.


The following verifyInclusion functions will pass when zero value is passed with _wtxId as the zero value is a valid wTXId for a coinbase transaction and it exists in all Bitcoin blocks. Thus the integrators must make sure to not provide the zero wTXId as input accidentally as it may happen in cases like sending information from a deleted Solidity user record which will have the zero bytes32 value as that is the default value for bytes32 in Solidity.

function verifyInclusion(bytes32 _blockHash, bytes32 _wtxId, bytes calldata _proof, uint256 _index) external view returns (bool)

Verifies the inclusion of a Bitcoin transaction in a particular Bitcoin block specified by its block hash. Returns whether the transaction is included in the given block. It functions by constructing the Merkle root from the wTXID of the queried transaction and provided Merkle path as _proof and then comparing it with the witness root stored in this contract of the block specified by the passed block hash.


function verifyInclusion(uint256 _blockNumber, bytes32 _wtxId, bytes calldata _proof, uint256 _index) external view returns (bool)

Verifies the inclusion of a Bitcoin transaction in a particular Bitcoin block specified by its block height. Returns whether the transaction is included in the given block. It functions by constructing the Merkle root from the wTXID of the queried transaction and provided Merkle path as _proof and then comparing it with the witness root stored in this contract of the block specified by the passed block height.

Last updated