Skip to content

Add snapshot_api_plugin and bootstrap from snapshot endpoint#248

Open
heifner wants to merge 13 commits intofeature/snapshot-servingfrom
feature/snapshot-endpoint
Open

Add snapshot_api_plugin and bootstrap from snapshot endpoint#248
heifner wants to merge 13 commits intofeature/snapshot-servingfrom
feature/snapshot-endpoint

Conversation

@heifner
Copy link
Copy Markdown
Contributor

@heifner heifner commented Mar 13, 2026

Summary

  • snapshot_api_plugin: New plugin with public read-only HTTP endpoints (/v1/snapshot/latest, /v1/snapshot/by_block, /v1/snapshot/download) for snapshot discovery and download. Adds snapshot_ro API category so operators can expose only snapshot serving publicly via --http-category-address. File serving uses Beast's file_body for zero-copy sendfile with Range header support for resumable downloads.

  • --snapshot-endpoint bootstrap: New CLI option on chain_plugin to bootstrap a node directly from a remote snapshot provider. Downloads snapshot, verifies root hash via footer metadata, loads and syncs, then verifies on-chain attestation with a retry-based check (12,500 block timeout). Strict enforcement for auto-fetched snapshots (fatal on missing attestation); warnings only for manual --snapshot.

  • Supporting changes: multiple snapshot finalized callbacks in snapshot_scheduler, send_file_response/get_request_header/add_raw_handler on http_plugin, post_to_file on fc::http_client, operator guide at plugins/snapshot_api_plugin/README.md

  • Integration test: 9 tests covering API endpoints (metadata, download, Range header, catalog updates) and bootstrap flows (latest + specific block number)

Key files

Area Files
New plugin plugins/snapshot_api_plugin/ (plugin, README)
HTTP extensions beast_http_session.hpp, common.hpp, http_plugin.hpp/.cpp, abstract_conn_fwd.hpp
Bootstrap chain_plugin.cpp (fetch_snapshot_from_endpoint, verify_snapshot_attestation)
Download support fc/http_client.hpp/.cpp (post_to_file)
Callback refactor snapshot_scheduler.hpp/.cpp, producer_plugin.hpp/.cpp
Docs docs/snapshot-serving-plan.md, plugins/snapshot_api_plugin/README.md
Test tests/snapshot_api_test.py

heifner and others added 13 commits March 12, 2026 12:54
Original plan covering BLS-signed snapshot distribution system with
multi-threaded generation, P2P hash voting, on-chain attestation,
HTTP serving, and bootstrap verification.
Phase 1: Mark complete with actual implementation details — single-file
binary format with buffered inline BLAKE3 hashing, performance results.

Phase 2: Replace BLS P2P voting with on-chain voting contract approach.
Producers register delegate snap_accounts via sysio.snapshot contract.
Attestation via votesnaphash with configurable quorum threshold:
max(min_providers, ceil(registered_count * 2/3) + 1). Add disagreement
detection, vote record purging, getsnaphash read-only query action.
Remove snapshot-hash-only config (unnecessary with contract approach).
Add snapshot hash attestation so bootstrapping nodes can verify snapshot
integrity against on-chain records after syncing.

Contract (sysio.system sub-contract, peer_keys pattern):
- Actions: regsnapprov, delsnapprov, votesnaphash, setsnpcfg, getsnaphash
- Tables: snapconfig, snapprovs, snapvotes, snaprecords
- Quorum: max(min_providers, ceil(provider_count * threshold_pct / 100))
- Disagreement detection rejects votes conflicting with attested records
- Vote purging on attestation to reclaim RAM

Snapshot scheduler (libraries/chain):
- Add BLAKE3 root_hash to snapshot_information and pending_snapshot
- Capture root_hash from threaded_snapshot_writer after finalize()
- Add snapshot_finalized_callback for producer_plugin integration

Producer plugin — snapshot provider mode:
- --snapshot-provider-account option (mutually exclusive with producer-name)
- Auto-schedules snapshots every 25,000 blocks at exact multiples
- Submits votesnaphash on each finalized snapshot
- Shuts down on disagreement error from contract

Chain plugin — snapshot verification on load:
- Captures snapshot block_num and root_hash when starting from --snapshot
- Verifies against snaprecords table once LIB advances past snapshot block
- Warns on missing attestation table/record (supports non-attesting chains)
- Fatal error on hash mismatch (corruption/tampering)

Tests:
- 19 contract tests (contracts/tests/sysio.snapshot_attest_tests.cpp)
- 5 unit tests (unittests/snapshot_attest_tests.cpp)
- 5 integration tests (tests/snapshot_attest_test.py)
…3 & 4)

Phase 3: New snapshot_api_plugin with public read-only HTTP endpoints for
snapshot discovery and download. Adds snapshot_ro API category allowing
operators to expose snapshot serving on a dedicated address while keeping
admin APIs on loopback. Endpoints: /v1/snapshot/latest, /v1/snapshot/by_block,
/v1/snapshot/download (with Range header support for resumable transfers).
File serving uses Beast's file_body for zero-copy sendfile.

Phase 4: --snapshot-endpoint CLI option on chain_plugin to bootstrap a node
from a remote snapshot provider. Downloads snapshot, verifies root hash via
footer metadata, loads snapshot, syncs forward, then verifies on-chain
attestation with retry-based check (12,500 block timeout). Strict enforcement
for auto-fetched snapshots (fatal on missing attestation); warnings only for
manual --snapshot.

Supporting changes:
- snapshot_scheduler: multiple finalized callbacks (vector instead of single)
- http_plugin: send_file_response/get_request_header on abstract_conn,
  add_raw_handler for binary responses
- producer_plugin: add_snapshot_finalized_callback and get_snapshots_dir
- fc::http_client: post_to_file for binary downloads
- Operator guide at plugins/snapshot_api_plugin/README.md
- Integration test (9 tests) covering API endpoints and bootstrap flows
…coded offsets

Fix all 6 Copilot review comments on the snapshot attestation PR:

- Fix undefined behavior in block_height_from_id by casting uint8_t to
  uint32_t before left-shifting; deduplicate into shared block_utils.hpp
- Use authorization_manager::get_required_keys() in submit_snapshot_vote
  to resolve the correct key for snap_account@active instead of using
  the first available private key
- Replace temporary fc::temp_directory() expressions with named locals
  and embed temp_directory in snapshot_info to prevent dangling paths
- Replace hard-coded byte offsets in verify_snapshot_attestation with
  abi_serializer-based row decoding via the system contract ABI
- Reuse read_snap_record helper in attestation_survives_snapshot_load
  test instead of duplicating inline table lookup
Make snapshot_api_test.py executable
@heifner heifner force-pushed the feature/snapshot-serving branch from 935cf5a to 8ca2ab5 Compare March 26, 2026 15:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants