Skip to content
Draft

Dev #12

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 0 additions & 20 deletions .github/actions/setup/action.yml

This file was deleted.

23 changes: 0 additions & 23 deletions .github/workflows/checks.yml

This file was deleted.

100 changes: 3 additions & 97 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,99 +1,5 @@
# ERC-8002: SPV Gateway
# ERC-8002: SPV Gateway

Introduce a singleton contract for on-chain verification of transactions that happened on Bitcoin. The contract acts as a trustless Simplified Payment Verification (SPV) gateway where anyone can submit Bitcoin block headers. The gateway maintains the mainchain of blocks and allows the existence of Bitcoin transactions to be verified via Merkle proofs.
This repository contains the smart contracts and services for the `SPV Gateway` — protocol that enables the trustless on-chain verification of transactions that happened on the Bitcoin network.

Link to [ERC-8002](https://ethereum-magicians.org/t/erc-8002-simplified-payment-verification-gateway/25038).

> [!NOTE]
> Since the ERC is currently a draft, there is no deployment on mainnet available. Please use [the contract on Sepolia](https://sepolia.etherscan.io/address/0xE8e6CA2113338c12eb397617371D92239f3E6A60) for testing purposes.

# How it Works

The gateway is a permissionless contract that operates by receiving raw Bitcoin block headers (anyone can submit them), which are then parsed and validated against Bitcoin's consensus rules:

1. Header Parsing: Raw 80-byte Bitcoin block headers are parsed into a structured *BlockHeader.HeaderData* format, handling Bitcoin's little-endian byte ordering.
2. Double SHA256 Hashing: Each block header is double SHA256 hashed to derive its unique block hash, which is then saved in a big-endian format.
3. Proof-of-Work Verification: The calculated block hash is checked against the current network difficulty target (derived from the *bits* field in the block header).
4. Chain Extension & Reorganization: New blocks are added to a data structure that allows for tracking multiple chains. When a new block extends a chain with larger cumulative work, the *mainchainHead* is updated, reflecting potential chain reorganizations.
5. Difficulty Adjustment: Every 2016 blocks, the contract calculates a new difficulty target based on the time taken to mine the preceding epoch. This ensures the 10-minute average block time is maintained.

Under the hood, the contract builds the mainchain but doesn't define its finality. The number of required block confirmations is up to the integration dApps to decide.

## Submitting Bitcoin Blocks

To submit a new Bitcoin block, call `addBlockHeader` function by passing a valid raw block header as a parameter. It is an open function that will revert in case Bitcoin PoW checks don't pass.

In case multiple blocks can be added, call `addBlockHeaderBatch` function to save ~15% on gas per block.

## Verifying Bitcoin Tx Inclusion

In order to verify the tx existence, the `checkTxInclusion` function needs to be called.

The list parameters to be passed:

1. `merkleProof` - Merkle path for a given transaction to be checked. The Merkle path can either be built locally or by calling `gettxoutproof` on a Bitcoin node.
2. `blockHash` - Hash of the block to check the tx inclusion against. This block is required to exist in the SPV storage.
3. `txId` - Tx hash (Merkle leaf) to be checked.
4. `txIndex` - The Merkle "direction bits" to decide on left or right hashing order.
5. `minConfirmationsCount` - Number of required mainchain confirmation for the block to have.

> [!TIP]
> Please check out [this test case](./test/SPVGateway.test.ts#L223) for more integration information.

## Permissionlessness

In order for the gateway to be truly permissionless, the contract's initialization needs to be permissionless as well. Alongside the regular `SPVGateway`, the repository hosts a `HistoricalSPVGateway` contract, that uses a "proof-of-bitcoin" ZK proof for its initialization. This enables verification of historical Bitcoin blocks and transactions otherwise too expensive to include. Since syncing up the gateway from Bitcoin's genesis would cost ~100 ETH on the mainnet.

# HistoricalSPVGateway

`HistoricalSPVGateway` is an extension of the basic `SPVGateway` contract. It uses "proof-of-bitcoin" ZK proof that compresses the entire Bitcoin block history into a single Merkle root to be used during the contract's initialization. This root can then used to verify the "historical" existence of some blocks and transactions.

> [!IMPORTANT]
> Currently, the "proof-of-bitcoin" ZK proof is generated to the first *912384* Bitcoin blocks. The circuits source code can be found [here](https://github.com/distributed-lab/bitcoin-prover).

## Building the History Merkle Tree

In order to prove the historical block existence, you need to pass the corresponding Merkle path to a smart contract. For that, the entire historical Merkle tree needs to be built:

1. Fetch all block hashes from the genesis block up to the height of `provedBlocksCount - 1`.
2. Split these blocks into *1024-block* chunks.
3. Create Level1 Merkle trees for each chunk.
4. Create an array containing all the Level1 tree roots.
5. Pad the array from the previous step with zeros for its length to reach the next power of 2.
6. Create a Level2 Merkle tree, using the array from the previous step as the tree's values.

> [!NOTE]
> For the Level1 Merkle tree use `SHA256("leaf1" | blockHash)` and `SHA256("node1" | left | right)` for hashing leaves and nodes. And for the Level2 Merkle tree, `SHA256("leaf2" | level1MerkleRoot)` and `SHA256("node2" | left | right)` respectively.

## Verifying History Bitcoin Blocks Inclusion

To verify the existence of a historical Bitcoin block, call the `checkHistoryBlockInclusion` function.

This function requires a `HistoryBlockInclusionProofData` struct as a parameter, which contains the following fields:

1. `level1MerkleProof` - Level1 Merkle path for the block hash being checked.
2. `level2MerkleProof` - Level2 Merkle path for the Level1 Merkle root (which is calculated from the `level1MerkleProof`)
3. `blockHash` - Block hash to be checked.
4. `blockHeight` - Block height of the passed block hash.

> [!TIP]
> Please check out [this test cases](./test/HistoricalSPVGateway.test.ts#L181) for more integration information.

## Verifying History Bitcoin Tx Inclusion

In order to verify the tx existence in the proven Bitcoin history, the `checkHistoryTxInclusion` function needs to be called.

The list of parameters to be passed:

1. `merkleProof` - Merkle path for a given transaction to be checked. The Merkle path can either be built locally or by calling `gettxoutproof` on a Bitcoin node.
2. `blockHeaderRaw` - Raw block header of the block to check the transaction's inclusion against.
3. `txId` - Tx hash (Merkle leaf) to be checked.
4. `txIndex` - The Merkle "direction bits" to decide on left or right hashing order.
5. `blockInclusionProofData` - The proof data for the historical block hash inclusion.

> [!TIP]
> Please check out [this test case](./test/HistoricalSPVGateway.test.ts#L309) for more integration information.

# Disclaimer

Bitcoin + Ethereum = <3
The protocol functions as a permissionless Simplified Payment Verification (SPV) gateway. Anyone can submit Bitcoin block headers to the gateway, which then validates them against Bitcoin's consensus rules. The gateway maintains the mainchain and allows dApps to verify a transaction's existence using Merkle proofs.
Loading