This is an implementation of LIDO LIP-23 sanity check oracle, using Succinct SP1. Repository contains the following:
- contracts - on-chain, LIP-23 compatible contract.
- program - ZK circuit implementation
- script - offchain oracle implementation (
submit.rs) - service - offchain oracle implementation (
submit.rs) + some development scripts (scripts/src/dev) - shared - common code shared between ZK (program) and oracle (script).
- dev_script - development scripts
- macros - macros implementations
The oracle comes in two forms:
- CLI interface (
submit) - Service (
service) with internal scheduler (optional, controlled by env vars) and HTTP endpoint to trigger running a report
Most of the configuration is shared between the two (in fact, both are just thin wrappers around common underlying logic) and delivered via env vars - see .env.example (and comments in it) for the list of required settings.
- (OPTIONAL) target_ref_slot: int - slot number for report; if not set, determined from Lido's HashConsensus contract for Accounting Oracle
- (OPTIONAL) previous_ref_slot:int - slot number for the previous report and cached validator state. If omitted, read from the contract
getLatestValidatorStateSlot. - (OPTIONAL) dry_run: bool - if set, prepares the input for proving, but do not request the proof (and hence do not submit the report for on-chain verification). Default: false
- (OPTIONAL) verify_input: bool - if set, verifies the input for consistency/correctness. Default: false.
- (OPTIONAL) verify_proof: bool - if set, verifies the proof locally. Default: false. Note: local proving requires docker to run.
- (OPTIONAL) report_cycles: bool - if set, measures the SP1 cycles require to generate the proof - by locally "executing" (in SP1 terms) the program. Default: false.
Examples:
- Run oracle for slot
5994112, submit to EVM contract:submit --target-ref-slot 5994112 - Run oracle for slot
5994112, locally verify the proof and public values (will crash if verification fails), submit to EVM contract:submit --target-ref-slot 5994112 --local_verify - Run oracle for slot
5994112, use5993824as a previous report slot, submit to EVM contract:submit --target-ref-slot 5994112 --previous-ref-slot 5993824
- GET
/health- used for healthcheck, just returns 'ok' when healthy - GET
/metrics- returns Prometheus metrics - GET
/get-report?target-slot=$d- reads report for a given slot from the contract. Iftarget-slotomitted, obtains the latest report from the contract - POST
/run-report- reads report for a given slot from the contract. Iftarget-slotomitted, obtains the latest report from the contract
NOTE: This project uses gitmodules. Please make sure to clone with --recurse-submodules and/or
git submodules update --init --recursive, and/or any other means to make sure contracts/lib/sp1-contracts exists
and is not empty. Otherwise, building contracts (forge build, also run by cargo build via crates/script/build.rs)
will not produce the contracts/out, which in turn will fail generating code for accessing the contract (eth_client.rs).
cargo test runs all unit (in cfg(test) blocks) and integration (in tests folders) tests, except:
- integration tests that take very long time to run (minutes)
- end-to-end tests that interact with the SP1 prover network (and hence incur real-life costs)
To run those, use cargo test -- --include-ignored - note it will use Sepolia testnet and SP1 prover network. As such,
env variables needed to access those (CONSENSUS_LAYER_RPC, BEACON_STATE_RPC, NETWORK_PRIVATE_KEY, etc.) need to be
set for those tests to work.
crates/dev_scripts/src/bin hosts a few scripts to support development and deployment workflows.
execute.rs- prepares the input and runs ZK circuit simulation, outputting number of cycles and instructions used. Does not interact with the prover network, safe to run to quickly check changes and estimate cycle count.write_test_fixture.rs- updates the test fixtures used in scripts integration tests and contract tests. Needs to be run whenvkeychanges (basically, any code or dependency change inprogramandshared).deploy.rs- have two orthogonal features: (1) write deploy manifesto (--store) and (2) deploy contract (--dry-run). Note: deployment works, but doesn't perform code verification yet. Preferred deployment workflow is to rundeploy.rswith--dry-run --store "../data/deploy/${EVM_CHAIN}-deploy.json"- and then run deployment script incontracts/script/Deploy.s.solthat automatically picks the deploy manifesto from that location.store_report.rs- generates report and stores it on disk for inspection and debugging.sumbit_cached.rs- intended to be used withstore_report.rsscript. Allows submitting a cached proof and report to the verification contract - skipping on the (most time-consuming) proof generation stage.