Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 0 additions & 82 deletions .claude/commands/bridge-out.md

This file was deleted.

14 changes: 7 additions & 7 deletions .claude/commands/rpc-health-monitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

Collects and summarizes:
1) graph status counts
2) instance status counts (bridge-in/out)
2) instance status counts (bridge-in) and swap escrow status counts (bridge-out)
3) node online or offline status
4) overall service health verdict
"""
Expand Down Expand Up @@ -482,7 +482,7 @@ def summarize_once(
"instance_wraps",
timeout,
page_size,
fixed_params={"is_bridge_in": "true"},
fixed_params={},
)
checks.extend(in_checks)
except Exception as err: # pylint: disable=broad-except
Expand All @@ -493,11 +493,11 @@ def summarize_once(
try:
instance_out_items, instance_out_total, out_checks = fetch_pages(
base_url,
"/v1/instances",
"instance_wraps",
"/v1/swaps",
"swaps",
timeout,
page_size,
fixed_params={"is_bridge_in": "false"},
fixed_params={},
)
checks.extend(out_checks)
except Exception as err: # pylint: disable=broad-except
Expand Down Expand Up @@ -562,8 +562,8 @@ def summarize_once(
instance_out_status_counts = count_by(
instance_out_items,
lambda x: (
(x.get("instance") or {}).get("status")
if isinstance(x, dict) and isinstance(x.get("instance"), dict)
(x.get("swap") or {}).get("status")
if isinstance(x, dict) and isinstance(x.get("swap"), dict)
else "MISSING_INSTANCE"
),
)
Expand Down
11 changes: 7 additions & 4 deletions .claude/commands/run-challenger-node.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ The Challenger verifies operator operations and submits challenges if necessary.
1. Ask the user for the following parameters (skip any already provided as arguments: $ARGUMENTS):
- **network**: Which network? `testnet4` or `regtest`
- **rpc_addr**: RPC listen address. Default: `127.0.0.1:8906`
- **metrics_addr**: Prometheus listen address. Default: `127.0.0.1:9902`
- **p2p_port**: P2P listen port. Default: `8449` (testnet4) or `8450` (regtest)
- **db_path**: SQLite database path. Default: `sqlite:$PWD/bitvm-node.db`

Expand All @@ -32,26 +33,28 @@ The Challenger verifies operator operations and submits challenges if necessary.
4. Start the challenger node:

```bash
./bin/bitvm-noded --rpc-addr <rpc_addr> --db-path <db_path> --p2p-port <p2p_port> --bootnodes "$BOOTNODES"
./bin/bitvm-noded --rpc-addr <rpc_addr> --metrics-addr <metrics_addr> --db-path <db_path> --p2p-port <p2p_port> --bootnodes "$BOOTNODES"
```

To run in the background:
```bash
nohup ./bin/bitvm-noded --rpc-addr <rpc_addr> --db-path <db_path> --p2p-port <p2p_port> --bootnodes "$BOOTNODES" >challenger_$(date +'%Y%m%d').log 2>&1 &
nohup ./bin/bitvm-noded --rpc-addr <rpc_addr> --metrics-addr <metrics_addr> --db-path <db_path> --p2p-port <p2p_port> --bootnodes "$BOOTNODES" >challenger_$(date +'%Y%m%d').log 2>&1 &
```

5. Verify the node is running:
```bash
curl -s http://<rpc_addr>/
curl -s http://<metrics_addr>/metrics
```
Should return `Hello, World!`.
The first request should return `Hello, World!`; the second should return
Prometheus metrics in OpenMetrics text format.

### Example (testnet4)

```bash
cp deployment/testnet4/bitvm-noded/challenge_0/.env.challenge_0 .env
# Edit .env to fill in BITVM_SECRET, GOAT_ADDRESS, PEER_KEY
./bin/bitvm-noded --rpc-addr 127.0.0.1:8906 --db-path sqlite:$PWD/bitvm-node.db --p2p-port 8449 --bootnodes /ip4/34.215.238.232/tcp/8445/p2p/12D3KooWCrPTAmhFdC5DBGgkxZvJi6iuSeiDWKRL87isrt4iMHXv
./bin/bitvm-noded --rpc-addr 127.0.0.1:8906 --metrics-addr 127.0.0.1:9902 --db-path sqlite:$PWD/bitvm-node.db --p2p-port 8449 --bootnodes /ip4/34.215.238.232/tcp/8445/p2p/12D3KooWCrPTAmhFdC5DBGgkxZvJi6iuSeiDWKRL87isrt4iMHXv
```

For full deployment documentation, see `deployment/README.md` (section **Challenger**).
11 changes: 7 additions & 4 deletions .claude/commands/run-operator-node.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ The Operator manages bridge operations, kickoff processing, and pegout (Gateway.
1. Ask the user for the following parameters (skip any already provided as arguments: $ARGUMENTS):
- **network**: Which network? `testnet4` or `regtest`
- **rpc_addr**: RPC listen address. Default: `127.0.0.1:8902`
- **metrics_addr**: Prometheus listen address. Default: `127.0.0.1:9903`
- **p2p_port**: P2P listen port. Default: `8445` (testnet4) or `8446` (regtest)
- **db_path**: SQLite database path. Default: `sqlite:$PWD/bitvm-node.db`

Expand Down Expand Up @@ -35,26 +36,28 @@ The Operator manages bridge operations, kickoff processing, and pegout (Gateway.
4. Start the operator node:

```bash
./bin/bitvm-noded --rpc-addr <rpc_addr> --db-path <db_path> --p2p-port <p2p_port> --bootnodes "$BOOTNODES"
./bin/bitvm-noded --rpc-addr <rpc_addr> --metrics-addr <metrics_addr> --db-path <db_path> --p2p-port <p2p_port> --bootnodes "$BOOTNODES"
```

To run in the background:
```bash
nohup ./bin/bitvm-noded --rpc-addr <rpc_addr> --db-path <db_path> --p2p-port <p2p_port> --bootnodes "$BOOTNODES" >operator_$(date +'%Y%m%d').log 2>&1 &
nohup ./bin/bitvm-noded --rpc-addr <rpc_addr> --metrics-addr <metrics_addr> --db-path <db_path> --p2p-port <p2p_port> --bootnodes "$BOOTNODES" >operator_$(date +'%Y%m%d').log 2>&1 &
```

5. Verify the node is running:
```bash
curl -s http://<rpc_addr>/
curl -s http://<metrics_addr>/metrics
```
Should return `Hello, World!`.
The first request should return `Hello, World!`; the second should return
Prometheus metrics in OpenMetrics text format.

### Example (testnet4)

```bash
cp deployment/testnet4/bitvm-noded/operator_0/.env.operator_0 .env
# Edit .env to fill in BITVM_SECRET, GOAT_ADDRESS, PEER_KEY, GOAT_PRIVATE_KEY
./bin/bitvm-noded --rpc-addr 127.0.0.1:8902 --db-path sqlite:$PWD/bitvm-node.db --p2p-port 8445 --bootnodes /ip4/34.215.238.232/tcp/8445/p2p/12D3KooWCrPTAmhFdC5DBGgkxZvJi6iuSeiDWKRL87isrt4iMHXv
./bin/bitvm-noded --rpc-addr 127.0.0.1:8902 --metrics-addr 127.0.0.1:9903 --db-path sqlite:$PWD/bitvm-node.db --p2p-port 8445 --bootnodes /ip4/34.215.238.232/tcp/8445/p2p/12D3KooWCrPTAmhFdC5DBGgkxZvJi6iuSeiDWKRL87isrt4iMHXv
```

For full deployment documentation, see `deployment/README.md` (section **Operator**).
7 changes: 4 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -116,16 +116,17 @@ jobs:
pass | MessageStateRaceFixed.cfg | MessageStateRace.tla | Finding 7 fix - terminal-guarded resurrect
pass | Take1ChallengeRaceFixed.cfg | Take1ChallengeRace.tla | Finding 9 fix - connector_a margin check added
pass | VerifierKickoffFailOpenFixed.cfg | VerifierKickoffFailOpen.tla | Issue #429 fix design - defer/retry mirrors committee
pass | KickoffScanCoverageFixed.cfg | KickoffScanCoverage.tla | Issue #431 fix - scan_kickoff_chain with adequate depth
pass | KickoffScanCoverageFixed.cfg | KickoffScanCoverage.tla | Issue #431 fix (#451) - root-only chain walk with adequate depth
pass | KickoffScanCoverageAllEntries.cfg | KickoffScanCoverage.tla | Issue #431 residual fix - every pending graph is a scan entry (holds with ScanDepth=0)
historical | GraphLifecycle.cfg | GraphLifecycle.tla | Finding 1: Graph.status race (fixed 991faaa)
historical | GraphLifecycleFineGrained.cfg | GraphLifecycleFineGrained.tla | Finding 1b: naive guard still unsafe (fixed 991faaa)
historical | InstancePresignedBug.cfg | InstancePresigned.tla | Finding 2: Instance.status regression past Presigned (fixed 991faaa)
historical | InstanceBridgeOutRace.cfg | InstanceBridgeOutRace.tla | Finding 6: InstanceBridgeOutStatus resurrection (fixed 991faaa)
historical | MessageStateRace.cfg | MessageStateRace.tla | Finding 7: MessageState resurrection (fixed 991faaa)
historical | Take1ChallengeRace.cfg | Take1ChallengeRace.tla | Finding 9: connector_a has no margin check (fixed 991faaa)
historical | KickoffScanCoverage.cfg | KickoffScanCoverage.tla | Issue #431: detect_kickoff one-per-operator coverage gap (fixed by #451)
live | VerifierKickoffFailOpen.cfg | VerifierKickoffFailOpen.tla | Issue #429: verifier KickoffSent fail-open (SPV lag skips Challenge, never retried)
live | KickoffScanCoverageResidual.cfg | KickoffScanCoverage.tla | Issue #431 residual: MAX_PREKICKOFF_SUCCESSORS_PER_SCAN=32 depth cap leaves deeper decoy chains uncovered
historical | VerifierKickoffFailOpen.cfg | VerifierKickoffFailOpen.tla | Issue #429: verifier KickoffSent fail-open (SPV lag skipped Challenge, never retried) (fixed by #455)
historical | KickoffScanCoverageResidual.cfg | KickoffScanCoverage.tla | Issue #431 residual: root-only walk capped at MAX_PREKICKOFF_SUCCESSORS_PER_SCAN=32 (fixed: all pending graphs are scan entries)
SPECS
{
echo
Expand Down
7 changes: 6 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,9 @@ circuits/*/*/*.bin.in
**/*.out
**/*/output.data*
proof-builder-rpc/*.ckpt
node/tla/states/
node/tla/states/

local_docs/
scripts/testnet/
scripts/devnet/
*.DS_Store
10 changes: 5 additions & 5 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion circuits/operator-proof/host/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ pub async fn fetch_target_block_and_watchtower_tx(
esplora_url: &str,
latest_sequencer_commit_txid: &str,
operator_committed_blockhash: &str,
watchtower_challenge_init_txid: &String,
watchtower_challenge_init_txid: &str,
watchtower_challenge_txids: &str,
watchtower_public_keys: &str,
bitcoin_network: Network,
Expand Down
2 changes: 1 addition & 1 deletion circuits/proof-builder/src/api_auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ fn sort_json_value(value: &mut Value) {
}

/// Adds one length-prefixed field to the authentication digest.
fn hash_field(hasher: &mut Sha256, field: &[u8]) {
pub fn hash_field(hasher: &mut Sha256, field: &[u8]) {
hasher.update((field.len() as u64).to_be_bytes());
hasher.update(field);
}
Expand Down
18 changes: 18 additions & 0 deletions crates/bitcoin-light-client-circuit/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@ pub const VK_HASH_SIZE: usize = 66;
pub const TOTAL_WORK_SIZE: usize = 32;
pub const CONSENSUS_BLOCK_HEIGHT_SIZE: usize = 4;

// 0xc3d8382a8efed79d564f8ec6da4dd00a4e77572d1e02f5f81dda441a36fdc9d8
pub const ROOT_COMMIT_PROGRAM_ID: verifier::ProgramId = [
195, 216, 56, 42, 142, 254, 215, 157, 86, 79, 142, 198, 218, 77, 208, 10, 78, 119, 87, 45, 30,
2, 245, 248, 29, 218, 68, 26, 54, 253, 201, 216,
];

#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct WatchtowerPublicOutputs {
pub total_work: [u8; TOTAL_WORK_SIZE],
Expand Down Expand Up @@ -74,15 +80,25 @@ fn checked_history_root(
}

/// Verifies that the latest Bitcoin commitment authorizes every supplied circuit proof.
///
/// `root_commit_program_id` is the pinned anchor; it is the only identity here that does not
/// come from the proofs being checked, so it is asserted before anything reads the
/// Commit-chain output. See [`ROOT_COMMIT_PROGRAM_ID`].
#[allow(clippy::too_many_arguments)]
fn verify_commitment_authorization(
commit_chain_output: &CommitChainCircuitOutput,
header_chain_output: &BlockHeaderCircuitOutput,
state_chain_output: &StateChainCircuitOutput,
header_program_id: verifier::ProgramId,
state_program_id: verifier::ProgramId,
commit_program_id: verifier::ProgramId,
root_commit_program_id: verifier::ProgramId,
sequencer_set_hash: [u8; 32],
) -> AuthorizedProgramIds {
assert_eq!(
commit_program_id, root_commit_program_id,
"commit proof program id does not match the pinned root anchor"
);
let authorized = commit_chain_output.chain_state.authorized_program_ids;
authorized.validate().expect("invalid authorized ProgramIds");
check_program_id(commit_program_id, commit_chain_output.self_program_id, authorized.commit);
Expand Down Expand Up @@ -215,6 +231,7 @@ pub fn watch_longest_chain(
header_program_id,
state_program_id,
commit_program_id,
ROOT_COMMIT_PROGRAM_ID,
sequencer_set_hash,
);
} else {
Expand Down Expand Up @@ -382,6 +399,7 @@ pub fn propose_longest_chain(
header_program_id,
state_program_id,
commit_program_id,
ROOT_COMMIT_PROGRAM_ID,
sequencer_set_hash,
)
} else {
Expand Down
Loading
Loading