From f1ab731eb302ad7971558d51af02576d88363758 Mon Sep 17 00:00:00 2001 From: eigmax Date: Sat, 7 Nov 2026 03:57:05 +0000 Subject: [PATCH 1/4] docs: add English transaction graph and update node guide --- README.md | 14 + node/README.md | 76 ++++-- transaction-graph.svg | 614 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 687 insertions(+), 17 deletions(-) create mode 100644 transaction-graph.svg diff --git a/README.md b/README.md index 44dd175c..fb446af2 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,20 @@ GOAT Network's BitVM bridge implementation. See [GOAT BitVM Whitepaper](https:// - `localnet/`: clone-and-run mock testnet (five `mock-gc` nodes on regtest + anvil + graph-node) and the on-demand e2e suite, see [localnet/README.md](localnet/README.md); `make localnet-reset`, `make e2e-smoke` +## Transaction graph + +[![BitVM Bitcoin transaction graph with per-input sighash labels](transaction-graph.svg)](transaction-graph.svg) + +Open the [full-size transaction graph](transaction-graph.svg) to inspect the +connectors, competing spends, CSV paths, and per-input signature types. Blue +paths show operator and claim transactions; red paths show challenges and +timeouts. Dots mark connected branches; crossings without dots are not connected. + +The graph includes peg-in funding and refunds, the Take-1 and Take-2 claim +paths, Watchtower and Verifier branches, and PreKickoff slots. See the +[node transaction guide](node/README.md#bitcoin-transaction-graph) for the +connector and signature notation. + ## Transaction graph checks The checks cover critical connector relationships, default network timing, and diff --git a/node/README.md b/node/README.md index 6646a79b..055e8cdc 100644 --- a/node/README.md +++ b/node/README.md @@ -7,6 +7,7 @@ The main node implementation for GOAT Network's BitVM bridge protocol. This modu - [Overview](#overview) - [Architecture](#architecture) - [Actor System](#actor-system) +- [Bitcoin Transaction Graph](#bitcoin-transaction-graph) - [Core Workflows](#core-workflows) - [Peg-in (Bridge-In)](#peg-in-bridge-in) - [Peg-out (Bridge-Out)](#peg-out-bridge-out) @@ -207,6 +208,40 @@ classDiagram --- +## Bitcoin Transaction Graph + +[![BitVM Bitcoin transaction graph with per-input sighash labels](../transaction-graph.svg)](../transaction-graph.svg) + +Open the [full-size SVG](../transaction-graph.svg) to follow individual inputs +and outputs. Blue paths show operator and claim transactions; red paths show +challenges and timeouts. A dot joins branches; a crossing without a dot does not. +The lower strip shows PreKickoff slots and early challenge transactions. + +The main paths are: + +- **Peg-in:** PegIn-Deposit creates Connector Z. PegIn-Confirm spends Z to + create Connector C0; PegIn-Refund is the competing refund path. +- **Unchallenged claim:** Kickoff creates A, B, C and Guardian output G. + Take-1 spends C0, A, B, C and G after A's CSV delay. +- **Watchtower branch:** Challenge spends A, and Watchtower-Challenge-Init + spends B to create E, F and the indexed Watchtower and ACK outputs. + Operator-Commit-Pubin publishes public-input data by spending E. +- **Verifier branch:** Operator-Assert spends C to create D and the indexed + Verifier outputs. Verifier-Assert, also called ChallengeAssert, creates the + prover output for Wrongly-Challenged or Disprove. Pubin-Disprove spends D + directly when the public-input evidence is invalid. +- **Challenged claim:** Take-2 requires C0, D, F and G, and must satisfy both + D's and F's CSV delays. A competing transaction that spends D or F prevents + this claim. + +Each `i0`, `i1`, and subsequent label identifies a transaction input. `ALL`, +`NONE`, and `SINGLE` abbreviate the corresponding `SIGHASH_` types; `ACP` means +`ANYONECANPAY`. `NONE` permits output changes while retaining a valid signature. +A dash marks an input authorized by WOTS data, a preimage, labels or evidence +rather than a transaction signature. Extra fee inputs and their signatures are +omitted from the drawing. The labels describe the illustrated templates, not +every signature type that a spending script might accept. + ## Core Workflows ### Peg-in (Bridge-In) @@ -308,11 +343,13 @@ sequenceDiagram alt No challenge (Happy Path) Operator->>BTC: Broadcast Take1 transaction - BTC->>User: BTC transferred to user address + BTC->>Operator: Take-1 reimburses the Operator end ``` -**Description**: The Happy Path is the simplest route - when no Watchtower challenges the Operator's claim, the Operator completes the withdrawal via Take1 transaction after the Timelock expires. +**Description**: If Connector A remains unchallenged until its CSV delay expires, +Take-1 reimburses the Operator from the bridge funds. The user payment and GOAT +settlement are separate from this Bitcoin claim path. #### Fig-03-4-Pegout-Challenge-Path @@ -322,12 +359,14 @@ sequenceDiagram participant User participant GOAT as GOAT L2 participant Operator + participant Challenger participant Watchtower participant Verifier participant BTC as Bitcoin User->>GOAT: InitWithdraw Operator->>BTC: Kickoff transaction + Challenger->>BTC: Challenge (spends A) rect rgb(255, 240, 240) Note over Operator,Watchtower: Challenge Phase @@ -335,29 +374,32 @@ sequenceDiagram loop For each Watchtower index Watchtower->>BTC: WatchtowerChallengeTx - alt Operator accepts - Operator->>BTC: ACK response - else Operator rejects - Operator->>BTC: NACK response - Verifier->>BTC: DisproveTx - end + Operator->>BTC: OperatorAckTx end - Operator->>BTC: CommitBlockHashTx - Operator->>BTC: AssertInitTx - Operator->>BTC: AssertCommitTx + Operator->>BTC: OperatorCommitPubinTx + Operator->>BTC: OperatorAssertTx end - alt All challenges passed - Operator->>BTC: Take2 transaction - BTC->>User: BTC transferred to user address - else Challenge failed + alt Invalid assertion + Verifier->>BTC: VerifierAssertTx (ChallengeAssert) + Note over Verifier,BTC: Wait for the prover-output CSV delay Verifier->>BTC: DisproveTx - Note over User,BTC: User funds safe, Operator penalized + else Invalid public-input evidence + Verifier->>BTC: PubinDisproveTx (spends D) + else Valid assertion and public inputs + Note over Operator,BTC: Wait for both D and F CSV delays + Operator->>BTC: Take2 transaction + BTC->>Operator: Take-2 reimburses the Operator end ``` -**Description**: The Challenge Path is triggered when Watchtowers detect anomalies. It contains three sub-phases: (1) Watchtower Challenge - watchers submit challenges; (2) BlockHash Commit - Operator commits block hash; (3) Assert Commit - Operator commits assertion proofs. Failure in any phase triggers Disprove. +**Description**: The challenged path publishes Watchtower responses, public-input +data and the Operator's assertion. A Verifier can challenge an invalid assertion +with Verifier-Assert and then Disprove. Invalid public-input evidence can instead +be answered with Pubin-Disprove, which spends D directly. Watchtower and commit +timeouts and Operator-Challenge-NACK are separate competing spends, as shown in +the transaction graph. ### Challenge Process diff --git a/transaction-graph.svg b/transaction-graph.svg new file mode 100644 index 00000000..7cf77800 --- /dev/null +++ b/transaction-graph.svg @@ -0,0 +1,614 @@ +BitVM transaction graph — classic BitVM2 layoutBitcoin transaction graph with input and output columns and per-input authorization types. Blue paths show operator transactions; red paths show challenges and timeouts. Dots mark connected branches; line crossings without dots are not connected. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +BitVM Transaction Graph +BitVM transaction graph — classic BitVM2 layout +Blue: operator / claim paths Red: challenge / timeout paths Gold dashes: protocol signals Dots mark connected branches +Labels beneath inputs show the sighash used by each transaction template, rather than every signature type a script might accept. +PegIn-Deposit +in +out +BTC +PegIn-Deposit, protocol input 0 (BTC): ALL (ECDSA) +i0: ALL (ECDSA) + +Z +PegIn-Confirm +in +out +Z +PegIn-Confirm, protocol input 0 (Z): ALL +i0: ALL + +C0 +PegIn-Refund +in +out +Z +PegIn-Refund, protocol input 0 (Z): ALL +i0: ALL + +User +CSV: connector_z +Kickoff +in +out +K-i +Kickoff, protocol input 0 (K-i): ALL +i0: ALL + +A +B +C +G +Take-1 +in +out +C0 +Take-1, protocol input 0 (C0): ALL +i0: ALL + +A +Take-1, protocol input 1 (A): ALL +i1: ALL + +B +Take-1, protocol input 2 (B): ALL +i2: ALL + +C +Take-1, protocol input 3 (C): ALL +i3: ALL + +G +Take-1, protocol input 4 (G): ALL +i4: ALL + +Operator +A: CSV · unchallenged claim +Challenge +in +out +A +Challenge, protocol input 0 (A): SINGLE|ACP +i0: SINGLE|ACP + +Operator +Watchtower-Challenge-Init +in +out +B +Watchtower-Challenge-Init, protocol input 0 (B): ALL +i0: ALL + +W-j +ACK-j +E +F +Watchtower-Challenge j +in +out +W-j +Watchtower-Challenge j, protocol input 0 (W-j): ALL|ACP +i0: ALL|ACP + +Operator-ACK j +in +out +ACK-j +Operator-ACK j, protocol input 0 (ACK-j): — preimage +i0: — preimage + +Watchtower-Timeout j +in +out +W-j +Watchtower-Timeout j, protocol input 0 (W-j): ALL +i0: ALL + +ACK-j +Watchtower-Timeout j, protocol input 1 (ACK-j): NONE +i1: NONE + +CSV: watchtower_challenge +Operator-Commit-Pubin +in +out +E +Operator-Commit-Pubin, protocol input 0 (E): — WOTS +i0: — WOTS + +NACK j +in +out +ACK-j +NACK j, protocol input 0 (ACK-j): ALL +i0: ALL + +F +NACK j, protocol input 1 (F): ALL +i1: ALL + +CSV: operator_ack +Commit-Timeout +in +out +E +Commit-Timeout, protocol input 0 (E): ALL +i0: ALL + +F +Commit-Timeout, protocol input 1 (F): ALL +i1: ALL + +CSV: operator_commit +Operator-Assert +in +out +C +Operator-Assert, protocol input 0 (C): — WOTS +i0: — WOTS + +D +V-k +Verifier-Assert k +in +out +V-k +Verifier-Assert k, protocol input 0 (V-k): — labels +i0: — labels + +P-k +ChallengeAssert +Wrongly-Challenged k +in +out +P-k +Wrongly-Challenged k, protocol input 0 (P-k): — preimage +i0: — preimage + +Disprove k +in +out +P-k +Disprove k, protocol input 0 (P-k): NONE +i0: NONE + +D +Disprove k, protocol input 1 (D): NONE +i1: NONE + +P-k: CSV · prover_connector +Pubin-Disprove +in +out +D +Pubin-Disprove, protocol input 0 (D): — evidence +i0: — evidence + +Take-2 +in +out +C0 +Take-2, protocol input 0 (C0): ALL +i0: ALL + +D +Take-2, protocol input 1 (D): ALL +i1: ALL + +F +Take-2, protocol input 2 (F): ALL +i2: ALL + +G +Take-2, protocol input 3 (G): ALL +i3: ALL + +Operator +D and F: CSV · challenged claim + +Z + +Refund + +Connector-0 · peg-in funds + +Same C0 + +A · CSV + +B + +C + +G · Guardian + +A + +B + +C + +G · Guardian + +Response + +W-j + +W-j + +ACK-j + +ACK-j + +ACK-j + +E + +E + +F · CSV + +F + +F + +D · CSV + +V-k + +P-k + +P-k · CSV + +D + +D +Sighash / input authorization +i0 / i1 …: template input indices; fee inputs are omitted. +ALL: commits to all outputs and, without ACP, all inputs. +NONE: commits to no outputs; the signature is still valid. +SINGLE|ACP: commits to this input and its same-index output. +ALL|ACP: commits to this input and all outputs. +ACP = ANYONECANPAY; labels omit the SIGHASH_ prefix. +—: no transaction signature; sighash does not apply. +WOTS signs data; scripts validate preimages, labels and evidence. +Watchtower-Timeout: W-j uses ALL; ACK-j uses NONE. +Deposit uses ECDSA ALL; other illustrated ALL signatures use Taproot. +Additional wallet and fee inputs require their own signatures. +Reading the graph +j and k identify Watchtower and Verifier branches; each may repeat. +Spending D or F in a dispute or timeout prevents Take-2. +Fee outputs, P2A outputs, change and GOAT settlement are omitted. +PreKickoff slots and early challenges — G comes from Kickoff above; K-i funds its input +PreKickoff i +in +out +Prev-P +PreKickoff i, protocol input 0 (Prev-P): ALL +i0: ALL + +K-i +P-i +PreKickoff i+1 +in +out +P-i +PreKickoff i+1, protocol input 0 (P-i): ALL +i0: ALL + +Next-FS +Next-P +Skip-Kickoff +in +out +K-i +Skip-Kickoff, protocol input 0 (K-i): ALL +i0: ALL + +Force-Skip-Kickoff +in +out +K-i +Force-Skip-Kickoff, protocol input 0 (K-i): NONE +i0: NONE + +Next-FS +Force-Skip-Kickoff, protocol input 1 (Next-FS): NONE +i1: NONE + +Quick-Challenge +in +out +G +Quick-Challenge, protocol input 0 (G): NONE +i0: NONE + +Next-FS +Quick-Challenge, protocol input 1 (Next-FS): NONE +i1: NONE + +Challenge-Incomplete-Kickoff +in +out +G +Challenge-Incomplete-Kickoff, protocol input 0 (G): NONE +i0: NONE + +Next-P +Challenge-Incomplete-Kickoff, protocol input 1 (Next-P): NONE +i1: NONE + + +K-i · from PreKickoff i + +G · Guardian + From 467a997b878e9083443a96e2e499f8865ec46918 Mon Sep 17 00:00:00 2001 From: eigmax Date: Sat, 7 Nov 2026 03:59:54 +0000 Subject: [PATCH 2/4] docs: simplify the node guide around the transaction SVG --- node/README.md | 937 +++++-------------------------------------------- 1 file changed, 80 insertions(+), 857 deletions(-) diff --git a/node/README.md b/node/README.md index 055e8cdc..21db3d4e 100644 --- a/node/README.md +++ b/node/README.md @@ -1,839 +1,71 @@ # BitVM Node -The main node implementation for GOAT Network's BitVM bridge protocol. This module handles P2P networking, message processing, scheduled tasks, and RPC services for secure cross-chain asset transfers between Bitcoin and GOAT L2. +`bitvm-noded` runs the Bitcoin and GOAT L2 bridge protocol: chain monitoring, +transaction graph setup and signing, P2P communication, and proof coordination. -## Table of Contents +## Contents -- [Overview](#overview) -- [Architecture](#architecture) -- [Actor System](#actor-system) -- [Bitcoin Transaction Graph](#bitcoin-transaction-graph) -- [Core Workflows](#core-workflows) - - [Peg-in (Bridge-In)](#peg-in-bridge-in) - - [Peg-out (Bridge-Out)](#peg-out-bridge-out) - - [Challenge Process](#challenge-process) -- [Graph State Machine](#graph-state-machine) -- [Graph Storage & Synchronization](#graph-storage--synchronization) -- [Message System](#message-system) -- [Scheduled Tasks](#scheduled-tasks) -- [Module Structure](#module-structure) +- [Transaction graph](#bitcoin-transaction-graph) +- [Roles](#roles) +- [Execution and storage](#execution-and-storage) - [Build & Run](#build--run) - [Configuration](#configuration) - [RPC API](#rpc-api) +- [Code map](#code-map) +- [Related documentation](#related-documentation) ---- - -## Overview - -The BitVM Node (`bitvm-noded`) is a multi-role distributed node that participates in the BitVM cross-chain bridge protocol. It enables trustless Bitcoin-to-L2 transfers through a combination of: - -- **Multi-signature Consensus**: Committee-based transaction presigning -- **Optimistic Verification**: Watchtower monitoring with dispute resolution -- **ZK Proofs**: Cryptographic verification of state transitions -- **P2P Graph Distribution**: graph definitions are pulled directly from relayers, committee members or the operator (`GetGraph` request-response) - -### Key Capabilities - -| Capability | Description | -|------------|-------------| -| **P2P Communication** | libp2p-based gossip network (Kademlia DHT + Gossipsub) plus a direct `GetGraph` protocol | -| **Chain Monitoring** | Bitcoin and GOAT L2 event watching | -| **Execution Engine** | One durable inbox, single-writer aggregates (instance, graph), one outbox, leased jobs (`crates/engine`) | -| **Graph Management** | Transaction graph creation, signing, and lifecycle tracking | -| **Challenge Processing** | Watchtower challenges and dispute resolution | -| **Proof Coordination** | ZK proof generation via proof-builder-rpc | - ---- - -## Architecture - -### Fig-01-1-System-Architecture - -```mermaid -flowchart TB - subgraph External["External Systems"] - BTC["Bitcoin Network"] - GOAT["GOAT L2 Chain"] - PB["Proof Builder RPC"] - end - - subgraph Node["bitvm-noded"] - subgraph Input["Input Layer"] - EW["Event Watch Task"] - P2P["P2P Swarm (libp2p)"] - RPC["RPC Service (Axum)"] - end - - subgraph Core["Execution Engine"] - INBOX[("engine_inbox")] - AGG["Aggregates\n(instance, graph)"] - OUTBOX[("engine_outbox")] - JOBS["Jobs\n(CPU pool, network pool)"] - end - - subgraph Tasks["Background Tasks"] - SCAN["Chain Scans\n(instance, graph)"] - NM["Node Maintenance"] - SPV["SPV Maintenance"] - end - - subgraph Storage["Persistence Layer"] - DB[(SQLite Database)] - GD[("graph_raw_data\n(Graph JSON)")] - GM_TBL[("graph\n(Metadata)")] - end - end - - BTC --> EW - GOAT --> EW - BTC --> SCAN - GOAT --> SCAN - EW --> INBOX - P2P --> INBOX - SCAN --> INBOX - RPC --> DB - INBOX --> AGG - AGG --> OUTBOX - AGG --> JOBS - JOBS --> INBOX - OUTBOX --> P2P - AGG --> DB - JOBS --> GD - JOBS --> GM_TBL - JOBS --> PB - NM --> DB - SPV --> DB -``` - -**Description**: Every input (an admitted P2P message, a chain event, a chain scan at a block height, a job result) is recorded once in `engine_inbox` and applied by the single-writer aggregate it belongs to (`instance:` or `graph:`) inside one SQLite transaction together with its effects: outbox rows, jobs and `waiting_for` registrations. The outbox is the only sender; it re-publishes until the aggregate closes the row. Heavy work (circuit setup, graph building, signing, proof verification, chain calls) runs in leased jobs whose results come back as inbox events. See `docs/node-protocol.md` §4–§5 and §10. - -### Fig-01-2-Component-Interaction - -```mermaid -flowchart LR - subgraph Actors["Actor Roles"] - C["Committee"] - O["Operator"] - V["Verifier"] - W["Watchtower"] - R["Relayer\n(Committee + Flag)"] - end - - subgraph Network["P2P Topics"] - TC["/goat/topic/Committee"] - TO["/goat/topic/Operator"] - TV["/goat/topic/Verifier"] - TW["/goat/topic/Watchtower"] - TA["/goat/topic/All"] - end - - C <--> TC - O <--> TO - V <--> TV - W <--> TW - C & O & V & W & R <--> TA - V -.->|"GetGraph (direct)"| R -``` - -**Description**: Each role subscribes to its corresponding gossipsub topic for message exchange. All roles subscribe to the `/All` topic for broadcast messages. Graph definitions are not gossiped on request: a node that lacks one asks a relayer, a committee member or the operator directly over the `GetGraph` request-response protocol and authenticates what it receives. Relayer nodes (Committee members with `ENABLE_RELAYER=true`) post graph data to GOAT and serve as the second pull source. - ---- - -## Actor System - -BitVM employs four primary actor roles plus an optional relayer capability: - -### Fig-02-1-Actor-Roles - -```mermaid -classDiagram - class Actor { - <> - Committee - Operator - Verifier - Watchtower - All - } - - class Committee { - +generate_nonces() - +presign_transactions() - +endorse_graph() - +confirm_pegin() - } - - class Operator { - +create_graph() - +push_data_to_l2() - +broadcast_kickoff() - +send_take1_take2() - } - - class Verifier { - +monitor_timeouts() - +submit_disprove() - } - - class Watchtower { - +monitor_block_headers() - +submit_challenge() - +ack_nack_response() - } - - class Relayer { - +respond_sync_request() - +distribute_graph_data() - +cache_all_graphs() - } - - Actor <|-- Committee - Actor <|-- Operator - Actor <|-- Verifier - Actor <|-- Watchtower - Committee <|-- Relayer : ENABLE_RELAYER=true -``` - -**Description**: The class diagram shows the inheritance relationship between the Actor enumeration and role implementations. Relayer is a special mode of Committee nodes enabled via environment variable. - -### Role Responsibilities - -| Role | Responsibilities | Key Messages | -|------|------------------|--------------| -| **Committee** | Multi-sig committee member, responsible for presigning, graph endorsement and the Peg-In-Confirm signature | `NonceGeneration`, `CommitteePresign`, `EndorseGraph`, `PeginConfirmPartialSig` | -| **Operator** | Bridge operator, creates graphs and executes withdrawal transactions (kickoff, takes are Bitcoin transactions driven by chain scans) | `InitGraph`, `CreateGraph`, `GraphFinalize` | -| **Verifier** | Dispute verifier, builds and solders circuits, monitors timeouts and submits disproofs | `GenCircuits`, `SolderingProofReady`, `VerifierGraphParamsEndorsement` | -| **Watchtower** | Chain monitor, validates block headers and submits challenges | (chain scans only) | -| **Relayer** | Committee member that posts peg-in and graph data to GOAT and serves `GetGraph` pulls | `GetGraph` (direct protocol) | - ---- - -## Bitcoin Transaction Graph +## Bitcoin transaction graph [![BitVM Bitcoin transaction graph with per-input sighash labels](../transaction-graph.svg)](../transaction-graph.svg) -Open the [full-size SVG](../transaction-graph.svg) to follow individual inputs -and outputs. Blue paths show operator and claim transactions; red paths show -challenges and timeouts. A dot joins branches; a crossing without a dot does not. -The lower strip shows PreKickoff slots and early challenge transactions. - -The main paths are: - -- **Peg-in:** PegIn-Deposit creates Connector Z. PegIn-Confirm spends Z to - create Connector C0; PegIn-Refund is the competing refund path. -- **Unchallenged claim:** Kickoff creates A, B, C and Guardian output G. - Take-1 spends C0, A, B, C and G after A's CSV delay. -- **Watchtower branch:** Challenge spends A, and Watchtower-Challenge-Init - spends B to create E, F and the indexed Watchtower and ACK outputs. - Operator-Commit-Pubin publishes public-input data by spending E. -- **Verifier branch:** Operator-Assert spends C to create D and the indexed - Verifier outputs. Verifier-Assert, also called ChallengeAssert, creates the - prover output for Wrongly-Challenged or Disprove. Pubin-Disprove spends D - directly when the public-input evidence is invalid. -- **Challenged claim:** Take-2 requires C0, D, F and G, and must satisfy both - D's and F's CSV delays. A competing transaction that spends D or F prevents - this claim. - -Each `i0`, `i1`, and subsequent label identifies a transaction input. `ALL`, -`NONE`, and `SINGLE` abbreviate the corresponding `SIGHASH_` types; `ACP` means -`ANYONECANPAY`. `NONE` permits output changes while retaining a valid signature. -A dash marks an input authorized by WOTS data, a preimage, labels or evidence -rather than a transaction signature. Extra fee inputs and their signatures are -omitted from the drawing. The labels describe the illustrated templates, not -every signature type that a spending script might accept. - -## Core Workflows - -### Peg-in (Bridge-In) - -Users deposit BTC into the bridge contract and receive equivalent assets on GOAT L2. - -#### Fig-03-1-Pegin-Sequence - -```mermaid -sequenceDiagram - autonumber - participant User - participant GOAT as GOAT L2 - participant EW as Event Watch - participant Committee - participant Operator - participant BTC as Bitcoin - participant DB as SQLite DB - - User->>GOAT: Initiate BridgeInRequest - GOAT-->>EW: Trigger BridgeInRequest event - EW->>DB: Store instance, pegin_request event - - Committee->>Committee: Validate fees and availability - Committee->>GOAT: answerPeginRequest - User->>BTC: Broadcast Peg-In-Prepare - BTC-->>Operator: Prepare confirmed (confirm_instance job) - - Operator->>Operator: Create SimplifiedbitvmGraph - Operator->>DB: Store graph_raw_data (JSON) - Operator->>Committee: CreateGraph (with graph data) - - loop Multi-sig rounds - Committee->>Committee: NonceGeneration - Committee->>Committee: CommitteePresign - end - - Committee->>Operator: EndorseGraph (graph endorsement) - Operator->>GOAT: PostGraphData - Operator->>BTC: Broadcast PreKickoff transaction - BTC-->>EW: PreKickoff confirmed - - Note over User,DB: Peg-in complete, user receives assets on L2 -``` - -**Description**: The Peg-in flow consists of three phases: (1) Request Phase - user initiates request on L2, committee validates; (2) Graph Construction Phase - Operator creates transaction graph (stored locally in SQLite), committee performs MuSig2 multi-signing; (3) Confirmation Phase - data posted to L2, PreKickoff transaction confirms to complete the process. - -#### Fig-03-2-Instance-BridgeIn-Status - -```mermaid -stateDiagram-v2 - [*] --> UserIniting: User initiates request - UserIniting --> UserInited: Event detected - UserInited --> CommitteesAnswered: Enough committee responses - UserInited --> NoEnoughCommitteesAnswered: Window timeout - UserInited --> UserDiscarded: UTXO spent - - CommitteesAnswered --> UserBroadcastPeginPrepare: Peg-In-Prepare confirmed - UserBroadcastPeginPrepare --> Presigned: Enough graphs finalized - UserBroadcastPeginPrepare --> UserDiscarded: Prepare reorged, UTXO spent - - Presigned --> RelayerL1Broadcasted: Peg-In-Confirm confirmed - UserBroadcastPeginPrepare --> RelayerL1Broadcasted: Peg-In-Confirm confirmed - RelayerL1Broadcasted --> RelayerL2Minted: L2 minting success - - UserBroadcastPeginPrepare --> UserCanceled: Peg-In-Cancel confirmed - Presigned --> UserCanceled: Peg-In-Cancel confirmed - UserBroadcastPeginPrepare --> Timeout: Abandon height, Confirm not visible - Presigned --> Timeout: Abandon height, Confirm not visible - Timeout --> UserCanceled: Peg-In-Cancel confirmed - - RelayerL2Minted --> [*] - UserCanceled --> [*] - UserDiscarded --> [*] - NoEnoughCommitteesAnswered --> [*] -``` - -**Description**: This state diagram shows the complete lifecycle of a bridge-in instance, from initial request through committee validation, signing, and final minting on L2. Every deadline is a Bitcoin height: from `Prepare height + connector_z` (T0) no node signs for the instance and the user may cancel; `PEGIN_ABANDON_BUFFER_BLOCKS` later the instance is abandoned (`Timeout`) unless the Peg-In-Confirm is confirmed or visible in the mempool. `Timeout` is a failure terminal that keeps the committee key for manual handling; the other failure states delete it (see `docs/node-protocol.md` §10.2). - -### Peg-out (Bridge-Out) - -Users initiate withdrawal on GOAT L2 and receive BTC on Bitcoin. Two paths exist: - -#### Fig-03-3-Pegout-Happy-Path - -```mermaid -sequenceDiagram - autonumber - participant User - participant GOAT as GOAT L2 - participant Operator - participant BTC as Bitcoin - - User->>GOAT: InitWithdraw (withdrawal request) - GOAT-->>Operator: Withdrawal event detected - - Operator->>BTC: Broadcast Kickoff transaction - Note over Operator,BTC: Wait for Timelock expiry - - alt No challenge (Happy Path) - Operator->>BTC: Broadcast Take1 transaction - BTC->>Operator: Take-1 reimburses the Operator - end -``` - -**Description**: If Connector A remains unchallenged until its CSV delay expires, -Take-1 reimburses the Operator from the bridge funds. The user payment and GOAT -settlement are separate from this Bitcoin claim path. - -#### Fig-03-4-Pegout-Challenge-Path - -```mermaid -sequenceDiagram - autonumber - participant User - participant GOAT as GOAT L2 - participant Operator - participant Challenger - participant Watchtower - participant Verifier - participant BTC as Bitcoin - - User->>GOAT: InitWithdraw - Operator->>BTC: Kickoff transaction - Challenger->>BTC: Challenge (spends A) - - rect rgb(255, 240, 240) - Note over Operator,Watchtower: Challenge Phase - Operator->>BTC: WatchtowerChallengeInitTx - - loop For each Watchtower index - Watchtower->>BTC: WatchtowerChallengeTx - Operator->>BTC: OperatorAckTx - end - - Operator->>BTC: OperatorCommitPubinTx - Operator->>BTC: OperatorAssertTx - end - - alt Invalid assertion - Verifier->>BTC: VerifierAssertTx (ChallengeAssert) - Note over Verifier,BTC: Wait for the prover-output CSV delay - Verifier->>BTC: DisproveTx - else Invalid public-input evidence - Verifier->>BTC: PubinDisproveTx (spends D) - else Valid assertion and public inputs - Note over Operator,BTC: Wait for both D and F CSV delays - Operator->>BTC: Take2 transaction - BTC->>Operator: Take-2 reimburses the Operator - end -``` - -**Description**: The challenged path publishes Watchtower responses, public-input -data and the Operator's assertion. A Verifier can challenge an invalid assertion -with Verifier-Assert and then Disprove. Invalid public-input evidence can instead -be answered with Pubin-Disprove, which spends D directly. Watchtower and commit -timeouts and Operator-Challenge-NACK are separate competing spends, as shown in -the transaction graph. - -### Challenge Process - -#### Fig-03-5-Challenge-Substatus - -```mermaid -flowchart TB - subgraph WTC["Watchtower Challenge Phase"] - WTC1["OperatorInit"] --> WTC2{"Watchtower response?"} - WTC2 -->|"Submit challenge"| WTC3["Challenge"] - WTC2 -->|"Timeout"| WTC4["ChallengeTimeout"] - WTC3 --> WTC5{"Operator response?"} - WTC5 -->|"ACK"| WTC6["OperatorACK"] - WTC5 -->|"NACK"| WTC7["OperatorNACK"] - WTC5 -->|"Timeout"| WTC8["ACKTimeout"] - end - - subgraph CBH["CommitBlockHash Phase"] - CBH1["WatchtowerChallengeProcessed"] - CBH2["OperatorCommit"] - CBH3["OperatorCommitTimeout"] - CBH1 --> CBH2 - CBH1 --> CBH3 - end - - subgraph AC["Assert Commit Phase"] - AC1["OperatorInit"] - AC2["OperatorCommit"] - AC3["OperatorCommitTimeout"] - AC1 --> AC2 - AC1 --> AC3 - end - - WTC6 --> CBH1 - CBH2 --> AC1 - AC2 --> TAKE2["Take2 Success"] - - WTC4 & WTC7 & WTC8 & CBH3 & AC3 --> DISP["Disprove"] -``` - -**Description**: The challenge process tracks three parallel state machines. Any timeout or failure in sub-phases triggers the Disprove path, ensuring system security. - ---- +Open the [full-size SVG](../transaction-graph.svg) for connector wiring, CSV +paths, competing spends, PreKickoff slots, and per-input authorization types. +Blue paths show operator and claim transactions; red paths show challenges and +timeouts. Dots join branches; crossings without dots do not. -## Graph State Machine +- **Peg-in:** PegIn-Deposit funds Z. PegIn-Confirm creates C0; PegIn-Refund is + the competing refund path. +- **Claims:** Take-1 reimburses the Operator after A's CSV delay. Take-2 requires + C0, D, F and G and must satisfy both D's and F's CSV delays. +- **Disputes:** Watchtower and Verifier branches can prevent a claim by spending + its required outputs. Verifier-Assert is also called ChallengeAssert; + Pubin-Disprove spends D directly. -Graph is the core data structure in BitVM, representing a set of presigned Bitcoin transactions. +The SVG's legend explains `ALL`, `NONE`, `SINGLE`, `ACP`, and inputs authorized +without a transaction signature. Fee inputs and GOAT settlement are omitted. -### Fig-04-1-Graph-Lifecycle +## Roles -```mermaid -stateDiagram-v2 - [*] --> OperatorPresigned: Operator creates graph +| Role | Responsibility | +|------|----------------| +| Committee | Presign transactions and endorse peg-ins and graphs | +| Operator | Build graphs, publish assertions, and execute Bitcoin claims | +| Verifier | Prepare circuits, verify assertions, and submit disproofs | +| Watchtower | Monitor Bitcoin and submit Watchtower challenges | +| Relayer | Committee mode that posts data to GOAT and serves graph requests | - OperatorPresigned --> CommitteePresigned: Collected enough committee signatures - OperatorPresigned --> Obsoleted: PreKickoff on-chain but data not posted +Set `ACTOR` to the node's role. Committee nodes enable relaying with +`ENABLE_RELAYER=true`. - CommitteePresigned --> OperatorDataPushed: Operator pushes L2 data - CommitteePresigned --> Obsoleted: PreKickoff on-chain but data not posted +## Execution and storage - OperatorDataPushed --> PreKickoff: PreKickoff tx confirmed - OperatorDataPushed --> Obsoleted: Pegin not withdrawable and no withdrawal request +Chain observations, admitted P2P messages, and job results enter a durable inbox. +Instance and Graph aggregates apply events in SQLite transactions and produce +outbox messages or leased jobs. Heavy setup, signing, proof work, and network +calls run in jobs; their results return through the inbox. - PreKickoff --> OperatorKickOff: Kickoff tx broadcast - PreKickoff --> Skipped: Guardian intervention or force skip +The Instance aggregate handles peg-in validation and signing. The Graph aggregate +handles graph setup, presigning, Bitcoin claims, and disputes. Chain scans supply +the facts used to advance their state. - Obsoleted --> OperatorKickOff: Kickoff tx observed on-chain after all - Obsoleted --> Skipped: Guardian intervention or force skip - - OperatorKickOff --> OperatorTake1: Timelock expired without challenge - OperatorKickOff --> Challenge: WatchtowerChallengeInit confirmed - OperatorKickOff --> Disprove: Guardian disprove detected before any Challenge opened - - Challenge --> OperatorTake2: Take2 tx confirmed and no disprove detected - Challenge --> Disprove: Guardian disprove, watchtower-flow disprove, verifier disprove, or unrecognized connector-D spend - - OperatorTake1 --> [*]: Happy Path complete - OperatorTake2 --> [*]: Challenge Path complete - Skipped --> [*]: Graph skipped - Disprove --> [*]: Dispute resolved -``` - -**Description**: Graph goes through 9 main states. The normal flow starts from `OperatorPresigned`, proceeds through signature collection, data publishing, and Kickoff, finally completing via Take1 (Happy Path) or Take2 (Challenge Path). `Skipped` and `Disprove` are terminal. - -**`Obsoleted` is not terminal.** It is a provisional status: the local node marks a graph `Obsoleted` when it observes the PreKickoff tx on-chain before graph data was posted (or the pegin becomes non-withdrawable), but if it later observes the actual kickoff tx confirm, the graph resumes into `OperatorKickOff` exactly as if it had come from `PreKickoff` — see `scan_graph_chain_state`, `node/src/utils.rs:1418-1434`, which checks `matches!(current_status, GraphStatus::PreKickoff | GraphStatus::Obsoleted)` for both the kickoff and force-skip cases. - -`OperatorKickOff --> Disprove` is a direct edge, distinct from the `Challenge --> Disprove` edge below: a guardian can detect and prove operator misbehavior (`detect_guardian_disprove`, `node/src/utils.rs:1237-1262`) before a watchtower ever opens a `Challenge` at all (`node/src/utils.rs:1448-1461`). - -### Fig-04-2-Graph-Status-Transitions - -| Source State | Target State | Trigger Condition | -|--------------|--------------|-------------------| -| `OperatorPresigned` | `CommitteePresigned` | Received enough committee presignatures | -| `OperatorPresigned` | `Obsoleted` | PreKickoff on-chain but graph data not posted | -| `CommitteePresigned` | `OperatorDataPushed` | Operator successfully pushed data to L2 | -| `OperatorDataPushed` | `PreKickoff` | PreKickoff tx confirmed on Bitcoin | -| `OperatorDataPushed` | `Obsoleted` | Pegin not withdrawable and no withdrawal request | -| `PreKickoff` | `OperatorKickOff` | Kickoff tx broadcast successfully | -| `PreKickoff` | `Skipped` | Guardian intervention or force skip | -| `Obsoleted` | `OperatorKickOff` | Kickoff tx broadcast successfully (Obsoleted is provisional, not terminal) | -| `Obsoleted` | `Skipped` | Guardian intervention or force skip | -| `OperatorKickOff` | `OperatorTake1` | Connector-A spent by the take1 tx | -| `OperatorKickOff` | `Challenge` | Connector-A spent by anything other than the take1 tx | -| `OperatorKickOff` | `Disprove` | Guardian disprove detected (bypasses `Challenge`) | -| `Challenge` | `OperatorTake2` | Take2 tx observed on-chain and no disprove detector fired | -| `Challenge` | `Disprove` | Any of: guardian disprove, watchtower-flow disprove (operator-challenge-nack or operator-commit-timeout tx), a verifier's assert answered by its matching disprove tx, or an unrecognized connector-D spend | - -Source: `scan_graph_chain_state`, `node/src/utils.rs:1328-1681` (the sole writer of these edges; verified by full read, 2026-07-17). - -### Fig-04-3-Challenge-SubStatus - -`ChallengeSubStatus` is **not** three parallel single-value status enums as earlier revisions of this document claimed — that shape does not exist in the code. The actual struct (`node/src/aggregates/graph_scan.rs`) is: - -```rust -pub struct ChallengeSubStatus { - pub watchtower_challenge_status: Vec, // per-watchtower: true once that watchtower's challenge connector is spent - pub verifier_challenge_status: Vec, // per-verifier progress - pub disprove_type: Option, - pub disprove_index: i32, -} - -pub enum VerifierChallengeStatus { None, VerifierAsserted, ProverAnswered, Disproved } - -pub enum DisproveTxType { Disprove, QuickChallenge, ChallengeIncompleteKickoff, PubinDisprove, OperatorChallengeNack, OperatorCommitTimeout } -``` - -`watchtower_challenge_status` and `verifier_challenge_status` are **observational bookkeeping only** — they are recorded for the frontend/API (`node/src/rpc_service/bitvm.rs:672-693`, collapsed there into a simpler `SimpleChallengeSubStatus{None, WatchtowerChallenge, Assert}` view) but are never read by anything that decides `GraphStatus`. The real `Challenge --> OperatorTake2` gate is purely `tx_on_chain(take2_txid)` after none of the four disprove detectors fired (`node/src/utils.rs:1661-1670`); the operator's actual authorization to broadcast take2 is enforced by Bitcoin-script timelocks (the `take2` job re-checks them), not by any application-level quorum over watchtower or verifier counts. - -### Concurrent graph status updates - -Bitcoin chain scans and GoatChain event handling can update `GraphStatus` -independently. Their updates pass through the transition guard rather than -depending on the order in which these tasks run. - -Status transitions use `StorageProcessor::transition_graph_status` -(`crates/store/src/localdb/graph.rs`). The allowed source statuses are part of -the conditional SQL update, so concurrent writers do not use a separate -read-then-write guard. - -The [transaction graph checks](../README.md#transaction-graph-checks) cover -connector wiring, CSV maturity relations and core dispute safety. They do not -model these database transitions or establish database safety or liveness. - ---- - -## Graph Storage & Synchronization - -Graph data is stored locally in SQLite. A node that lacks a definition pulls it over the direct `GetGraph` protocol; nothing is re-gossiped. - -### Fig-05-1-Graph-Storage-Architecture - -```mermaid -flowchart TB - subgraph Storage["SQLite Database"] - GT[("graph table\n(Metadata, TxIDs, Status)")] - GRD[("graph_raw_data table\n(Serialized JSON)")] - end - - subgraph Operations["Graph Operations"] - CREATE["store_graph()"] - READ["get_graph()"] - PARSE["parse_graph_raw_data()"] - SERIALIZE["serialize_graph_raw_data()"] - end - - subgraph Pull["Direct Pull"] - REQ["GetGraphRequest\n(graph_id or operator slot)"] - RESP["GetGraphResponse"] - PEERS["Relayer / Committee / Operator"] - end - - CREATE -->|"Atomic Transaction"| GT - CREATE -->|"JSON Serialization"| GRD - READ --> GT - READ --> GRD - PARSE -->|"spawn_blocking"| GRD - SERIALIZE -->|"spawn_blocking"| GRD - - REQ -->|"request-response"| PEERS - PEERS -->|"Lookup Local DB"| GRD - PEERS -->|"Answer"| RESP -``` - -**Description**: Graph storage uses a two-table approach: `graph` for metadata/transaction IDs and `graph_raw_data` for full serialized graph JSON. Large graph serialization uses `spawn_blocking` to prevent async runtime blocking. The `graph` table is unique per `(operator_pubkey, kickoff_index)`: one definition per operator slot. - -### Fig-05-2-Graph-Pull-Sequence - -```mermaid -sequenceDiagram - autonumber - participant NodeA as Node A (Missing Graph) - participant Peer as Relayer / Committee / Operator - participant DB as Peer DB - - NodeA->>NodeA: Apply parks on the missing definition (waiting_for) - NodeA->>Peer: GetGraphRequest(graph_id | operator slot) over /get-graph/1 - Peer->>Peer: Admission: class budget, per-peer bucket, cooldown, in-flight slots - Peer->>DB: Query graph + graph_raw_data - DB-->>Peer: Serialized graph - Peer-->>NodeA: GetGraphResponse - - NodeA->>NodeA: Authenticate: operator pre-signatures, instance parameters, committee pre-signatures if finalized - NodeA->>NodeA: store_graph() locally, wake the waiting events -``` - -**Description**: The `fetch_graph` job of the Graph aggregate asks relayers and committee members first and the operator last; a definition claimed to be finalized must carry valid committee pre-signatures, and a graph already posted on GOAT is never accepted as an unsigned copy. Serving is rate limited per requester class and per peer (see `docs/node-protocol.md` §2.3). - -### Graph Data Tables - -#### graph table (Metadata) - -| Column | Type | Description | -|--------|------|-------------| -| `graph_id` | UUID | Primary key | -| `instance_id` | UUID | Associated bridge instance | -| `status` | String | Current GraphStatus | -| `sub_status` | String | Challenge sub-status JSON | -| `operator_pubkey` | String | Operator's public key | -| `*_txid` | Txid | Transaction IDs for all graph transactions | -| `created_at`, `updated_at` | i64 | Timestamps | - -#### graph_raw_data table (Full Graph) - -| Column | Type | Description | -|--------|------|-------------| -| `graph_id` | UUID | Primary key (FK to graph) | -| `raw_data` | TEXT | JSON-serialized SimplifiedbitvmGraph | -| `created_at`, `updated_at` | i64 | Timestamps | - ---- - -## Message System - -### Fig-06-1-Message-Structure - -```mermaid -classDiagram - class GOATMessage { - +Actor actor - +GOATMessageContent content - +serialize_message() Vec~u8~ - +deserialize_message() GOATMessage - } - - class GOATMessageContent { - <> - InitGraph - GenCircuits - CutCircuits - SolderingProofReady - CreateGraph - VerifierGraphParamsEndorsement - NonceGeneration - AggNonceConsensus - CommitteePresign - EndorseGraph - GraphFinalize - PeginConfirmNonce - PeginConfirmNonceConsensus - PeginConfirmPartialSig - GraphSetupAck - RequestNodeInfo - ResponseNodeInfo - } - - class Actor { - <> - Committee - Operator - Verifier - Watchtower - All - } - - GOATMessage --> Actor : target - GOATMessage --> GOATMessageContent : payload -``` - -**Description**: The message system uses role-based addressing. Each message specifies a target topic and a content type, broadcast via Gossipsub. Messages are JSON (`GenCircuits` is bincode behind a `GOATBIN1` prefix). Only the 17 kinds above exist on the wire; chain observations are engine events, never messages. An admitted durable message becomes an inbox event of its aggregate (content id `H(author ‖ kind ‖ business id ‖ H(payload))`), so a re-published copy is a no-op; heavy messages are acknowledged with `GraphSetupAck` once their material is durably stored. - -### Message Categories - -#### Graph setup and signing (Graph aggregate) - -| Message | Sender | Receiver | ACK | Description | -|---------|--------|----------|-----|-------------| -| `InitGraph` | Operator | Verifier | no | Recruit verifiers for a new graph | -| `GenCircuits` | Verifier | Operator | yes | Candidate's circuit setup package | -| `CutCircuits` | Operator | Verifier | yes | Which circuits the candidate opens or proves | -| `SolderingProofReady` | Verifier | Operator | yes | Soldering proof descriptor (payload out of band) | -| `CreateGraph` | Operator | Verifier, Committee | yes | The operator-presigned graph definition | -| `VerifierGraphParamsEndorsement` | Verifier | Committee | no | Verifier's endorsement of the graph parameters | -| `NonceGeneration` | Committee | Committee, Operator | no | MuSig2 public nonces | -| `AggNonceConsensus` | Committee | Committee | no | Signature over the agreed nonce set | -| `CommitteePresign` | Committee | Committee, Operator | no | Committee partial signatures | -| `EndorseGraph` | Committee | Operator | no | EVM endorsements of the graph | -| `GraphFinalize` | Operator | All | yes | The finalized graph with every endorsement | - -#### Peg-In-Confirm round (Instance aggregate, committee only) - -| Message | Sender | Receiver | Description | -|---------|--------|----------|-------------| -| `PeginConfirmNonce` | Committee | Committee | Deterministic nonce for the Peg-In-Confirm | -| `PeginConfirmNonceConsensus` | Committee | Committee | Signature over the agreed nonce set | -| `PeginConfirmPartialSig` | Committee | Committee | Partial signature plus the EVM endorsement the relayer posts | - -#### Control messages (not persisted) - -| Message | Sender | Receiver | Description | -|---------|--------|----------|-------------| -| `GraphSetupAck` | Receiver of a heavy message | Sender | Delivery acknowledged (`delivery_id`) | -| `RequestNodeInfo` / `ResponseNodeInfo` | Any | All | Peer discovery and the operator key binding | - -Peg-out has no messages: the Graph aggregate scans both chains every Bitcoin block and turns what it sees (kickoff, challenge, asserts, takes) into jobs for the roles concerned. - ---- - -## Scheduled Tasks - -### Fig-07-1-Task-Overview - -```mermaid -flowchart TB - subgraph EventWatch["Event Watch Task (Continuous)"] - EW1["fetch_and_handle_gateway_events"] - EW2["fetch_and_handle_bridge_out_events"] - EW1 --> EV1["BridgeInRequest record, l2_minted, graph_posted, goat_status events"] - EW2 --> EV2["withdraw_init / withdraw_cancel events"] - end - - subgraph Maint["Maintenance (10s interval)"] - M1["pegin_request_monitor"] - M2["instance_answer_window_scan"] - M3["instance_btc_scan"] - M4["graph_chain_scan"] - M5["graph_setup_abandon_scan (operator)"] - M6["swap_escrow_timeout_monitor"] - end - - subgraph Engine["Execution Engine"] - INBOX["engine_inbox"] - APPLY["Instance / Graph apply"] - JOBS["jobs"] - end - - subgraph Other["Other Tasks"] - NM["Node Maintenance"] - SPV["SPV Header Updates"] - end - - EventWatch --> INBOX - Maint --> INBOX - INBOX --> APPLY --> JOBS -``` - -**Description**: The event watcher indexes GOAT events; the maintenance tick gathers chain facts (it is the only place that queries the chains for the aggregates) and records them as inbox events; the engine applies them and runs the resulting jobs. No task decides a status by itself. - -### Task Responsibilities - -| Task | Interval | Responsibility | -|------|----------|----------------| -| `run_watch_event_task` | Continuous | Index GOAT gateway and swap events; record `l2_minted`, `graph_posted`, `goat_status`, `withdraw_init` / `withdraw_cancel` events | -| `pegin_request_monitor` | 10s | Turn pending `BridgeInRequest` records into instance rows and `pegin_request` events (committee nodes answer from the event); late requests with spent inputs are recorded `UserDiscarded` | -| `instance_answer_window_scan` | 10s | Record the committee answers of each `UserInited` instance once its GOAT response window closed | -| `instance_btc_scan` | 10s | One `btc_snapshot` per live instance and Bitcoin height: Prepare / Confirm / Cancel status and input spends | -| `graph_chain_scan` | 10s | One `chain_scan` per non-closed graph and Bitcoin height: chain stage, unusable facts, peg-out signals | -| `graph_setup_abandon_scan` | 10s (operator) | Give up the operator's unfinished setups once the instance passed its abandon height | -| `swap_escrow_timeout_monitor` | 10s | Mark swap escrows past their refund deadline as timed out | -| `node_available_pbtc_update_monitor` | 10s (operator, relayer) | Refresh the node's available pegBTC | -| `spv_header_hash_update` | Periodic | Update SPV header hashes | -| `babe_setup_state_cleanup_monitor` | 10s (optional) | Remove orphaned BABE setup state files | - -Admission maintenance (registry refresh, drop summaries, node table purge) runs on its own 20-second timer next to the swarm. - ---- - -## Module Structure - -``` -node/src/ -├── main.rs # Entry point, starts the background tasks and the engine -├── lib.rs # Module exports -├── action.rs # Wire message types, admission entry point, publish -├── handle.rs # Control messages (NodeInfo, GraphSetupAck) -├── p2p_admission.rs # Inbound admission: registry, replay window, rate limits, quota -├── p2p_msg_handler.rs # Swarm handler: admission, control worker, GetGraph service -├── engine_bridge.rs # Engine assembly, gossip transport, ACK forwarder -├── aggregates/ # Aggregates on the execution engine -│ ├── instance.rs # Instance apply: deadlines, F, Answer/Presign/Confirm/Post phases -│ ├── instance_jobs.rs # answerPeginRequest, confirm_instance, PeginConfirm round, post -│ ├── instance_scan.rs # Bitcoin / answer-window facts for instances -│ ├── graph.rs # Graph apply: setup, collect, signing, deliver, post -│ ├── graph_jobs.rs # Setup, signing and finalize jobs -│ ├── graph_setup.rs # Setup helpers -│ ├── graph_fetch.rs # GetGraph pull and authentication -│ ├── graph_pegout.rs # Kickoff / Settlement apply, Skip premise -│ ├── graph_pegout_jobs.rs # Peg-out jobs -│ └── graph_scan.rs # Chain scan of every non-closed graph -├── env.rs # Environment configuration -├── utils.rs # Graph state management & storage utilities -├── error.rs # Error types -├── vk.rs # Verification key management -├── metrics_service.rs # Prometheus metrics -├── rpc_service/ # REST API implementation -│ ├── mod.rs # Service orchestration -│ ├── bitvm.rs # BitVM-specific endpoints -│ ├── routes.rs # HTTP route definitions -│ ├── validation.rs # Input validation -│ └── handler/ # Request handlers -├── middleware/ # P2P network layer -│ ├── swarm.rs # BitvmNetworkManager, libp2p configuration -│ ├── behaviour.rs # Kademlia + Gossipsub + GetGraph behaviour -│ ├── get_graph.rs # GetGraph request-response codec -│ ├── publisher.rs # Bounded access to the swarm from other tasks -│ └── connection_gate.rs # Inbound connection limits -└── scheduled_tasks/ # Background tasks - ├── mod.rs # Maintenance tick - ├── event_watch_task.rs # Chain event monitoring - ├── instance_maintenance_tasks.rs # Peg-in request monitor, swap timeouts - ├── node_maintenance_tasks.rs # Node health - └── spv_maintenance_tasks.rs # SPV updates -``` - -The execution engine itself lives in `crates/engine`; its tables (`engine_inbox`, `engine_aggregate`, `engine_outbox`, `engine_job`) in `crates/store`. - ---- +SQLite stores graph metadata in `graph`, serialized definitions in +`graph_raw_data`, and execution state in the engine tables. Missing graph +definitions are fetched directly with `GetGraph` from relayers, committee +members, or the Operator and authenticated before use. Gossip carries setup +messages and acknowledgements. ## Build & Run -### Prerequisites - -- Rust nightly-2025-06-30+ -- ZKM toolchain (optional, for proof generation) - ### Build Commands ```bash @@ -847,25 +79,15 @@ BITCOIN_NETWORK=testnet4 cargo build -r cargo build -r -p bitvm-noded ``` -### Mock build for local testnets (`mock-gc`) +### Local testnets -`cargo build -r -p bitvm-noded --features "rpc-debug-endpoints mock-gc" --bins` replaces the -garbled-circuit, soldering and proof machinery with deterministic mocks and additionally builds -`mock-proof-builder` (a stand-in for the proof builder RPC) and `rpc-sign` (prints the -`x-auth-*` headers of a signed request for shell scripts). Everything on chain stays real: -epk commitments, hash locks, the soldered wire deltas and the peg-out transactions are the -genuine ones, so the challenge → assert → disprove / take lifecycle runs unchanged on regtest; -only the proof verdicts are policy-driven. Never deploy a `mock-gc` build. +```bash +cargo build -r -p bitvm-noded --features "rpc-debug-endpoints mock-gc" --bins +``` -Knobs (read at call time, seconds, fractional allowed): `MOCK_GC_BUILDER_INIT_DELAY_SECS`, -`MOCK_GC_SETUP_DELAY_SECS`, `MOCK_GC_SOLDER_DELAY_SECS`, `MOCK_GC_VERIFY_DELAY_SECS`, -`MOCK_GC_CHALLENGE_DELAY_SECS`, `MOCK_GC_EVAL_DELAY_SECS` (the last two are capped at 60 s), -`MOCK_GC_DELAY_SECS` as the fallback; `MOCK_GC_PROOF_VERDICT=valid|always-invalid` decides -the verifier's verdict on an operator assert. The mock proof builder takes -`MOCK_PROOF_DELAY_SECS` / `MOCK_PROOF_OPERATOR_DELAY_SECS` / `MOCK_PROOF_WATCHTOWER_DELAY_SECS` -("not ready" window), `MOCK_PROOF_RESPONSE_LATENCY_MS`, and serves the operator proof fixture -`node/testdata/test-operator-proof.bin`, so `OPERATOR_VK_HASH` / `OPERATOR_ZKM_VERSION` on the -nodes must equal the values the mock builder reports (its defaults), not the testnet ones. +`mock-gc` replaces proof machinery with deterministic mocks for local testing. +Use it only on local testnets. See the [localnet guide](../localnet/README.md) +for setup and end-to-end scenarios. ### Generate Node Keys @@ -928,8 +150,6 @@ real graph raw data in the database. | `--metrics-path` | Path served by the dedicated metrics listener | `/metrics` | | `--enable-kademlia` | Enable Kademlia DHT | `true` | ---- - ## Configuration ### Environment Variables @@ -972,17 +192,10 @@ To run a Committee node as a graph data relayer: ```bash export ACTOR=Committee export ENABLE_RELAYER=true -export GOAT_PRIVATE_KEY= +export GOAT_PRIVATE_KEY='your-private-key' # ... other required variables ``` -Relayer nodes should: -- Run 24/7 for network reliability -- Have sufficient storage for all graph data -- Be geographically distributed for redundancy - ---- - ## RPC API Prometheus metrics are not served by the business RPC listener. Set @@ -1009,20 +222,30 @@ Prometheus metrics are not served by the business RPC listener. Set | `/v1/debug/status`, `/v1/debug/engine` | GET | Node status and the execution engine snapshot (rows by state, waiting and poisoned aggregates); `rpc-debug-endpoints` feature only | | `/v1/debug/engine/clear-poison`, `/v1/graphs/:id/send-challenge`, `/v1/graphs/:id/send-verifier-challenge` | POST | Release poisoned actions, send a challenge / verifier challenge (signed requests); `rpc-debug-endpoints` feature only | -### Health and observability - -- **Readiness.** `bitvm_node_ready` (and `ready` in `/v1/health`) is the AND of four bits: start-up done, database reachable (pinged by every `/v1/health` call and every metrics scrape), backends reachable (the height probe of every 6th maintenance tick AND none of the Esplora, GOAT and subgraph availability states below is `unavailable`; the proof builder is informational only, it is called too rarely to drive readiness), event watcher healthy. A node that is up but not ready still serves the RPC and the metrics listener. -- **Backend availability.** The Esplora (`btc`), GOAT RPC (`goat`), subgraph (`graph`) and proof-builder (`proof`) backends each carry one availability state: two consecutive failed calls log a single `event=backend_availability outcome=unavailable` WARN and set `bitvm_node_backend_up{backend}=0` plus `bitvm_node_backend_unavailable_since_seconds{backend}`; once no call has failed for 30 s the next success logs one `outcome=recovered` INFO with `downtime_secs` and `failed_calls`. While a backend is unavailable its individual probe failures are logged at debug. Per-call counters stay in `bitvm_node_btc_backend_requests` / `bitvm_node_goat_backend_requests`. -- **Start-up.** The GOAT reads needed to boot (`eth_chainId`, the gateway's relay contracts) are retried every 5 s for a minute (`event=goat_boot_retry`) before the node gives up; a restart during a short GOAT outage therefore waits instead of exiting. The `event=service_started` line prints the backend URLs, the client timeouts and the maintenance interval the process runs with. -- **Peers.** When the last connection to a bootnode closes the node re-dials it after 5 s and then every 20 s (`event=p2p_bootnode_disconnected` / `p2p_bootnode_redial` / `p2p_bootnode_connected`); `bitvm_node_p2p_connected_peers` and `bitvm_node_p2p_required_topics_healthy` show the result. -- **Maintenance scheduling.** BTC graph/instance scans run in a separate serial loop from balance, SPV and L2 maintenance. Each subtask has its own `MAINTENANCE_SUBTASK_TIMEOUT_SECS` budget; timeout records `maintenance_subtask_result outcome=timed_out`, and later subtasks still run. Each loop reports its own result (`bitcoin_maintenance` / `maintenance` metrics and `maintenance_tick_result lane=bitcoin|maintenance` logs). A failed or timed-out subtask makes that loop's result `failed`; normal history catch-up is `deferred`, and an unavailable or timed-out history check is `failed`. Cancelling the maintenance service cancels both loops and their in-flight work. -- **Jobs.** An engine job attempt that fails on an error path logs `event=engine_jobs outcome=attempt_error` (WARN) with the error and the attempt number before the backoff (10, 30, 60, 120, 300, then 600 s); an explicit wait (proof not ready, SPV behind, tx not yet confirmed) logs the reason at INFO. The row's `last_error` keeps the latest reason either way. -- **Tooling.** `scripts/ops/` holds read-only helpers for one node: `triage.sh` (one-screen health from `/v1/health`, `/metrics`, the debug routes and the log), `logq.sh` (JSON log queries) and `trace.sh` (timeline of one instance or graph across RPC, database and log). - ---- - -## Related Documentation - -- [Circuits README](../circuits/README.md) - ZK proof generation -- [Deployment Guide](../deployment/README.md) - Deployment instructions -- [Incentives](../docs/incentives.md) - Incentives +### Operations + +Use `/v1/health` for readiness and backend status, and the dedicated metrics +listener for Prometheus. The [operator tools](../scripts/ops/README.md) provide +health triage, structured log queries, and instance or graph timelines. + +## Code map + +| Location | Purpose | +|----------|---------| +| [aggregates/](src/aggregates/) | Instance and graph state, scans, and jobs | +| [engine_bridge.rs](src/engine_bridge.rs) | Execution engine assembly and transport | +| [messages.rs](src/messages.rs) | Wire message definitions | +| [p2p_admission/](src/p2p_admission/) | Peer admission, replay protection, and limits | +| [middleware/](src/middleware/) | P2P swarm and direct graph requests | +| [scheduled_tasks/](src/scheduled_tasks/) | Chain event monitoring and maintenance | +| [rpc_service/](src/rpc_service/) | HTTP routes and handlers | +| [env.rs](src/env.rs) | Environment configuration | + +## Related documentation + +- [Project README](../README.md) — project layout and transaction graph checks +- [Localnet guide](../localnet/README.md) — local testing +- [Proof Builder RPC](../proof-builder-rpc/README.md) — proof service +- [Circuits README](../circuits/README.md) — proof generation +- [Deployment guide](../deployment/README.md) — deployment +- [Incentives](../docs/incentives.md) — incentives From 5545acd0f4842d63f1096f7ce675fd8ca9370d2a Mon Sep 17 00:00:00 2001 From: eigmax Date: Sat, 7 Nov 2026 04:05:46 +0000 Subject: [PATCH 3/4] docs: refresh deployment and proof guides and correct README examples --- README.md | 2 +- circuits/README.md | 102 ++++++------ deployment/README.md | 301 ++++++++++-------------------------- localnet/README.md | 27 +--- localnet/e2e/README.md | 3 +- node/README.md | 2 +- proof-builder-rpc/README.md | 67 ++++---- 7 files changed, 162 insertions(+), 342 deletions(-) diff --git a/README.md b/README.md index fb446af2..59fb0710 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ core dispute safety for Bitcoin, Testnet4, Signet and Regtest: committed pubin. It models the current Commit-Timeout and verifier gates, including an operator withholding evidence and a possibly offline watchtower. An honest verifier's enabled defences have an explicit bounded response time. -- `tests/tla_shipped_values.rs` checks that the TLA values match Rust. A timing +- `crates/bitvm-gc/tests/tla_shipped_values.rs` checks that the TLA values match Rust. A timing change requires regenerating the values and rerunning the checks. - Every other `audit/tla/.tla` with a `.cfg` is checked as well; its header states what it models and which code it follows. diff --git a/circuits/README.md b/circuits/README.md index 4b6676a3..84bbc0de 100644 --- a/circuits/README.md +++ b/circuits/README.md @@ -2,7 +2,8 @@ ## Overview -Trust Setup: choose a snapshot of GOAT Pre Alpha Mainnet, which consists of (Seqeuncer Set, EVM Block Hash) +The initial trust anchor is a GOAT snapshot containing the sequencer set and EVM block hash. +For Bitcoin transaction wiring and signature types, see the [transaction graph](../transaction-graph.svg). Main components: @@ -29,13 +30,13 @@ Circuits: >> * The latest_sequencer_commit_txid is included in the header chain proof >> * The latest_sequencer_commit_txid is the latest commit txn in the commit chain >> * The state chain's latest block(EVM block) is signed by the sequencer set in the latest block of commit chain ->> * For each watchtower proof, +>> * For each included Watchtower proof, >>> * The watchtower challenge transaction is valid >>> * The proof is valid >>> * The graph is as same as the operator's graph id ->>> * The operator's total work >= Watchtowers' largest total work ->>> * The operator's block height that includes the latest sequencer commit transaction is larger than the watchtower's +>>> * For claims from the same genesis, the operator's total work is at least the Watchtower's +>>> * The operator's commitment inclusion height is at least the watchtower's for a claim from the same genesis >> * Verify that the withdrawal state change in the Gateway contract is correct @@ -65,17 +66,17 @@ under 2.0, so the header, commit and state chain proofs restart from genesis at BABE garbled-circuit verifier treats `vkey_hash` and `vk_root` as static inputs and `committed_values_digest` as the dynamic one. -## Guest workspace +## Build inputs -All guest programs (`*/guest`) form one workspace rooted at `circuits/Cargo.toml`, with a single -`Cargo.lock` and `[patch.crates-io]`. The guest-side shared crates live in `circuits/crates/`, inside -that root, because cargo hashes a path dependency outside the workspace root by its absolute path, -which would make each guest ELF, and so its vk, depend on where the repository is checked out. Keep any -new guest-side path dependency under `circuits/`. The ELF also depends on `ZKM_IMM_WRAP_VK` and -`BITCOIN_NETWORK` at build time. +Build all five guest programs with the same `BITCOIN_NETWORK` and +`ZKM_IMM_WRAP_VK` settings used by the nodes and Proof Builder. Program or proof +system changes require matching verification keys and proof artifacts. ## Preparation +Run the proof examples from `circuits/`. The host binaries load `.env` there; +export the same configuration before running the helper scripts. + ```bash mkdir -p data/header-chain mkdir -p data/commit-chain @@ -89,19 +90,18 @@ if `Network Prover` is used, see [this](https://docs.zkm.io/dev/prover.html#netw Launch the Regtest. ```bash -cd scripts -docker compose up -d +(cd ../scripts && docker compose up -d) ``` ## Bitcoin Header Chain ``` # regtest -# export BITCOIN_NETWOKR=regtest +# export BITCOIN_NETWORK=regtest # testnet -# export BITCOIN_NETWOKR=testnet4 -# export ESPLORA_URL=https://mempool.space/testnet/api +# export BITCOIN_NETWORK=testnet4 +# export ESPLORA_URL=https://mempool.space/testnet4/api bash cron-header-chain-proof.sh $start $batch @@ -114,14 +114,15 @@ bash cron-header-chain-proof.sh $start $batch Example: ```bash -cd node +cd ../node GOAT_BLOCK_NUMBER=9511050 bash -x ssp-ci.sh +cd ../circuits ``` -All the initial publishers are hardcoded. In the `ssp-ci.sh`, we simutate 2-round publisher rotations. +This publication script is a Regtest fixture with hardcoded publishers. In the `ssp-ci.sh`, we simulate 2-round publisher rotations. `GOAT_BLOCK_NUMBER` is the GOAT's current block number, which is used as the key to fetch sequencer set commitment. -Note that we should deploy [SequencerSetPublisher Contract](https://github.com/GOATNetwork/bitvm2-L2-contracts/tree/main/script#deploy) before publishing the sequencer set. +Deploy the SequencerSetPublisher contract before publishing the sequencer set. Then setup the correct contract address in your `.env`. @@ -168,7 +169,7 @@ RUST_LOG=info cargo run --package commit-chain-proof --bin commit-chain-proof -r ## State Chain -State Chain represents the L2's state transition, which checks the EVM's execution, withdrawal transaction inclusion and sequencers' aggrement. +State Chain represents the L2's state transition, which checks the EVM's execution, withdrawal transaction inclusion and sequencers' agreement. We generate `state-chain-proof` periodically, like by 5 GOAT EVM blocks. Optionally, the block may contain a `proceedWithdraw` transaction. @@ -177,7 +178,7 @@ We generate `state-chain-proof` periodically, like by 5 GOAT EVM blocks. Optiona ``` export BATCH_SIZE=10 -export L2_CONTRACT_ADDRESS=0x21f619040AC2eAcacEF8Fe17Ae8bDF53ec69C66f +export L2_CONTRACT_ADDRESSES="$GOAT_GATEWAY_CONTRACT_ADDRESS" export EL_START_BLOCK_NUMBER=10346748 export start=$EL_START_BLOCK_NUMBER @@ -186,7 +187,8 @@ bash cron-state-chain-proof.sh $start $BATCH_SIZE ## Watchtower proof -If a challenge is happened, each watchtower should broadcast a `watchtower-challenge-tx` to submit its longest chain. +When a challenge occurs, each Watchtower can publish a `watchtower-challenge-tx` +containing its proof commitment. * Generate proofs @@ -196,7 +198,6 @@ export GENESIS_SEQUENCER_COMMIT_TXID=$(cat ./data/commit-chain/commit_info.json. export LATEST_SEQUENCER_COMMIT_TXID=$(cat ./data/commit-chain/commit_info.json.0 | jq -r .txid) export HEADER_CHAIN_INPUT_PROOF="data/header-chain/0-116000.bin" export COMMIT_CHAIN_INPUT_PROOF="data/commit-chain/0-1.bin" -export LATEST_STATE_BLOCK_HASH="0x7908184bce067fa5a4508d309cbaf22dd1e0b586ad2dd42c0e51a5308a7bd815" export STATE_CHAIN_INPUT_PROOF="data/state-chain/9511050-10.bin" RUST_LOG=info cargo run --package watchtower-proof --bin watchtower-proof -r -- --output "data/watchtower/output.bin" @@ -216,46 +217,37 @@ RUST_LOG=info cargo run --package watchtower-proof --bin watchtower-proof -r -- ## Operator proof -* Simutate a withdraw challenge +* Simulate a withdraw challenge ```bash -cd crates/bitvm-gc -cargo test -r test_take2 -``` - -Make sure the operator has enough balance, if not, run this command to fund the operator. - -``` -bitcoin-cli -regtest -rpcuser=$... -rpcpassword=$... sendtoaddress bcrt1qhnmlpxyxdntekge4u24m4a7yk6elc3zs4v89e7fqja8vagfnrs8sq28cwd 50 +(cd .. && cargo test -r -p bitvm-gc --test regtest regtest_take2_flow -- --ignored) ``` -Get the withdraw-challenge-init-txid , graph-id, watchtower's challenge transaction id and compressed public key. +Fund the Operator on Regtest and obtain the graph ID, Watchtower-Challenge-Init +transaction ID, and indexed Watchtower transactions and public keys from that run. * Generate proofs -After calling the [`proceedWithdraw`](https://github.com/GOATNetwork/bitvm2-L2-contracts/blob/main/src/Gateway.sol#L588), we generate the operator proof with corresponding `graph_id` and transaction id. +After `proceedWithdraw`, generate the Operator proof for the corresponding graph +and withdrawal block. Use values from the same graph and proof-chain history. -``` +```bash export BITCOIN_NETWORK=regtest -export DIR="/home/ubuntu/data/proof-builder-rpc/circuits" -export GENESIS_SEQUENCER_COMMIT_TXID=$(cat ${DIR}/data/commit-chain/commit_info.json.0 | jq -r .genesis_txid) - -export LATEST_SEQUENCER_COMMIT_TXID=$(cat ${DIR}/data/commit-chain/commit_info.json.11 | jq -r .txid) -export OPERATOR_COMMITTED_BLOCKHASH =$(cat ${DIR}/data/commit-chain/commit_info.json.11 | jq -r .txid) - -export HEADER_CHAIN_INPUT_PROOF="$DIR/data/header-chain/1024-1.bin" -export COMMIT_CHAIN_INPUT_PROOF="$DIR/data/commit-chain/11-1.bin" -export STATE_CHAIN_INPUT_PROOF="$DIR/data/state-chain/10558271-40.bin" - -export GRAPH_ID="3C2917B82FE14EF7B8CC8BEF3ECD700F" -export EXECUTION_LAYER_BLOCK_NUMBER=10558309 - -export INCLUDED_WATCHTOWERS=0 -export WATCHTOWER_PUBLIC_KEYS="02e7a08db9093c279535bd0078582469b82bf9f12c6dcb7588e187d2b9cc724279,02f6dce5d37a801064bdf42759dba98afccc80440c32cdc3a8d85c0ed9ae2e749b" -export WATCHTOWER_CHALLENGE_TXIDS="6247824c7c96c4701ef52163316d938412b15cf15962622b3c63f3cf41193f96,fe96c90162c369f45ae4f08140c6197a15c5f3cfe23f04be60f18802e97f4f91" -export WATCHTOWER_CHALLENGE_INIT_TXID="e7723e03ac97172cf033e40d4b9d9c0e22efa7a41eb855a1576f467684a0f6b3" - -RUST_LOG=info cargo run --package operator-proof --bin operator-proof -r -- --output "data/operator-proof/output.bin" +export HEADER_CHAIN_INPUT_PROOF="data/header-chain/header.bin" +export COMMIT_CHAIN_INPUT_PROOF="data/commit-chain/commit.bin" +export STATE_CHAIN_INPUT_PROOF="data/state-chain/state.bin" + +export GENESIS_SEQUENCER_COMMIT_TXID="${GENESIS_SEQUENCER_COMMIT_TXID:?Set the genesis commitment transaction ID}" +export LATEST_SEQUENCER_COMMIT_TXID="${LATEST_SEQUENCER_COMMIT_TXID:?Set the latest commitment transaction ID}" +export OPERATOR_COMMITTED_BLOCKHASH="${OPERATOR_COMMITTED_BLOCKHASH:?Set the committed Bitcoin block hash}" +export GRAPH_ID="${GRAPH_ID:?Set the graph ID as 32 hexadecimal characters}" +export EXECUTION_LAYER_BLOCK_NUMBER="${EXECUTION_LAYER_BLOCK_NUMBER:?Set the withdrawal block height}" +export INCLUDED_WATCHTOWERS="${INCLUDED_WATCHTOWERS:?Set the Watchtower inclusion bitmask}" +export WATCHTOWER_PUBLIC_KEYS="${WATCHTOWER_PUBLIC_KEYS:?Set the indexed public-key list}" +export WATCHTOWER_CHALLENGE_TXIDS="${WATCHTOWER_CHALLENGE_TXIDS:?Set the indexed transaction-ID list}" +export WATCHTOWER_CHALLENGE_INIT_TXID="${WATCHTOWER_CHALLENGE_INIT_TXID:?Set the challenge-init transaction ID}" + +RUST_LOG=info cargo run --package operator-proof --bin operator-proof -r -- --output "data/operator/output.bin" ``` The operator proof is consumed directly by the Assert flow. BABE setup binds its static public @@ -266,5 +258,5 @@ input, while the dynamic public input is committed after the watchtower challeng * commit-chain-input-proof: the commit chain's proof, input and vk. * included-watchtower: a 256-bit bitmask; each bit flags a valid watchtower inside operator proof. * execution-layer-block-number: the block number that including `proceedWithdraw`(Peg-out) transaction of GOAT Network's execution layer(Geth). -* watchtower-challenge-info: list of watchtower's challenge transaction id and compressed public key, i.e: [wachtower_info.json](./data/watchtower/watchtower_info.json). +* watchtower-challenge-txids and watchtower-public-keys: comma-separated lists in graph slot order. The inclusion bitmask uses the same indices. * watchtower-challenge-init-txid: the watchtower challenge init transaction id in GOAT's BitVM graph. diff --git a/deployment/README.md b/deployment/README.md index 0f78c713..c217c8c4 100644 --- a/deployment/README.md +++ b/deployment/README.md @@ -1,252 +1,109 @@ # Deployment Guide -This document describes how to deploy the different roles in the BitVM system: Committee, Operator, Challenger, Watchtower, and Relayer, by manually compiling and running the [node](../node/README.md). - -## Prerequisites - -Before building and running the node, ensure you have the following installed: - -- **Rust Toolchain**: Latest stable version. -- **ZKM Toolchain**: Required for compiling the circuits. - - Ensure the toolchain is installed in `~/.zkm-toolchain`. - - You need to source the environment before building: `source ~/.zkm-toolchain/env`. +Deploy Committee, Operator, Verifier and Watchtower nodes with `bitvm-noded`. +Relayer is a Committee mode, enabled with `ENABLE_RELAYER=true`. See the +[node guide](../node/README.md) for configuration and RPC details, and the +[transaction graph](../transaction-graph.svg) for Bitcoin claim and dispute paths. +For a local test environment, use the [localnet guide](../localnet/README.md). ## Build -1. **Source the ZKM Toolchain environment:** - - ```bash - source ~/.zkm-toolchain/env - ``` - -2. **Build the project in release mode:** - - ```bash - cargo build -r --all-targets - ``` - - The compiled binary will be located at `target/release/bitvm-noded`. - -## Configuration - -The node loads environment variables from a `.env` file in the current working directory. - -### Common Environment Variables - -Create a `.env` file and include necessary environment variables: - -| Variable | Description | Required | -|----------|-------------|----------| -| `ACTOR` | The role of the node (`Committee`, `Operator`, `Challenger`, `Watchtower`) | Yes | -| `BITCOIN_NETWORK` | Bitcoin network (`bitcoin`, `testnet`, `regtest`) | Yes | -| `GOAT_NETWORK` | Goat network (`main`, `test`) | Yes | -| `GOAT_CHAIN_URL` | RPC URL for the Goat chain | Yes | -| `GOAT_PROOF_BUILD_URL` | URL for the proof builder service | Yes | -| `PROOF_SEVER_URL` | URL for the proof server | Yes | -| `PEER_KEY` | The private key for the P2P node identity (libp2p) | Yes | -| `GOAT_GATEWAY_CONTRACT_ADDRESS` | Address of the Gateway contract on Goat | Yes | -| `GOAT_GATEWAY_EVENT_FILTER_FROM` | The block number to start filtering Gateway events from | Yes | -| `GOAT_GATEWAY_EVENT_THE_GRAPH_URL` | The Graph URL for querying Gateway events | Yes | -| `BITVM_SECRET` | Secret key or seed for BTC interaction | Yes | -| `GOAT_ADDRESS` | The Goat chain address of the operator/node | Yes | -| `PROTO_NAME` | The P2P protocol name (default: `bitvm`) | Yes | -| `GOAT_PRIVATE_KEY` | Private key for the Goat chain interaction | Optional | -| `GOAT_SEQUENCER_SET_PUBLISHER_CONTRACT_ADDRESS` | Address of the Sequencer Set Publisher contract | Optional | -| `GOAT_SEQUENCER_SET_MULTI_SIG_VERIFIER_ADDRESS` | Address of the MultiSig Verifier contract | Optional | -| `GOAT_SWAP_CONTRACT_ADDRESS` | Address of the Swap contract on Goat | Optional | -| `GOAT_SWAP_EVENT_FILTER_FROM` | The block number to start filtering Swap events from | Optional | -| `GOAT_SWAP_EVENT_THE_GRAPH_URL` | The Graph URL for querying Swap events | Optional | -| `BOOTNODES` | Multiaddr of bootnodes for P2P discovery | Optional | -| `NODE_NAME` | The name of the node | Optional | -| `MIN_REQUIRED_VERIFIER` | Positive verifier-slot count for newly created graphs (default: `1`); must be identical on all participating nodes | Optional | - -`MIN_REQUIRED_VERIFIER` changes the transaction topology of newly created graphs. It does not add Verifier slots to existing finalized graphs, which continue to use the slots embedded when they were created. Configure the same value on every Operator, Verifier, Committee, Watchtower, and Relayer node before creating new graphs. - -## Roles Deployment - -Configure the `.env` file for the specific role and run the node. - -**Common Arguments:** - -- `--rpc-addr `: Address for the RPC server (default: `0.0.0.0:8080`) -- `--metrics-addr `: Address for the dedicated Prometheus listener (disabled when omitted) -- `--metrics-path `: Path served by the metrics listener (default: `/metrics`) -- `--db-path `: Path to the SQLite database (default: `sqlite:/tmp/bitvm-node.db`) -- `--p2p-port `: Port for P2P communication (default: `0`) -- `--bootnodes `: Bootnodes to connect to - -Bind metrics to a private interface and use a unique port for every node running -on the same host. The business RPC listener does not serve metrics, so -`GET /metrics` on `--rpc-addr` returns `404`. For remote Prometheus servers, -expose the dedicated listener through a private network, proxy, or access-control -layer instead of binding it directly to a public interface. - -For liveness and readiness probes use `GET /v1/health` on `--rpc-addr`: it only pings the local -database and otherwise answers from memory, `200` while the node is ready and `503` (with the same JSON body naming -the failing component or backend) otherwise. A node whose GOAT RPC is unreachable at start-up retries -for about a minute before exiting, so a supervisor restart during a short outage does not crash-loop. - -The provided Docker Compose deployment enables the listener on port `9108` -inside each container and publishes it only on the host loopback interface: - -| Service | Host metrics endpoint | -|---------|-----------------------| -| `committee_0` | `http://127.0.0.1:9900/metrics` | -| `committee_1` | `http://127.0.0.1:9901/metrics` | -| `verifier_0` | `http://127.0.0.1:9902/metrics` | -| `operator_0` | `http://127.0.0.1:9903/metrics` | -| `watchtower_0` | `http://127.0.0.1:9904/metrics` | - -### Committee - -The Committee is responsible for signing presign transactions. - -**example `.env`:** - -```env -RUST_LOG=info - -# required -ACTOR=Committee -BITCOIN_NETWORK=testnet # bitcoin / testnet / regtest -GOAT_NETWORK=test # main / test -GOAT_CHAIN_URL=https://rpc.testnet3.goat.network -GOAT_PROOF_BUILD_URL=... -PROOF_SEVER_URL=... -PEER_KEY=... -BITVM_SECRET=... # committee can setup a seed string -GOAT_ADDRESS=... -GOAT_GATEWAY_CONTRACT_ADDRESS=0x21f619040AC2eAcacEF8Fe17Ae8bDF53ec69C66f -GOAT_GATEWAY_EVENT_THE_GRAPH_URL=https://api.goat.0xgraph.xyz/api/public/1030419e-065f-45e9-8cf5-69c42207cbc7/subgraphs/bitvm2_gateway_ga_dev_0/0.0.3/gn -GOAT_GATEWAY_EVENT_FILTER_FROM=9689342 -PROTO_NAME=bitvmt3 -BOOTNODES=... # empty if this is the first node - -# optional, relayer only -ENABLE_RELAYER=true -GOAT_PRIVATE_KEY=... - -# optional, RPC server only -GOAT_SWAP_CONTRACT_ADDRESS=0xe510D5781C6C849284Fb25Dc20b1684cEC445C8B -GOAT_SWAP_EVENT_THE_GRAPH_URL=https://api.goat.0xgraph.xyz/api/public/1030419e-065f-45e9-8cf5-69c42207cbc7/subgraphs/escrow_manager_ga_dev_0/0.0.1/gn -GOAT_SWAP_EVENT_FILTER_FROM=9368978 -``` - -**Run Command:** +Run from the repository root: ```bash -./target/release/bitvm-noded \ - --rpc-addr 0.0.0.0:9100 \ - --metrics-addr 127.0.0.1:9108 \ - --p2p-port 8443 \ - --db-path ./committee.db +source ~/.zkm-toolchain/env +cargo build -r -p bitvm-noded --bin bitvm-noded ``` -### Operator +The binary is `target/release/bitvm-noded`. -The Operator manages the bridge operations. +## Configure a node -**Add to `.env`:** +The node loads `.env` from its working directory. Use a separate directory and +SQLite database for each node. -```env +```dotenv RUST_LOG=info - -# required -ACTOR=Operator -BITCOIN_NETWORK=testnet # bitcoin / testnet / regtest -GOAT_NETWORK=test # main / test +ACTOR=Verifier +BITCOIN_NETWORK=testnet4 +GOAT_NETWORK=test GOAT_CHAIN_URL=https://rpc.testnet3.goat.network -GOAT_PROOF_BUILD_URL=... -PROOF_SEVER_URL=... -PEER_KEY=... -BITVM_SECRET=... # operator should setup its BTC private key -GOAT_ADDRESS=... -GOAT_GATEWAY_CONTRACT_ADDRESS=0x21f619040AC2eAcacEF8Fe17Ae8bDF53ec69C66f -GOAT_GATEWAY_EVENT_THE_GRAPH_URL=https://api.goat.0xgraph.xyz/api/public/1030419e-065f-45e9-8cf5-69c42207cbc7/subgraphs/bitvm2_gateway_ga_dev_0/0.0.3/gn -GOAT_GATEWAY_EVENT_FILTER_FROM=9689342 -PROTO_NAME=bitvmt3 -BOOTNODES=... # empty if this is the first node +GOAT_GATEWAY_CONTRACT_ADDRESS= +GOAT_GATEWAY_EVENT_THE_GRAPH_URL= +GOAT_GATEWAY_EVENT_FILTER_FROM= +GOAT_PROOF_BUILD_URL=http://127.0.0.1:7777 +PEER_KEY= +BITVM_SECRET= +GOAT_ADDRESS= ``` -**Run Command:** +Replace the placeholders with values for your deployment. Contract addresses, +subgraph URLs and starting blocks must describe the same deployment. +Generate peer and funding keys with the commands in the +[node guide](../node/README.md#generate-node-keys). + +| Role | Configuration | +|------|---------------| +| Committee | `ACTOR=Committee`; set `GOAT_PRIVATE_KEY` | +| Operator | `ACTOR=Operator`; set `GOAT_ADDRESS` or `GOAT_PRIVATE_KEY`, and fund the Bitcoin signing key | +| Verifier | `ACTOR=Verifier`; set `GOAT_ADDRESS` or `GOAT_PRIVATE_KEY`, and fund the Bitcoin signing key | +| Watchtower | `ACTOR=Watchtower`; configure its registered Bitcoin signing key | +| Relayer | `ACTOR=Committee`, `ENABLE_RELAYER=true`; set `GOAT_PRIVATE_KEY` | + +Optional settings include: + +| Variable | Purpose | +|----------|---------| +| `BTC_CHAIN_URL` | Bitcoin Esplora endpoint | +| `PROTO_NAME` | P2P protocol namespace; use the same value for participating nodes | +| `NODE_NAME` | Display name | +| `EXTERNAL_SOCKET_ADDR` | Advertised node RPC socket address; bypasses automatic discovery | +| `GOAT_SEQUENCER_SET_PUBLISHER_CONTRACT_ADDRESS` | Sequencer-set publisher contract | +| `ENV_GOAT_SEQUENCER_SET_MULTI_SIG_VERIFIER_ADDRESS` | Sequencer-set multisignature verifier contract | +| `GOAT_SWAP_CONTRACT_ADDRESS` | Swap contract for swap-enabled services | +| `GOAT_SWAP_EVENT_THE_GRAPH_URL` / `GOAT_SWAP_EVENT_FILTER_FROM` | Swap subgraph and starting block | +| `MIN_REQUIRED_VERIFIER` | Verifier slots for new graphs; default `1` | + +Set the same positive `MIN_REQUIRED_VERIFIER` on all participating nodes before +creating graphs. Existing finalized graphs retain their original Verifier slots. +The [configuration reference](../node/README.md#configuration) covers engine, +network limits, timeouts and key-retention settings. + +## Run ```bash ./target/release/bitvm-noded \ --rpc-addr 0.0.0.0:9100 \ --metrics-addr 127.0.0.1:9108 \ --p2p-port 8443 \ - --db-path ./operator.db + --db-path 'sqlite:./node.db?mode=rwc' ``` -### Challenger - -The Challenger verifies the operations and submits challenges if necessary. +Use `--bootnodes ''` to join existing peers. The Docker entrypoint +also accepts `BOOTNODES` and passes it to this CLI option. Give each process +its own database and listening ports. -**Add to `.env`:** +## Health and metrics -```env -RUST_LOG=info +`GET /v1/health` on the business RPC listener returns `200` when ready and `503` +otherwise, with readiness and backend status. The node retries an unavailable +GOAT RPC during startup before exiting if initialization still cannot complete. -# required -ACTOR=Challenger -BITCOIN_NETWORK=testnet # bitcoin / testnet / regtest -GOAT_NETWORK=test # main / test -GOAT_CHAIN_URL=https://rpc.testnet3.goat.network -GOAT_PROOF_BUILD_URL=... -PROOF_SEVER_URL=... -PEER_KEY=... -BITVM_SECRET=... # operator should setup its BTC private key -GOAT_ADDRESS=... -GOAT_GATEWAY_CONTRACT_ADDRESS=0x21f619040AC2eAcacEF8Fe17Ae8bDF53ec69C66f -GOAT_GATEWAY_EVENT_THE_GRAPH_URL=https://api.goat.0xgraph.xyz/api/public/1030419e-065f-45e9-8cf5-69c42207cbc7/subgraphs/bitvm2_gateway_ga_dev_0/0.0.3/gn -GOAT_GATEWAY_EVENT_FILTER_FROM=9689342 -PROTO_NAME=bitvmt3 -BOOTNODES=... # empty if this is the first node -``` +Prometheus uses the dedicated `--metrics-addr` listener and `/metrics` path. +`GET /metrics` on the business RPC listener returns `404`. Bind metrics to a +private interface and use a distinct port per process. -**Run Command:** +The [Docker Compose configuration](docker-compose.yml) publishes metrics on +host loopback: -```bash -./target/release/bitvm-noded \ - --rpc-addr 0.0.0.0:9100 \ - --metrics-addr 127.0.0.1:9108 \ - --p2p-port 8443 \ - --db-path ./challenger.db -``` - -### Watchtower - -The Watchtower submit the btc-chain-proof when needed. - -**Add to `.env`:** - -```env -RUST_LOG=info - -# required -ACTOR=Watchtower -BITCOIN_NETWORK=testnet # bitcoin / testnet / regtest -GOAT_NETWORK=test # main / test -GOAT_CHAIN_URL=https://rpc.testnet3.goat.network -GOAT_PROOF_BUILD_URL=... -PROOF_SEVER_URL=... -PEER_KEY=... -BITVM_SECRET=... # operator should setup its BTC private key -GOAT_GATEWAY_CONTRACT_ADDRESS=0x21f619040AC2eAcacEF8Fe17Ae8bDF53ec69C66f -GOAT_GATEWAY_EVENT_THE_GRAPH_URL=https://api.goat.0xgraph.xyz/api/public/1030419e-065f-45e9-8cf5-69c42207cbc7/subgraphs/bitvm2_gateway_ga_dev_0/0.0.3/gn -GOAT_GATEWAY_EVENT_FILTER_FROM=9689342 -PROTO_NAME=bitvmt3 -BOOTNODES=... # empty if this is the first node -``` - -**Run Command:** - -```bash -./target/release/bitvm-noded \ - --rpc-addr 0.0.0.0:9100 \ - --metrics-addr 127.0.0.1:9108 \ - --p2p-port 8443 \ - --db-path ./watchtower.db -``` +| Service | Host metrics endpoint | +|---------|-----------------------| +| `committee_0` | `http://127.0.0.1:9900/metrics` | +| `committee_1` | `http://127.0.0.1:9901/metrics` | +| `verifier_0` | `http://127.0.0.1:9902/metrics` | +| `operator_0` | `http://127.0.0.1:9903/metrics` | +| `watchtower_0` | `http://127.0.0.1:9904/metrics` | -For `sequencer-set-publish` and `proof-builder-rpc` deployment and failure recovery, please refer to the [Proof Builder RPC README](../proof-builder-rpc/README.md) for detailed instructions. +Use the [operator tools](../scripts/ops/README.md) for health triage, log queries +and instance or graph timelines. Proof service configuration and recovery are +covered in the [Proof Builder RPC guide](../proof-builder-rpc/README.md). diff --git a/localnet/README.md b/localnet/README.md index c97de48c..965a7364 100644 --- a/localnet/README.md +++ b/localnet/README.md @@ -5,7 +5,7 @@ regtest + a GOAT chain (a local anvil, or the public GOAT testnet3, see "GOAT ba graph-node, every endpoint on 127.0.0.1. The garbled circuits, soldering and proofs are deterministic mocks with configurable delays; everything on chain is real, so peg-in, peg-out, challenge/assert/take-2 and disprove run the genuine transaction graph -(see `node/README.md`, "Mock build for local testnets"). The on-demand regression suite lives in +(see the [node guide](../node/README.md#local-testnets) and [transaction graph](../transaction-graph.svg)). The on-demand regression suite lives in [e2e/](e2e/README.md). CI runs the whole suite after pushes to main / dev, see "CI" below. ## Host requirements @@ -19,7 +19,7 @@ The p2p-isolation e2e case additionally needs passwordless `sudo iptables`. ## Quick start ```bash -git clone --recurse-submodules && cd bitvm-node # or: git submodule update --init --recursive +git clone --recurse-submodules https://github.com/GOATNetwork/bitvm-node.git && cd bitvm-node # or: git submodule update --init --recursive make localnet-reset # builds the binaries if needed, then wipes+creates the whole localnet (2 min; 7 min when keys are generated; + the build) make localnet-status make e2e-smoke # pegin_happy pegout_happy challenge_take2 (~23 min) @@ -94,14 +94,9 @@ WronglyChallenged race. ## Contracts -`contracts/` is a git submodule of the L2 contracts. It is pinned to PR #26 of -GOATNetwork/bitvm-L2-contracts ("fix GUARDIAN_CONNECTOR_VOUT & remove debug contracts", head -`3a679bf`, fetched from the fork `KSlashh/bitvm-L2-contracts`); once that PR is merged, point -`.gitmodules` back at `GOATNetwork/bitvm-L2-contracts` and bump the pin. The PR sets -`GUARDIAN_CONNECTOR_VOUT = 3`, which is what the node's kickoff topology uses (`goat` -`output_topology::kickoff::guardian_connector()`); older contract revisions parse peg-outs wrong. -No upstream source is patched. The localnet GOAT chain runs at chain id 48816 (= the contracts' -testnet id, so `Constants.magicBytes()` accepts the regtest OP_RETURN magic the node emits). +`contracts/` contains the L2 contracts used by the local deployment. The +Gateway must recognize Guardian output index 3 in Kickoff. The local GOAT chain +uses chain ID 48816 so it accepts the node's Regtest transaction metadata. `contracts-local/` is a second foundry project that imports the submodule (`bitvm-l2/` remapping): @@ -136,18 +131,6 @@ change it there and `scripts/reset.sh --yes`. - Logs: one JSON file per boot under `logs/nodes//`, `current` points at the newest; `scripts/logq.sh`, `scripts/trace.sh`. - DBs: `nodes//bitvm-node.db` (`sqlite3 -readonly`; UUIDs are 16-byte BLOBs, use `hex(col)`). -## Measured (2026-10-16, fresh clone on a loaded 16-core host) - -| step | time | -|---|---| -| first `cargo build -r` of the mock-gc binaries (crates.io registry already cached) | 14 min | -| `make localnet-reset`, first time (includes gen-keys: ~1 min per role for the peer-id check) | 7 min | -| `make localnet-reset`, keys kept | 2 min | -| `make e2e-smoke` (pegin 6.5 min, pegout 3 min, challenge_take2 13 min incl. its own peg-in) | 23 min | -| `make e2e`, all 13 cases, fast delay tier (2 s GC / 5 s proof); three full passes on 2026-10-16 | 95–110 min | - -Nodes report `ready=1` two to three minutes after a reset; the suite's pre-check waits for it. - ## CI `.github/workflows/e2e_localnet.yml` runs on the self-hosted `bitvm2-node` runner on every push to diff --git a/localnet/e2e/README.md b/localnet/e2e/README.md index 7b2f29a3..23d8f29f 100644 --- a/localnet/e2e/README.md +++ b/localnet/e2e/README.md @@ -1,7 +1,6 @@ # e2e — on-demand end-to-end regression of the node -Not CI: run it by hand after a change, on the localnet of [../README.md](../README.md) (five mocked nodes on -regtest + the GOAT chain + local graph). Honours `LOCALNET_DATA` / `PORT_BASE` / `COMPOSE_PROJECT` like every other script. +Run this suite manually after a change, or through the [Localnet e2e workflow](../../.github/workflows/e2e_localnet.yml) on pushes to `main` / `dev` and manual dispatch. It uses the [localnet](../README.md) (five mocked nodes on regtest, a GOAT chain and a local graph). `LOCALNET_DATA`, `PORT_BASE` and `COMPOSE_PROJECT` select the environment. ``` localnet/scripts/status.sh # infra, chains, nodes all up diff --git a/node/README.md b/node/README.md index 21db3d4e..c562b7bb 100644 --- a/node/README.md +++ b/node/README.md @@ -112,7 +112,7 @@ bitvm-noded \ --metrics-addr 127.0.0.1:9108 \ --db-path ./node.db \ --p2p-port 4001 \ - --bootnodes /ip4/x.x.x.x/tcp/4001/p2p/ + --bootnodes '/ip4/x.x.x.x/tcp/4001/p2p/' ``` ### Start Local Mock RPC diff --git a/proof-builder-rpc/README.md b/proof-builder-rpc/README.md index 5f3fb490..24816c2e 100644 --- a/proof-builder-rpc/README.md +++ b/proof-builder-rpc/README.md @@ -2,19 +2,26 @@ ## Build -Use the following command to build the project: +From the repository root: ``` -BITCOIN_NETWORK=testnet4 cargo build -r +BITCOIN_NETWORK=testnet4 cargo build -r -p proof-builder-rpc ``` ## Deployment +Run the service from `proof-builder-rpc/` so the example configuration's relative +proof paths resolve correctly. Copy `proof-builder.toml.example` to +`proof-builder.toml` and configure the chain endpoints and proof inputs before +startup. + Initial parameters are read from `proof-builder.toml` (see [proof-builder.toml.example](./proof-builder.toml.example)). After that, they will be loaded from the database. -Field descriptions for the configuration are available in the circuits documentation: [circuits README](../circuits/README.md). +Proof inputs are described in the [circuits guide](../circuits/README.md). The +[transaction graph](../transaction-graph.svg) shows where the on-demand proofs +are used. To reuse local Bitcoin headers for the first batch built from Genesis, set `prefer_local_headers_on_init = true` in `[header_chain]`, together with `init_input = true` @@ -51,8 +58,9 @@ and exits if any configured contract set cannot be initialized. Operator request ownership and a matching instance/graph relation. Operator registration and stake are enforced when graphs are admitted and are not rechecked for existing proof tasks. Watchtower requests require membership in the current global Watchtower registry and the request -public key must match the authenticated signer. Contract authorization is queried for every -request; failures return HTTP 503 rather than falling back to stale authorization data. +public key must match the authenticated signer. Operator graph authorization is queried for each request. Watchtower membership +uses the short-lived registry cache described below. Failed authorization queries +return HTTP 503. Each authenticated request selects a configured deployment with the signed `gateway_address` field. For staged upgrades, the field may be omitted while Proof Builder has exactly one Gateway; @@ -158,44 +166,25 @@ Prometheus source network to reach it. The listener does not provide TLS or auth should not be exposed directly to the public internet. An unavailable metrics port causes startup to fail. -## Failure recovery - -Long-running proof tasks (stored in the `long_running_task_proof` table) — such as header-chain, commit-chain, and state-chain proofs — can be recovered from the database. Recovery notes: - -- **Header Chain**: A newly confirmed block (>=1) must wait for the configured number of confirmations before being included in a proof. If the confirmation count is insufficient, delete the corresponding entries from the `long_running_task_proof` table; proof generation will resume from the database state. +## Progress and recovery -- **Commit Chain**: The `sequencer-set-publish` process is manual. When a new publish is required, run the publication script with the appropriate `GOAT_BLOCK_NUMBER` to create a sequencer-set commitment. Example invocation: +Long-running header, commit and state-chain tasks persist their progress in +SQLite. Restarting the service resumes from that progress; retain the matching +proof files and sidecars when restoring a database backup. -```bash -GOAT_BLOCK_NUMBER=${THE_GOAT_BLOCK_NUMBER} bash -x scp.sh -``` +Operator and Watchtower tasks with unavailable inputs stay pending while later +tasks are checked. Forward and bounded retry scans alternate, so older tasks are +revisited even while new work arrives. Timeout requests prevent a subsequently +completed proof from overwriting a task that is no longer pending. -Example `scp.sh` used for Regtest integration tests, remember to set the `OPERATOR_VK_HASH` environment variable before running: +Sequencer-set publication is a separate operation. Inspect the publisher CLI +before advancing or rotating the publisher set: ```bash -#!/bin/bash -set -e -source .env - -DIR="$( cd "$( dirname "$0" )" && pwd )" - -if [ -f $OUTPUT_FILE ]; then - cp $OUTPUT_FILE ${OUTPUT_FILE}.bk -fi - -cargo build -r --bin sequencer-set-publish -export RUST_LOG=info -CMD="../target/release/sequencer-set-publish" - -echo "Recovering publisher set: next_publishers => publishers" -$CMD payfee --total 3 - -$CMD sign-seq --owner-btc-key-wif $PUBLISHER1 --goat-block-number $GOAT_BLOCK_NUMBER \ --next-publisher-btc-pubkeys=$PUBLISHER_BTC_PUBKEYS --publisher-btc-pubkeys=$NEXT_PUBLISHER_BTC_PUBKEYS -$CMD sign-seq --owner-btc-key-wif $PUBLISHER2 --goat-block-number $GOAT_BLOCK_NUMBER \ --next-publisher-btc-pubkeys=$PUBLISHER_BTC_PUBKEYS --publisher-btc-pubkeys=$NEXT_PUBLISHER_BTC_PUBKEYS -$CMD sign-seq --owner-btc-key-wif $PUBLISHER3 --goat-block-number $GOAT_BLOCK_NUMBER \ --next-publisher-btc-pubkeys=$PUBLISHER_BTC_PUBKEYS --publisher-btc-pubkeys=$NEXT_PUBLISHER_BTC_PUBKEYS - -# broadcast publisher changes to Bitcoin -$CMD push-seq --goat-block-number $GOAT_BLOCK_NUMBER --next-publisher-btc-pubkeys=$PUBLISHER_BTC_PUBKEYS --publisher-btc-pubkeys=$NEXT_PUBLISHER_BTC_PUBKEYS --commit-info="${DIR}/../circuits/data/commit-chain/commit_info.json.latest" +cargo run -r -p bitvm-noded --bin sequencer-set-publish -- --help ``` -- **State Chain**: For sequencer-set genesis commitments or when re-anchoring the state chain, modify the latest record of state chain in `long_running_task_proof` with `block_end = 0` and `proof_state = 'Failed'` to trigger recovery handling. +The [Regtest publication fixture](../node/ssp-ci.sh) demonstrates the sequence +with test publishers. For state-chain initialization and proof inputs, see the +[circuits guide](../circuits/README.md#state-chain) and the +[configuration example](proof-builder.toml.example). From 463f389f1b63bb54e94aa4776b23eaac7eb101cd Mon Sep 17 00:00:00 2001 From: eigmax Date: Sat, 7 Nov 2026 04:06:10 +0000 Subject: [PATCH 4/4] docs: remove the node README code map --- node/README.md | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/node/README.md b/node/README.md index c562b7bb..4353b452 100644 --- a/node/README.md +++ b/node/README.md @@ -11,7 +11,6 @@ transaction graph setup and signing, P2P communication, and proof coordination. - [Build & Run](#build--run) - [Configuration](#configuration) - [RPC API](#rpc-api) -- [Code map](#code-map) - [Related documentation](#related-documentation) ## Bitcoin transaction graph @@ -228,19 +227,6 @@ Use `/v1/health` for readiness and backend status, and the dedicated metrics listener for Prometheus. The [operator tools](../scripts/ops/README.md) provide health triage, structured log queries, and instance or graph timelines. -## Code map - -| Location | Purpose | -|----------|---------| -| [aggregates/](src/aggregates/) | Instance and graph state, scans, and jobs | -| [engine_bridge.rs](src/engine_bridge.rs) | Execution engine assembly and transport | -| [messages.rs](src/messages.rs) | Wire message definitions | -| [p2p_admission/](src/p2p_admission/) | Peer admission, replay protection, and limits | -| [middleware/](src/middleware/) | P2P swarm and direct graph requests | -| [scheduled_tasks/](src/scheduled_tasks/) | Chain event monitoring and maintenance | -| [rpc_service/](src/rpc_service/) | HTTP routes and handlers | -| [env.rs](src/env.rs) | Environment configuration | - ## Related documentation - [Project README](../README.md) — project layout and transaction graph checks