Skip to content

Commit e06f633

Browse files
authored
Merge pull request #10 from distributed-lab/fix/readme
Readme
2 parents 4ecf776 + 67bdd42 commit e06f633

File tree

5 files changed

+51
-332
lines changed

5 files changed

+51
-332
lines changed

.github/workflows/docs.yml

Lines changed: 0 additions & 51 deletions
This file was deleted.

README.md

Lines changed: 51 additions & 233 deletions
Original file line numberDiff line numberDiff line change
@@ -1,233 +1,51 @@
1-
# 🛡️ SPV Gateway: Bitcoin Light Client on EVM
2-
Welcome to the **SPV Gateway**, a robust and efficient Solidity implementation for verifying Bitcoin block headers directly on an EVM-compatible blockchain. This contract empowers dApps to act as a **Simplified Payment Verification (SPV)** client, allowing them to validate the existence and inclusion of Bitcoin transactions without needing to run a full Bitcoin node.
3-
4-
# ✨ Why this SPV Gateway?
5-
In the decentralized world, connecting different blockchain ecosystems securely is paramount. This SPV Gateway provides a trust-minimized bridge, enabling smart contracts on EVM chains to cryptographically verify the state of the Bitcoin blockchain. This opens doors for exciting use cases like:
6-
- **Cross-chain bridges** for Bitcoin-backed assets
7-
- **Light clients** for dApps that need to confirm Bitcoin transaction finality
8-
- **Decentralized custodianship** solutions
9-
- **Oracle services** for Bitcoin data on EVM
10-
11-
# 🚀 Key Features
12-
- **Block Header Submission:** Efficiently add individual or batches of Bitcoin block headers to the contract.
13-
- **Mainchain Tracking:** Automatically identifies and updates the "main" Bitcoin chain based on accumulated work.
14-
- **Block Validation:** Verifies block headers against Bitcoin's consensus rules, including:
15-
- Proof-of-Work (target difficulty)
16-
- Block time validity (median time past)
17-
- Chain continuity (previous block hash)
18-
- **Block Information Retrieval:** Query detailed information about any stored block, such as:
19-
- Its Merkle root
20-
- Its height
21-
- Its inclusion status in the mainchain
22-
- Its cumulative work (difficulty)
23-
- Its confirmation count relative to the mainchain head
24-
- **Difficulty Adjustment:** Integrates Bitcoin's precise difficulty adjustment algorithm to accurately calculate current and future targets.
25-
26-
# ⚙️ How it Works (Under the Hood)
27-
The contract operates by receiving raw Bitcoin block headers, which are then parsed and validated against Bitcoin's strict consensus rules.
28-
29-
1. **Header Parsing:** Raw 80-byte Bitcoin block headers are parsed into a structured *BlockHeader.HeaderData* format. This involves handling Bitcoin's unique little-endian byte ordering.
30-
2. **Double SHA256 Hashing:** Each block header is double SHA256 hashed to derive its unique block hash, which is then byte-reversed for standard representation.
31-
3. **Proof-of-Work Verification:** The calculated block hash is checked against the current network difficulty target (derived from the *bits* field in the header).
32-
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 higher cumulative work, the *mainchainHead* is updated, reflecting potential chain reorganizations.
33-
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.
34-
35-
# 📊 Flow Diagrams
36-
These diagrams outline the step-by-step process for adding block headers to the SPV Gateway.
37-
38-
### `addBlockHeader(bytes calldata blockHeaderRaw_)` Sequence Diagram
39-
40-
```mermaid
41-
sequenceDiagram
42-
participant Caller
43-
participant SPVGateway
44-
participant BlockHeaderLib
45-
participant TargetsHelperLib
46-
47-
Caller->>SPVGateway: addBlockHeader(blockHeaderRaw)
48-
activate SPVGateway
49-
50-
SPVGateway->>BlockHeaderLib: 1. Parse blockHeaderRaw_ (parseBlockHeaderData)
51-
activate BlockHeaderLib
52-
BlockHeaderLib-->>SPVGateway: 1.1. Check length (80 bytes) & LE to BE
53-
alt Length Invalid
54-
BlockHeaderLib--xSPVGateway: Error: InvalidBlockHeaderDataLength
55-
SPVGateway--xCaller: Revert
56-
end
57-
BlockHeaderLib-->>SPVGateway: 1.2. Return BlockHeaderData & blockHash
58-
deactivate BlockHeaderLib
59-
60-
SPVGateway->>SPVGateway: 1.3. Check blockHash existence
61-
alt BlockHash Exists
62-
SPVGateway--xCaller: Error: BlockAlreadyExists
63-
end
64-
65-
SPVGateway->>SPVGateway: 2. Check prevBlockHash existence
66-
alt Prev Block Missing
67-
SPVGateway--xCaller: Error: PrevBlockDoesNotExist
68-
end
69-
70-
SPVGateway->>SPVGateway: 3. Calculate newBlockHeight = prevBlockHeight + 1
71-
72-
SPVGateway->>SPVGateway: 4. Get Current Target
73-
SPVGateway->>SPVGateway: 4.1. Get target from prevBlockBits
74-
SPVGateway->>TargetsHelperLib: Check if newBlockHeight is Recalculation Block (isTargetAdjustmentBlock)
75-
activate TargetsHelperLib
76-
alt Recalculation Block
77-
SPVGateway->>SPVGateway: Recalculate target & Save lastEpochCumulativeWork
78-
TargetsHelperLib-->>SPVGateway: Return newNetworkTarget
79-
else Not Recalculation Block
80-
TargetsHelperLib-->>SPVGateway: Use prevBlockTarget as networkTarget
81-
end
82-
deactivate TargetsHelperLib
83-
84-
SPVGateway->>SPVGateway: 5. Check Block Rules
85-
SPVGateway->>TargetsHelperLib: 5.1. Check Header Target == Contract Target
86-
activate TargetsHelperLib
87-
TargetsHelperLib-->>SPVGateway: Result
88-
deactivate TargetsHelperLib
89-
alt Invalid Target
90-
SPVGateway--xCaller: Error: InvalidTarget
91-
end
92-
93-
SPVGateway->>SPVGateway: 5.2. Check newBlockHash <= networkTarget (PoW)
94-
alt Invalid Block Hash
95-
SPVGateway--xCaller: Error: InvalidBlockHash
96-
end
97-
98-
SPVGateway->>SPVGateway: 5.3. Check newBlockTime >= medianTime
99-
alt Invalid Block Time
100-
SPVGateway--xCaller: Error: InvalidBlockTime
101-
end
102-
103-
SPVGateway->>SPVGateway: 6. Add Block To Chain
104-
SPVGateway->>SPVGateway: 6.1. Save newBlockHeader & newBlockHash to Storage
105-
106-
SPVGateway->>SPVGateway: 6.2. Update Mainchain
107-
alt 6.2.1. prevBlockHash == mainchainHead?
108-
SPVGateway->>SPVGateway: Move mainchainHead to newBlockHash
109-
else
110-
SPVGateway->>SPVGateway: 6.2.2. Calculate New Block & Current Head Cumulative Work
111-
SPVGateway->>SPVGateway: 6.2.3. newBlock Cumulative Work > Current Head?
112-
alt New Block Has Higher Work
113-
SPVGateway->>SPVGateway: Set New Block as mainchainHead
114-
SPVGateway->>SPVGateway: Recursively update mainchain path backwards (do-while loop)
115-
end
116-
end
117-
118-
SPVGateway->>SPVGateway: Emit BlockHeaderAdded
119-
SPVGateway-->>Caller: Transaction Complete
120-
deactivate SPVGateway
121-
```
122-
123-
### `addBlockHeaderBatch(bytes[] calldata blockHeaderRawArr_)` Sequence Diagram
124-
125-
This function processes multiple block headers in a single transaction, iterating through the array and validating each sequentially.
126-
127-
```mermaid
128-
sequenceDiagram
129-
participant Caller
130-
participant SPVGateway
131-
participant BlockHeaderLib
132-
participant TargetsHelperLib
133-
134-
Caller->>SPVGateway: addBlockHeaderBatch(blockHeaderRawArray_)
135-
activate SPVGateway
136-
137-
SPVGateway->>SPVGateway: Check if Header Array is Empty
138-
alt Array Empty
139-
SPVGateway--xCaller: Error: EmptyBlockHeaderArray
140-
end
141-
142-
SPVGateway->>BlockHeaderLib: 1. Parse Block Headers Array (_parseBlockHeadersRaw)
143-
activate BlockHeaderLib
144-
BlockHeaderLib-->>SPVGateway: Returns BlockHeaderData[] & bytes32[]
145-
deactivate BlockHeaderLib
146-
147-
loop For each blockHeader in parsed array (from i=0 to length-1)
148-
SPVGateway->>SPVGateway: 2. Check prevBlockHash for current block
149-
alt First block in batch
150-
SPVGateway->>SPVGateway: Check prevBlockHash existence (like addBlockHeader)
151-
alt Prev Block Missing
152-
SPVGateway--xCaller: Error: PrevBlockDoesNotExist
153-
end
154-
else Subsequent blocks
155-
SPVGateway->>SPVGateway: Check prevBlockHash == blockHash of (i-1)th block
156-
alt Order Invalid
157-
SPVGateway--xCaller: Error: InvalidBlockHeadersOrder
158-
end
159-
end
160-
161-
SPVGateway->>SPVGateway: 3. Calculate currentBlockHeight = prevBlockHeight + 1
162-
163-
SPVGateway->>SPVGateway: 4. Get Current Target (like addBlockHeader)
164-
SPVGateway->>TargetsHelperLib: Check for Recalculation Block & Recalculate if needed
165-
activate TargetsHelperLib
166-
TargetsHelperLib-->>SPVGateway: Return networkTarget
167-
deactivate TargetsHelperLib
168-
169-
SPVGateway->>SPVGateway: 5. Get Median Time
170-
alt 5.1. Num blocks added < 12
171-
SPVGateway->>SPVGateway: Use _getStorageMedianTime (like addBlockHeader)
172-
else 5.2. Num blocks added >= 12
173-
SPVGateway->>SPVGateway: Use _getMemoryMedianTime (from batch data)
174-
end
175-
176-
SPVGateway->>SPVGateway: 6. Validate Block Rules (_validateBlockRules)
177-
alt Validation Fails
178-
SPVGateway--xCaller: Error: InvalidTarget / InvalidBlockHash / InvalidBlockTime
179-
end
180-
181-
SPVGateway->>SPVGateway: 7. Add Block To Chain (_addBlock)
182-
SPVGateway->>SPVGateway: Emit BlockHeaderAdded
183-
end
184-
185-
SPVGateway-->>Caller: Transaction Complete
186-
deactivate SPVGateway
187-
```
188-
189-
190-
# 📦 Contract Components
191-
The solution primarily consists of the main SPV Gateway contract and the TargetsHelper library, which manages difficulty adjustments.
192-
193-
## SPVGateway
194-
This is the central contract that users will interact with. It serves as the primary interface for managing Bitcoin block headers on the EVM. It handles the core logic for adding and validating blocks, tracking the main Bitcoin chain, and providing querying functionalities. All custom errors and events related to the SPV operations are defined here, ensuring clear feedback and transparency during contract execution.
195-
196-
## TargetsHelper Library
197-
This library encapsulates all the complex mathematical and logical operations related to Bitcoin's difficulty targets. It provides functions to accurately calculate new difficulty targets based on elapsed time between blocks, ensuring the contract adheres to Bitcoin's dynamic difficulty adjustment rules. Additionally, it offers utilities for converting between the compact "bits" format (as found in Bitcoin block headers) and the full 256-bit target value, and it calculates the cumulative work associated with a given block or epoch, which is vital for determining the most valid chain.
198-
199-
# 💻 Dev Info
200-
## Compilation
201-
To compile the contracts, use the next script:
202-
203-
```bash
204-
npm run compile
205-
```
206-
207-
## Test
208-
To run the tests, execute the following command:
209-
210-
```bash
211-
npm run test
212-
```
213-
214-
Or to see the coverage, run:
215-
216-
```bash
217-
npm run coverage
218-
```
219-
220-
## Local deployment
221-
To deploy the contracts locally, run the following commands (in the different terminals):
222-
223-
```bash
224-
npm run private-network
225-
npm run deploy-localhost
226-
```
227-
228-
## Bindings
229-
The command to generate the bindings is as follows:
230-
231-
```bash
232-
npm run generate-types
233-
```
1+
# ERC-8002: SPV Gateway
2+
3+
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.
4+
5+
Link to [ERC-8002](https://ethereum-magicians.org/t/erc-8002-simplified-payment-verification-gateway/25038).
6+
7+
> [!NOTE]
8+
> 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.
9+
10+
# How it Works
11+
12+
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:
13+
14+
1. Header Parsing: Raw 80-byte Bitcoin block headers are parsed into a structured *BlockHeader.HeaderData* format, handling Bitcoin's little-endian byte ordering.
15+
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.
16+
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).
17+
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.
18+
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.
19+
20+
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.
21+
22+
## Submitting Bitcoin Blocks
23+
24+
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.
25+
26+
In case multiple blocks can be added, call `addBlockHeaderBatch` function to save ~15% on gas per block.
27+
28+
## Verifying Bitcoin Tx Inclusion
29+
30+
In order to verify the tx existence, the `checkTxInclusion` function needs to be called.
31+
32+
The list parameters to be passed:
33+
34+
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.
35+
2. `blockHash` - Hash of the block to check the tx inclusion against. This block is required to exist in the SPV storage.
36+
3. `txId` - Tx hash (Merkle leaf) to be checked.
37+
4. `txIndex` - The Merkle "direction bits" to decide on left or right hashing order.
38+
5. `minConfirmationsCount` - Number of required mainchain confirmation for the block to have.
39+
40+
> [!TIP]
41+
> Please check out [this test case](./test/SPVContract.test.ts#L223) for more integration information.
42+
43+
## Permissionlessness
44+
45+
In order for the gateway to be truly permissionless, the contract's bootstrapping needs to be permissionless as well. We are working on a "proof-of-bitcoin" ZK proof to initialize the gateway in a trustless manner.
46+
47+
This will enable verification of historical Bitcoin transactions otherwise too expensive to include. Syncing up the gateway from Bitcoin's genesis would cost ~100 ETH on the mainnet.
48+
49+
# Disclaimer
50+
51+
Bitcoin + Ethereum = <3

docs/.nojekyll

Whitespace-only changes.

docs/index.html

Lines changed: 0 additions & 42 deletions
This file was deleted.

scripts/generateDocs.sh

Lines changed: 0 additions & 6 deletions
This file was deleted.

0 commit comments

Comments
 (0)