diff --git a/.all-contributorsrc b/.all-contributorsrc
index be74b079..0974e3de 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -144,6 +144,60 @@
"contributions": [
"code"
]
+ },
+ {
+ "login": "Gerson2102",
+ "name": "Gerson",
+ "avatar_url": "https://avatars.githubusercontent.com/u/71728860?v=4",
+ "profile": "https://github.com/Gerson2102",
+ "contributions": [
+ "code"
+ ]
+ },
+ {
+ "login": "PavitraAgarwal21",
+ "name": "PavitraAgarwal21",
+ "avatar_url": "https://avatars.githubusercontent.com/u/85789615?v=4",
+ "profile": "https://github.com/PavitraAgarwal21",
+ "contributions": [
+ "code"
+ ]
+ },
+ {
+ "login": "bloomingpeach",
+ "name": "Nguyen Dao",
+ "avatar_url": "https://avatars.githubusercontent.com/u/177087057?v=4",
+ "profile": "https://github.com/bloomingpeach",
+ "contributions": [
+ "code"
+ ]
+ },
+ {
+ "login": "od-hunter",
+ "name": "Hunter001",
+ "avatar_url": "https://avatars.githubusercontent.com/u/146340502?v=4",
+ "profile": "https://github.com/od-hunter",
+ "contributions": [
+ "code"
+ ]
+ },
+ {
+ "login": "feltroidprime",
+ "name": "feltroid Prime",
+ "avatar_url": "https://avatars.githubusercontent.com/u/96737978?v=4",
+ "profile": "https://github.com/feltroidprime",
+ "contributions": [
+ "code"
+ ]
+ },
+ {
+ "login": "mexes20",
+ "name": "Mexes",
+ "avatar_url": "https://avatars.githubusercontent.com/u/127276944?v=4",
+ "profile": "https://github.com/mexes20",
+ "contributions": [
+ "code"
+ ]
}
],
"contributorsPerLine": 7,
diff --git a/.github/workflows/python-lint.yml b/.github/workflows/python-lint.yml
new file mode 100644
index 00000000..120c8f8e
--- /dev/null
+++ b/.github/workflows/python-lint.yml
@@ -0,0 +1,31 @@
+name: Python Lint and Formatting Check
+
+on: [push, pull_request]
+
+jobs:
+ lint:
+ name: Lint and Format Check
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout Code
+ uses: actions/checkout@v3
+
+ - name: Set up Python
+ uses: actions/setup-python@v4
+ with:
+ python-version: '3.x'
+
+ - name: Install dependencies
+ run: |
+ python -m pip install --upgrade pip
+ pip install flake8 black
+
+ - name: Lint with flake8
+ run: |
+ flake8 scripts/ --count --select=E9,F63,F7,F82 --show-source --statistics
+ flake8 scripts/ --count --exit-zero --max-complexity=10 --max-line-length=88 --statistics
+
+ - name: Check code formatting with black
+ run: |
+ black --check scripts/
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index b2c7f1ca..2fb090f2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -25,4 +25,4 @@ Cargo.lock
.python-version
__pycache__
-.raito
\ No newline at end of file
+.client_cache/
\ No newline at end of file
diff --git a/README.md b/README.md
index a9e15c56..76b31c63 100644
--- a/README.md
+++ b/README.md
@@ -17,7 +17,7 @@ Raito is a zero-knowledge Bitcoin client implemented in Cairo. It aims to provid
```mermaid
flowchart TB
-Pnm1(STARK proof of the chain state up to the block n - 1 , including utxo accumulator) --> Vp(zk verifier)
+Pnm1(STARK proof of the chain state up to the block n - 1 , including utxo accumulator) --> Vp(zk verifier)
Bn(blocks n..m ) ----> Vb
subgraph Cairo
@@ -26,7 +26,7 @@ subgraph Cairo
Vb --> ChS
end
-Vb --> Pn(STARK proof of the chain state up to the block m , including utxo accumulator)
+Vb --> Pn(STARK proof of the chain state up to the block m , including utxo accumulator)
style Bn fill:pink
style Pn fill:lightgreen
@@ -49,6 +49,10 @@ Although this is a highly experimental project without immediate plans for deplo
## Roadmap
+
+
+
+
### Milestone 1 - Block header validation
Implement a reduced light client that can verify a range of blocks starting at genesis.
@@ -70,7 +74,7 @@ Extend light client with partial transaction validation, but without UTXO checks
Tasks:
-* [ ] reassess validation check list (analyze Bitcoin core codebase)
+* [x] reassess validation check list (analyze Bitcoin core codebase)
* [x] generate & run integration tests e2e instead of Cairo codegen
* [x] transaction ID calculation
* [x] transaction root computation
@@ -131,40 +135,18 @@ Raito is a reference to Light Yagami (夜神月, Yagami Raito) from the manga/an
## Usage
-This will compile all the components:
+This will compile all the packages:
```bash
scarb build
```
-This will run unit and integration tests:
+This will run tests for all the packages:
```bash
scarb test
```
-For integration tests ony:
-
-```bash
-scarb run integration_tests
-```
-
-Run for specific test file(s):
-
-```bash
-scarb run integration_tests tests/data/light_481823.json
-```
-
-Re-generate integration test data:
-
-```base
-scarb run regenerate_tests --force
-```
-
-* Without `--force` flag only non-existent files will be created
-* Files are located in [tests/data/](https://github.com/keep-starknet-strange/raito/blob/main/tests/data)
-* If you want to add a new test case, edit [scripts/data/regenerate_tests.sh](https://github.com/keep-starknet-strange/raito/blob/main/scripts/data/regenerate_tests.sh)
-
## Build dependencies
Install necessary packages required by Python scripts:
@@ -213,6 +195,9 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
Gerson 💻
PavitraAgarwal21 💻
Nguyen Dao 💻
+ Hunter001 💻
+ feltroid Prime 💻
+ Mexes 💻
diff --git a/Scarb.lock b/Scarb.lock
index a0e0284f..8beea944 100644
--- a/Scarb.lock
+++ b/Scarb.lock
@@ -2,5 +2,19 @@
version = 1
[[package]]
-name = "raito"
+name = "client"
+version = "0.1.0"
+dependencies = [
+ "consensus",
+]
+
+[[package]]
+name = "consensus"
+version = "0.1.0"
+dependencies = [
+ "utils",
+]
+
+[[package]]
+name = "utils"
version = "0.1.0"
diff --git a/Scarb.toml b/Scarb.toml
index 8f063046..95012dcc 100644
--- a/Scarb.toml
+++ b/Scarb.toml
@@ -1,15 +1,13 @@
-[package]
-name = "raito"
-version = "0.1.0"
-edition = "2024_07"
-
-[scripts]
-regenerate_tests= "./scripts/data/regenerate_tests.sh"
-integration_tests = "scarb build && ./scripts/data/integration_tests.sh"
-client= "scarb build && ./scripts/data/client.sh"
-test = "scarb cairo-test && scarb run integration_tests"
+[workspace]
+members = ["packages/*"]
-[dependencies]
+[workspace.package]
+description = "Bitcoin ZK client."
+cairo-version = "2.8.2"
+version = "0.1.0"
+readme = "README.md"
+repository = "https://github.com/keep-starknet-strange/raito"
+license-file = "LICENSE"
-[dev-dependencies]
+[workspace.dependencies]
cairo_test = "2.8.0"
diff --git a/docs/img/components.excalidraw b/docs/img/components.excalidraw
new file mode 100644
index 00000000..a1d08fd7
--- /dev/null
+++ b/docs/img/components.excalidraw
@@ -0,0 +1,2079 @@
+{
+ "type": "excalidraw",
+ "version": 2,
+ "source": "https://excalidraw.com",
+ "elements": [
+ {
+ "id": "vFRNXFX39m9q9jMcfiUTs",
+ "type": "rectangle",
+ "x": 773.8748840617886,
+ "y": -364.6578263794893,
+ "width": 443.20001220703125,
+ "height": 762.3999633789062,
+ "angle": 0,
+ "strokeColor": "#ffd43b",
+ "backgroundColor": "#fff9db",
+ "fillStyle": "cross-hatch",
+ "strokeWidth": 2,
+ "strokeStyle": "dotted",
+ "roughness": 0,
+ "opacity": 100,
+ "groupIds": [],
+ "frameId": null,
+ "index": "Zn",
+ "roundness": null,
+ "seed": 1196178576,
+ "version": 681,
+ "versionNonce": 1570713200,
+ "isDeleted": false,
+ "boundElements": [],
+ "updated": 1726051252954,
+ "link": null,
+ "locked": false
+ },
+ {
+ "id": "OlQhyNzC4xYaxYiMVIpNp",
+ "type": "rectangle",
+ "x": 819.0748962688199,
+ "y": -66.05769820566115,
+ "width": 358.4000244140625,
+ "height": 441.60003662109375,
+ "angle": 0,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "#e3fafc",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "dotted",
+ "roughness": 1,
+ "opacity": 100,
+ "groupIds": [],
+ "frameId": null,
+ "index": "Zo",
+ "roundness": null,
+ "seed": 253553776,
+ "version": 819,
+ "versionNonce": 1755594384,
+ "isDeleted": false,
+ "boundElements": [
+ {
+ "type": "text",
+ "id": "4IRy5JWO9w3bjNd3vAALY"
+ },
+ {
+ "id": "0mlUBxdk542WH_plyugqH",
+ "type": "arrow"
+ },
+ {
+ "id": "zap4kyaz0rdo0-hRwtXJT",
+ "type": "arrow"
+ },
+ {
+ "id": "3FaeA6gbXhf3lFDHI-1by",
+ "type": "arrow"
+ },
+ {
+ "id": "adQ0gG4ND7sWaO3NgRvCg",
+ "type": "arrow"
+ }
+ ],
+ "updated": 1726051226631,
+ "link": null,
+ "locked": false
+ },
+ {
+ "id": "4IRy5JWO9w3bjNd3vAALY",
+ "type": "text",
+ "x": 898.805021696066,
+ "y": -61.057698205661154,
+ "width": 198.9397735595703,
+ "height": 25,
+ "angle": 0,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "groupIds": [],
+ "frameId": null,
+ "index": "Zp",
+ "roundness": null,
+ "seed": 258474640,
+ "version": 695,
+ "versionNonce": 2127389328,
+ "isDeleted": false,
+ "boundElements": null,
+ "updated": 1726046483406,
+ "link": null,
+ "locked": false,
+ "text": "consensus validation",
+ "fontSize": 20,
+ "fontFamily": 1,
+ "textAlign": "center",
+ "verticalAlign": "top",
+ "containerId": "OlQhyNzC4xYaxYiMVIpNp",
+ "originalText": "consensus validation",
+ "autoResize": true,
+ "lineHeight": 1.25
+ },
+ {
+ "id": "p1SkBd3U9KUtb31g2b5og",
+ "type": "rectangle",
+ "x": 864.8750366496793,
+ "y": -11.657978967379904,
+ "width": 288.0000305175781,
+ "height": 367.199951171875,
+ "angle": 0,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "#99e9f2",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "dotted",
+ "roughness": 1,
+ "opacity": 100,
+ "groupIds": [],
+ "frameId": null,
+ "index": "Zs",
+ "roundness": null,
+ "seed": 1190119568,
+ "version": 702,
+ "versionNonce": 707434128,
+ "isDeleted": false,
+ "boundElements": [
+ {
+ "type": "text",
+ "id": "VTu4_oVkyOEMO4CjPRMhW"
+ },
+ {
+ "id": "0mlUBxdk542WH_plyugqH",
+ "type": "arrow"
+ },
+ {
+ "id": "3FaeA6gbXhf3lFDHI-1by",
+ "type": "arrow"
+ }
+ ],
+ "updated": 1726047632268,
+ "link": null,
+ "locked": false
+ },
+ {
+ "id": "VTu4_oVkyOEMO4CjPRMhW",
+ "type": "text",
+ "x": 933.6051391887418,
+ "y": -6.657978967379904,
+ "width": 150.53982543945312,
+ "height": 25,
+ "angle": 0,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "groupIds": [],
+ "frameId": null,
+ "index": "Zt",
+ "roundness": null,
+ "seed": 945675408,
+ "version": 600,
+ "versionNonce": 767674000,
+ "isDeleted": false,
+ "boundElements": null,
+ "updated": 1726046477932,
+ "link": null,
+ "locked": false,
+ "text": "block validation",
+ "fontSize": 20,
+ "fontFamily": 1,
+ "textAlign": "center",
+ "verticalAlign": "top",
+ "containerId": "p1SkBd3U9KUtb31g2b5og",
+ "originalText": "block validation",
+ "autoResize": true,
+ "lineHeight": 1.25
+ },
+ {
+ "type": "rectangle",
+ "version": 906,
+ "versionNonce": 109459600,
+ "index": "Zu",
+ "isDeleted": false,
+ "id": "46TXE340NfJVz-ExR_Ntg",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "dotted",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 889.0748352336636,
+ "y": 123.74195389394822,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 246.3999633789062,
+ "height": 222.400146484375,
+ "seed": 779618448,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": null,
+ "boundElements": [
+ {
+ "type": "text",
+ "id": "OT5Pjyf0K1R184eX3jIFY"
+ },
+ {
+ "id": "3FaeA6gbXhf3lFDHI-1by",
+ "type": "arrow"
+ }
+ ],
+ "updated": 1726050163287,
+ "link": null,
+ "locked": false
+ },
+ {
+ "type": "text",
+ "version": 830,
+ "versionNonce": 1501684336,
+ "index": "Zv",
+ "isDeleted": false,
+ "id": "OT5Pjyf0K1R184eX3jIFY",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 903.354940824484,
+ "y": 128.74195389394822,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 217.83975219726562,
+ "height": 25,
+ "seed": 1367897744,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": null,
+ "boundElements": [],
+ "updated": 1726046374765,
+ "link": null,
+ "locked": false,
+ "fontSize": 20,
+ "fontFamily": 1,
+ "text": "transaction validation",
+ "textAlign": "center",
+ "verticalAlign": "top",
+ "containerId": "46TXE340NfJVz-ExR_Ntg",
+ "originalText": "transaction validation",
+ "autoResize": true,
+ "lineHeight": 1.25
+ },
+ {
+ "id": "Jq37eLzJFtAphIByXXJ8J",
+ "type": "rectangle",
+ "x": 883.8749450969449,
+ "y": 31.542155309963846,
+ "width": 244.7999877929688,
+ "height": 64.00006103515625,
+ "angle": 0,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "#ffffff",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "groupIds": [],
+ "frameId": null,
+ "index": "a0",
+ "roundness": {
+ "type": 3
+ },
+ "seed": 2100957808,
+ "version": 543,
+ "versionNonce": 68680848,
+ "isDeleted": false,
+ "boundElements": [
+ {
+ "type": "text",
+ "id": "KxKd8R05CEMH2kYjmvG1K"
+ }
+ ],
+ "updated": 1726046848776,
+ "link": null,
+ "locked": false
+ },
+ {
+ "id": "KxKd8R05CEMH2kYjmvG1K",
+ "type": "text",
+ "x": 921.6050400066129,
+ "y": 51.04218582754197,
+ "width": 169.3397979736328,
+ "height": 25,
+ "angle": 0,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "groupIds": [],
+ "frameId": null,
+ "index": "a0V",
+ "roundness": null,
+ "seed": 1007192208,
+ "version": 446,
+ "versionNonce": 591404656,
+ "isDeleted": false,
+ "boundElements": null,
+ "updated": 1726045175596,
+ "link": null,
+ "locked": false,
+ "text": "header validation",
+ "fontSize": 20,
+ "fontFamily": 1,
+ "textAlign": "center",
+ "verticalAlign": "middle",
+ "containerId": "Jq37eLzJFtAphIByXXJ8J",
+ "originalText": "header validation",
+ "autoResize": true,
+ "lineHeight": 1.25
+ },
+ {
+ "id": "6d5F4qlkBsianjtDW-DFS",
+ "type": "rectangle",
+ "x": 515.675024442648,
+ "y": -33.85789962167678,
+ "width": 165.5999755859375,
+ "height": 93.60000610351562,
+ "angle": 0,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "groupIds": [],
+ "frameId": null,
+ "index": "aB",
+ "roundness": {
+ "type": 3
+ },
+ "seed": 2066883696,
+ "version": 728,
+ "versionNonce": 812569200,
+ "isDeleted": false,
+ "boundElements": [
+ {
+ "type": "text",
+ "id": "iiOg1LCjOHC5ozMm407bS"
+ },
+ {
+ "id": "UgL2Tuek8HSxxStjQYB0q",
+ "type": "arrow"
+ },
+ {
+ "id": "0mlUBxdk542WH_plyugqH",
+ "type": "arrow"
+ }
+ ],
+ "updated": 1726051262809,
+ "link": null,
+ "locked": false
+ },
+ {
+ "id": "iiOg1LCjOHC5ozMm407bS",
+ "type": "text",
+ "x": 555.2750534343472,
+ "y": 0.44210343008103337,
+ "width": 86.39991760253906,
+ "height": 25,
+ "angle": 0,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "groupIds": [],
+ "frameId": null,
+ "index": "aC",
+ "roundness": null,
+ "seed": 1322088560,
+ "version": 688,
+ "versionNonce": 1716037744,
+ "isDeleted": false,
+ "boundElements": null,
+ "updated": 1726051262811,
+ "link": null,
+ "locked": false,
+ "text": "full node",
+ "fontSize": 20,
+ "fontFamily": 1,
+ "textAlign": "center",
+ "verticalAlign": "middle",
+ "containerId": "6d5F4qlkBsianjtDW-DFS",
+ "originalText": "full node",
+ "autoResize": true,
+ "lineHeight": 1.25
+ },
+ {
+ "id": "ia3NpRXin76YPLtFP4Yl3",
+ "type": "rectangle",
+ "x": 919.6749939250699,
+ "y": 284.94208817129197,
+ "width": 195.20001220703125,
+ "height": 41.600067138671875,
+ "angle": 0,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "#ffffff",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "groupIds": [],
+ "frameId": null,
+ "index": "aC8",
+ "roundness": {
+ "type": 3
+ },
+ "seed": 379577488,
+ "version": 617,
+ "versionNonce": 1085809296,
+ "isDeleted": false,
+ "boundElements": [
+ {
+ "type": "text",
+ "id": "WnFHta4VWF5MQyUmBCxW8"
+ }
+ ],
+ "updated": 1726046864018,
+ "link": null,
+ "locked": false
+ },
+ {
+ "id": "WnFHta4VWF5MQyUmBCxW8",
+ "type": "text",
+ "x": 937.6250976848355,
+ "y": 293.2421217406279,
+ "width": 159.2998046875,
+ "height": 25,
+ "angle": 0,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "groupIds": [],
+ "frameId": null,
+ "index": "aCG",
+ "roundness": null,
+ "seed": 726540944,
+ "version": 588,
+ "versionNonce": 129134224,
+ "isDeleted": false,
+ "boundElements": null,
+ "updated": 1726046408098,
+ "link": null,
+ "locked": false,
+ "text": "script validation",
+ "fontSize": 20,
+ "fontFamily": 1,
+ "textAlign": "center",
+ "verticalAlign": "middle",
+ "containerId": "ia3NpRXin76YPLtFP4Yl3",
+ "originalText": "script validation",
+ "autoResize": true,
+ "lineHeight": 1.25
+ },
+ {
+ "type": "rectangle",
+ "version": 904,
+ "versionNonce": 260106864,
+ "index": "aCd",
+ "isDeleted": false,
+ "id": "Ss1_PWLNhrSWpBTmOopDV",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 916.6747192668668,
+ "y": 226.94225601797166,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "#ffffff",
+ "width": 195.20001220703125,
+ "height": 44.000091552734375,
+ "seed": 1266475120,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": {
+ "type": 3
+ },
+ "boundElements": [
+ {
+ "type": "text",
+ "id": "cQiXWAbergoCUDlg7BMCc"
+ },
+ {
+ "id": "adQ0gG4ND7sWaO3NgRvCg",
+ "type": "arrow"
+ }
+ ],
+ "updated": 1726046859355,
+ "link": null,
+ "locked": false
+ },
+ {
+ "type": "text",
+ "version": 893,
+ "versionNonce": 1380229232,
+ "index": "aCl",
+ "isDeleted": false,
+ "id": "cQiXWAbergoCUDlg7BMCc",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 926.8748230266324,
+ "y": 236.44230179433885,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 174.7998046875,
+ "height": 25,
+ "seed": 1273451120,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": null,
+ "boundElements": [],
+ "updated": 1726046394358,
+ "link": null,
+ "locked": false,
+ "fontSize": 20,
+ "fontFamily": 1,
+ "text": "UTXO verification",
+ "textAlign": "center",
+ "verticalAlign": "middle",
+ "containerId": "Ss1_PWLNhrSWpBTmOopDV",
+ "originalText": "UTXO verification",
+ "autoResize": true,
+ "lineHeight": 1.25
+ },
+ {
+ "type": "rectangle",
+ "version": 1127,
+ "versionNonce": 107678352,
+ "index": "aD",
+ "isDeleted": false,
+ "id": "Y-atAe5CEQudIM5qB3LGl",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 510.67520754811676,
+ "y": 198.34206680898728,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 165.5999755859375,
+ "height": 93.60000610351562,
+ "seed": 879980688,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": {
+ "type": 3
+ },
+ "boundElements": [
+ {
+ "type": "text",
+ "id": "puxQis3GvrmQmj6Ewshuy"
+ },
+ {
+ "id": "adQ0gG4ND7sWaO3NgRvCg",
+ "type": "arrow"
+ },
+ {
+ "id": "UgL2Tuek8HSxxStjQYB0q",
+ "type": "arrow"
+ }
+ ],
+ "updated": 1726051280505,
+ "link": null,
+ "locked": false
+ },
+ {
+ "type": "text",
+ "version": 1122,
+ "versionNonce": 1721914512,
+ "index": "aE",
+ "isDeleted": false,
+ "id": "puxQis3GvrmQmj6Ewshuy",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 538.8352493571988,
+ "y": 220.1420698607451,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 109.27989196777344,
+ "height": 50,
+ "seed": 1406590608,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": null,
+ "boundElements": [],
+ "updated": 1726051280506,
+ "link": null,
+ "locked": false,
+ "fontSize": 20,
+ "fontFamily": 1,
+ "text": "utreexo\nbridge node",
+ "textAlign": "center",
+ "verticalAlign": "middle",
+ "containerId": "Y-atAe5CEQudIM5qB3LGl",
+ "originalText": "utreexo\nbridge node",
+ "autoResize": true,
+ "lineHeight": 1.25
+ },
+ {
+ "id": "adQ0gG4ND7sWaO3NgRvCg",
+ "type": "arrow",
+ "x": 677.2751831340543,
+ "y": 249.72548691501987,
+ "width": 138.79955291748047,
+ "height": 0.9433040090914915,
+ "angle": 0,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "groupIds": [],
+ "frameId": null,
+ "index": "aF",
+ "roundness": {
+ "type": 2
+ },
+ "seed": 274845296,
+ "version": 2082,
+ "versionNonce": 2009806992,
+ "isDeleted": false,
+ "boundElements": [
+ {
+ "type": "text",
+ "id": "0FIupR64RF-AbNbrvCDwP"
+ }
+ ],
+ "updated": 1726051280506,
+ "link": null,
+ "locked": false,
+ "points": [
+ [
+ 0,
+ 0
+ ],
+ [
+ 138.79955291748047,
+ -0.9433040090914915
+ ]
+ ],
+ "lastCommittedPoint": null,
+ "startBinding": {
+ "elementId": "Y-atAe5CEQudIM5qB3LGl",
+ "focus": 0.10879727040177857,
+ "gap": 1,
+ "fixedPoint": null
+ },
+ "endBinding": {
+ "elementId": "OlQhyNzC4xYaxYiMVIpNp",
+ "focus": -0.41810056413000074,
+ "gap": 3.0001602172851562,
+ "fixedPoint": null
+ },
+ "startArrowhead": null,
+ "endArrowhead": "arrow",
+ "elbowed": false
+ },
+ {
+ "id": "0FIupR64RF-AbNbrvCDwP",
+ "type": "text",
+ "x": 1230.2597323995374,
+ "y": 173.66878046063067,
+ "width": 76.0399169921875,
+ "height": 75,
+ "angle": 0,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "groupIds": [],
+ "frameId": null,
+ "index": "aG",
+ "roundness": null,
+ "seed": 452208272,
+ "version": 32,
+ "versionNonce": 1394634864,
+ "isDeleted": false,
+ "boundElements": null,
+ "updated": 1726045282081,
+ "link": null,
+ "locked": false,
+ "text": "utxo\ninclusion\nproofs",
+ "fontSize": 20,
+ "fontFamily": 1,
+ "textAlign": "center",
+ "verticalAlign": "middle",
+ "containerId": "adQ0gG4ND7sWaO3NgRvCg",
+ "originalText": "utxo\ninclusion\nproofs",
+ "autoResize": true,
+ "lineHeight": 1.25
+ },
+ {
+ "id": "UgL2Tuek8HSxxStjQYB0q",
+ "type": "arrow",
+ "x": 602.359464326293,
+ "y": 60.742106481838846,
+ "width": 3.252438008386207,
+ "height": 135.59994506835938,
+ "angle": 0,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "groupIds": [],
+ "frameId": null,
+ "index": "aH",
+ "roundness": {
+ "type": 2
+ },
+ "seed": 232236176,
+ "version": 1675,
+ "versionNonce": 1760929424,
+ "isDeleted": false,
+ "boundElements": [
+ {
+ "type": "text",
+ "id": "lzW_E-Dknz3Cjp3-7IVvd"
+ }
+ ],
+ "updated": 1726051280506,
+ "link": null,
+ "locked": false,
+ "points": [
+ [
+ 0,
+ 0
+ ],
+ [
+ -3.252438008386207,
+ 135.59994506835938
+ ]
+ ],
+ "lastCommittedPoint": null,
+ "startBinding": {
+ "elementId": "6d5F4qlkBsianjtDW-DFS",
+ "focus": -0.0848461298687917,
+ "gap": 1,
+ "fixedPoint": null
+ },
+ "endBinding": {
+ "elementId": "Y-atAe5CEQudIM5qB3LGl",
+ "focus": 0.053160184157585534,
+ "gap": 2.0000152587890625,
+ "fixedPoint": null
+ },
+ "startArrowhead": null,
+ "endArrowhead": "arrow",
+ "elbowed": false
+ },
+ {
+ "id": "lzW_E-Dknz3Cjp3-7IVvd",
+ "type": "text",
+ "x": 1339.8186975423196,
+ "y": 63.542170568752894,
+ "width": 57.27995300292969,
+ "height": 25,
+ "angle": 0,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "groupIds": [],
+ "frameId": null,
+ "index": "aHV",
+ "roundness": null,
+ "seed": 1272586896,
+ "version": 8,
+ "versionNonce": 480416400,
+ "isDeleted": false,
+ "boundElements": null,
+ "updated": 1726043762970,
+ "link": null,
+ "locked": false,
+ "text": "blocks",
+ "fontSize": 20,
+ "fontFamily": 1,
+ "textAlign": "center",
+ "verticalAlign": "middle",
+ "containerId": "UgL2Tuek8HSxxStjQYB0q",
+ "originalText": "blocks",
+ "autoResize": true,
+ "lineHeight": 1.25
+ },
+ {
+ "id": "0mlUBxdk542WH_plyugqH",
+ "type": "arrow",
+ "x": 682.2750000285855,
+ "y": 12.953114543529589,
+ "width": 136.4517173655363,
+ "height": 1.7043832129644851,
+ "angle": 0,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "groupIds": [],
+ "frameId": null,
+ "index": "aI",
+ "roundness": {
+ "type": 2
+ },
+ "seed": 1104431216,
+ "version": 1752,
+ "versionNonce": 1020327536,
+ "isDeleted": false,
+ "boundElements": [
+ {
+ "type": "text",
+ "id": "vZTRp78c_rn0-LAvcVhkn"
+ }
+ ],
+ "updated": 1726051262810,
+ "link": null,
+ "locked": false,
+ "points": [
+ [
+ 0,
+ 0
+ ],
+ [
+ 136.4517173655363,
+ -1.7043832129644851
+ ]
+ ],
+ "lastCommittedPoint": null,
+ "startBinding": {
+ "elementId": "6d5F4qlkBsianjtDW-DFS",
+ "focus": 0.022112512524973975,
+ "gap": 1,
+ "fixedPoint": null
+ },
+ "endBinding": {
+ "elementId": "OlQhyNzC4xYaxYiMVIpNp",
+ "focus": 0.6359857359815234,
+ "gap": 1,
+ "fixedPoint": null
+ },
+ "startArrowhead": null,
+ "endArrowhead": "arrow",
+ "elbowed": false
+ },
+ {
+ "id": "vZTRp78c_rn0-LAvcVhkn",
+ "type": "text",
+ "x": 1138.8349441814175,
+ "y": -64.95781417245803,
+ "width": 57.27995300292969,
+ "height": 25,
+ "angle": 0,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "groupIds": [],
+ "frameId": null,
+ "index": "aJ",
+ "roundness": null,
+ "seed": 349960816,
+ "version": 8,
+ "versionNonce": 1181125232,
+ "isDeleted": false,
+ "boundElements": null,
+ "updated": 1726043727503,
+ "link": null,
+ "locked": false,
+ "text": "blocks",
+ "fontSize": 20,
+ "fontFamily": 1,
+ "textAlign": "center",
+ "verticalAlign": "middle",
+ "containerId": "0mlUBxdk542WH_plyugqH",
+ "originalText": "blocks",
+ "autoResize": true,
+ "lineHeight": 1.25
+ },
+ {
+ "id": "3FaeA6gbXhf3lFDHI-1by",
+ "type": "arrow",
+ "x": 1181.1332952764878,
+ "y": 267.5422163451201,
+ "width": 71.54169864858204,
+ "height": 1.567668477541588,
+ "angle": 0,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "groupIds": [],
+ "frameId": null,
+ "index": "ah",
+ "roundness": {
+ "type": 2
+ },
+ "seed": 2089958032,
+ "version": 934,
+ "versionNonce": 137755792,
+ "isDeleted": false,
+ "boundElements": null,
+ "updated": 1726051175901,
+ "link": null,
+ "locked": false,
+ "points": [
+ [
+ 0,
+ 0
+ ],
+ [
+ 71.54169864858204,
+ -1.567668477541588
+ ]
+ ],
+ "lastCommittedPoint": null,
+ "startBinding": {
+ "elementId": "p1SkBd3U9KUtb31g2b5og",
+ "focus": 0.5321123566425469,
+ "gap": 28.25822810923046,
+ "fixedPoint": null
+ },
+ "endBinding": {
+ "elementId": "meCDK-TD6HL11SHWrQCBW",
+ "focus": -0.0881613568239664,
+ "gap": 1,
+ "fixedPoint": null
+ },
+ "startArrowhead": null,
+ "endArrowhead": "arrow",
+ "elbowed": false
+ },
+ {
+ "id": "Sx7Xvkm8n1gPTX2MebqV0",
+ "type": "rectangle",
+ "x": 896.6748413371793,
+ "y": -334.25786300058303,
+ "width": 180.800048828125,
+ "height": 56.000030517578125,
+ "angle": 0,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "#ffd43b",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "groupIds": [],
+ "frameId": null,
+ "index": "ai",
+ "roundness": {
+ "type": 3
+ },
+ "seed": 1513587312,
+ "version": 391,
+ "versionNonce": 474861200,
+ "isDeleted": false,
+ "boundElements": [
+ {
+ "type": "text",
+ "id": "BNjgoH0KcjIxXt9pYsPgf"
+ },
+ {
+ "id": "IwaIfRpdALQBDgV0u-ATE",
+ "type": "arrow"
+ },
+ {
+ "id": "zr6A3arcQYrb0Em0BgkHX",
+ "type": "arrow"
+ }
+ ],
+ "updated": 1726047038018,
+ "link": null,
+ "locked": false
+ },
+ {
+ "id": "BNjgoH0KcjIxXt9pYsPgf",
+ "type": "text",
+ "x": 920.4449447917691,
+ "y": -318.75784774179397,
+ "width": 133.2598419189453,
+ "height": 25,
+ "angle": 0,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "groupIds": [],
+ "frameId": null,
+ "index": "aiV",
+ "roundness": null,
+ "seed": 94841456,
+ "version": 273,
+ "versionNonce": 1286962320,
+ "isDeleted": false,
+ "boundElements": null,
+ "updated": 1726047038018,
+ "link": null,
+ "locked": false,
+ "text": "stark verifier",
+ "fontSize": 20,
+ "fontFamily": 1,
+ "textAlign": "center",
+ "verticalAlign": "middle",
+ "containerId": "Sx7Xvkm8n1gPTX2MebqV0",
+ "originalText": "stark verifier",
+ "autoResize": true,
+ "lineHeight": 1.25
+ },
+ {
+ "type": "rectangle",
+ "version": 870,
+ "versionNonce": 957720720,
+ "index": "as",
+ "isDeleted": false,
+ "id": "A7N4kLQMptJOkqU5E4DfL",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "dotted",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 821.6749328899136,
+ "y": -232.65779586191115,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "#b2f2bb",
+ "width": 335.19995117187506,
+ "height": 118.39990234374997,
+ "seed": 1604022928,
+ "groupIds": [
+ "t-XPndLuq3N4YvRhUk6XX"
+ ],
+ "frameId": null,
+ "roundness": null,
+ "boundElements": [
+ {
+ "type": "text",
+ "id": "W-a8bRzcGmPEjXd4jALkn"
+ },
+ {
+ "id": "zr6A3arcQYrb0Em0BgkHX",
+ "type": "arrow"
+ },
+ {
+ "id": "zap4kyaz0rdo0-hRwtXJT",
+ "type": "arrow"
+ }
+ ],
+ "updated": 1726047035918,
+ "link": null,
+ "locked": false
+ },
+ {
+ "type": "text",
+ "version": 689,
+ "versionNonce": 2003965584,
+ "index": "at",
+ "isDeleted": false,
+ "id": "W-a8bRzcGmPEjXd4jALkn",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 953.0649551677457,
+ "y": -227.65779586191115,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "#b2f2bb",
+ "width": 72.41990661621094,
+ "height": 25,
+ "seed": 514760848,
+ "groupIds": [
+ "t-XPndLuq3N4YvRhUk6XX"
+ ],
+ "frameId": null,
+ "roundness": {
+ "type": 2
+ },
+ "boundElements": [],
+ "updated": 1726047035918,
+ "link": null,
+ "locked": false,
+ "fontSize": 20,
+ "fontFamily": 5,
+ "text": "verified",
+ "textAlign": "center",
+ "verticalAlign": "top",
+ "containerId": "A7N4kLQMptJOkqU5E4DfL",
+ "originalText": "verified",
+ "autoResize": true,
+ "lineHeight": 1.25
+ },
+ {
+ "type": "rectangle",
+ "version": 999,
+ "versionNonce": 938795152,
+ "index": "au",
+ "isDeleted": false,
+ "id": "xiLjXbKFxuf582YFoRlCJ",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 838.8151754298465,
+ "y": -195.95775313730178,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "#ffffff",
+ "width": 143.31571977535447,
+ "height": 63.19996643066406,
+ "seed": 791416464,
+ "groupIds": [
+ "t-XPndLuq3N4YvRhUk6XX"
+ ],
+ "frameId": null,
+ "roundness": {
+ "type": 3
+ },
+ "boundElements": [
+ {
+ "id": "Qn4GW_gGfSRHpCZs3FwEn",
+ "type": "text"
+ }
+ ],
+ "updated": 1726047035918,
+ "link": null,
+ "locked": false
+ },
+ {
+ "type": "text",
+ "version": 827,
+ "versionNonce": 1168789136,
+ "index": "av",
+ "isDeleted": false,
+ "id": "Qn4GW_gGfSRHpCZs3FwEn",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 854.5530905543401,
+ "y": -176.85776992196975,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "#b2f2bb",
+ "width": 111.83988952636719,
+ "height": 25,
+ "seed": 1774959760,
+ "groupIds": [
+ "t-XPndLuq3N4YvRhUk6XX"
+ ],
+ "frameId": null,
+ "roundness": {
+ "type": 2
+ },
+ "boundElements": [],
+ "updated": 1726047035918,
+ "link": null,
+ "locked": false,
+ "fontSize": 20,
+ "fontFamily": 5,
+ "text": "chain state",
+ "textAlign": "center",
+ "verticalAlign": "middle",
+ "containerId": "xiLjXbKFxuf582YFoRlCJ",
+ "originalText": "chain state",
+ "autoResize": true,
+ "lineHeight": 1.25
+ },
+ {
+ "type": "rectangle",
+ "version": 1392,
+ "versionNonce": 377617552,
+ "index": "aw",
+ "isDeleted": false,
+ "id": "wDJ5UcgOitmQVb6wFc-BV",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 996.8661636121401,
+ "y": -195.55771346445022,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "#ffffff",
+ "width": 145.49011817706395,
+ "height": 64,
+ "seed": 1346742928,
+ "groupIds": [
+ "t-XPndLuq3N4YvRhUk6XX"
+ ],
+ "frameId": null,
+ "roundness": {
+ "type": 3
+ },
+ "boundElements": [
+ {
+ "id": "axqPpvy7aOZU_TExH_LMz",
+ "type": "text"
+ }
+ ],
+ "updated": 1726047035918,
+ "link": null,
+ "locked": false
+ },
+ {
+ "type": "text",
+ "version": 1142,
+ "versionNonce": 204728976,
+ "index": "ax",
+ "isDeleted": false,
+ "id": "axqPpvy7aOZU_TExH_LMz",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 1009.6212706132698,
+ "y": -188.55771346445022,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "#b2f2bb",
+ "width": 119.97990417480469,
+ "height": 50,
+ "seed": 1834080400,
+ "groupIds": [
+ "t-XPndLuq3N4YvRhUk6XX"
+ ],
+ "frameId": null,
+ "roundness": {
+ "type": 2
+ },
+ "boundElements": [],
+ "updated": 1726047035918,
+ "link": null,
+ "locked": false,
+ "fontSize": 20,
+ "fontFamily": 5,
+ "text": "utxo merkle \naccumulator",
+ "textAlign": "center",
+ "verticalAlign": "middle",
+ "containerId": "wDJ5UcgOitmQVb6wFc-BV",
+ "originalText": "utxo merkle accumulator",
+ "autoResize": true,
+ "lineHeight": 1.25
+ },
+ {
+ "type": "rectangle",
+ "version": 1265,
+ "versionNonce": 1064197776,
+ "index": "azG",
+ "isDeleted": false,
+ "id": "meCDK-TD6HL11SHWrQCBW",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "dotted",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 1252.0749573039761,
+ "y": 150.14237503652635,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "#ebfbee",
+ "width": 187.99987792968759,
+ "height": 208.7998046875,
+ "seed": 732126832,
+ "groupIds": [
+ "FzZYbLV792S3RtinrAqt8"
+ ],
+ "frameId": null,
+ "roundness": null,
+ "boundElements": [
+ {
+ "type": "text",
+ "id": "wJiOgag0fhKyd-7ulo941"
+ },
+ {
+ "id": "3FaeA6gbXhf3lFDHI-1by",
+ "type": "arrow"
+ }
+ ],
+ "updated": 1726051167308,
+ "link": null,
+ "locked": false
+ },
+ {
+ "type": "text",
+ "version": 1068,
+ "versionNonce": 1345583760,
+ "index": "azV",
+ "isDeleted": false,
+ "id": "wJiOgag0fhKyd-7ulo941",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 1319.084921293234,
+ "y": 155.14237503652635,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "#ebfbee",
+ "width": 53.979949951171875,
+ "height": 25,
+ "seed": 512626800,
+ "groupIds": [
+ "FzZYbLV792S3RtinrAqt8"
+ ],
+ "frameId": null,
+ "roundness": {
+ "type": 2
+ },
+ "boundElements": [],
+ "updated": 1726051167309,
+ "link": null,
+ "locked": false,
+ "fontSize": 20,
+ "fontFamily": 5,
+ "text": "proof",
+ "textAlign": "center",
+ "verticalAlign": "top",
+ "containerId": "meCDK-TD6HL11SHWrQCBW",
+ "originalText": "proof",
+ "autoResize": true,
+ "lineHeight": 1.25
+ },
+ {
+ "type": "rectangle",
+ "version": 1284,
+ "versionNonce": 2062952592,
+ "index": "azl",
+ "isDeleted": false,
+ "id": "6MJcYEo6mHeF_YEA28iJO",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 1274.815297500159,
+ "y": 195.24244217519822,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "#ffffff",
+ "width": 143.31571977535447,
+ "height": 63.19996643066406,
+ "seed": 89293424,
+ "groupIds": [
+ "FzZYbLV792S3RtinrAqt8"
+ ],
+ "frameId": null,
+ "roundness": {
+ "type": 3
+ },
+ "boundElements": [
+ {
+ "id": "zjsEKV9bbiImLOha8078C",
+ "type": "text"
+ }
+ ],
+ "updated": 1726051167309,
+ "link": null,
+ "locked": false
+ },
+ {
+ "type": "text",
+ "version": 1112,
+ "versionNonce": 692229776,
+ "index": "b00",
+ "isDeleted": false,
+ "id": "zjsEKV9bbiImLOha8078C",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 1290.5532126246526,
+ "y": 214.34242539053025,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "#ebfbee",
+ "width": 111.83988952636719,
+ "height": 25,
+ "seed": 1052292208,
+ "groupIds": [
+ "FzZYbLV792S3RtinrAqt8"
+ ],
+ "frameId": null,
+ "roundness": {
+ "type": 2
+ },
+ "boundElements": [],
+ "updated": 1726051167309,
+ "link": null,
+ "locked": false,
+ "fontSize": 20,
+ "fontFamily": 5,
+ "text": "chain state",
+ "textAlign": "center",
+ "verticalAlign": "middle",
+ "containerId": "6MJcYEo6mHeF_YEA28iJO",
+ "originalText": "chain state",
+ "autoResize": true,
+ "lineHeight": 1.25
+ },
+ {
+ "type": "rectangle",
+ "version": 1723,
+ "versionNonce": 1875985552,
+ "index": "b00V",
+ "isDeleted": false,
+ "id": "jOgsVLQFNDDfjLwkM1oUr",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 1275.8662856824526,
+ "y": 273.8424330199248,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "#ffffff",
+ "width": 145.49011817706395,
+ "height": 64,
+ "seed": 277390960,
+ "groupIds": [
+ "FzZYbLV792S3RtinrAqt8"
+ ],
+ "frameId": null,
+ "roundness": {
+ "type": 3
+ },
+ "boundElements": [
+ {
+ "id": "Gtil3CQd9GWRJfyo0XBFJ",
+ "type": "text"
+ }
+ ],
+ "updated": 1726051167309,
+ "link": null,
+ "locked": false
+ },
+ {
+ "type": "text",
+ "version": 1474,
+ "versionNonce": 207237776,
+ "index": "b01",
+ "isDeleted": false,
+ "id": "Gtil3CQd9GWRJfyo0XBFJ",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 1288.6213926835821,
+ "y": 280.8424330199248,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "#ebfbee",
+ "width": 119.97990417480469,
+ "height": 50,
+ "seed": 1200248944,
+ "groupIds": [
+ "FzZYbLV792S3RtinrAqt8"
+ ],
+ "frameId": null,
+ "roundness": {
+ "type": 2
+ },
+ "boundElements": [],
+ "updated": 1726051167309,
+ "link": null,
+ "locked": false,
+ "fontSize": 20,
+ "fontFamily": 5,
+ "text": "utxo merkle \naccumulator",
+ "textAlign": "center",
+ "verticalAlign": "middle",
+ "containerId": "jOgsVLQFNDDfjLwkM1oUr",
+ "originalText": "utxo merkle accumulator",
+ "autoResize": true,
+ "lineHeight": 1.25
+ },
+ {
+ "id": "IwaIfRpdALQBDgV0u-ATE",
+ "type": "arrow",
+ "x": 696.0747131633511,
+ "y": -304.11763979415537,
+ "width": 199.02465149538898,
+ "height": 1.5402171029120382,
+ "angle": 0,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "groupIds": [],
+ "frameId": null,
+ "index": "b06",
+ "roundness": {
+ "type": 2
+ },
+ "seed": 904018576,
+ "version": 686,
+ "versionNonce": 1950726256,
+ "isDeleted": false,
+ "boundElements": null,
+ "updated": 1726051209826,
+ "link": null,
+ "locked": false,
+ "points": [
+ [
+ 0,
+ 0
+ ],
+ [
+ 199.02465149538898,
+ -1.5402171029120382
+ ]
+ ],
+ "lastCommittedPoint": null,
+ "startBinding": {
+ "elementId": "cwLLnN-1jTMdIZNDEow_n",
+ "focus": -0.45026786372359473,
+ "gap": 1,
+ "fixedPoint": null
+ },
+ "endBinding": {
+ "elementId": "Sx7Xvkm8n1gPTX2MebqV0",
+ "focus": 0.0038952289644372906,
+ "gap": 1.575476678439145,
+ "fixedPoint": null
+ },
+ "startArrowhead": null,
+ "endArrowhead": "arrow",
+ "elbowed": false
+ },
+ {
+ "id": "zr6A3arcQYrb0Em0BgkHX",
+ "type": "arrow",
+ "x": 982.5732480335655,
+ "y": -277.2578095948213,
+ "width": 0.48651040507729704,
+ "height": 38.999977111816406,
+ "angle": 0,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "groupIds": [],
+ "frameId": null,
+ "index": "b07",
+ "roundness": {
+ "type": 2
+ },
+ "seed": 723379312,
+ "version": 293,
+ "versionNonce": 587904144,
+ "isDeleted": false,
+ "boundElements": null,
+ "updated": 1726047038040,
+ "link": null,
+ "locked": false,
+ "points": [
+ [
+ 0,
+ 0
+ ],
+ [
+ -0.48651040507729704,
+ 38.999977111816406
+ ]
+ ],
+ "lastCommittedPoint": null,
+ "startBinding": {
+ "elementId": "Sx7Xvkm8n1gPTX2MebqV0",
+ "focus": 0.04561855825192419,
+ "gap": 1.0000228881835938,
+ "fixedPoint": null
+ },
+ "endBinding": {
+ "elementId": "A7N4kLQMptJOkqU5E4DfL",
+ "focus": -0.037986458919341964,
+ "gap": 5.600036621093764,
+ "fixedPoint": null
+ },
+ "startArrowhead": null,
+ "endArrowhead": "arrow",
+ "elbowed": false
+ },
+ {
+ "id": "zap4kyaz0rdo0-hRwtXJT",
+ "type": "arrow",
+ "x": 983.6910781344301,
+ "y": -113.25789351816118,
+ "width": 3.017949999096004,
+ "height": 42.20007324218753,
+ "angle": 0,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "groupIds": [],
+ "frameId": null,
+ "index": "b08",
+ "roundness": {
+ "type": 2
+ },
+ "seed": 1327634032,
+ "version": 173,
+ "versionNonce": 2047248016,
+ "isDeleted": false,
+ "boundElements": null,
+ "updated": 1726047035985,
+ "link": null,
+ "locked": false,
+ "points": [
+ [
+ 0,
+ 0
+ ],
+ [
+ 3.017949999096004,
+ 42.20007324218753
+ ]
+ ],
+ "lastCommittedPoint": null,
+ "startBinding": {
+ "elementId": "A7N4kLQMptJOkqU5E4DfL",
+ "focus": 0.05755010789097818,
+ "gap": 1,
+ "fixedPoint": null
+ },
+ "endBinding": {
+ "elementId": "OlQhyNzC4xYaxYiMVIpNp",
+ "focus": 0.015207863669545869,
+ "gap": 5.0001220703125,
+ "fixedPoint": null
+ },
+ "startArrowhead": null,
+ "endArrowhead": "arrow",
+ "elbowed": false
+ },
+ {
+ "type": "rectangle",
+ "version": 675,
+ "versionNonce": 294525072,
+ "index": "b09",
+ "isDeleted": false,
+ "id": "-kMJn4t02d3BEj1iHbvsI",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 914.6749023723355,
+ "y": 169.74218277578416,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "#ffffff",
+ "width": 195.20001220703125,
+ "height": 41.600067138671875,
+ "seed": 713915024,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": {
+ "type": 3
+ },
+ "boundElements": [
+ {
+ "type": "text",
+ "id": "qODkEh4lm-W3hsbAvtR-i"
+ }
+ ],
+ "updated": 1726046854154,
+ "link": null,
+ "locked": false
+ },
+ {
+ "type": "text",
+ "version": 663,
+ "versionNonce": 50382448,
+ "index": "b0A",
+ "isDeleted": false,
+ "id": "qODkEh4lm-W3hsbAvtR-i",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 936.3549866008511,
+ "y": 178.0422163451201,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "transparent",
+ "width": 151.83984375,
+ "height": 25,
+ "seed": 1310697616,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": null,
+ "boundElements": [],
+ "updated": 1726046421370,
+ "link": null,
+ "locked": false,
+ "fontSize": 20,
+ "fontFamily": 1,
+ "text": "consensus rules",
+ "textAlign": "center",
+ "verticalAlign": "middle",
+ "containerId": "-kMJn4t02d3BEj1iHbvsI",
+ "originalText": "consensus rules",
+ "autoResize": true,
+ "lineHeight": 1.25
+ },
+ {
+ "id": "6VvMekiLDQkruhQDgnoct",
+ "type": "text",
+ "x": 1139.4749206828824,
+ "y": -340.65779586191115,
+ "width": 49.21995544433594,
+ "height": 25,
+ "angle": 0,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "#fff9db",
+ "fillStyle": "hachure",
+ "strokeWidth": 2,
+ "strokeStyle": "dotted",
+ "roughness": 0,
+ "opacity": 100,
+ "groupIds": [],
+ "frameId": null,
+ "index": "b0C",
+ "roundness": null,
+ "seed": 380584560,
+ "version": 33,
+ "versionNonce": 1305454192,
+ "isDeleted": false,
+ "boundElements": null,
+ "updated": 1726047161439,
+ "link": null,
+ "locked": false,
+ "text": "Cairo",
+ "fontSize": 20,
+ "fontFamily": 5,
+ "textAlign": "left",
+ "verticalAlign": "top",
+ "containerId": null,
+ "originalText": "Cairo",
+ "autoResize": true,
+ "lineHeight": 1.25
+ },
+ {
+ "type": "rectangle",
+ "version": 1419,
+ "versionNonce": 1876825744,
+ "index": "b0D",
+ "isDeleted": false,
+ "id": "cwLLnN-1jTMdIZNDEow_n",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "dotted",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 508.47510378835113,
+ "y": -360.45772261972365,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "#ebfbee",
+ "width": 187.99987792968759,
+ "height": 208.7998046875,
+ "seed": 1914053264,
+ "groupIds": [
+ "gKhb0zfr_4XXWP_0mOYtd"
+ ],
+ "frameId": null,
+ "roundness": null,
+ "boundElements": [
+ {
+ "type": "text",
+ "id": "Hc1h69tP3l0GVZB4vPvCg"
+ },
+ {
+ "id": "IwaIfRpdALQBDgV0u-ATE",
+ "type": "arrow"
+ }
+ ],
+ "updated": 1726051204516,
+ "link": null,
+ "locked": false
+ },
+ {
+ "type": "text",
+ "version": 1221,
+ "versionNonce": 1459405968,
+ "index": "b0E",
+ "isDeleted": false,
+ "id": "Hc1h69tP3l0GVZB4vPvCg",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 575.485067777609,
+ "y": -355.45772261972365,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "#ebfbee",
+ "width": 53.979949951171875,
+ "height": 25,
+ "seed": 1850953872,
+ "groupIds": [
+ "gKhb0zfr_4XXWP_0mOYtd"
+ ],
+ "frameId": null,
+ "roundness": {
+ "type": 2
+ },
+ "boundElements": [],
+ "updated": 1726051204516,
+ "link": null,
+ "locked": false,
+ "fontSize": 20,
+ "fontFamily": 5,
+ "text": "proof",
+ "textAlign": "center",
+ "verticalAlign": "top",
+ "containerId": "cwLLnN-1jTMdIZNDEow_n",
+ "originalText": "proof",
+ "autoResize": true,
+ "lineHeight": 1.25
+ },
+ {
+ "type": "rectangle",
+ "version": 1437,
+ "versionNonce": 2011226256,
+ "index": "b0F",
+ "isDeleted": false,
+ "id": "aNm6PI-DtRQWT2Sj0bi7s",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 531.215443984534,
+ "y": -315.3576554810518,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "#ffffff",
+ "width": 143.31571977535447,
+ "height": 63.19996643066406,
+ "seed": 112901776,
+ "groupIds": [
+ "gKhb0zfr_4XXWP_0mOYtd"
+ ],
+ "frameId": null,
+ "roundness": {
+ "type": 3
+ },
+ "boundElements": [
+ {
+ "id": "uziA6oySDKPMBkhclY7Na",
+ "type": "text"
+ }
+ ],
+ "updated": 1726051204516,
+ "link": null,
+ "locked": false
+ },
+ {
+ "type": "text",
+ "version": 1265,
+ "versionNonce": 672550544,
+ "index": "b0G",
+ "isDeleted": false,
+ "id": "uziA6oySDKPMBkhclY7Na",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 546.9533591090276,
+ "y": -296.25767226571975,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "#ebfbee",
+ "width": 111.83988952636719,
+ "height": 25,
+ "seed": 1006922896,
+ "groupIds": [
+ "gKhb0zfr_4XXWP_0mOYtd"
+ ],
+ "frameId": null,
+ "roundness": {
+ "type": 2
+ },
+ "boundElements": [],
+ "updated": 1726051204516,
+ "link": null,
+ "locked": false,
+ "fontSize": 20,
+ "fontFamily": 5,
+ "text": "chain state",
+ "textAlign": "center",
+ "verticalAlign": "middle",
+ "containerId": "aNm6PI-DtRQWT2Sj0bi7s",
+ "originalText": "chain state",
+ "autoResize": true,
+ "lineHeight": 1.25
+ },
+ {
+ "type": "rectangle",
+ "version": 1876,
+ "versionNonce": 1265499280,
+ "index": "b0H",
+ "isDeleted": false,
+ "id": "ydKJB4ugsrqufvEqVHRk5",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 532.2664321668276,
+ "y": -236.75766463632522,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "#ffffff",
+ "width": 145.49011817706395,
+ "height": 64,
+ "seed": 937974416,
+ "groupIds": [
+ "gKhb0zfr_4XXWP_0mOYtd"
+ ],
+ "frameId": null,
+ "roundness": {
+ "type": 3
+ },
+ "boundElements": [
+ {
+ "id": "I1QEZkbQosDrXZjKyV4O5",
+ "type": "text"
+ }
+ ],
+ "updated": 1726051204516,
+ "link": null,
+ "locked": false
+ },
+ {
+ "type": "text",
+ "version": 1627,
+ "versionNonce": 1134553744,
+ "index": "b0I",
+ "isDeleted": false,
+ "id": "I1QEZkbQosDrXZjKyV4O5",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 545.0215391679571,
+ "y": -229.75766463632522,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "#ebfbee",
+ "width": 119.97990417480469,
+ "height": 50,
+ "seed": 756975760,
+ "groupIds": [
+ "gKhb0zfr_4XXWP_0mOYtd"
+ ],
+ "frameId": null,
+ "roundness": {
+ "type": 2
+ },
+ "boundElements": [],
+ "updated": 1726051204516,
+ "link": null,
+ "locked": false,
+ "fontSize": 20,
+ "fontFamily": 5,
+ "text": "utxo merkle \naccumulator",
+ "textAlign": "center",
+ "verticalAlign": "middle",
+ "containerId": "ydKJB4ugsrqufvEqVHRk5",
+ "originalText": "utxo merkle accumulator",
+ "autoResize": true,
+ "lineHeight": 1.25
+ }
+ ],
+ "appState": {
+ "gridSize": 20,
+ "gridStep": 5,
+ "gridModeEnabled": false,
+ "viewBackgroundColor": "#ffffff"
+ },
+ "files": {}
+}
\ No newline at end of file
diff --git a/docs/img/components.svg b/docs/img/components.svg
new file mode 100644
index 00000000..0f42a0c9
--- /dev/null
+++ b/docs/img/components.svg
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+ consensus validation block validation transaction validation header validation full node script validation UTXO verification utreexo bridge node utxo inclusion proofs blocks blocks stark verifier verified chain state utxo merkle accumulator proof chain state utxo merkle accumulator consensus rules Cairo proof chain state utxo merkle accumulator
\ No newline at end of file
diff --git a/packages/client/README.md b/packages/client/README.md
new file mode 100644
index 00000000..f99b53d9
--- /dev/null
+++ b/packages/client/README.md
@@ -0,0 +1,45 @@
+# Bitcoin client in Cairo
+
+This package is a standalone Cairo program (outside of Starknet context) that implements a Bitcoin client which can work in two modes:
+- Light mode: block header validation only
+- Full mode: full Bitcoin consensus validation
+
+## Usage
+
+```sh
+# You have to be in the "packages/client" directory
+scarb run client START_HEIGHT END_HEIGHT BATCH_SIZE MODE STRATEGY
+```
+
+Client expects the following arguments:
+* `START_HEIGHT` height of the initial chain state
+* `END_HEIGHT` height of the final (resulting) chain state
+* `BATCH_SIZE` number of blocks applied per single program run
+* `MODE` either `light` or `full` (default is light)
+* `STRATEGY` either `sequential` or `random` (default is sequential)
+
+## Integration tests
+
+In order to run integration tests:
+
+```sh
+scarb test
+```
+
+Run a specific test file (or several files):
+
+```sh
+# You have to be in the "packages/client" directory
+scarb test tests/data/light_481823.json
+```
+
+Re-generate integration test data:
+
+```sh
+# You have to be in the "packages/client" directory
+scarb run regenerate_tests --force
+```
+
+If you want to just add a new test case, edit `scripts/data/regenerate_tests.sh` and run without `--force` flag.
+
+You can also add/remove ignored scenarios, check out `scripts/data/regenerate_tests.sh` as well.
diff --git a/packages/client/Scarb.toml b/packages/client/Scarb.toml
new file mode 100644
index 00000000..b2189723
--- /dev/null
+++ b/packages/client/Scarb.toml
@@ -0,0 +1,16 @@
+[package]
+name = "client"
+version = "0.1.0"
+edition = "2024_07"
+
+[dependencies]
+consensus = { path = "../consensus" }
+
+[dev-dependencies]
+cairo_test.workspace = true
+
+[scripts]
+test = "scarb build && ../../scripts/data/integration_tests.sh"
+regenerate_tests= "../../scripts/data/regenerate_tests.sh"
+client = "scarb build && ../../scripts/data/client.sh"
+lint = "flake8 scripts/ && black --check scripts/ && scarb fmt"
diff --git a/packages/client/src/lib.cairo b/packages/client/src/lib.cairo
new file mode 100644
index 00000000..c1bd37d3
--- /dev/null
+++ b/packages/client/src/lib.cairo
@@ -0,0 +1,4 @@
+mod main;
+// TODO: scarb cairo-run should support "features" argument
+// so that we can conditionally compile this module
+mod test;
diff --git a/src/main.cairo b/packages/client/src/main.cairo
similarity index 88%
rename from src/main.cairo
rename to packages/client/src/main.cairo
index 714279e5..34c65fc2 100644
--- a/src/main.cairo
+++ b/packages/client/src/main.cairo
@@ -1,5 +1,5 @@
-use crate::types::block::Block;
-use crate::types::chain_state::{ChainState, BlockValidator};
+use consensus::types::block::Block;
+use consensus::types::chain_state::{ChainState, BlockValidator};
/// Raito program arguments.
#[derive(Serde)]
diff --git a/src/test.cairo b/packages/client/src/test.cairo
similarity index 94%
rename from src/test.cairo
rename to packages/client/src/test.cairo
index da9f7d80..a8d03acf 100644
--- a/src/test.cairo
+++ b/packages/client/src/test.cairo
@@ -1,5 +1,5 @@
-use crate::types::block::Block;
-use crate::types::chain_state::{ChainState, BlockValidator};
+use consensus::types::block::Block;
+use consensus::types::chain_state::{ChainState, BlockValidator};
use core::testing::get_available_gas;
/// Integration testing program arguments.
diff --git a/tests/data/full_169.json b/packages/client/tests/data/full_169.json
similarity index 100%
rename from tests/data/full_169.json
rename to packages/client/tests/data/full_169.json
diff --git a/tests/data/full_757738.json b/packages/client/tests/data/full_757738.json
similarity index 100%
rename from tests/data/full_757738.json
rename to packages/client/tests/data/full_757738.json
diff --git a/tests/data/light_150012.json b/packages/client/tests/data/light_150012.json
similarity index 100%
rename from tests/data/light_150012.json
rename to packages/client/tests/data/light_150012.json
diff --git a/tests/data/light_169.json b/packages/client/tests/data/light_169.json
similarity index 100%
rename from tests/data/light_169.json
rename to packages/client/tests/data/light_169.json
diff --git a/tests/data/light_2015.json b/packages/client/tests/data/light_2015.json
similarity index 100%
rename from tests/data/light_2015.json
rename to packages/client/tests/data/light_2015.json
diff --git a/tests/data/light_209999.json b/packages/client/tests/data/light_209999.json
similarity index 100%
rename from tests/data/light_209999.json
rename to packages/client/tests/data/light_209999.json
diff --git a/tests/data/light_24834.json b/packages/client/tests/data/light_24834.json
similarity index 100%
rename from tests/data/light_24834.json
rename to packages/client/tests/data/light_24834.json
diff --git a/tests/data/light_32255.json b/packages/client/tests/data/light_32255.json
similarity index 100%
rename from tests/data/light_32255.json
rename to packages/client/tests/data/light_32255.json
diff --git a/tests/data/light_478557.json b/packages/client/tests/data/light_478557.json
similarity index 100%
rename from tests/data/light_478557.json
rename to packages/client/tests/data/light_478557.json
diff --git a/tests/data/light_481823.json b/packages/client/tests/data/light_481823.json
similarity index 100%
rename from tests/data/light_481823.json
rename to packages/client/tests/data/light_481823.json
diff --git a/tests/data/light_491406.json b/packages/client/tests/data/light_491406.json
similarity index 100%
rename from tests/data/light_491406.json
rename to packages/client/tests/data/light_491406.json
diff --git a/tests/data/light_57042.json b/packages/client/tests/data/light_57042.json
similarity index 100%
rename from tests/data/light_57042.json
rename to packages/client/tests/data/light_57042.json
diff --git a/tests/data/light_629999.json b/packages/client/tests/data/light_629999.json
similarity index 100%
rename from tests/data/light_629999.json
rename to packages/client/tests/data/light_629999.json
diff --git a/tests/data/light_709631.json b/packages/client/tests/data/light_709631.json
similarity index 100%
rename from tests/data/light_709631.json
rename to packages/client/tests/data/light_709631.json
diff --git a/tests/data/light_757738.json b/packages/client/tests/data/light_757738.json
similarity index 100%
rename from tests/data/light_757738.json
rename to packages/client/tests/data/light_757738.json
diff --git a/tests/data/light_757752.json b/packages/client/tests/data/light_757752.json
similarity index 100%
rename from tests/data/light_757752.json
rename to packages/client/tests/data/light_757752.json
diff --git a/tests/data/light_774627.json b/packages/client/tests/data/light_774627.json
similarity index 100%
rename from tests/data/light_774627.json
rename to packages/client/tests/data/light_774627.json
diff --git a/tests/data/light_839999.json b/packages/client/tests/data/light_839999.json
similarity index 100%
rename from tests/data/light_839999.json
rename to packages/client/tests/data/light_839999.json
diff --git a/packages/consensus/README.md b/packages/consensus/README.md
new file mode 100644
index 00000000..1c89183f
--- /dev/null
+++ b/packages/consensus/README.md
@@ -0,0 +1,8 @@
+# Bitcoin consensus in Cairo
+
+This package is a Cairo library providing primitives for validating Bitcoin consensus.
+
+It is structured as follows:
+* `types` module contains all Bitcoin specific entities (start your codebase tour with this folder) adapted for recursive verification;
+* `validation` module contains most of the consensus validation logic;
+* `codec` module contains implementation of Bitcoin binary codec for transaction types.
diff --git a/packages/consensus/Scarb.toml b/packages/consensus/Scarb.toml
new file mode 100644
index 00000000..7ca44ee0
--- /dev/null
+++ b/packages/consensus/Scarb.toml
@@ -0,0 +1,14 @@
+[package]
+name = "consensus"
+version = "0.1.0"
+edition = "2024_07"
+
+[dependencies]
+utils = { path = "../utils" }
+
+[dev-dependencies]
+cairo_test.workspace = true
+
+[scripts]
+# TODO: cairo lint
+lint = "scarb fmt"
diff --git a/src/codec.cairo b/packages/consensus/src/codec.cairo
similarity index 99%
rename from src/codec.cairo
rename to packages/consensus/src/codec.cairo
index d967b12e..ac5820d4 100644
--- a/src/codec.cairo
+++ b/packages/consensus/src/codec.cairo
@@ -1,7 +1,7 @@
//! Bitcoin binary codec traits, implementations, and helpers.
use super::types::transaction::{Transaction, TxIn, TxOut, OutPoint};
-use raito::utils::hash::Digest;
+use utils::hash::Digest;
pub trait Encode {
/// Encode using Bitcoin codec and append to the buffer.
@@ -133,8 +133,8 @@ pub fn encode_compact_size(len: usize, ref dest: ByteArray) {
}
#[cfg(test)]
mod tests {
- use raito::types::transaction::{Transaction, TxIn, TxOut, OutPoint};
- use raito::utils::hex::{from_hex, hex_to_hash_rev};
+ use utils::hex::{from_hex, hex_to_hash_rev};
+ use crate::types::transaction::{Transaction, TxIn, TxOut, OutPoint};
use super::{Encode, TransactionCodec, encode_compact_size};
#[test]
diff --git a/packages/consensus/src/lib.cairo b/packages/consensus/src/lib.cairo
new file mode 100644
index 00000000..238e5741
--- /dev/null
+++ b/packages/consensus/src/lib.cairo
@@ -0,0 +1,17 @@
+pub mod validation {
+ pub mod difficulty;
+ pub mod coinbase;
+ pub mod locktime;
+ pub mod timestamp;
+ pub mod transaction;
+ pub mod work;
+ pub mod block;
+}
+pub mod codec;
+pub mod types {
+ pub mod utreexo;
+ pub mod chain_state;
+ pub mod block;
+ pub mod transaction;
+ pub mod utxo_set;
+}
diff --git a/src/types/block.cairo b/packages/consensus/src/types/block.cairo
similarity index 78%
rename from src/types/block.cairo
rename to packages/consensus/src/types/block.cairo
index a404b19e..19f63b4a 100644
--- a/src/types/block.cairo
+++ b/packages/consensus/src/types/block.cairo
@@ -2,10 +2,11 @@
//!
//! The data is expected to be prepared in advance and passed as program arguments.
-use crate::utils::hash::Digest;
-use crate::utils::sha256::double_sha256_u32_array;
-use crate::utils::numeric::u32_byte_reverse;
+use utils::hash::Digest;
+use utils::sha256::double_sha256_u32_array;
+use utils::numeric::u32_byte_reverse;
use super::transaction::Transaction;
+use core::fmt::{Display, Formatter, Error};
/// Represents a block in the blockchain.
#[derive(Drop, Copy, Debug, PartialEq, Default, Serde)]
@@ -76,11 +77,49 @@ pub impl TransactionDataDefault of Default {
}
}
+impl BlockDisplay of Display {
+ fn fmt(self: @Block, ref f: Formatter) -> Result<(), Error> {
+ let data = match *self.data {
+ TransactionData::MerkleRoot(root) => format!("{}", root),
+ TransactionData::Transactions(txs) => format!("{}", txs.len())
+ };
+ let str: ByteArray = format!(" Block {{ header: {}, data: {} }}", *self.header, @data);
+ f.buffer.append(@str);
+ Result::Ok(())
+ }
+}
+
+impl HeaderDisplay of Display {
+ fn fmt(self: @Header, ref f: Formatter) -> Result<(), Error> {
+ let str: ByteArray = format!(
+ "Header {{ version: {}, time: {}, bits: {}, nonce: {}}}",
+ *self.version,
+ *self.time,
+ *self.bits,
+ *self.nonce
+ );
+ f.buffer.append(@str);
+ Result::Ok(())
+ }
+}
+
+impl TransactionDataDisplay of Display {
+ fn fmt(self: @TransactionData, ref f: Formatter) -> Result<(), Error> {
+ match *self {
+ TransactionData::MerkleRoot(root) => f.buffer.append(@format!("MerkleRoot: {}", root)),
+ TransactionData::Transactions(txs) => f
+ .buffer
+ .append(@format!("Transactions: {}", txs.len()))
+ };
+ Result::Ok(())
+ }
+}
+
#[cfg(test)]
mod tests {
use super::{Header, BlockHash};
- use raito::types::chain_state::ChainState;
- use raito::utils::hash::Digest;
+ use crate::types::chain_state::ChainState;
+ use utils::hash::Digest;
#[test]
fn test_block_hash() {
diff --git a/src/types/chain_state.cairo b/packages/consensus/src/types/chain_state.cairo
similarity index 83%
rename from src/types/chain_state.cairo
rename to packages/consensus/src/types/chain_state.cairo
index f1a50a11..37b01eee 100644
--- a/src/types/chain_state.cairo
+++ b/packages/consensus/src/types/chain_state.cairo
@@ -4,13 +4,14 @@
//! Chain state alone is not enough to do full block validation, however
//! it is sufficient to validate block headers.
-use crate::utils::hash::Digest;
+use utils::hash::Digest;
use crate::validation::{
difficulty::{validate_bits, adjust_difficulty}, coinbase::validate_coinbase,
timestamp::{validate_timestamp, next_prev_timestamps},
work::{validate_proof_of_work, compute_total_work}, block::{compute_and_validate_tx_data},
};
use super::block::{BlockHash, Block, TransactionData};
+use core::fmt::{Display, Formatter, Error};
/// Represents the state of the blockchain.
#[derive(Drop, Copy, Debug, PartialEq, Serde)]
@@ -97,6 +98,33 @@ pub impl BlockValidatorImpl of BlockValidator {
)
}
}
+
+impl ChainStateDisplay of Display {
+ fn fmt(self: @ChainState, ref f: Formatter) -> Result<(), Error> {
+ let mut prev_ts: ByteArray = Default::default();
+ for ts in *self.prev_timestamps {
+ prev_ts.append(@format!("{},", ts));
+ };
+ let str: ByteArray = format!(
+ "
+ block_height: {}
+ total_work: {}
+ best_block_hash: {}
+ current_target: {}
+ epoch_start_time: {}
+ prev_timestamps: [{}]
+}}",
+ *self.block_height,
+ *self.total_work,
+ *self.best_block_hash,
+ *self.current_target,
+ *self.epoch_start_time,
+ @prev_ts
+ );
+ f.buffer.append(@str);
+ Result::Ok(())
+ }
+}
// TODO: implement Digest trait for ChainState
diff --git a/src/types/transaction.cairo b/packages/consensus/src/types/transaction.cairo
similarity index 78%
rename from src/types/transaction.cairo
rename to packages/consensus/src/types/transaction.cairo
index 41471ca0..e5ae7d11 100644
--- a/src/types/transaction.cairo
+++ b/packages/consensus/src/types/transaction.cairo
@@ -3,7 +3,8 @@
//! Types are extended with extra information required for validation.
//! The data is expected to be prepared in advance and passed as program arguments.
-use crate::utils::{hash::Digest, bytearray::{ByteArraySnapHash, ByteArraySnapSerde}};
+use utils::{hash::Digest, bytearray::{ByteArraySnapHash, ByteArraySnapSerde}};
+use core::fmt::{Display, Formatter, Error};
/// Represents a transaction.
/// https://learnmeabitcoin.com/technical/transaction/
@@ -128,13 +129,78 @@ impl TxOutDefault of Default {
}
}
+impl TransactionDisplay of Display {
+ fn fmt(self: @Transaction, ref f: Formatter) -> Result<(), Error> {
+ let str: ByteArray = format!(
+ "Transaction {{ version: {}, is_segwit: {}, inputs: {}, outputs: {}, lock_time: {} }}",
+ *self.version,
+ *self.is_segwit,
+ (*self.inputs).len(),
+ (*self.outputs).len(),
+ *self.lock_time
+ );
+ f.buffer.append(@str);
+ Result::Ok(())
+ }
+}
+
+impl TxInDisplay of Display {
+ fn fmt(self: @TxIn, ref f: Formatter) -> Result<(), Error> {
+ let str: ByteArray = format!(
+ "TxIn {{ script: {}, sequence: {}, previous_output: {}, witness: {} }}",
+ *self.script,
+ *self.sequence,
+ *self.previous_output.txid,
+ (*self.witness).len()
+ );
+ f.buffer.append(@str);
+ Result::Ok(())
+ }
+}
+
+impl OutPointDisplay of Display {
+ fn fmt(self: @OutPoint, ref f: Formatter) -> Result<(), Error> {
+ let str: ByteArray = format!(
+ "OutPoint {{
+ txid: {},
+ vout: {},
+ data: {},
+ block_height: {},
+ block_time: {},
+ is_coinbase: {},
+ }}",
+ *self.txid,
+ *self.vout,
+ *self.data,
+ *self.block_height,
+ *self.block_time,
+ *self.is_coinbase
+ );
+ f.buffer.append(@str);
+ Result::Ok(())
+ }
+}
+
+impl TxOutDisplay of Display {
+ fn fmt(self: @TxOut, ref f: Formatter) -> Result<(), Error> {
+ let str: ByteArray = format!(
+ "TxOut {{ value: {}, pk_script: {}, cached: {} }}",
+ *self.value,
+ *self.pk_script,
+ *self.cached
+ );
+ f.buffer.append(@str);
+ Result::Ok(())
+ }
+}
+
#[cfg(test)]
mod tests {
use core::hash::HashStateTrait;
use core::hash::HashStateExTrait;
use core::poseidon::PoseidonTrait;
use super::{OutPoint, TxOut};
- use crate::utils::{hash::{DigestTrait}};
+ use utils::hash::{DigestTrait};
#[test]
pub fn test_outpoint_poseidon_hash() {
diff --git a/src/types/utreexo.cairo b/packages/consensus/src/types/utreexo.cairo
similarity index 73%
rename from src/types/utreexo.cairo
rename to packages/consensus/src/types/utreexo.cairo
index 9ba075c7..5ae1468e 100644
--- a/src/types/utreexo.cairo
+++ b/packages/consensus/src/types/utreexo.cairo
@@ -28,10 +28,11 @@
//! Read more about utreexo: https://eprint.iacr.org/2019/611.pdf
use super::transaction::OutPoint;
+use core::fmt::{Display, Formatter, Error};
/// Accumulator representation of the state aka "Compact State Node".
/// Part of the chain state.
-#[derive(Drop, Copy)]
+#[derive(Drop, Copy, PartialEq, Serde, Debug)]
pub struct UtreexoState {
/// Roots of the Merkle tree forest.
/// Index is the root height, None means a gap.
@@ -99,3 +100,45 @@ pub impl UtreexoStateDefault of Default {
UtreexoState { roots: array![].span(), num_leaves: 0, }
}
}
+
+impl UtreexoStateDisplay of Display {
+ fn fmt(self: @UtreexoState, ref f: Formatter) -> Result<(), Error> {
+ let str: ByteArray = format!(
+ "UtreexoState {{ roots: {}, num_leaves: {}, }}", (*self.roots).len(), *self.num_leaves
+ );
+ f.buffer.append(@str);
+ Result::Ok(())
+ }
+}
+
+impl UtreexoProofDisplay of Display {
+ fn fmt(self: @UtreexoProof, ref f: Formatter) -> Result<(), Error> {
+ let mut proofs: ByteArray = Default::default();
+ for proof in *self.proof {
+ proofs.append(@format!("{},", proof));
+ };
+ let str: ByteArray = format!(
+ "UtreexoProof {{ leaf_index: {}, proof: {}, }}", *self.leaf_index, @proofs
+ );
+ f.buffer.append(@str);
+ Result::Ok(())
+ }
+}
+
+impl UtreexoBatchProofDisplay of Display {
+ fn fmt(self: @UtreexoBatchProof, ref f: Formatter) -> Result<(), Error> {
+ let mut targets: ByteArray = Default::default();
+ let mut proofs: ByteArray = Default::default();
+ for target in *self.targets {
+ targets.append(@format!("{},", target));
+ };
+ for proof in *self.proof {
+ proofs.append(@format!("{},", proof));
+ };
+ let str: ByteArray = format!(
+ "UtreexoBatchProof {{ leaf_index: [{}], proof: [{}] }}", @targets, @proofs
+ );
+ f.buffer.append(@str);
+ Result::Ok(())
+ }
+}
diff --git a/src/types/utxo_set.cairo b/packages/consensus/src/types/utxo_set.cairo
similarity index 100%
rename from src/types/utxo_set.cairo
rename to packages/consensus/src/types/utxo_set.cairo
diff --git a/src/validation/block.cairo b/packages/consensus/src/validation/block.cairo
similarity index 96%
rename from src/validation/block.cairo
rename to packages/consensus/src/validation/block.cairo
index f329336a..425be5bd 100644
--- a/src/validation/block.cairo
+++ b/packages/consensus/src/validation/block.cairo
@@ -1,7 +1,7 @@
//! Block validation helpers.
use crate::types::transaction::{Transaction};
use crate::codec::{Encode, TransactionCodec};
-use crate::utils::{hash::Digest, merkle_tree::merkle_root, sha256::double_sha256_byte_array};
+use utils::{hash::Digest, merkle_tree::merkle_root, sha256::double_sha256_byte_array};
use super::transaction::validate_transaction;
const MAX_BLOCK_WEIGHT_LEGACY: usize = 1_000_000;
diff --git a/src/validation/coinbase.cairo b/packages/consensus/src/validation/coinbase.cairo
similarity index 99%
rename from src/validation/coinbase.cairo
rename to packages/consensus/src/validation/coinbase.cairo
index 7ab82405..90addf81 100644
--- a/src/validation/coinbase.cairo
+++ b/packages/consensus/src/validation/coinbase.cairo
@@ -3,7 +3,7 @@
//! https://learnmeabitcoin.com/technical/mining/coinbase-transaction/
use crate::types::transaction::{Transaction, TxIn, TxOut};
-use crate::utils::{
+use utils::{
bit_shifts::shr, hash::{Digest, DigestIntoByteArray}, sha256::{double_sha256_byte_array}
};
@@ -84,7 +84,6 @@ fn validate_coinbase_input(input: @TxIn, block_height: u32) -> Result<(), ByteAr
Result::Ok(())
}
-#[inline]
/// Validate coinbase sig script (BIP-34)
fn validate_coinbase_sig_script(script: @ByteArray, block_height: u32) -> Result<(), ByteArray> {
let script_len = script.len();
@@ -199,7 +198,7 @@ mod tests {
validate_coinbase_sig_script, validate_coinbase_witness, validate_segwit_output,
calculate_wtxid_commitment
};
- use crate::utils::{hex::{from_hex, hex_to_hash_rev}, hash::Digest};
+ use utils::{hex::{from_hex, hex_to_hash_rev}, hash::Digest};
// Ref implementation here:
// https://github.com/bitcoin/bitcoin/blob/0f68a05c084bef3e53e3f549c403bc90b1db319c/src/test/validation_tests.cpp#L24
diff --git a/src/validation/difficulty.cairo b/packages/consensus/src/validation/difficulty.cairo
similarity index 99%
rename from src/validation/difficulty.cairo
rename to packages/consensus/src/validation/difficulty.cairo
index 3e894691..1f4bf558 100644
--- a/src/validation/difficulty.cairo
+++ b/packages/consensus/src/validation/difficulty.cairo
@@ -4,7 +4,7 @@
//! - https://learnmeabitcoin.com/technical/mining/target/
//! - https://learnmeabitcoin.com/technical/block/bits/
-use crate::utils::{bit_shifts::{shl, shr}};
+use utils::{bit_shifts::{shl, shr}};
/// Maximum difficulty target allowed
const MAX_TARGET: u256 = 0x00000000FFFF0000000000000000000000000000000000000000000000000000;
diff --git a/src/validation/locktime.cairo b/packages/consensus/src/validation/locktime.cairo
similarity index 99%
rename from src/validation/locktime.cairo
rename to packages/consensus/src/validation/locktime.cairo
index a12c5a60..d930702c 100644
--- a/src/validation/locktime.cairo
+++ b/packages/consensus/src/validation/locktime.cairo
@@ -116,7 +116,7 @@ pub fn validate_relative_locktime(
#[cfg(test)]
mod tests {
use crate::types::transaction::{TxIn, OutPoint, TxOut};
- use crate::utils::hex::{from_hex, hex_to_hash_rev};
+ use utils::hex::{from_hex, hex_to_hash_rev};
use super::{validate_absolute_locktime, validate_relative_locktime};
// TODO: tests for invalid relative locktime
diff --git a/src/validation/timestamp.cairo b/packages/consensus/src/validation/timestamp.cairo
similarity index 100%
rename from src/validation/timestamp.cairo
rename to packages/consensus/src/validation/timestamp.cairo
diff --git a/src/validation/transaction.cairo b/packages/consensus/src/validation/transaction.cairo
similarity index 99%
rename from src/validation/transaction.cairo
rename to packages/consensus/src/validation/transaction.cairo
index a0e5c2bf..d21a13d4 100644
--- a/src/validation/transaction.cairo
+++ b/packages/consensus/src/validation/transaction.cairo
@@ -67,7 +67,6 @@ pub fn validate_transaction(
return compute_transaction_fee(total_input_amount, total_output_amount);
}
-#[inline]
/// Ensure transaction fee is not negative.
fn compute_transaction_fee(
total_input_amount: u64, total_output_amount: u64
@@ -80,7 +79,6 @@ fn compute_transaction_fee(
return Result::Ok(total_input_amount - total_output_amount);
}
-#[inline]
/// Ensure than coinbase output is old enough to be spent.
fn validate_coinbase_maturity(output_height: u32, block_height: u32) -> Result<(), ByteArray> {
if block_height <= output_height + 100 {
@@ -99,7 +97,7 @@ fn validate_coinbase_maturity(output_height: u32, block_height: u32) -> Result<(
#[cfg(test)]
mod tests {
use crate::types::transaction::{Transaction, TxIn, TxOut, OutPoint};
- use crate::utils::hex::{from_hex, hex_to_hash_rev};
+ use utils::hex::{from_hex, hex_to_hash_rev};
use super::validate_transaction;
// TODO: tests for coinbase maturity
diff --git a/src/validation/work.cairo b/packages/consensus/src/validation/work.cairo
similarity index 99%
rename from src/validation/work.cairo
rename to packages/consensus/src/validation/work.cairo
index c9b272d8..cfaeaf9c 100644
--- a/src/validation/work.cairo
+++ b/packages/consensus/src/validation/work.cairo
@@ -1,6 +1,6 @@
//! Proof-of-work validation helpers.
-use crate::utils::hash::Digest;
+use utils::hash::Digest;
/// Check if the work done (by calculating the block hash) satisfies the difficulty target.
pub fn validate_proof_of_work(target: u256, block_hash: Digest) -> Result<(), ByteArray> {
diff --git a/packages/utils/README.md b/packages/utils/README.md
new file mode 100644
index 00000000..8d47ad55
--- /dev/null
+++ b/packages/utils/README.md
@@ -0,0 +1,3 @@
+# Common utilities
+
+This package contains common helpers that are not Bitcoin-specific.
diff --git a/packages/utils/Scarb.toml b/packages/utils/Scarb.toml
new file mode 100644
index 00000000..81475f48
--- /dev/null
+++ b/packages/utils/Scarb.toml
@@ -0,0 +1,11 @@
+[package]
+name = "utils"
+version = "0.1.0"
+edition = "2024_07"
+
+[dev-dependencies]
+cairo_test.workspace = true
+
+[scripts]
+# TODO: cairo lint
+lint = "scarb fmt"
diff --git a/src/utils/bit_shifts.cairo b/packages/utils/src/bit_shifts.cairo
similarity index 100%
rename from src/utils/bit_shifts.cairo
rename to packages/utils/src/bit_shifts.cairo
diff --git a/src/utils/bytearray.cairo b/packages/utils/src/bytearray.cairo
similarity index 98%
rename from src/utils/bytearray.cairo
rename to packages/utils/src/bytearray.cairo
index 064f50dd..e123e30f 100644
--- a/src/utils/bytearray.cairo
+++ b/packages/utils/src/bytearray.cairo
@@ -16,7 +16,6 @@ pub impl ByteArraySnapSerde of Serde<@ByteArray> {
}
pub impl ByteArraySnapHash, +Drop> of Hash<@ByteArray, S> {
- #[inline]
fn update_state(mut state: S, value: @ByteArray) -> S {
let mut serialized_bytearray: Array = array![];
value.serialize(ref serialized_bytearray);
diff --git a/src/utils/hash.cairo b/packages/utils/src/hash.cairo
similarity index 99%
rename from src/utils/hash.cairo
rename to packages/utils/src/hash.cairo
index ceed2390..bfb4eed4 100644
--- a/src/utils/hash.cairo
+++ b/packages/utils/src/hash.cairo
@@ -112,7 +112,7 @@ pub impl DigestHash, +Drop> of Hash {
#[cfg(test)]
mod tests {
- use crate::utils::hex::from_hex;
+ use crate::hex::from_hex;
use super::Digest;
#[test]
diff --git a/src/utils/hex.cairo b/packages/utils/src/hex.cairo
similarity index 97%
rename from src/utils/hex.cairo
rename to packages/utils/src/hex.cairo
index 52830eed..736a403c 100644
--- a/src/utils/hex.cairo
+++ b/packages/utils/src/hex.cairo
@@ -1,5 +1,5 @@
//! Hex helpers
-use raito::utils::hash::Digest;
+use crate::hash::Digest;
/// Get bytes from hex (base16)
pub fn from_hex(hex_string: ByteArray) -> ByteArray {
@@ -86,7 +86,7 @@ fn hex_char_to_nibble(hex_char: u8) -> u8 {
#[cfg(test)]
mod tests {
use super::{from_hex, to_hex, hex_to_hash_rev};
- use raito::utils::hash::Digest;
+ use crate::hash::Digest;
#[test]
fn test_bytes_from_hex() {
diff --git a/packages/utils/src/lib.cairo b/packages/utils/src/lib.cairo
new file mode 100644
index 00000000..e85c50e3
--- /dev/null
+++ b/packages/utils/src/lib.cairo
@@ -0,0 +1,9 @@
+pub mod bytearray;
+pub mod sha256;
+pub mod hash;
+pub mod bit_shifts;
+pub mod merkle_tree;
+pub mod numeric;
+
+#[cfg(target: 'test')]
+pub mod hex;
diff --git a/src/utils/merkle_tree.cairo b/packages/utils/src/merkle_tree.cairo
similarity index 99%
rename from src/utils/merkle_tree.cairo
rename to packages/utils/src/merkle_tree.cairo
index 18c967dd..026dd4b7 100644
--- a/src/utils/merkle_tree.cairo
+++ b/packages/utils/src/merkle_tree.cairo
@@ -29,7 +29,7 @@ pub fn merkle_root(ref hashes: Array) -> Digest {
#[cfg(test)]
mod tests {
- use crate::utils::{hash::{Digest, U256IntoDigest}, hex::hex_to_hash_rev};
+ use crate::{hash::{Digest, U256IntoDigest}, hex::hex_to_hash_rev};
use super::{merkle_root};
#[test]
diff --git a/src/utils/numeric.cairo b/packages/utils/src/numeric.cairo
similarity index 100%
rename from src/utils/numeric.cairo
rename to packages/utils/src/numeric.cairo
diff --git a/src/utils/sha256.cairo b/packages/utils/src/sha256.cairo
similarity index 97%
rename from src/utils/sha256.cairo
rename to packages/utils/src/sha256.cairo
index 57d83951..707c69af 100644
--- a/src/utils/sha256.cairo
+++ b/packages/utils/src/sha256.cairo
@@ -36,7 +36,7 @@ pub fn double_sha256_u32_array(words: Array) -> Digest {
#[cfg(test)]
mod tests {
- use crate::utils::{hex::from_hex, hash::Digest};
+ use crate::{hex::from_hex, hash::Digest};
use super::{double_sha256_byte_array, double_sha256_u32_array, double_sha256_parent};
#[test]
diff --git a/scripts/data/client.sh b/scripts/data/client.sh
index a8235da9..5b39d1a2 100644
--- a/scripts/data/client.sh
+++ b/scripts/data/client.sh
@@ -1,9 +1,9 @@
#!/usr/bin/env bash
-set -e;
-set -o pipefail;
+#set -e;
+#set -o pipefail;
-base_dir=".raito"
+base_dir=".client_cache"
start=${1:-0}
end=${2:-100}
@@ -23,11 +23,11 @@ run_client() {
batch_file=${base_dir}/${mode}_${initial_height}_${num_blocks}.json
if [ ! -f "$batch_file" ]; then
- python scripts/data/generate_data.py $mode $initial_height $num_blocks true $batch_file
+ python ../../scripts/data/generate_data.py $mode $initial_height $num_blocks true $batch_file
fi
- arguments=$(python scripts/data/format_args.py $batch_file)
- output=$(scarb cairo-run --no-build --function test "$arguments")
+ arguments=$(python ../../scripts/data/format_args.py $batch_file)
+ output=$(scarb cairo-run --no-build --package client --function test "$arguments")
if [[ "$output" == *"FAIL"* ]]; then
echo " fail"
echo $output
diff --git a/scripts/data/format_args.py b/scripts/data/format_args.py
index 9d3c18cd..9d054e8e 100644
--- a/scripts/data/format_args.py
+++ b/scripts/data/format_args.py
@@ -20,7 +20,7 @@ def serialize(obj):
return 1 if obj else 0
elif isinstance(obj, int):
# This covers u8, u16, u32, u64, u128, felt252
- assert(obj >= 0 and obj < 2 ** 252)
+ assert obj >= 0 and obj < 2**252
return obj
elif isinstance(obj, str):
if obj == "0" * 64:
@@ -30,25 +30,27 @@ def serialize(obj):
# TODO: there might still be collisions with hashes
# Try to cast to int and then to low/high parts
num = int(obj)
- assert(num >= 0 and num < 2 ** 256)
- lo = num % 2 ** 128
- hi = num // 2 ** 128
+ assert num >= 0 and num < 2**256
+ lo = num % 2**128
+ hi = num // 2**128
return (lo, hi)
- elif obj.startswith('0x'):
+ elif obj.startswith("0x"):
# Split into 31-byte chunks and save the remainder
src = bytes.fromhex(obj[2:])
num_chunks = len(src) // 31
main_len = num_chunks * 31
rem_len = len(src) - main_len
- main = [int.from_bytes(src[i:i+31], 'big') for i in range(0, main_len, 31)]
+ main = [
+ int.from_bytes(src[i : i + 31], "big") for i in range(0, main_len, 31)
+ ]
# TODO: check if this is how byte31 is implemented
- rem = int.from_bytes(src[main_len:].rjust(31, b'\x00'), 'big')
+ rem = int.from_bytes(src[main_len:].rjust(31, b"\x00"), "big")
return tuple([len(main)] + main + [rem, rem_len])
else:
# Reversed hex string into 4-byte words then into BE u32
- assert(len(obj) == 64)
+ assert len(obj) == 64
rev = list(reversed(bytes.fromhex(obj)))
- return tuple(int.from_bytes(rev[i:i+4], 'big') for i in range(0, 32, 4))
+ return tuple(int.from_bytes(rev[i : i + 4], "big") for i in range(0, 32, 4))
elif isinstance(obj, list):
arr = list(map(serialize, obj))
return tuple([len(arr)] + arr)
@@ -68,6 +70,7 @@ def flatten_tuples(src):
:return: an object that can only contain integers and lists, top-level tuple converts to a list.
"""
res = []
+
def append_obj(obj, to):
if isinstance(obj, int):
to.append(obj)
@@ -81,6 +84,7 @@ def append_obj(obj, to):
append_obj(item, to)
else:
raise NotImplementedError(obj)
+
append_obj(src, res)
return res
@@ -92,12 +96,14 @@ def format_cairo1_run(args: list) -> str:
:param args: Python object containing already processed arguments.
:return: Returns string with removed commas.
"""
+
def format_item(item):
if isinstance(item, list):
arr = " ".join(map(format_item, item))
- return f'[{arr}]'
+ return f"[{arr}]"
else:
return str(item)
+
return format_item(args)
@@ -106,12 +112,12 @@ def format_args():
Expects a single CLI argument containing file path.
Output is compatible with the Scarb runner arguments format.
"""
- if (len(sys.argv) != 2):
+ if len(sys.argv) != 2:
raise TypeError("Expected single argument")
args = json.loads(Path(sys.argv[1]).read_text())
res = flatten_tuples(serialize(args))
print([res])
-if __name__ == '__main__':
+if __name__ == "__main__":
format_args()
diff --git a/scripts/data/generate_data.py b/scripts/data/generate_data.py
index aa4855f2..691a42e6 100755
--- a/scripts/data/generate_data.py
+++ b/scripts/data/generate_data.py
@@ -190,13 +190,15 @@ def format_coinbase_input(input: dict):
"block_time": 0,
"is_coinbase": False,
},
- "witness": ["0x0000000000000000000000000000000000000000000000000000000000000000"],
+ "witness": [
+ "0x0000000000000000000000000000000000000000000000000000000000000000"
+ ],
}
def format_output(output: dict):
"""Formats transaction output according to the Cairo type."""
- value = (Decimal(str(output["value"])) * Decimal('100000000')).to_integral_value()
+ value = (Decimal(str(output["value"])) * Decimal("100000000")).to_integral_value()
return {
"value": int(value),
"pk_script": f'0x{output["scriptPubKey"]["hex"]}',
diff --git a/scripts/data/integration_tests.sh b/scripts/data/integration_tests.sh
index 4f40ad80..bd51c13d 100755
--- a/scripts/data/integration_tests.sh
+++ b/scripts/data/integration_tests.sh
@@ -21,15 +21,17 @@ if [ $# -gt 0 ]; then
test_files="${args[@]}"
fi
+echo "running integration tests ..."
+
for test_file in $test_files; do
if [ -f "$test_file" ]; then
- echo -n "test e2e:$test_file ..."
+ echo -n "test $test_file ..."
if [[ "$ignored" =~ "$test_file" ]]; then
echo " ignored"
num_ignored=$((num_ignored + 1))
else
- arguments=$(python scripts/data/format_args.py ${test_file})
+ arguments=$(python ../../scripts/data/format_args.py ${test_file})
output=$(scarb cairo-run --no-build --function test "$arguments")
gas_spent=$(echo $output | grep -o 'gas_spent=[0-9]*' | sed 's/gas_spent=//')
@@ -37,8 +39,7 @@ for test_file in $test_files; do
echo -e "${RED} fail ${RESET}(gas usage est.: $gas_spent)"
num_fail=$((num_fail + 1))
error=$(echo $output | grep -o "error='[^']*'" | sed "s/error=//")
- failures+="\te2e:$test_file — Panicked with $error:\n"
- failures+="\te2e:$test_file — output:\n$output\n"
+ failures+="\t$test_file — Panicked with $error\n"
elif [[ "$output" == *"OK"* ]]; then
echo -e "${GREEN} ok ${RESET}(gas usage est.: $gas_spent)"
num_ok=$((num_ok + 1))
@@ -46,8 +47,7 @@ for test_file in $test_files; do
echo -e "${RED} fail ${RESET}(gas usage est.: 0)"
num_fail=$((num_fail + 1))
error=$(echo "$output" | sed '1d')
- failures+="\te2e:$test_file — $error\n"
- failures+="\te2e:$test_file — output:\n$output\n"
+ failures+="\t$test_file — $error\n"
fi
fi
fi
diff --git a/scripts/data/regenerate_tests.sh b/scripts/data/regenerate_tests.sh
index 3a314723..fabc833e 100755
--- a/scripts/data/regenerate_tests.sh
+++ b/scripts/data/regenerate_tests.sh
@@ -9,6 +9,7 @@ then
fi
force=0
+data_dir="tests/data"
if [[ "$1" == "--force" ]]; then
force=1
@@ -25,8 +26,6 @@ light_test_cases=(
478557 # Bitcoin Cash hard fork block (478558)
481823 # Segwit soft fork block (481824)
491406 # Bitcoin Gold hard fork block (491407)
- 542212 # (542213)
- 553723 # (553724)
629999 # Third halving block (630000)
709631 # Taproot soft fort block (709632)
757738 # Block with witness (757739)
@@ -37,20 +36,18 @@ light_test_cases=(
full_test_cases=(
169 # Block containing first P2P tx to Hal Finney (170)
- 542212
- 553723 # (553724)
757738 # Block with witness (757739)
)
-mkdir tests/data || true
+mkdir $data_dir || true
# Generate test file if it does not exist yet or if "force" flag is set
generate_test() {
local mode=$1
local height=$2
- test_file="tests/data/${mode}_${test_case}.json"
+ test_file="${data_dir}/${mode}_${test_case}.json"
if [[ ! -f "$test_file" || $force -eq 1 ]]; then
- python scripts/data/generate_data.py $mode $height 1 true $test_file
+ python ../../scripts/data/generate_data.py $mode $height 1 true $test_file
fi
}
diff --git a/scripts/data/requirements.txt b/scripts/data/requirements.txt
index ef487e06..4ce787d1 100644
--- a/scripts/data/requirements.txt
+++ b/scripts/data/requirements.txt
@@ -1 +1,4 @@
-requests==2.32.3
\ No newline at end of file
+requests==2.32.3
+black==24.8.0
+flake8==7.1.1
+flake8-black==0.3.6
\ No newline at end of file
diff --git a/scripts/misc/create_issues.py b/scripts/misc/create_issues.py
index 4cd113ff..a6b88330 100644
--- a/scripts/misc/create_issues.py
+++ b/scripts/misc/create_issues.py
@@ -3,14 +3,20 @@
import sys
import argparse
+
def create_issue(title, body, labels):
cmd = [
- "gh", "issue", "create",
- "--title", title,
- "--body", body,
- "--label", ",".join(labels)
+ "gh",
+ "issue",
+ "create",
+ "--title",
+ title,
+ "--body",
+ body,
+ "--label",
+ ",".join(labels),
]
-
+
try:
subprocess.run(cmd, check=True)
print(f"Successfully created issue: {title}")
@@ -19,8 +25,11 @@ def create_issue(title, body, labels):
print(f"Error message: {e}")
sys.exit(1)
+
def main():
- parser = argparse.ArgumentParser(description="Create GitHub issues from a JSON file.")
+ parser = argparse.ArgumentParser(
+ description="Create GitHub issues from a JSON file."
+ )
parser.add_argument("json_file", help="Path to the JSON file containing issue data")
args = parser.parse_args()
@@ -41,5 +50,6 @@ def main():
for issue in data["issues"]:
create_issue(issue["title"], issue["body"], issue["labels"])
+
if __name__ == "__main__":
- main()
\ No newline at end of file
+ main()
diff --git a/src/lib.cairo b/src/lib.cairo
deleted file mode 100644
index 7767f8d3..00000000
--- a/src/lib.cairo
+++ /dev/null
@@ -1,35 +0,0 @@
-pub mod utils {
- pub mod bytearray;
- pub mod sha256;
- pub mod hash;
- pub mod bit_shifts;
- pub mod merkle_tree;
- pub mod numeric;
-
- // #[cfg(target: 'test')]
- pub mod hex;
-}
-pub mod validation {
- pub mod difficulty;
- pub mod coinbase;
- pub mod locktime;
- pub mod timestamp;
- pub mod transaction;
- pub mod work;
- pub mod block;
-}
-pub mod codec;
-pub mod types {
- pub mod utreexo;
- pub mod chain_state;
- pub mod block;
- pub mod transaction;
- pub mod utxo_set;
-}
-
-mod main;
-
-// TODO: move this module to a separate package
-// Scarb does not support features when using cairo-run
-// neither it allows to run function from the "tests" folder
-mod test;
diff --git a/tests/data/full_542212.json b/tests/data/full_542212.json
deleted file mode 100644
index f57eb2c5..00000000
--- a/tests/data/full_542212.json
+++ /dev/null
@@ -1,359 +0,0 @@
-{
- "chain_state": {
- "block_height": 542212,
- "total_work": "1005317431382460840667183195",
- "best_block_hash": "000000000000000000085a38ccf9c046c51b96add547c466ccba3612b1eb8089",
- "current_target": "3840827764407250199942201944063224491938810378873470976",
- "epoch_start_time": 1536290079,
- "prev_timestamps": [
- 1537424869,
- 1537425316,
- 1537425370,
- 1537425379,
- 1537425770,
- 1537425986,
- 1537427160,
- 1537428220,
- 1537428564,
- 1537429315,
- 1537429661
- ]
- },
- "blocks": [
- {
- "header": {
- "version": 536870912,
- "time": 1537429727,
- "bits": 388503969,
- "nonce": 31692307
- },
- "data": {
- "variant_id": 1,
- "transactions": [
- {
- "version": 1,
- "is_segwit": true,
- "inputs": [
- {
- "script": "0x03054608174d696e656420627920416e74506f6f6c393b205ba350dffabe6d6d3a3e92d9efff857664de632e89fa3182f1e793d00be2e71a117b273145945a810400000000000000db250000acba0500",
- "sequence": 4294967295,
- "previous_output": {
- "txid": "0000000000000000000000000000000000000000000000000000000000000000",
- "vout": 4294967295,
- "data": {
- "value": 0,
- "pk_script": "0x",
- "cached": false
- },
- "block_height": 0,
- "block_time": 0,
- "is_coinbase": false
- },
- "witness": [
- "0x0000000000000000000000000000000000000000000000000000000000000000"
- ]
- }
- ],
- "outputs": [
- {
- "value": 1250004874,
- "pk_script": "0x76a914edf10a7fac6b32e24daa5305c723f3de58db1bc888ac",
- "cached": false
- },
- {
- "value": 0,
- "pk_script": "0x6a24aa21a9ed4a657fcaa2149342376247e2e283a55a6b92dcc35d4d89e4ac7b74488cb63be2",
- "cached": false
- }
- ],
- "lock_time": 0
- },
- {
- "version": 1,
- "is_segwit": false,
- "inputs": [
- {
- "script": "0x483045022100e2e9bc1f6bae2deed086e935bb49fd6ac1e13dc3a44c36cd8b9a6f4257efb70d022076537c7021f12d761e1202796029f13798503bc22ab8c2ee8cb98207cbfeb414012102071c2c88e4560b47a03c033c736149a2ddd6071aea54ab85c5169cee156712f8",
- "sequence": 4294967295,
- "previous_output": {
- "txid": "db636bb7d1c79b38b496766dcf37fbc215edb1fd4f19b5ec9993d4983f2798b8",
- "vout": 1,
- "data": {
- "value": 20000000,
- "pk_script": "0x76a914682d27c2f705e69a7c291aa4860d1fac01ff3cb388ac",
- "cached": false
- },
- "block_height": 542034,
- "block_time": 1537329301,
- "is_coinbase": false
- },
- "witness": []
- }
- ],
- "outputs": [
- {
- "value": 750000,
- "pk_script": "0x76a914849a95fc65eeaa2ac47b6b6fc1f1883edb2c6c9788ac",
- "cached": false
- },
- {
- "value": 19248870,
- "pk_script": "0x76a9142964198f7ae9f7b920a2ab7c0b96b90e4ec9b14d88ac",
- "cached": false
- }
- ],
- "lock_time": 0
- },
- {
- "version": 1,
- "is_segwit": true,
- "inputs": [
- {
- "script": "0x160014dde2f1a9a4bfda011ba9ec4062990c7e1a531585",
- "sequence": 4294967295,
- "previous_output": {
- "txid": "88a7846ff8f618cd70c9ee0cf1be9bbbb7b3b0a12434f640355b0560265e4052",
- "vout": 0,
- "data": {
- "value": 1629016,
- "pk_script": "0xa914c460985af9c3b4213ac834a91cc22b8dd6ef82f987",
- "cached": false
- },
- "block_height": 542212,
- "block_time": 1537429661,
- "is_coinbase": false
- },
- "witness": [
- "0x3045022100f93bd5d3529418f60dddd477f169c32ea5ab340c99573438ee7c40d705db9ba20220323f1b4d8840098b1271c95365cdc7e8f81d0bf1fcc568c68fc7de8b871b4bee01",
- "0x03211d047d92547bca4aa116bc51ec4b09188e5991f69f0432fe1b5dfd89478597"
- ]
- }
- ],
- "outputs": [
- {
- "value": 1627238,
- "pk_script": "0xa914adc5ec550548f087371e645047170864d5fbdc0387",
- "cached": false
- },
- {
- "value": 1150,
- "pk_script": "0x001441f6746110cc0fec102e83053d4c0ae56fab1bdd",
- "cached": false
- }
- ],
- "lock_time": 0
- },
- {
- "version": 1,
- "is_segwit": false,
- "inputs": [
- {
- "script": "0x483045022100fa00a6651015ac807b03d8d54559831db40d80329f46a886b93ca6b3996daf9b02201d0fafccc88c4654a9c3d205ef0828e32376ecb42f79587615203f23fc8f2d42012102a2cda42f6954605e40cbc5601f65673621c057f8c12f16149fbbf632e8be8ed8",
- "sequence": 4294967295,
- "previous_output": {
- "txid": "21e78cdeb8e642c3617104a9517cb56f01fcf7b98ed096ae9227b9e55498a1c1",
- "vout": 0,
- "data": {
- "value": 4262994,
- "pk_script": "0x76a9140a1f8d3cff7cdcd57e0b9a6f18021e22cf6db4c388ac",
- "cached": false
- },
- "block_height": 542093,
- "block_time": 1537364214,
- "is_coinbase": false
- },
- "witness": []
- },
- {
- "script": "0x4730440220167b4777a23db304f50ac75febfae5db0b1578c90d85769bc76e0f5458484319022023f763e95ea7771c15ea0df91c17519014b2223cd726a3b0a8b1a6f67f99b2bf012103b9492a823f03b70a1750e0fac44f58f5c81e09f4c18d0b28755b44c911ffab5f",
- "sequence": 4294967295,
- "previous_output": {
- "txid": "5fc2e2941b3da3c969f53df56c42dfe98d1640a7d4e5d5168ff724734aff16da",
- "vout": 0,
- "data": {
- "value": 4228088,
- "pk_script": "0x76a914ebc43e4d992d3f9c07d439b6e8fb0bd6dacf056a88ac",
- "cached": false
- },
- "block_height": 540089,
- "block_time": 1536180961,
- "is_coinbase": false
- },
- "witness": []
- },
- {
- "script": "0x483045022100be0b8dc174f4136e3fb4f3ccf1a2be67a44d2086179c5726c61a1af010d5232f02205c0fb4cdd7c9cb8698ceed05e688e10a0cbdd0ee5db1a0a2ef92f322e1a60e9f0121020b9f404317cc6ab5a699f607a9bb0acd0bf5588777672f8f7f4c1a13304e9f76",
- "sequence": 4294967295,
- "previous_output": {
- "txid": "701be2ca7a438771484515919c38d45a10d65968bb5be02b9d854ba32e3f53f1",
- "vout": 0,
- "data": {
- "value": 4371107,
- "pk_script": "0x76a914a7ec934b55c0b849f185f3efd786e227a7f6fc2188ac",
- "cached": false
- },
- "block_height": 538892,
- "block_time": 1535461055,
- "is_coinbase": false
- },
- "witness": []
- },
- {
- "script": "0x483045022100ef3c61b5ba155b94fd02a96bf788e9a9be2de0ee53e3fe1fa6c24dd9d9aaee12022044c07be54a9c59fed96dfb778da0079f6753ab634d1920bf0fac25ebf7ac49d0012103f93e29be8b393773228f704151964662a91df4c1a3e15364e4cfb38a8cacbda9",
- "sequence": 4294967295,
- "previous_output": {
- "txid": "72951146c456f5857a0f5a798a8e197dda6b6d9da7c24cfa1c5baa3718199513",
- "vout": 0,
- "data": {
- "value": 4111308,
- "pk_script": "0x76a914a970862cc2755b0b682dddb587148f9a3786a2f888ac",
- "cached": false
- },
- "block_height": 539663,
- "block_time": 1535905599,
- "is_coinbase": false
- },
- "witness": []
- },
- {
- "script": "0x4730440220421aef290bbd39a18d1281ecfbb420b43daf2cc1c315b6bb44c895f88cb3cfcc022007a512c65b7768b1505f789b6d78479063d04ffb243072f2061eeb66fb1ade81012102712eea19c72fd644b2698c5480ebe77ce6face0bed64238a34a32085567f2f8e",
- "sequence": 4294967295,
- "previous_output": {
- "txid": "7cfdf540f7d74367f36b908fdc409fc26fe434d78c19d05f84bb5f4d680f1255",
- "vout": 0,
- "data": {
- "value": 4410420,
- "pk_script": "0x76a9141bbf3fbab89d6dc4f54a296cc5e43c03fdd5030a88ac",
- "cached": false
- },
- "block_height": 539312,
- "block_time": 1535707474,
- "is_coinbase": false
- },
- "witness": []
- },
- {
- "script": "0x483045022100a29aea775d2c46028f40dceb1707b23e720bb314cef455854313569200c83162022009d0cdcef2e1f0a9217794991fa838fe6ce2bdc6e3c04ad490343c7e4a0ee7d3012102ed59ec6d98f9c2a4dd1324d46d74c56ff7e15935925f69799e547969a523ea98",
- "sequence": 4294967295,
- "previous_output": {
- "txid": "a62b4710ba33b2aaebe2d6ca6cb1019d9d0f26a506fa9c4e465631ce193d55f3",
- "vout": 0,
- "data": {
- "value": 4676554,
- "pk_script": "0x76a914465215552ce0ef787217718e4e73f9b44c6dd2c888ac",
- "cached": false
- },
- "block_height": 541513,
- "block_time": 1537012975,
- "is_coinbase": false
- },
- "witness": []
- },
- {
- "script": "0x483045022100fad9f10989ab4ab019da4f6e430f9fe9ebe76941a9200d7346447358e93b1dce0220756c864b029a64ed9d6eedc13cf8b7d602572fcd7a3d3cb528350bb032d7e3ec012102e3e0c78d034627b1616cf196aa69bfaf20009ba9ebf09cf069453cc0423239e2",
- "sequence": 4294967295,
- "previous_output": {
- "txid": "b63dfef28758e3a02bce39512538a66cbefe83e9cb12fb9b66830d5fd9b60a53",
- "vout": 0,
- "data": {
- "value": 4570694,
- "pk_script": "0x76a914a3666f0e4a31d9be5ee063ea5df05424cb49d73d88ac",
- "cached": false
- },
- "block_height": 538129,
- "block_time": 1535042216,
- "is_coinbase": false
- },
- "witness": []
- },
- {
- "script": "0x48304502210095f37fb2700c9f96d5e5c02d4b043a7cd804f79dd071d8b221b7ae781f0f5b4e02200ae3135b8bebf813449956ae19e7c02db5eff2472da023afa8b8d4e9baba0cdd01210226cc53dfc0a41cc0cf7117dfd406db2b87161e89e2bab9908a2382173fc6dbe1",
- "sequence": 4294967295,
- "previous_output": {
- "txid": "d8e47e4abae931f98f529e0240c09bf7bcfaadac3c7099df65d9414982708e4b",
- "vout": 0,
- "data": {
- "value": 4320873,
- "pk_script": "0x76a914268b4fd271aff252177751747505e5c504f43cc788ac",
- "cached": false
- },
- "block_height": 539037,
- "block_time": 1535546708,
- "is_coinbase": false
- },
- "witness": []
- },
- {
- "script": "0x473044022032361f724fe006079cf37b3df61cb6c51cb0c5fd77f29b61a318134ca4948d0e02202fbe6d484a78730899230244f3662fd5578b87e9eaaccdf9bf8f05d23917de8301210254e84223b3d7f7cfd14315be8fa0c7d7eb1a1a34a672f08e2b8ec134472a66d4",
- "sequence": 4294967295,
- "previous_output": {
- "txid": "dfab9fae87944c4947c69b3be2d953ee832bed82487e7f212b7281989e126252",
- "vout": 0,
- "data": {
- "value": 4068982,
- "pk_script": "0x76a91473c603a415a4e845f5f71724e9642388a27a3e4488ac",
- "cached": false
- },
- "block_height": 538932,
- "block_time": 1535482136,
- "is_coinbase": false
- },
- "witness": []
- },
- {
- "script": "0x483045022100b78b9c24f5f3e950aba637b827d5b11615c17ae2f43105941d172cc4a8b73c80022064998c17becd06abbcfde47c91b9d87da5ac67873ed9a412010b08b954e0b5cd01210329a0acc2b0d60dd243eef46073a672ed0caf467c92f63ef7293f2036a3851a1e",
- "sequence": 4294967295,
- "previous_output": {
- "txid": "f4b9d1b9075f753ccaa73eb1584498c949081305b7b75dbe2e288832e0407006",
- "vout": 0,
- "data": {
- "value": 4768471,
- "pk_script": "0x76a914daf4983be7452bb38d0d75fcc44115dce5bc990a88ac",
- "cached": false
- },
- "block_height": 540164,
- "block_time": 1536220801,
- "is_coinbase": false
- },
- "witness": []
- }
- ],
- "outputs": [
- {
- "value": 32514,
- "pk_script": "0x76a914c6a396ae979670eeaa6929df3dd1c2d8fba31c3d88ac",
- "cached": false
- },
- {
- "value": 43753861,
- "pk_script": "0xa914409dbd0e9a1ab27853186367130e6aab2509e47f87",
- "cached": false
- }
- ],
- "lock_time": 0
- }
- ]
- }
- }
- ],
- "expected": {
- "block_height": 542213,
- "total_work": "1005347579073620115088156986",
- "best_block_hash": "000000000000000000143a2c56c0214236dadfd30df41d4a0345492ad6d861ec",
- "current_target": "3840827764407250199942201944063224491938810378873470976",
- "epoch_start_time": 1536290079,
- "prev_timestamps": [
- 1537425316,
- 1537425370,
- 1537425379,
- 1537425770,
- 1537425986,
- 1537427160,
- 1537428220,
- 1537428564,
- 1537429315,
- 1537429661,
- 1537429727
- ]
- }
-}
\ No newline at end of file
diff --git a/tests/data/full_553723.json b/tests/data/full_553723.json
deleted file mode 100644
index 26aa73a8..00000000
--- a/tests/data/full_553723.json
+++ /dev/null
@@ -1,214 +0,0 @@
-{
- "chain_state": {
- "block_height": 553723,
- "total_work": "1349054508381181651674186396",
- "best_block_hash": "0000000000000000000567a96e76bb24f8e954d24a981af937fb566f9624d70e",
- "current_target": "4774638159061819979596346127394133648234752261950013440",
- "epoch_start_time": 1543838368,
- "prev_timestamps": [
- 1544748510,
- 1544748579,
- 1544748881,
- 1544749065,
- 1544749190,
- 1544749434,
- 1544750432,
- 1544750860,
- 1544750935,
- 1544751014,
- 1544751144
- ]
- },
- "blocks": [
- {
- "header": {
- "version": 536870912,
- "time": 1544751216,
- "bits": 389142908,
- "nonce": 430846328
- },
- "data": {
- "variant_id": 1,
- "transactions": [
- {
- "version": 1,
- "is_segwit": true,
- "inputs": [
- {
- "script": "0x03fc72081b4d696e656420627920416e74506f6f6c31384e00a103205c130870fabe6d6d0782f935d81e4948c75d613779fe7c53eab4c35616d073755df5fe49f3cdb16d0400000000000000cc050000d38d0200",
- "sequence": 4294967295,
- "previous_output": {
- "txid": "0000000000000000000000000000000000000000000000000000000000000000",
- "vout": 4294967295,
- "data": {
- "value": 0,
- "pk_script": "0x",
- "cached": false
- },
- "block_height": 0,
- "block_time": 0,
- "is_coinbase": false
- },
- "witness": [
- "0x0000000000000000000000000000000000000000000000000000000000000000"
- ]
- }
- ],
- "outputs": [
- {
- "value": 1250005141,
- "pk_script": "0x76a914edf10a7fac6b32e24daa5305c723f3de58db1bc888ac",
- "cached": false
- },
- {
- "value": 0,
- "pk_script": "0x6a24aa21a9ed6502e8637ba29cd8a820021915339c7341223d571e5e8d66edd83786d387e715",
- "cached": false
- },
- {
- "value": 0,
- "pk_script": "0x52534b424c4f434b3abcb062d40bf073e3eac877f2b1bad4eddc4f8d882ab014a8d2278563f832e95b",
- "cached": false
- }
- ],
- "lock_time": 0
- },
- {
- "version": 1,
- "is_segwit": true,
- "inputs": [
- {
- "script": "0x16001473e8ab17ce626fc190105f583f0073c76a6b37d9",
- "sequence": 4294967295,
- "previous_output": {
- "txid": "bca6b51a545e7ba7c8c65c93a496b38c52d2dd17318e1ee515928514cd52e9d5",
- "vout": 0,
- "data": {
- "value": 7520877,
- "pk_script": "0xa914f351628496269cf29ce89a61a0b549641f38731e87",
- "cached": false
- },
- "block_height": 553723,
- "block_time": 1544751144,
- "is_coinbase": false
- },
- "witness": [
- "0x304402200fd489534abd79ef87d0c2a3e5db3d3e77b91c2c19d76421f7b61ce6cf3789e202206fa79d2e723462694880b37a93e4155a11b4a533c3a2c82f5d917f9cb30b134101",
- "0x034d12143057d8154b0a0044548861a29fb93ec1e1da607c9661c46a1dfef6bf6f"
- ]
- }
- ],
- "outputs": [
- {
- "value": 218247,
- "pk_script": "0x0014d3421512c645bcfa2af9743a18731001f0173904",
- "cached": false
- },
- {
- "value": 7300000,
- "pk_script": "0xa914379056a3f6d10caa54ee8ef27131c348a7ccf31f87",
- "cached": false
- }
- ],
- "lock_time": 0
- },
- {
- "version": 1,
- "is_segwit": true,
- "inputs": [
- {
- "script": "0x",
- "sequence": 4294967295,
- "previous_output": {
- "txid": "34c5844262f47603acc025d9cba6a34bae74120e4bb7b2c874471671a3662589",
- "vout": 0,
- "data": {
- "value": 14467222,
- "pk_script": "0x0014957970e18969de99dd4b9aed13b77811006a0b40",
- "cached": false
- },
- "block_height": 553720,
- "block_time": 1544750860,
- "is_coinbase": false
- },
- "witness": [
- "0x30440220212ed58e54c2fbf219fb6db8c4ea4854e62d56667ff1a74da91cd27fc62e10c4022018923a537ba525f68e64ce0b70a36b4839b55aecd791dab8d85052c69594f1f501",
- "0x034e6622f089ad175ab1aca77487577e350fb00413a7420250d60422a2e0cc40a9"
- ]
- }
- ],
- "outputs": [
- {
- "value": 2427272,
- "pk_script": "0x0014bed752ca565818fee0c7be61713dec3b9b4841e2",
- "cached": false
- },
- {
- "value": 12037687,
- "pk_script": "0xa9144c13003630a952f25cfc24728b69e5b65dc7fc6787",
- "cached": false
- }
- ],
- "lock_time": 0
- },
- {
- "version": 2,
- "is_segwit": false,
- "inputs": [
- {
- "script": "0x483045022100da31f58b0e2ec9da2e8fadaa38e7b1d0084433fc62160e02c7b7016e6e31477f02206a0462df44e82869798337f5523286972c93d66d523f137c0db5a4baa6e6930d0121034b11147333a38bfb9466c60bec7ce3dc608a4fd2315227fae928a7c10556e9a5",
- "sequence": 4294967294,
- "previous_output": {
- "txid": "13cc7b4ba4dc602ecb4c2580bcceb7276ef68d82807790952ef1206651fbec6f",
- "vout": 0,
- "data": {
- "value": 1383599,
- "pk_script": "0x76a9146c5e8d9e82ea507e34746a36471a66f6e2e1329e88ac",
- "cached": false
- },
- "block_height": 549207,
- "block_time": 1541643907,
- "is_coinbase": false
- },
- "witness": []
- }
- ],
- "outputs": [
- {
- "value": 120000,
- "pk_script": "0xa91401f7b90f5653e8c2a45093c3b2168cfa7e46811e87",
- "cached": false
- },
- {
- "value": 1263351,
- "pk_script": "0x76a914b95067af2d4ebef77ddeae544963fa04df66bb0a88ac",
- "cached": false
- }
- ],
- "lock_time": 553722
- }
- ]
- }
- }
- ],
- "expected": {
- "block_height": 553724,
- "total_work": "1349078759871112371043869813",
- "best_block_hash": "0000000000000000002849bd7ea6df81fa2f07652af0600ffa0f2b0bc47d736c",
- "current_target": "4774638159061819979596346127394133648234752261950013440",
- "epoch_start_time": 1543838368,
- "prev_timestamps": [
- 1544748579,
- 1544748881,
- 1544749065,
- 1544749190,
- 1544749434,
- 1544750432,
- 1544750860,
- 1544750935,
- 1544751014,
- 1544751144,
- 1544751216
- ]
- }
-}
\ No newline at end of file
diff --git a/tests/data/light_542212.json b/tests/data/light_542212.json
deleted file mode 100644
index 597da2f8..00000000
--- a/tests/data/light_542212.json
+++ /dev/null
@@ -1,56 +0,0 @@
-{
- "chain_state": {
- "block_height": 542212,
- "total_work": "1005317431382460840667183195",
- "best_block_hash": "000000000000000000085a38ccf9c046c51b96add547c466ccba3612b1eb8089",
- "current_target": "3840827764407250199942201944063224491938810378873470976",
- "epoch_start_time": 1536290079,
- "prev_timestamps": [
- 1537424869,
- 1537425316,
- 1537425370,
- 1537425379,
- 1537425770,
- 1537425986,
- 1537427160,
- 1537428220,
- 1537428564,
- 1537429315,
- 1537429661
- ]
- },
- "blocks": [
- {
- "header": {
- "version": 536870912,
- "time": 1537429727,
- "bits": 388503969,
- "nonce": 31692307
- },
- "data": {
- "variant_id": 0,
- "merkle_root": "64a8b69cb7100430aec35825d54a48f4434f3db52dff8a02709aee3a659b5e13"
- }
- }
- ],
- "expected": {
- "block_height": 542213,
- "total_work": "1005347579073620115088156986",
- "best_block_hash": "000000000000000000143a2c56c0214236dadfd30df41d4a0345492ad6d861ec",
- "current_target": "3840827764407250199942201944063224491938810378873470976",
- "epoch_start_time": 1536290079,
- "prev_timestamps": [
- 1537425316,
- 1537425370,
- 1537425379,
- 1537425770,
- 1537425986,
- 1537427160,
- 1537428220,
- 1537428564,
- 1537429315,
- 1537429661,
- 1537429727
- ]
- }
-}
\ No newline at end of file
diff --git a/tests/data/light_553723.json b/tests/data/light_553723.json
deleted file mode 100644
index 8786a1b6..00000000
--- a/tests/data/light_553723.json
+++ /dev/null
@@ -1,56 +0,0 @@
-{
- "chain_state": {
- "block_height": 553723,
- "total_work": "1349054508381181651674186396",
- "best_block_hash": "0000000000000000000567a96e76bb24f8e954d24a981af937fb566f9624d70e",
- "current_target": "4774638159061819979596346127394133648234752261950013440",
- "epoch_start_time": 1543838368,
- "prev_timestamps": [
- 1544748510,
- 1544748579,
- 1544748881,
- 1544749065,
- 1544749190,
- 1544749434,
- 1544750432,
- 1544750860,
- 1544750935,
- 1544751014,
- 1544751144
- ]
- },
- "blocks": [
- {
- "header": {
- "version": 536870912,
- "time": 1544751216,
- "bits": 389142908,
- "nonce": 430846328
- },
- "data": {
- "variant_id": 0,
- "merkle_root": "0e5b14f4c65043f1776b0f5940d7bd8d414d1e9de4aafb0984dc2273467da307"
- }
- }
- ],
- "expected": {
- "block_height": 553724,
- "total_work": "1349078759871112371043869813",
- "best_block_hash": "0000000000000000002849bd7ea6df81fa2f07652af0600ffa0f2b0bc47d736c",
- "current_target": "4774638159061819979596346127394133648234752261950013440",
- "epoch_start_time": 1543838368,
- "prev_timestamps": [
- 1544748579,
- 1544748881,
- 1544749065,
- 1544749190,
- 1544749434,
- 1544750432,
- 1544750860,
- 1544750935,
- 1544751014,
- 1544751144,
- 1544751216
- ]
- }
-}
\ No newline at end of file