Skip to content

Commit 585b94c

Browse files
committed
Add README file
1 parent 529a6f6 commit 585b94c

File tree

6 files changed

+81
-41
lines changed

6 files changed

+81
-41
lines changed

README.md

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,76 @@
1-
# SPV Contracts
1+
# SPV Contracts
2+
3+
Smart contract for verifying Bitcoin block headers on EVM-compatible chains using the **Simple Payment Verification (SPV)** method.
4+
5+
This contract behaves like an SPV node: it builds a valid chain of Bitcoin block headers, verifies them according to Bitcoin consensus rules, and enables Merkle Proof-based verification of Bitcoin transactions.
6+
7+
## Features
8+
9+
- Stores and verifies Bitcoin block headers
10+
- Validates headers using:
11+
- Proof of Work (`bits``target`)
12+
- Median time rule
13+
- Chain continuity
14+
- Handles difficulty adjustment every 2016 blocks
15+
- Supports pending difficulty epochs before finalization
16+
- Stores historical targets and supports reorg handling
17+
18+
## Contract: `SPVContract.sol`
19+
20+
### Key Functions
21+
22+
#### `addBlockHeader(bytes calldata blockHeaderRaw)`
23+
Adds and validates a new block header, updates internal state, and emits an event.
24+
25+
### Validation Rules
26+
- `prevBlockHash` must point to a known block
27+
- New `blockHash` must not exist
28+
- Header `bits` must match the expected network target
29+
- Header `time` must be > median of last 11 blocks
30+
- `blockHash` must be less than or equal to the target (valid PoW)
31+
32+
## Storage Structure
33+
34+
- `BlocksData` – stores block headers, timestamps, and chain height
35+
- `TargetsData` – handles target values and difficulty epochs
36+
- `pendingTargetHeightCount` – controls target finalization after N blocks
37+
38+
## Dev Info
39+
### Compilation
40+
41+
To compile the contracts, use the next script:
42+
43+
```bash
44+
npm run compile
45+
```
46+
47+
### Test
48+
49+
To run the tests, execute the following command:
50+
51+
```bash
52+
npm run test
53+
```
54+
55+
Or to see the coverage, run:
56+
57+
```bash
58+
npm run coverage
59+
```
60+
61+
### Local deployment
62+
63+
To deploy the contracts locally, run the following commands (in the different terminals):
64+
65+
```bash
66+
npm run private-network
67+
npm run deploy-localhost
68+
```
69+
70+
### Bindings
71+
72+
The command to generate the bindings is as follows:
73+
74+
```bash
75+
npm run generate-types
76+
```

contracts/libs/BlocksStorage.sol

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ library BlocksStorage {
2222
Unknown,
2323
Pending,
2424
Stale,
25-
Active
25+
Confirmed
2626
}
2727

2828
struct BlockData {
@@ -195,7 +195,7 @@ library BlocksStorage {
195195
return BlockStatus.Stale;
196196
}
197197

198-
return BlockStatus.Active;
198+
return BlockStatus.Confirmed;
199199
}
200200

201201
function getMedianTime(

hardhat.config.ts

Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -38,38 +38,6 @@ const config: HardhatUserConfig = {
3838
accounts: privateKey(),
3939
gasMultiplier: 1.2,
4040
},
41-
chapel: {
42-
url: "https://data-seed-prebsc-1-s1.binance.org:8545",
43-
accounts: privateKey(),
44-
gasMultiplier: 1.2,
45-
timeout: 60000,
46-
},
47-
fuji: {
48-
url: `https://avalanche-fuji.infura.io/v3/${process.env.INFURA_KEY}`,
49-
accounts: privateKey(),
50-
gasMultiplier: 1.2,
51-
},
52-
bsc: {
53-
url: "https://bsc-dataseed.binance.org/",
54-
accounts: privateKey(),
55-
gasMultiplier: 1.2,
56-
},
57-
ethereum: {
58-
url: `https://mainnet.infura.io/v3/${process.env.INFURA_KEY}`,
59-
accounts: privateKey(),
60-
gasMultiplier: 1.2,
61-
},
62-
polygon: {
63-
url: `https://matic-mainnet.chainstacklabs.com`,
64-
accounts: privateKey(),
65-
gasMultiplier: 1.2,
66-
},
67-
avalanche: {
68-
url: `https://api.avax.network/ext/bc/C/rpc`,
69-
accounts: privateKey(),
70-
gasMultiplier: 1.2,
71-
timeout: 60000,
72-
},
7341
},
7442
solidity: {
7543
version: "0.8.28",

package.json

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,6 @@
2525
"private-network-fork": "npx hardhat node --fork https://mainnet.infura.io/v3/$(grep INFURA_KEY .env | cut -d '\"' -f2)",
2626
"deploy-localhost": "npx hardhat migrate --network localhost",
2727
"deploy-sepolia": "npx hardhat migrate --network sepolia --verify",
28-
"deploy-fuji": "npx hardhat migrate --network fuji --verify",
29-
"deploy-ethereum": "npx hardhat migrate --network ethereum --verify",
30-
"deploy-avalanche": "npx hardhat migrate --network avalanche --verify",
3128
"generate-types": "TYPECHAIN_FORCE=true npx hardhat typechain && npx hardhat gobind",
3229
"generate-docs": "npx hardhat markup",
3330
"solhint-check": "solhint \"./contracts/**/*.sol\"",

test/helpers/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,5 @@ export enum BlockStatus {
2929
Unknown = 0,
3030
Pending = 1,
3131
Stale = 2,
32-
Active = 3,
32+
Confirmed = 3,
3333
}

test/libs/BlocksStorage.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ describe("BlocksStorage", () => {
151151
if (i > defaultPendingBlocksCount) {
152152
expect(
153153
await blocksStorageLib.getBlockStatus(blocksData[i - defaultPendingBlocksCount - 1].blockHash),
154-
).to.be.eq(BlockStatus.Active);
154+
).to.be.eq(BlockStatus.Confirmed);
155155
}
156156
}
157157
});
@@ -202,7 +202,7 @@ describe("BlocksStorage", () => {
202202
if (i > defaultPendingBlocksCount) {
203203
expect(
204204
await blocksStorageLib.getBlockStatus(blocksData[i - defaultPendingBlocksCount - 1].blockHash),
205-
).to.be.eq(BlockStatus.Active);
205+
).to.be.eq(BlockStatus.Confirmed);
206206
}
207207
}
208208
});

0 commit comments

Comments
 (0)