diff --git a/Cargo.lock b/Cargo.lock index 0511e65d3..78de56dc0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2954,7 +2954,7 @@ dependencies = [ "bitflags 2.11.0", "cexpr", "clang-sys", - "itertools 0.11.0", + "itertools 0.13.0", "log", "prettyplease", "proc-macro2", @@ -2974,7 +2974,7 @@ dependencies = [ "bitflags 2.11.0", "cexpr", "clang-sys", - "itertools 0.11.0", + "itertools 0.13.0", "proc-macro2", "quote", "regex", @@ -3008,7 +3008,7 @@ checksum = "90dbd31c98227229239363921e60fcf5e558e43ec69094d46fc4996f08d1d5bc" dependencies = [ "bitcoin_hashes", "rand 0.7.3", - "rand_core 0.4.2", + "rand_core 0.5.1", "serde", "unicode-normalization", ] @@ -9123,7 +9123,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2 0.4.10", + "socket2 0.5.10", "tokio", "tower-service", "tracing", @@ -19551,8 +19551,8 @@ version = "0.13.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be769465445e8c1474e9c5dac2018218498557af32d9ed057325ec9a41ae81bf" dependencies = [ - "heck 0.4.1", - "itertools 0.11.0", + "heck 0.5.0", + "itertools 0.14.0", "log", "multimap", "once_cell", @@ -19571,8 +19571,8 @@ version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "343d3bd7056eda839b03204e68deff7d1b13aba7af2b2fd16890697274262ee7" dependencies = [ - "heck 0.4.1", - "itertools 0.11.0", + "heck 0.5.0", + "itertools 0.14.0", "log", "multimap", "petgraph 0.8.3", @@ -19591,7 +19591,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" dependencies = [ "anyhow", - "itertools 0.11.0", + "itertools 0.12.1", "proc-macro2", "quote", "syn 2.0.116", @@ -19604,7 +19604,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" dependencies = [ "anyhow", - "itertools 0.11.0", + "itertools 0.14.0", "proc-macro2", "quote", "syn 2.0.116", @@ -19617,7 +19617,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "27c6023962132f4b30eb4c172c91ce92d933da334c59c23cddee82358ddafb0b" dependencies = [ "anyhow", - "itertools 0.11.0", + "itertools 0.14.0", "proc-macro2", "quote", "syn 2.0.116", @@ -25724,7 +25724,7 @@ dependencies = [ [[package]] name = "sp1-beefy" version = "0.1.0" -source = "git+ssh://git@github.com/polytope-labs/sp1-beefy.git?tag=v1.0.0#0c306928e8751e846bd407f1839d1f4b5218ede9" +source = "git+ssh://git@github.com/polytope-labs/sp1-beefy.git?tag=v1.1.0#35e6cdd6a5f5eded9241fb0dfd49b1def7ac99a2" dependencies = [ "alloy-sol-types 0.7.7", "anyhow", @@ -25746,7 +25746,7 @@ dependencies = [ [[package]] name = "sp1-beefy-primitives" version = "0.1.0" -source = "git+ssh://git@github.com/polytope-labs/sp1-beefy.git?tag=v1.0.0#0c306928e8751e846bd407f1839d1f4b5218ede9" +source = "git+ssh://git@github.com/polytope-labs/sp1-beefy.git?tag=v1.1.0#35e6cdd6a5f5eded9241fb0dfd49b1def7ac99a2" dependencies = [ "alloy-sol-types 0.7.7", "parity-scale-codec", @@ -27847,7 +27847,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0136791f7c95b1f6dd99f9cc786b91bb81c3800b639b3478e561ddb7be95e5f1" dependencies = [ "fastrand", - "getrandom 0.3.4", + "getrandom 0.4.2", "once_cell", "rustix 1.1.3", "windows-sys 0.61.2", @@ -28093,6 +28093,7 @@ dependencies = [ name = "tesseract-beefy" version = "0.1.0" dependencies = [ + "alloy", "alloy-primitives 1.5.7", "alloy-sol-types 1.5.7", "anyhow", @@ -28102,6 +28103,7 @@ dependencies = [ "beefy-verifier-primitives", "bytes", "derive_more 1.0.0", + "dotenv", "finality-grandpa", "futures", "hex", @@ -28523,10 +28525,11 @@ dependencies = [ [[package]] name = "tesseract-prover" -version = "2.0.2" +version = "2.1.0" dependencies = [ "anyhow", "clap", + "primitive-types 0.13.1", "rustls 0.23.36", "subxt-utils", "tesseract-beefy", @@ -29813,7 +29816,7 @@ checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" dependencies = [ "cfg-if", "digest 0.10.7", - "rand 0.4.6", + "rand 0.7.3", "static_assertions", ] diff --git a/docs/content/developers/explore/provers.mdx b/docs/content/developers/explore/provers.mdx index 98f102260..1cf37174d 100644 --- a/docs/content/developers/explore/provers.mdx +++ b/docs/content/developers/explore/provers.mdx @@ -32,16 +32,29 @@ Provers are rewarded with `$BRIDGE` tokens from the Hyperbridge treasury for eac - **Rotation proofs** — Proofs that carry a new BEEFY authority set transition. - **Messaging proofs** — Proofs that advance the proven parachain height past blocks containing new cross-chain message dispatches. -The reward amount is configurable via governance through `pallet-beefy-consensus-proofs::set_proof_reward`. +The base reward amount is configurable via governance through `pallet-beefy-consensus-proofs::set_proof_reward` (currently **100 `$BRIDGE`** per proof). ### The Reward Mechanism The process for earning rewards is deterministic and transparent: 1. **The Triggering Action**: A prover monitors the relay chain for BEEFY finality and Hyperbridge for new cross-chain message dispatches. -2. **Proof Generation**: When new work is detected, the prover generates a consensus proof (either ECDSA or SP1) and submits it to the Hyperbridge runtime. +2. **Proof Generation**: When new work is detected, the prover generates a consensus proof (either ECDSA or SP1) and submits it as a **signed** extrinsic — the signer is the reward payee. 3. **Verification and State Update**: The runtime verifies the proof. If it is valid and advances the proven state (either by rotating the authority set or proving new message dispatches), it is accepted. -4. **Automated Reward Issuance**: Upon acceptance, the protocol transfers a fixed `$BRIDGE` reward from the treasury to the prover's account. +4. **Automated Reward Issuance**: Upon acceptance, the protocol transfers a `$BRIDGE` reward from the treasury to the prover's account (the amount depends on the prover's position — see below — and an equal amount of non-transferable Reputation Asset is minted). + +### Uncle Proofs + +To reward redundancy and keep proving live, Hyperbridge rewards more than just the single fastest prover. The **first** prover to land a valid proof for a given finality target advances the chain's state and earns the **full** reward. Additional **independent** provers that generate their own valid proof for the **same** target are accepted as **uncles** and paid on a *decreasing reward curve*, up to a governance-configured limit (`MaxUncleProvers`). + +The curve (set via `set_reward_curve`) pays each position a fraction of the base reward. The current curve is **100% / 50% / 30% / 20% / 10% / 5%** — the first prover receives the full reward (100%), and the next five uncles receive 50%, 30%, 20%, 10%, and 5% respectively. Uncle rewards apply to SP1 proofs only. + +### Prover-Bound Proofs + +Each SP1 proof commits a nonce into its public values, and the runtime requires that nonce to equal the extrinsic signer. This binds a proof to the prover that produced it: + +- A proof **cannot be stolen** — copying the proof bytes from the mempool and submitting them under a different account is rejected, because the committed account no longer matches the signer. +- Reward **deduplication is per-account** — an account is rewarded at most once per finality target, so a single prover cannot mint many byte-distinct variants of one proof (e.g. via Groth16 re-randomization) to sweep multiple uncle slots. ## Reputation and the Path to Becoming a Collator @@ -51,7 +64,7 @@ This means that running a prover is a direct path to becoming a Collator and ear ## A Competitive, Permissionless Environment -The incentive structure fosters a healthy, competitive market. Only the **first prover** to successfully submit a proof for a given state advance receives the reward. This encourages provers to optimize their operations for low latency and efficiency, ensuring that Hyperbridge's cross-chain message pipeline remains fast and reliable. +The incentive structure fosters a healthy, competitive market. The **first prover** to submit a proof for a given state advance earns the full reward and advances the chain, which rewards low-latency, efficient operations. Independent provers for the same target still earn a smaller, decreasing reward as uncles, so redundant provers are compensated for the liveness they provide rather than racing winner-take-all. This model is inherently permissionless — no staking or whitelisting is required to participate. Any operator can run a prover and begin competing to submit proofs and earn rewards. diff --git a/evm/rust/abi/SP1Beefy.json b/evm/rust/abi/SP1Beefy.json index 76f930e75..212f909e6 100644 --- a/evm/rust/abi/SP1Beefy.json +++ b/evm/rust/abi/SP1Beefy.json @@ -1 +1 @@ -{"abi":[{"type":"constructor","inputs":[{"name":"v","type":"address","internalType":"contract ISP1Verifier"},{"name":"vk","type":"bytes32","internalType":"bytes32"}],"stateMutability":"nonpayable"},{"type":"function","name":"noOp","inputs":[{"name":"s","type":"tuple","internalType":"struct SP1BeefyProof","components":[{"name":"commitment","type":"tuple","internalType":"struct MiniCommitment","components":[{"name":"blockNumber","type":"uint256","internalType":"uint256"},{"name":"validatorSetId","type":"uint256","internalType":"uint256"}]},{"name":"mmrLeaf","type":"tuple","internalType":"struct PartialBeefyMmrLeaf","components":[{"name":"version","type":"uint8","internalType":"uint8"},{"name":"parentNumber","type":"uint32","internalType":"uint32"},{"name":"parentHash","type":"bytes32","internalType":"bytes32"},{"name":"nextAuthoritySet","type":"tuple","internalType":"struct AuthoritySetCommitment","components":[{"name":"id","type":"uint64","internalType":"uint64"},{"name":"len","type":"uint32","internalType":"uint32"},{"name":"root","type":"bytes32","internalType":"bytes32"}]},{"name":"extra","type":"bytes32","internalType":"bytes32"}]},{"name":"headers","type":"tuple[]","internalType":"struct ParachainHeader[]","components":[{"name":"id","type":"uint256","internalType":"uint256"},{"name":"header","type":"bytes","internalType":"bytes"}]},{"name":"proof","type":"bytes","internalType":"bytes"}]},{"name":"p","type":"tuple","internalType":"struct PublicInputs","components":[{"name":"authorities_root","type":"bytes32","internalType":"bytes32"},{"name":"authorities_len","type":"uint256","internalType":"uint256"},{"name":"leaf_hash","type":"bytes32","internalType":"bytes32"},{"name":"block_number","type":"uint256","internalType":"uint256"},{"name":"headers","type":"tuple[]","internalType":"struct ParachainHeaderHash[]","components":[{"name":"id","type":"uint256","internalType":"uint256"},{"name":"hash","type":"bytes32","internalType":"bytes32"}]}]}],"outputs":[],"stateMutability":"pure"},{"type":"function","name":"supportsInterface","inputs":[{"name":"interfaceId","type":"bytes4","internalType":"bytes4"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"type":"function","name":"verificationKey","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"verifier","inputs":[],"outputs":[{"name":"","type":"address","internalType":"contract ISP1Verifier"}],"stateMutability":"view"},{"type":"function","name":"verify","inputs":[{"name":"previousState","type":"bytes","internalType":"bytes"},{"name":"proof","type":"bytes","internalType":"bytes"}],"outputs":[{"name":"","type":"bytes","internalType":"bytes"},{"name":"","type":"tuple[]","internalType":"struct IntermediateState[]","components":[{"name":"stateMachineId","type":"uint256","internalType":"uint256"},{"name":"height","type":"uint256","internalType":"uint256"},{"name":"commitment","type":"tuple","internalType":"struct StateCommitment","components":[{"name":"timestamp","type":"uint256","internalType":"uint256"},{"name":"overlayRoot","type":"bytes32","internalType":"bytes32"},{"name":"stateRoot","type":"bytes32","internalType":"bytes32"}]}]},{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"verifyConsensus","inputs":[{"name":"encodedState","type":"bytes","internalType":"bytes"},{"name":"encodedProof","type":"bytes","internalType":"bytes"}],"outputs":[{"name":"","type":"bytes","internalType":"bytes"},{"name":"","type":"tuple[]","internalType":"struct IntermediateState[]","components":[{"name":"stateMachineId","type":"uint256","internalType":"uint256"},{"name":"height","type":"uint256","internalType":"uint256"},{"name":"commitment","type":"tuple","internalType":"struct StateCommitment","components":[{"name":"timestamp","type":"uint256","internalType":"uint256"},{"name":"overlayRoot","type":"bytes32","internalType":"bytes32"},{"name":"stateRoot","type":"bytes32","internalType":"bytes32"}]}]}],"stateMutability":"view"},{"type":"error","name":"IllegalGenesisBlock","inputs":[]},{"type":"error","name":"TimestampNotFound","inputs":[]},{"type":"error","name":"UnknownAuthoritySet","inputs":[]}],"bytecode":{"object":"0x60c03461008a57601f611bac38819003918201601f19168301916001600160401b0383118484101761008e57808492604094855283398101031261008a578051906001600160a01b038216820361008a57602001519060a052608052604051611b0990816100a382396080518181816107860152610cd5015260a05181818161059e0152610c8f0152f35b5f80fd5b634e487b7160e01b5f52604160045260245ffdfe60806040526004361015610011575f80fd5b5f3560e01c806301ffc9a7146100745780632a692d731461006f5780632b7ac3f31461006a5780637d755598146100655780637ddc907d146100605763f7e83aee1461005b575f80fd5b6107a9565b61076f565b6106cb565b610589565b6104ad565b346100e45760203660031901126100e45760043563ffffffff60e01b81168091036100e457630faeaab360e31b81149081156100d3575b81156100c2575b501515608052607f1960a0016080f35b6301ffc9a760e01b149050816100b2565b637bf41d7760e11b811491506100ab565b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b604081019081106001600160401b0382111761011757604052565b6100e8565b606081019081106001600160401b0382111761011757604052565b60a081019081106001600160401b0382111761011757604052565b608081019081106001600160401b0382111761011757604052565b90601f801991011681019081106001600160401b0382111761011757604052565b6040519061019d60408361016d565b565b6040519061019d60a08361016d565b6040519061019d60608361016d565b91908260409103126100e4576040516101d5816100fc565b6020808294803584520135910152565b359063ffffffff821682036100e457565b91908260609103126100e45760405161020e8161011c565b809280356001600160401b03811681036100e45760409182918452610235602082016101e5565b60208501520135910152565b91909160e0818403126100e4576040519061025b82610137565b819381359160ff831683036100e45761029960c0926080948652610281602084016101e5565b602087015260408301356040870152606083016101f6565b60608501520135910152565b6001600160401b0381116101175760051b60200190565b6001600160401b03811161011757601f01601f191660200190565b81601f820112156100e4578035906102ee826102bc565b926102fc604051948561016d565b828452602083830101116100e457815f926020809301838601378301015290565b9080601f830112156100e457813591610335836102a5565b92610343604051948561016d565b80845260208085019160051b830101918383116100e45760208101915b83831061036f57505050505090565b82356001600160401b0381116100e4578201906040828703601f1901126100e4576040519061039d826100fc565b602083013582526040830135916001600160401b0383116100e4576103ca886020809695819601016102d7565b83820152815201920191610360565b919060a0838203126100e4576040516103f181610137565b8093803582526020810135602083015260408101356040830152606081013560608301526080810135906001600160401b0382116100e4570182601f820112156100e457803590610441826102a5565b9361044f604051958661016d565b82855260208086019360061b830101918183116100e457602001925b82841061047c575050505060800152565b6040848303126100e45760206040918251610496816100fc565b86358152828701358382015281520193019261046b565b346100e45760403660031901126100e4576004356001600160401b0381116100e45761016060031982360301126100e457604051906104eb82610152565b6104f836826004016101bd565b82526105073660448301610241565b60208301526101248101356001600160401b0381116100e457610530906004369184010161031d565b60408301526101448101356001600160401b0381116100e457606091600461055b92369201016102d7565b9101526024356001600160401b0381116100e45761057d9036906004016103d9565b005b5f9103126100e457565b346100e4575f3660031901126100e4576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b9181601f840112156100e4578235916001600160401b0383116100e457602083818601950101116100e457565b60406003198201126100e4576004356001600160401b0381116100e45781610624916004016105cd565b92909291602435906001600160401b0382116100e457610646916004016105cd565b9091565b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b90602080835192838152019201905f5b81811061068b5750505090565b909192602060a06001926040808851805184528581015186850152015180518284015284810151606084015201516080820152019401910191909161067e565b346100e45761075d61073b61076b61074961072a6106fa6107036106ee366105fa565b94918391930190610824565b92810190610871565b916040949394519461071486610152565b8552602085015260408401526060830152610b97565b9190604051948591602083016108d8565b03601f19810185528461016d565b60405193849360408552604085019061064a565b90838203602085015261066e565b0390f35b346100e4575f3660031901126100e45760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346100e45761080c6107c36106fa6107036106ee366105fa565b61081a6001600160401b036060604051946107f3866107e583602083016108d8565b03601f19810188528761016d565b015151169160405194859460608652606086019061064a565b90848203602086015261066e565b9060408301520390f35b90610100828203126100e4576108699060a06040519361084385610152565b803585526020810135602086015261085e83604083016101f6565b6040860152016101f6565b606082015290565b90610160828203126100e45761088781836101bd565b926108958260408501610241565b926101208101356001600160401b0381116100e457836108b691830161031d565b926101408201356001600160401b0381116100e4576108d592016102d7565b90565b61019d9092919260a06060610100830195805184526020810151602085015261092c60408201516040860190604080916001600160401b03815116845263ffffffff60208201511660208501520151910152565b0151910190604080916001600160401b03815116845263ffffffff60208201511660208501520151910152565b604051906109668261011c565b5f6040838281528260208201520152565b6040519061098482610152565b815f81525f6020820152610996610959565b604082015260606109a5610959565b910152565b604051906109b960208361016d565b5f80835282815b8281106109cc57505050565b6020906040516109db8161011c565b5f81525f838201526109eb610959565b6040820152828285010152016109c0565b90610a06826102a5565b610a13604051918261016d565b8281528092610a24601f19916102a5565b01905f5b828110610a3457505050565b602090604051610a438161011c565b5f81525f83820152610a53610959565b604082015282828501015201610a28565b90610a6e826102a5565b610a7b604051918261016d565b8281528092610a8c601f19916102a5565b01905f5b828110610a9c57505050565b602090604051610aab816100fc565b5f81525f8382015282828501015201610a90565b634e487b7160e01b5f52603260045260245ffd5b8051821015610ae75760209160051b010190565b610abf565b9060208252602060e0608060c08501938051848701528381015160408701526040810151606087015260608101518287015201519360a0808201528451809452019201905f5b818110610b3f5750505090565b8251805185526020908101518186015260409094019390920191600101610b32565b91610b7e906108d59492845260606020850152606084019061064a565b91604081840391015261064a565b6040513d5f823e3d90fd5b919091610ba2610977565b508251815181511115610e9c57610bb7610959565b5060208101516060830190610be4610bd883516001600160401b0390511690565b6001600160401b031690565b8103610e67575080515b6040860195865151610bff81610a64565b905f5b818110610e13575050610c84610c76916040610c25602087015163ffffffff1690565b950151908751602086019663ffffffff610c3f8951610f30565b6020815191012091610c4f61019f565b95865216602085015260408401526060830152608082015260405192839160208301610aec565b03601f19810183528261016d565b606060018060a01b037f000000000000000000000000000000000000000000000000000000000000000016920151823b156100e45760405163020a49e360e51b8152925f92849283918291610cfd917f000000000000000000000000000000000000000000000000000000000000000060048501610b61565b03915afa8015610e0e57610df4575b50855151610d19816109fc565b965f5b828110610d7e575050815160600151516001600160401b03169050908251916001600160401b03610d57610bd885516001600160401b031690565b911611610d69575b5050505181529190565b606091604086015251015190525f8080610d5f565b610d89818351610ad3565b5190610d9860208301516111f2565b916020830190815115610de557610db060019461133e565b90519151610dbc6101ae565b92835260208301526040820152610dd3828c610ad3565b52610dde818b610ad3565b5001610d1c565b63b4eb9e5160e01b5f5260045ffd5b80610e025f610e089361016d565b8061057f565b5f610d0c565b610b8c565b808a6020610e3183610e286001968551610ad3565b51519351610ad3565b51015160208151910120610e4361018e565b9182526020820152610e558286610ad3565b52610e608185610ad3565b5001610c02565b6040840190610e82610bd883516001600160401b0390511690565b03610e8d5751610bee565b637202e68560e11b5f5260045ffd5b5091506108d56109aa565b805191908290602001825e015f815290565b949291969593909660405197889660208801610ed491610ea7565b9063ffffffff60e01b168152600401610eec91610ea7565b916001600160401b0360c01b16825263ffffffff60e01b166008820152600c01610f1591610ea7565b610f1e91610ea7565b03601f198101835261019d908361016d565b6110e36110c0610f6d6108d593610f7b610f4b825160ff1690565b60405160f89190911b6001600160f81b03191660208201529283906021820190565b03601f19810184528361016d565b610f6d610fcc610f92602084015163ffffffff1690565b63ff00ff00600882811b9190911691901c62ff00ff1617601081811b63ffff00001691901c61ffff161760e01b6001600160e01b03191690565b610fe760408401516040519384916020830160209181520190565b6060830151936110f1608061109061100688516001600160401b031690565b67ffffffffffff000067ff00ff00ff00ff0066ff00ff00ff00ff8360081c169260081b169165ffff0000ffff65ffff0000ff0065ffffffffffff67ffff0000ffff0000861666ff0000ffff000085161760101c16941691161760101b161767ffffffff0000000063ffffffff8260201c169160201b166001600160401b0360c01b911760c01b1690565b956110ce60406110aa610f9260208c015163ffffffff1690565b9901516040519a8b916020830160209181520190565b03601f1981018b528a61016d565b01516040519889916020830160209181520190565b03601f19810189528861016d565b610eb9565b6040519061110382610137565b60606080835f81525f60208201525f60408201525f838201520152565b6040519061112d826100fc565b60606020835f81520152565b6040519061012082018281106001600160401b03821117610117576040525f61010083828152611167611120565b602082015282604082015261117a611120565b606082015282608082015261118d611120565b60a08201528260c0820152606060e08201520152565b906111ad826102a5565b6111ba604051918261016d565b82815280926111cb601f19916102a5565b01905f5b8281106111db57505050565b6020906111e6611139565b828285010152016111cf565b6111fa6110f6565b5061120361018e565b9081525f602082015261121d611218826114d1565b611581565b9061122781611671565b611233611218836114d1565b61123f611218846114d1565b9161124984611671565b611252816111a3565b945f5b8281106112815750505061126761019f565b948552602085015260408401526060830152608082015290565b60019061128d836117ef565b60ff611297611139565b9116806112c35750600160c08201525b6112b1828a610ad3565b526112bc8189610ad3565b5001611255565b600481036112e75750600160408201526112dc8461186c565b60608201525b6112a7565b6005810361130a5750600160808201526113008461186c565b60a08201526112a7565b6006810361132a5750600181526113208461186c565b60208201526112a7565b6008036112e25760016101008201526112a7565b611346610959565b505f5f925f5f5b608085018051805183101561147757604061136b8461137393610ad3565b510151151590565b8061144f575b611406575b61138e604061136b848451610ad3565b806113cd575b6113a2575b5060010161134d565b8192506113c5602060606113bb60809560019551610ad3565b51015101516119a7565b929150611399565b50634953544d60e01b63ffffffff60e01b6113ff60606113ee868651610ad3565b510151516001600160e01b03191690565b1614611394565b955092506114296112186020606061141f878a51610ad3565b5101510151611948565b926114496112186020606061143f858b51610ad3565b510151015161197a565b9561137e565b5063049534d560e41b63ffffffff60e01b61147060606113ee868651610ad3565b1614611379565b50505092509290821561149c5761148c6101ae565b9283526020830152604082015290565b633eba99d160e21b5f5260045ffd5b634e487b7160e01b5f52601160045260245ffd5b919082018092116114cc57565b6114ab565b60208101908151602081018091116114cc57815151106100e4576020905181835182010191829101116114cc57602061150991611a1e565b90805190602082018092116114cc575290565b90602082019182518281018091116114cc57815151106100e457811561156a576020905181845182010191829101116114cc578161155991611a1e565b9180519182018092116114cc575290565b50505060405161157b60208261016d565b5f815290565b6020815110611591576020015190565b60405162461bcd60e51b8152602060048201526024808201527f42797465733a3a20746f427974657333323a206461746120697320746f20736860448201526337b93a1760e11b6064820152608490fd5b60ff60049116019060ff82116114cc57565b156115fb57565b60405162461bcd60e51b815260206004820152602860248201527f756e657870656374656420707265666978206465636f64696e6720436f6d706160448201526731ba1e2ab4b73a1f60c11b6064820152608490fd5b906001600160401b03809116911601906001600160401b0382116114cc57565b61167a816117ef565b600381168061169657506108d5915060021c603f165b60ff1690565b600181036116db5750610bd8906116d56116906116cb6116bb6116906108d5976117ef565b60061b67ffffffffffffffc01690565b9260021c603f1690565b90611651565b6002810361175a57506117519061174460ff84611735826116fe6108d5986117ef565b958161172481611716611710886117ef565b976117ef565b991660081b63ffffff001690565b911617921660101b63ffff00001690565b17921660181b63ff0000001690565b1760021c633fffffff1690565b63ffffffff1690565b600303611799576108d59160ff61178061177b61179494603f9060021c1690565b6115e2565b169061178f60088311156115f4565b61151c565b6119a7565b60405162461bcd60e51b815260206004820152601a60248201527f436f64652073686f756c6420626520756e726561636861626c650000000000006044820152606490fd5b908151811015610ae7570160200190565b60208101908151600181018091116114cc5781515110611838575181516001600160f81b03199161182091906117de565b511660f81c90805190600182018092116114cc575290565b60405162461bcd60e51b815260206004820152600c60248201526b4f7574206f662072616e676560a01b6044820152606490fd5b611874611120565b5060208101908151600481018091116114cc57815151106100e4576020815181845182010191829101116114cc5760046118ad91611a1e565b91805190600482018092116114cc57525f915f905b60048210611902575050806118d96118df92611671565b9061151c565b6118fa6118ea61018e565b6001600160e01b03199093168352565b602082015290565b90926001600160f81b031961191785846117de565b5116908460031b91858304600814861517156114cc576001926001600160e01b0319918216901c16179301906118c2565b80516020116100e4576020806108d59201611a1e565b60200390602082116114cc57565b5f198101919082116114cc57565b8051806020116100e457601f1981019081116114cc57604082019160200182106114cc576108d591611a1e565b80515f91815b6119b657505090565b90915f1983018381116114cc576119cd81846117de565b5160f81c90600381901b906001600160fd1b038116036114cc5760ff81116114cc576001901b908181029181830414901517156114cc57611a0d916114bf565b9180156114cc575f190190816119ad565b919091611a2a836102bc565b611a37604051918261016d565b838152611a43846102bc565b602082019190601f1901368337939091905b6020811015611a945780611a7557505f19905b5182518216911916179052565b611a89611a84611a8e9261195e565b611ac4565b61196c565b90611a68565b909182518152602081018091116114cc5791602081018091116114cc5790601f19810190811115611a55576114ab565b601f81116114cc576101000a9056fea2646970667358221220af0eb58afb4c67b33aae2b305e264f698dd0d024e1f68d04717a9b8769cf95a464736f6c634300081e0033","sourceMap":"2019:5864:151:-:0;;;;;;;;;;;;;-1:-1:-1;;2019:5864:151;;;;-1:-1:-1;;;;;2019:5864:151;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;2019:5864:151;;;;;;;;;2469:12;;;2491:20;;2019:5864;;;;;;;;2491:20;2019:5864;;;;;;;;;;2469:12;2019:5864;;;;;;;;;;;;-1:-1:-1;2019:5864:151;;;;;;-1:-1:-1;2019:5864:151;;;;;-1:-1:-1;2019:5864:151","linkReferences":{}},"deployedBytecode":{"object":"0x60806040526004361015610011575f80fd5b5f3560e01c806301ffc9a7146100745780632a692d731461006f5780632b7ac3f31461006a5780637d755598146100655780637ddc907d146100605763f7e83aee1461005b575f80fd5b6107a9565b61076f565b6106cb565b610589565b6104ad565b346100e45760203660031901126100e45760043563ffffffff60e01b81168091036100e457630faeaab360e31b81149081156100d3575b81156100c2575b501515608052607f1960a0016080f35b6301ffc9a760e01b149050816100b2565b637bf41d7760e11b811491506100ab565b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b604081019081106001600160401b0382111761011757604052565b6100e8565b606081019081106001600160401b0382111761011757604052565b60a081019081106001600160401b0382111761011757604052565b608081019081106001600160401b0382111761011757604052565b90601f801991011681019081106001600160401b0382111761011757604052565b6040519061019d60408361016d565b565b6040519061019d60a08361016d565b6040519061019d60608361016d565b91908260409103126100e4576040516101d5816100fc565b6020808294803584520135910152565b359063ffffffff821682036100e457565b91908260609103126100e45760405161020e8161011c565b809280356001600160401b03811681036100e45760409182918452610235602082016101e5565b60208501520135910152565b91909160e0818403126100e4576040519061025b82610137565b819381359160ff831683036100e45761029960c0926080948652610281602084016101e5565b602087015260408301356040870152606083016101f6565b60608501520135910152565b6001600160401b0381116101175760051b60200190565b6001600160401b03811161011757601f01601f191660200190565b81601f820112156100e4578035906102ee826102bc565b926102fc604051948561016d565b828452602083830101116100e457815f926020809301838601378301015290565b9080601f830112156100e457813591610335836102a5565b92610343604051948561016d565b80845260208085019160051b830101918383116100e45760208101915b83831061036f57505050505090565b82356001600160401b0381116100e4578201906040828703601f1901126100e4576040519061039d826100fc565b602083013582526040830135916001600160401b0383116100e4576103ca886020809695819601016102d7565b83820152815201920191610360565b919060a0838203126100e4576040516103f181610137565b8093803582526020810135602083015260408101356040830152606081013560608301526080810135906001600160401b0382116100e4570182601f820112156100e457803590610441826102a5565b9361044f604051958661016d565b82855260208086019360061b830101918183116100e457602001925b82841061047c575050505060800152565b6040848303126100e45760206040918251610496816100fc565b86358152828701358382015281520193019261046b565b346100e45760403660031901126100e4576004356001600160401b0381116100e45761016060031982360301126100e457604051906104eb82610152565b6104f836826004016101bd565b82526105073660448301610241565b60208301526101248101356001600160401b0381116100e457610530906004369184010161031d565b60408301526101448101356001600160401b0381116100e457606091600461055b92369201016102d7565b9101526024356001600160401b0381116100e45761057d9036906004016103d9565b005b5f9103126100e457565b346100e4575f3660031901126100e4576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b9181601f840112156100e4578235916001600160401b0383116100e457602083818601950101116100e457565b60406003198201126100e4576004356001600160401b0381116100e45781610624916004016105cd565b92909291602435906001600160401b0382116100e457610646916004016105cd565b9091565b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b90602080835192838152019201905f5b81811061068b5750505090565b909192602060a06001926040808851805184528581015186850152015180518284015284810151606084015201516080820152019401910191909161067e565b346100e45761075d61073b61076b61074961072a6106fa6107036106ee366105fa565b94918391930190610824565b92810190610871565b916040949394519461071486610152565b8552602085015260408401526060830152610b97565b9190604051948591602083016108d8565b03601f19810185528461016d565b60405193849360408552604085019061064a565b90838203602085015261066e565b0390f35b346100e4575f3660031901126100e45760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346100e45761080c6107c36106fa6107036106ee366105fa565b61081a6001600160401b036060604051946107f3866107e583602083016108d8565b03601f19810188528761016d565b015151169160405194859460608652606086019061064a565b90848203602086015261066e565b9060408301520390f35b90610100828203126100e4576108699060a06040519361084385610152565b803585526020810135602086015261085e83604083016101f6565b6040860152016101f6565b606082015290565b90610160828203126100e45761088781836101bd565b926108958260408501610241565b926101208101356001600160401b0381116100e457836108b691830161031d565b926101408201356001600160401b0381116100e4576108d592016102d7565b90565b61019d9092919260a06060610100830195805184526020810151602085015261092c60408201516040860190604080916001600160401b03815116845263ffffffff60208201511660208501520151910152565b0151910190604080916001600160401b03815116845263ffffffff60208201511660208501520151910152565b604051906109668261011c565b5f6040838281528260208201520152565b6040519061098482610152565b815f81525f6020820152610996610959565b604082015260606109a5610959565b910152565b604051906109b960208361016d565b5f80835282815b8281106109cc57505050565b6020906040516109db8161011c565b5f81525f838201526109eb610959565b6040820152828285010152016109c0565b90610a06826102a5565b610a13604051918261016d565b8281528092610a24601f19916102a5565b01905f5b828110610a3457505050565b602090604051610a438161011c565b5f81525f83820152610a53610959565b604082015282828501015201610a28565b90610a6e826102a5565b610a7b604051918261016d565b8281528092610a8c601f19916102a5565b01905f5b828110610a9c57505050565b602090604051610aab816100fc565b5f81525f8382015282828501015201610a90565b634e487b7160e01b5f52603260045260245ffd5b8051821015610ae75760209160051b010190565b610abf565b9060208252602060e0608060c08501938051848701528381015160408701526040810151606087015260608101518287015201519360a0808201528451809452019201905f5b818110610b3f5750505090565b8251805185526020908101518186015260409094019390920191600101610b32565b91610b7e906108d59492845260606020850152606084019061064a565b91604081840391015261064a565b6040513d5f823e3d90fd5b919091610ba2610977565b508251815181511115610e9c57610bb7610959565b5060208101516060830190610be4610bd883516001600160401b0390511690565b6001600160401b031690565b8103610e67575080515b6040860195865151610bff81610a64565b905f5b818110610e13575050610c84610c76916040610c25602087015163ffffffff1690565b950151908751602086019663ffffffff610c3f8951610f30565b6020815191012091610c4f61019f565b95865216602085015260408401526060830152608082015260405192839160208301610aec565b03601f19810183528261016d565b606060018060a01b037f000000000000000000000000000000000000000000000000000000000000000016920151823b156100e45760405163020a49e360e51b8152925f92849283918291610cfd917f000000000000000000000000000000000000000000000000000000000000000060048501610b61565b03915afa8015610e0e57610df4575b50855151610d19816109fc565b965f5b828110610d7e575050815160600151516001600160401b03169050908251916001600160401b03610d57610bd885516001600160401b031690565b911611610d69575b5050505181529190565b606091604086015251015190525f8080610d5f565b610d89818351610ad3565b5190610d9860208301516111f2565b916020830190815115610de557610db060019461133e565b90519151610dbc6101ae565b92835260208301526040820152610dd3828c610ad3565b52610dde818b610ad3565b5001610d1c565b63b4eb9e5160e01b5f5260045ffd5b80610e025f610e089361016d565b8061057f565b5f610d0c565b610b8c565b808a6020610e3183610e286001968551610ad3565b51519351610ad3565b51015160208151910120610e4361018e565b9182526020820152610e558286610ad3565b52610e608185610ad3565b5001610c02565b6040840190610e82610bd883516001600160401b0390511690565b03610e8d5751610bee565b637202e68560e11b5f5260045ffd5b5091506108d56109aa565b805191908290602001825e015f815290565b949291969593909660405197889660208801610ed491610ea7565b9063ffffffff60e01b168152600401610eec91610ea7565b916001600160401b0360c01b16825263ffffffff60e01b166008820152600c01610f1591610ea7565b610f1e91610ea7565b03601f198101835261019d908361016d565b6110e36110c0610f6d6108d593610f7b610f4b825160ff1690565b60405160f89190911b6001600160f81b03191660208201529283906021820190565b03601f19810184528361016d565b610f6d610fcc610f92602084015163ffffffff1690565b63ff00ff00600882811b9190911691901c62ff00ff1617601081811b63ffff00001691901c61ffff161760e01b6001600160e01b03191690565b610fe760408401516040519384916020830160209181520190565b6060830151936110f1608061109061100688516001600160401b031690565b67ffffffffffff000067ff00ff00ff00ff0066ff00ff00ff00ff8360081c169260081b169165ffff0000ffff65ffff0000ff0065ffffffffffff67ffff0000ffff0000861666ff0000ffff000085161760101c16941691161760101b161767ffffffff0000000063ffffffff8260201c169160201b166001600160401b0360c01b911760c01b1690565b956110ce60406110aa610f9260208c015163ffffffff1690565b9901516040519a8b916020830160209181520190565b03601f1981018b528a61016d565b01516040519889916020830160209181520190565b03601f19810189528861016d565b610eb9565b6040519061110382610137565b60606080835f81525f60208201525f60408201525f838201520152565b6040519061112d826100fc565b60606020835f81520152565b6040519061012082018281106001600160401b03821117610117576040525f61010083828152611167611120565b602082015282604082015261117a611120565b606082015282608082015261118d611120565b60a08201528260c0820152606060e08201520152565b906111ad826102a5565b6111ba604051918261016d565b82815280926111cb601f19916102a5565b01905f5b8281106111db57505050565b6020906111e6611139565b828285010152016111cf565b6111fa6110f6565b5061120361018e565b9081525f602082015261121d611218826114d1565b611581565b9061122781611671565b611233611218836114d1565b61123f611218846114d1565b9161124984611671565b611252816111a3565b945f5b8281106112815750505061126761019f565b948552602085015260408401526060830152608082015290565b60019061128d836117ef565b60ff611297611139565b9116806112c35750600160c08201525b6112b1828a610ad3565b526112bc8189610ad3565b5001611255565b600481036112e75750600160408201526112dc8461186c565b60608201525b6112a7565b6005810361130a5750600160808201526113008461186c565b60a08201526112a7565b6006810361132a5750600181526113208461186c565b60208201526112a7565b6008036112e25760016101008201526112a7565b611346610959565b505f5f925f5f5b608085018051805183101561147757604061136b8461137393610ad3565b510151151590565b8061144f575b611406575b61138e604061136b848451610ad3565b806113cd575b6113a2575b5060010161134d565b8192506113c5602060606113bb60809560019551610ad3565b51015101516119a7565b929150611399565b50634953544d60e01b63ffffffff60e01b6113ff60606113ee868651610ad3565b510151516001600160e01b03191690565b1614611394565b955092506114296112186020606061141f878a51610ad3565b5101510151611948565b926114496112186020606061143f858b51610ad3565b510151015161197a565b9561137e565b5063049534d560e41b63ffffffff60e01b61147060606113ee868651610ad3565b1614611379565b50505092509290821561149c5761148c6101ae565b9283526020830152604082015290565b633eba99d160e21b5f5260045ffd5b634e487b7160e01b5f52601160045260245ffd5b919082018092116114cc57565b6114ab565b60208101908151602081018091116114cc57815151106100e4576020905181835182010191829101116114cc57602061150991611a1e565b90805190602082018092116114cc575290565b90602082019182518281018091116114cc57815151106100e457811561156a576020905181845182010191829101116114cc578161155991611a1e565b9180519182018092116114cc575290565b50505060405161157b60208261016d565b5f815290565b6020815110611591576020015190565b60405162461bcd60e51b8152602060048201526024808201527f42797465733a3a20746f427974657333323a206461746120697320746f20736860448201526337b93a1760e11b6064820152608490fd5b60ff60049116019060ff82116114cc57565b156115fb57565b60405162461bcd60e51b815260206004820152602860248201527f756e657870656374656420707265666978206465636f64696e6720436f6d706160448201526731ba1e2ab4b73a1f60c11b6064820152608490fd5b906001600160401b03809116911601906001600160401b0382116114cc57565b61167a816117ef565b600381168061169657506108d5915060021c603f165b60ff1690565b600181036116db5750610bd8906116d56116906116cb6116bb6116906108d5976117ef565b60061b67ffffffffffffffc01690565b9260021c603f1690565b90611651565b6002810361175a57506117519061174460ff84611735826116fe6108d5986117ef565b958161172481611716611710886117ef565b976117ef565b991660081b63ffffff001690565b911617921660101b63ffff00001690565b17921660181b63ff0000001690565b1760021c633fffffff1690565b63ffffffff1690565b600303611799576108d59160ff61178061177b61179494603f9060021c1690565b6115e2565b169061178f60088311156115f4565b61151c565b6119a7565b60405162461bcd60e51b815260206004820152601a60248201527f436f64652073686f756c6420626520756e726561636861626c650000000000006044820152606490fd5b908151811015610ae7570160200190565b60208101908151600181018091116114cc5781515110611838575181516001600160f81b03199161182091906117de565b511660f81c90805190600182018092116114cc575290565b60405162461bcd60e51b815260206004820152600c60248201526b4f7574206f662072616e676560a01b6044820152606490fd5b611874611120565b5060208101908151600481018091116114cc57815151106100e4576020815181845182010191829101116114cc5760046118ad91611a1e565b91805190600482018092116114cc57525f915f905b60048210611902575050806118d96118df92611671565b9061151c565b6118fa6118ea61018e565b6001600160e01b03199093168352565b602082015290565b90926001600160f81b031961191785846117de565b5116908460031b91858304600814861517156114cc576001926001600160e01b0319918216901c16179301906118c2565b80516020116100e4576020806108d59201611a1e565b60200390602082116114cc57565b5f198101919082116114cc57565b8051806020116100e457601f1981019081116114cc57604082019160200182106114cc576108d591611a1e565b80515f91815b6119b657505090565b90915f1983018381116114cc576119cd81846117de565b5160f81c90600381901b906001600160fd1b038116036114cc5760ff81116114cc576001901b908181029181830414901517156114cc57611a0d916114bf565b9180156114cc575f190190816119ad565b919091611a2a836102bc565b611a37604051918261016d565b838152611a43846102bc565b602082019190601f1901368337939091905b6020811015611a945780611a7557505f19905b5182518216911916179052565b611a89611a84611a8e9261195e565b611ac4565b61196c565b90611a68565b909182518152602081018091116114cc5791602081018091116114cc5790601f19810190811115611a55576114ab565b601f81116114cc576101000a9056fea2646970667358221220af0eb58afb4c67b33aae2b305e264f698dd0d024e1f68d04717a9b8769cf95a464736f6c634300081e0033","sourceMap":"2019:5864:151:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;;;;;-1:-1:-1;;2019:5864:151;;;;;;;;;;;;;;;;-1:-1:-1;;;2693:43:151;;;:92;;;;2019:5864;2693:144;;;;2019:5864;-1:-1:-1;2019:5864:151;;;;-1:-1:-1;;2019:5864:151;;;;2693:144;-1:-1:-1;;;829:40:62;;-1:-1:-1;2693:144:151;;;:92;-1:-1:-1;;;2740:45:151;;;-1:-1:-1;2693:92:151;;2019:5864;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;2019:5864:151;;;;;;;:::o;:::-;;:::i;:::-;;;;;;;-1:-1:-1;;;;;2019:5864:151;;;;;;;:::o;:::-;;;;;;;-1:-1:-1;;;;;2019:5864:151;;;;;;;:::o;:::-;;;;;;;-1:-1:-1;;;;;2019:5864:151;;;;;;;:::o;:::-;;;;;;;;;;;;;-1:-1:-1;;;;;2019:5864:151;;;;;;;:::o;:::-;5941:13;2019:5864;;;5941:13;2019:5864;;:::i;:::-;:::o;:::-;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;:::i;:::-;;;;;-1:-1:-1;;;;;2019:5864:151;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;:::o;:::-;-1:-1:-1;;;;;2019:5864:151;;;;;;;;;:::o;:::-;-1:-1:-1;;;;;2019:5864:151;;;;;;-1:-1:-1;;2019:5864:151;;;;:::o;:::-;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;;;;;;-1:-1:-1;2019:5864:151;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;-1:-1:-1;;;;;2019:5864:151;;;;;;;;;;;-1:-1:-1;;2019:5864:151;;;;;;;;;;:::i;:::-;;;;;;;;;;;;-1:-1:-1;;;;;2019:5864:151;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;2019:5864:151;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;2019:5864:151;;;;;;-1:-1:-1;;;;;2019:5864:151;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;;:::i;:::-;;;;;;;;;-1:-1:-1;;;;;2019:5864:151;;;;;;;;;;;;;:::i;:::-;;;;;;;;;-1:-1:-1;;;;;2019:5864:151;;;;;;;;;;;;;;:::i;:::-;;;;;;-1:-1:-1;;;;;2019:5864:151;;;;;;;;;;;:::i;:::-;;;;;;;;;:::o;:::-;;;;;;-1:-1:-1;;2019:5864:151;;;;;;2217:38;-1:-1:-1;;;;;2019:5864:151;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;2019:5864:151;;;;;;;;;;;;;;;:::o;:::-;;-1:-1:-1;;2019:5864:151;;;;;;;-1:-1:-1;;;;;2019:5864:151;;;;;;;;;;:::i;:::-;;;;;;;;-1:-1:-1;;;;;2019:5864:151;;;;;;;;;:::i;:::-;;;:::o;:::-;;;;;;;;;;;;;;;;;-1:-1:-1;2019:5864:151;;;;;;;;-1:-1:-1;;2019:5864:151;;;;:::o;:::-;;;;;;;;;;;;;;-1:-1:-1;2019:5864:151;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4961:20;2019:5864;4961:20;4901:41;4318:47;4562:89;2019:5864;;;:::i;:::-;4318:47;;;;;;;;:::i;:::-;4562:89;;;;;:::i;:::-;2019:5864;;;;;;;;;;:::i;:::-;;;4705:91;;;2019:5864;;4705:91;;2019:5864;4705:91;;;2019:5864;4901:41;:::i;:::-;2019:5864;;;;4961:20;;;4705:91;4961:20;;;:::i;:::-;;2019:5864;;4961:20;;;;;;:::i;:::-;2019:5864;;;;;;;;;;;;;:::i;:::-;;;;;4705:91;2019:5864;;;;:::i;:::-;;;;;;;;;;-1:-1:-1;;2019:5864:151;;;;;;;2141:40;2019:5864;;;;;;;;3814:41;3237:48;3482:82;2019:5864;;;:::i;3814:41::-;2019:5864;-1:-1:-1;;;;;3618:91:151;2019:5864;;3874:20;;;;;3618:91;3874:20;;;:::i;:::-;;2019:5864;;3874:20;;;;;;:::i;:::-;3911:25;;2019:5864;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;:::o;:::-;;;;;;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;-1:-1:-1;;;;;2019:5864:151;;;;;;;;;;:::i;:::-;;;;;;-1:-1:-1;;;;;2019:5864:151;;;;;;;;:::i;:::-;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;2019:5864:151;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;2019:5864:151;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;2019:5864:151;;;;;;;;;;;;:::o;:::-;;;;;;;:::i;:::-;;-1:-1:-1;2019:5864:151;;-1:-1:-1;2019:5864:151;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;:::o;:::-;;;;;;;;:::i;:::-;5320:16;2019:5864;;;;5320:16;2019:5864;;;;;;;;;:::o;:::-;;;;;;;;:::i;:::-;5320:16;2019:5864;;5320:16;2019:5864;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;;;;:::i;:::-;;;-1:-1:-1;2019:5864:151;;;;;;;;;:::o;:::-;;;;;;;;:::i;:::-;-1:-1:-1;2019:5864:151;;-1:-1:-1;2019:5864:151;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;;;;:::i;:::-;;;-1:-1:-1;2019:5864:151;;;;;;;;;:::o;:::-;;;;;;;;:::i;:::-;-1:-1:-1;2019:5864:151;;-1:-1:-1;2019:5864:151;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;:::i;:::-;;;;;;;;;;5074:2671;;;;2019:5864;;:::i;:::-;5243:26;5320:16;;2019:5864;;;;-1:-1:-1;5386:51:151;5382:131;;2019:5864;;:::i;:::-;5576:25;;;;2019:5864;;5605:29;;;5576:61;5605:32;:29;;-1:-1:-1;;;;;2019:5864:151;;;;;5605:32;-1:-1:-1;;;;;2019:5864:151;;;5576:61;;;5605:29;;5665;;;5572:337;5941:13;;;;;;2019:5864;6010:38;;;:::i;:::-;6063:13;-1:-1:-1;6078:15:151;;;;;;6382:13;;6310:315;;6382:13;5941;2019:5864;5576:25;6382:13;;2019:5864;;;;;;6431:14;;2019:5864;;;;5576:25;6585:13;;;2019:5864;6572:27;6585:13;;6572:27;:::i;:::-;5576:25;2019:5864;;;;6562:38;2019:5864;;;:::i;:::-;;;;;5576:25;6334:281;;2019:5864;5941:13;6334:281;;2019:5864;;6334:281;;2019:5864;6334:281;;;2019:5864;5941:13;2019:5864;6310:315;;;5576:25;6310:315;;;:::i;:::-;;2019:5864;;6310:315;;;;;;:::i;:::-;2019:5864;;;;;;6635:8;2019:5864;6687:11;;;6635:64;;;;;5941:13;2019:5864;-1:-1:-1;;;6635:64:151;;2019:5864;-1:-1:-1;;2019:5864:151;;;;;;6635:64;;6656:15;6635:64;;;;:::i;:::-;;;;;;;;;;;6058:214;6730:13;;;2019:5864;6803:34;;;:::i;:::-;6852:13;-1:-1:-1;6867:13:151;;;;;;-1:-1:-1;;7397:13:151;;2019:5864;7397:30;;2019:5864;-1:-1:-1;;;;;2019:5864:151;;-1:-1:-1;7433:29:151;;;2019:5864;-1:-1:-1;;;;;7397:68:151;2019:5864;;;-1:-1:-1;;;;;2019:5864:151;;;7397:68;2019:5864;;7397:68;7393:239;;6847:536;2019:5864;;;;;;7702:36;5074:2671;:::o;7393:239::-;2019:5864;7481:32;5941:13;7481:32;;:64;7591:13;:30;;7559:62;;7393:239;;;;;6882:3;6931:16;:13;;;:16;:::i;:::-;;7003:11;6984:31;5576:25;7003:11;;;6984:31;:::i;:::-;7033:13;5576:25;7033:13;;2019:5864;;;7033:18;7029:52;;7137:24;2019:5864;7137:24;;:::i;:::-;2019:5864;;;;;;:::i;:::-;;;;5576:25;7231:96;;2019:5864;5941:13;7231:96;;2019:5864;7341:31;;;;:::i;:::-;;;;;;:::i;:::-;;2019:5864;6852:13;;7029:52;7060:21;;;-1:-1:-1;7060:21:151;6635:64;-1:-1:-1;7060:21:151;6635:64;;;-1:-1:-1;6635:64:151;;;:::i;:::-;;;:::i;:::-;;;;;;:::i;6095:3::-;6169:13;;5576:25;6222:16;6169:13;:16;2019:5864;6169:13;;;:16;:::i;:::-;;2019:5864;6222:13;;:16;:::i;:::-;;:23;;5576:25;2019:5864;;;;6212:34;2019:5864;;:::i;:::-;;;;5576:25;6127:134;;2019:5864;6114:147;;;;:::i;:::-;;;;;;:::i;:::-;;2019:5864;6063:13;;5572:337;5744:32;;;;5715:64;5744:35;:32;;-1:-1:-1;;;;;2019:5864:151;;;;;5715:64;;5744:32;;5807;5572:337;;5711:198;5877:21;;;-1:-1:-1;5877:21:151;;-1:-1:-1;5877:21:151;5382:131;5475:26;;;;;:::i;2019:5864::-;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;:::i;:::-;;-1:-1:-1;;;;;2019:5864:151;;;;;;;;;;;;;;;;;;:::i;:::-;;;;:::i;:::-;;;;;;;;;;;;:::i;2305:494:148:-;2754:28;2696:44;2434:30;2408:384;2305:494;2434:30;2019:5864:151;;;;;;;;;;;;;;;-1:-1:-1;;;;;;2019:5864:151;2434:30:148;;;2019:5864:151;;;;;;;;;2434:30:148;;2019:5864:151;;2434:30:148;;;;;;:::i;:::-;2530:33;2478:38;2019:5864:151;2434:30:148;2498:17;;2019:5864:151;;;;;;;;;;;;;;;;;;8200:10:78;2019:5864:151;8168:49:78;2019:5864:151;;;;;;;;;;;8266:21:78;2019:5864:151;;-1:-1:-1;;;;;;2019:5864:151;;8815:111:78;2478:38:148;2530:33;2019:5864:151;2547:15:148;;2019:5864:151;;;2530:33:148;;;2434:30;2530:33;;2019:5864:151;;;;;;;2530:33:148;2597:21;;;;2019:5864:151;2754:28:148;2771:10;2577:45;2019:5864:151;;;-1:-1:-1;;;;;2019:5864:151;;;;;7788:18:78;2019:5864:151;;;;;;;;;;7937:18:78;7933:22;2019:5864:151;7902:18:78;7898:22;;;;;;2019:5864:151;;;7932:30:78;7933:22;;;;2019:5864:151;;;7896:67:78;2019:5864:151;;;;;;8025:7:78;2019:5864:151;;;-1:-1:-1;;;;;2019:5864:151;;8012:21:78;;2019:5864:151;;;8698:111:78;;2577:45:148;2656:25;2696:44;2019:5864:151;2636:46:148;2019:5864:151;2434:30:148;2656:25;;2019:5864:151;;;;;2636:46:148;2713:26;;2019:5864:151;;;2696:44:148;;;2434:30;2696:44;;2019:5864:151;;;;;;;2696:44:148;;2019:5864:151;;2696:44:148;;;;;;:::i;:::-;2771:10;2019:5864:151;;;2754:28:148;;;2434:30;2754:28;;2019:5864:151;;;;;;;2754:28:148;;2019:5864:151;;2754:28:148;;;;;;:::i;:::-;2408:384;:::i;2019:5864:151:-;;;;;;;:::i;:::-;;;;-1:-1:-1;2019:5864:151;;-1:-1:-1;2019:5864:151;;;;-1:-1:-1;2019:5864:151;;;;-1:-1:-1;2019:5864:151;;;;;;:::o;:::-;;;;;;;:::i;:::-;;;;-1:-1:-1;2019:5864:151;;;;:::o;:::-;;;;;;;;;;-1:-1:-1;;;;;2019:5864:151;;;;;;;-1:-1:-1;2019:5864:151;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;:::o;:::-;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;;;;:::i;:::-;;;-1:-1:-1;2019:5864:151;;;;;;;;;:::o;:::-;;;;;:::i;:::-;;;;;;;;;;2849:1495:148;2019:5864:151;;:::i;:::-;;;;:::i;:::-;;;;2985:1:148;2966:21;;;2019:5864:151;3018:38:148;3034:21;;;:::i;:::-;3018:38;:::i;:::-;3088:35;;;;:::i;:::-;3153:38;3169:21;;;:::i;3153:38::-;3226;3242:21;;;:::i;3226:38::-;3292:35;;;;:::i;:::-;3363:20;;;:::i;:::-;3399:13;2985:1;3414:10;;;;;;2019:5864:151;;;;;:::i;:::-;;;;2966:21:148;4270:67;;2019:5864:151;;4270:67:148;;2019:5864:151;4270:67:148;;;2019:5864:151;4270:67:148;;;2019:5864:151;2849:1495:148;:::o;3426:3::-;2019:5864:151;3458:21:148;;;;:::i;:::-;2019:5864:151;;;:::i;:::-;;;3531:25:148;;;-1:-1:-1;2019:5864:151;3576:14:148;;;1506:1;3576:21;4223:19;;;;:::i;:::-;;;;;;:::i;:::-;;2019:5864:151;3399:13:148;;3527:683;1327:1;3622:29;;1327:1;;-1:-1:-1;2019:5864:151;;3671:18:148;;1506:1;3733:23;;;:::i;:::-;3714:16;;;:42;3618:592;3527:683;;3618:592;1377:1;3781:24;;1377:1;;-1:-1:-1;2019:5864:151;3825:13:148;;;1506:1;3877:23;;;:::i;:::-;3863:11;;;:37;3527:683;;3777:433;1433:1;3925:30;;1433:1;;-1:-1:-1;2019:5864:151;1506:1:148;;4039:23;;;:::i;:::-;2966:21;4019:17;;:43;3527:683;;3921:289;1506:1;4087:47;3777:433;4083:127;2019:5864:151;4154:34:148;;;1506:1;3527:683;;5508:967:152;2019:5864:151;;:::i;:::-;;-1:-1:-1;;5666:17:152;-1:-1:-1;;5739:3:152;5718:12;;;;;2019:5864:151;;5714:23:152;;;;;5762:27;:15;;:27;:15;;:::i;:::-;;:27;2019:5864:151;;;;;5762:27:152;:89;;;5739:3;5758:305;;5739:3;6081:27;5762;6081:15;:12;;;:15;:::i;:27::-;:89;;;5739:3;6077:196;;5739:3;-1:-1:-1;2019:5864:151;;5699:13:152;;6077:196;6227:12;;;6202:56;6227:30;:25;:15;5718:12;6227;2019:5864:151;6227:12:152;;:15;:::i;:::-;;:25;;:30;;6202:56;:::i;:::-;6077:196;;;;;6081:89;5133:14;;;;2019:5864:151;;;6112:37:152;:25;:15;:12;;;:15;:::i;:::-;;:25;;2019:5864:151;-1:-1:-1;;;;;;2019:5864:151;;;6112:37:152;2019:5864:151;6112:58:152;6081:89;;5758:305;5910:12;;;;5881:68;5897:51;5910:30;:25;:15;:12;;;:15;:::i;:::-;;:25;;:30;;5897:51;:::i;5881:68::-;6012:12;5983:65;5999:48;5910:30;:25;6012:15;:12;;;:15;:::i;:::-;;:25;;:30;;5999:48;:::i;5983:65::-;5758:305;;;5762:89;2019:5864:151;;;;;;;5793:37:152;:25;:15;:12;;;:15;:::i;:37::-;2019:5864:151;5793:58:152;5762:89;;5714:23;;;;;;;;6321:14;;6317:46;;2019:5864:151;;:::i;:::-;;;;6381:87:152;;;2019:5864:151;5762:27:152;6381:87;;2019:5864:151;5508:967:152;:::o;6317:46::-;6344:19;;;-1:-1:-1;6344:19:152;;-1:-1:-1;6344:19:152;2019:5864:151;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;:::i;2089:399:71:-;2966:21:148;2216:11:71;;2019:5864:151;;;2966:21:148;2019:5864:151;;;;;;;2237:9:71;;2019:5864:151;-1:-1:-1;2019:5864:151;;2966:21:148;2264:48:71;2351:9;2019:5864:151;;;;;;1938:75:72;;;;2019:5864:151;;;2966:21:148;2392:39:71;;;:::i;:::-;2019:5864:151;;;;2966:21:148;2019:5864:151;;;;;;;;2089:399:71;:::o;:::-;;2216:11;;;2019:5864:151;;;;;;;;;;;2237:9:71;;2019:5864:151;-1:-1:-1;2019:5864:151;;2268:8:71;;2264:48;;2216:11;2351:9;;2019:5864:151;;;;;;1938:75:72;;;;2019:5864:151;;;2392:39:71;;;;:::i;:::-;2019:5864:151;;;;;;;;;;;;2089:399:71;:::o;2264:48::-;2019:5864:151;;;;;;;;;:::i;:::-;-1:-1:-1;2019:5864:151;;2292:9:71;:::o;4543:226::-;4650:2;2019:5864:151;;4635:17:71;2019:5864:151;;4650:2:71;4703:60;;4543:226;:::o;2019:5864:151:-;;;-1:-1:-1;;;2019:5864:151;;4650:2:71;2019:5864:151;;;;;;;;;;;;;;-1:-1:-1;;;2019:5864:151;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;:::o;:::-;;;-1:-1:-1;;;2019:5864:151;;;;;;;;;;;;;;;;;-1:-1:-1;;;2019:5864:151;;;;;;;;;-1:-1:-1;;;;;2019:5864:151;;;;;;;-1:-1:-1;;;;;2019:5864:151;;;;:::o;1205:1510:78:-;1323:20;;;:::i;:::-;2019:5864:151;;;;1453:9:78;;-1:-1:-1;1501:14:78;;-1:-1:-1;2019:5864:151;;;;1509:6:78;2019:5864:151;;;;1449:1238:78;1579:1;1571:9;;1579:1;;1634:20;1782:11;1634:20;1782:11;1787:6;1740:7;1692:13;1634:20;1842:9;1634:20;;:::i;1692:13::-;2019:5864:151;;;;;;1740:7:78;1787:6;2019:5864:151;;;;;;1782:11:78;;;:::i;1567:1120::-;1880:1;1872:9;;1880:1;;1943:20;2275:8;1943:20;2243:16;2019:5864:151;1943:20:78;2194:16;1943:20;;2336:11;1943:20;;:::i;:::-;2013;;2118:15;2013:20;2058;2013;;;:::i;:::-;2058;;:::i;:::-;2019:5864:151;;;;;;;;2118:15:78;2019:5864:151;;2105:29:78;;2019:5864:151;;;;;;;2194:16:78;2188:23;;2019:5864:151;;;;;;;2243:16:78;2237:23;2019:5864:151;;;;;;2275:8:78;2019:5864:151;;;;1868:819:78;2376:1;2368:9;2376:1;;2575:34;2450:6;2019:5864:151;2449:12:78;2450:6;2589:19;2450:6;2019:5864:151;;;;;;;2450:6:78;2449:12;:::i;:::-;2019:5864:151;2503:6:78;2495:59;2508:1;2503:6;;;2495:59;:::i;:::-;2589:19;:::i;:::-;2575:34;:::i;2364:323::-;2019:5864:151;;-1:-1:-1;;;2640:36:78;;2019:5864:151;1393:1:78;2640:36;;2019:5864:151;;;;;;;;;;;;;2640:36:78;2019:5864:151;;;;;;;;;;;;;:::o;1564:269:71:-;1649:11;;;2019:5864:151;;;1663:1:71;2019:5864:151;;;;;;;1667:9:71;;2019:5864:151;-1:-1:-1;1645:87:71;;1758:9;2019:5864:151;;-1:-1:-1;;;;;;2019:5864:151;1758:22:71;;2019:5864:151;1758:22:71;:::i;:::-;2019:5864:151;;;;;;;1791:16:71;1663:1;2019:5864:151;;;;;;;;1564:269:71;:::o;1645:87::-;2019:5864:151;;-1:-1:-1;;;1699:22:71;;1649:11;1699:22;;;2019:5864:151;;;;;;-1:-1:-1;;;2019:5864:151;;;;1699:22:71;;;4445:308:148;2019:5864:151;;:::i;:::-;;2216:11:71;;;2019:5864:151;;;4586:1:148;2019:5864:151;;;;;;;2237:9:71;;2019:5864:151;-1:-1:-1;2019:5864:151;;2216:11:71;2351:9;;2019:5864:151;;;;;;1938:75:72;;;;2019:5864:151;;;4586:1:148;2392:39:71;;;:::i;:::-;2019:5864:151;;;;4586:1:148;2019:5864:151;;;;;;;;4590:1:148;5413:13:71;4590:1:148;5408:106:71;5428:5;4586:1:148;5428:5:71;;;;4619:35:148;;;;4684:25;4619:35;;:::i;:::-;4684:25;;:::i;:::-;4726:20;2019:5864:151;;:::i;:::-;-1:-1:-1;;;;;;2019:5864:151;;;;;;4726:20:148;2216:11:71;4726:20:148;;2019:5864:151;4445:308:148;:::o;5435:3:71:-;2019:5864:151;;-1:-1:-1;;;;;;5468:16:71;2019:5864:151;;5468:16:71;:::i;:::-;2019:5864:151;;;;;;;;;;5501:1:71;2019:5864:151;;;;;;;;;-1:-1:-1;;;;;;2019:5864:151;;;;;;5454:49:71;5435:3;2019:5864:151;5413:13:71;;;3313:349;2019:5864:151;;5910:30:152;3466:31:71;2019:5864:151;;5910:30:152;3512:8:71;3617:38;3512:8;1938:75:72;3617:38:71;:::i;2019:5864:151:-;;;;;;;;;:::o;:::-;-1:-1:-1;;2019:5864:151;;;;;;;;:::o;2744:313:71:-;2019:5864:151;;2876:25:71;5910:30:152;2876:25:71;2019:5864:151;;-1:-1:-1;;2019:5864:151;;;;;;;;;;;5910:30:152;1938:75:72;2019:5864:151;-1:-1:-1;2019:5864:151;;3012:38:71;;;:::i;823:320:78:-;2019:5864:151;;;;;961:5:78;;;1123:13;;823:320;:::o;968:3::-;2019:5864:151;;-1:-1:-1;;2019:5864:151;;;;;;;1051:11:78;;;;:::i;:::-;2019:5864:151;;;;;;;;;-1:-1:-1;;;;;2019:5864:151;;;;;;;;;;;;;1037:66:78;2019:5864:151;;;;;;;;;;;;;;1012:91:78;;;:::i;:::-;968:3;2019:5864:151;;;;-1:-1:-1;;2019:5864:151;;;936:23:78;;2284:287:72;;;;2019:5864:151;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;-1:-1:-1;;2019:5864:151;;;;2560:3:72;;;3244:193;3251:16;2019:5864:151;3251:16:72;;;;;3494:8;;;-1:-1:-1;;;2019:5864:151;3494:132:72;3636:173;;;;;;;;;;;2284:287::o;3494:132::-;3598:24;3606:15;3598:28;3606:15;;:::i;:::-;3598:24;:::i;:::-;:28;:::i;:::-;3494:132;;;3269:16;3301:65;;;;;;2019:5864:151;;;;;;;;;;;;;;;;;3269:16:72;-1:-1:-1;;2019:5864:151;;;;;;3244:193:72;2019:5864:151;;:::i;713:2:72:-;;;;;;;;;:::o","linkReferences":{},"immutableReferences":{"87434":[{"start":1926,"length":32},{"start":3285,"length":32}],"87437":[{"start":1438,"length":32},{"start":3215,"length":32}]}},"methodIdentifiers":{"noOp(((uint256,uint256),(uint8,uint32,bytes32,(uint64,uint32,bytes32),bytes32),(uint256,bytes)[],bytes),(bytes32,uint256,bytes32,uint256,(uint256,bytes32)[]))":"2a692d73","supportsInterface(bytes4)":"01ffc9a7","verificationKey()":"7ddc907d","verifier()":"2b7ac3f3","verify(bytes,bytes)":"f7e83aee","verifyConsensus(bytes,bytes)":"7d755598"},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.30+commit.73712a01\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract ISP1Verifier\",\"name\":\"v\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"vk\",\"type\":\"bytes32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"IllegalGenesisBlock\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TimestampNotFound\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnknownAuthoritySet\",\"type\":\"error\"},{\"inputs\":[{\"components\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"validatorSetId\",\"type\":\"uint256\"}],\"internalType\":\"struct MiniCommitment\",\"name\":\"commitment\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"parentNumber\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"parentHash\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"id\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"len\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"root\",\"type\":\"bytes32\"}],\"internalType\":\"struct AuthoritySetCommitment\",\"name\":\"nextAuthoritySet\",\"type\":\"tuple\"},{\"internalType\":\"bytes32\",\"name\":\"extra\",\"type\":\"bytes32\"}],\"internalType\":\"struct PartialBeefyMmrLeaf\",\"name\":\"mmrLeaf\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"header\",\"type\":\"bytes\"}],\"internalType\":\"struct ParachainHeader[]\",\"name\":\"headers\",\"type\":\"tuple[]\"},{\"internalType\":\"bytes\",\"name\":\"proof\",\"type\":\"bytes\"}],\"internalType\":\"struct SP1BeefyProof\",\"name\":\"s\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"authorities_root\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"authorities_len\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"leaf_hash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"block_number\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"hash\",\"type\":\"bytes32\"}],\"internalType\":\"struct ParachainHeaderHash[]\",\"name\":\"headers\",\"type\":\"tuple[]\"}],\"internalType\":\"struct PublicInputs\",\"name\":\"p\",\"type\":\"tuple\"}],\"name\":\"noOp\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"verificationKey\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"verifier\",\"outputs\":[{\"internalType\":\"contract ISP1Verifier\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"previousState\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"proof\",\"type\":\"bytes\"}],\"name\":\"verify\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"stateMachineId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"height\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"overlayRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"stateRoot\",\"type\":\"bytes32\"}],\"internalType\":\"struct StateCommitment\",\"name\":\"commitment\",\"type\":\"tuple\"}],\"internalType\":\"struct IntermediateState[]\",\"name\":\"\",\"type\":\"tuple[]\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedState\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"encodedProof\",\"type\":\"bytes\"}],\"name\":\"verifyConsensus\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"stateMachineId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"height\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"overlayRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"stateRoot\",\"type\":\"bytes32\"}],\"internalType\":\"struct StateCommitment\",\"name\":\"commitment\",\"type\":\"tuple\"}],\"internalType\":\"struct IntermediateState[]\",\"name\":\"\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"author\":\"Polytope Labs (hello@polytope.technology)\",\"details\":\"The verification key is set at construction time as an immutable. Stale proofs (where the commitment block number <= the trusted latest height) are treated as no-ops and return the existing state with no intermediates.\",\"kind\":\"dev\",\"methods\":{\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"},\"verify(bytes,bytes)\":{\"details\":\"IConsensusV2 entry point. Decodes the proof, verifies the SP1 ZK proof, and returns the updated state along with the latest authority set id.\"}},\"title\":\"The SP1 BEEFY Consensus Client.\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"notice\":\"Verifies BEEFY consensus proofs using an SP1 zero-knowledge proof, offloading secp256k1 signature verification, authority set membership checks, and MMR leaf inclusion to an off-chain SP1 program. The on-chain contract only verifies the resulting proof against a fixed verification key and a set of public inputs (authority set commitment, parachain header hashes, MMR leaf hash, and block number).\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/consensus/SP1Beefy.sol\":\"SP1Beefy\"},\"evmVersion\":\"cancun\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[\":@hyperbridge/core/=node_modules/@hyperbridge/core/contracts/\",\":@openzeppelin/=node_modules/@openzeppelin/\",\":@polytope-labs/=node_modules/@polytope-labs/\",\":@sp1-contracts/=lib/sp1-contracts/contracts/src/\",\":@uniswap/=node_modules/@uniswap/\",\":ds-test/=lib/solidity-stringutils/lib/ds-test/src/\",\":erc4626-tests/=lib/sp1-contracts/contracts/lib/openzeppelin-contracts/lib/erc4626-tests/\",\":forge-std/=node_modules/forge-std/src/\",\":openzeppelin-contracts/=lib/sp1-contracts/contracts/lib/openzeppelin-contracts/\",\":solidity-stringutils/=lib/solidity-stringutils/\",\":sp1-contracts/=lib/sp1-contracts/contracts/\",\":stringutils/=lib/solidity-stringutils/src/\"],\"viaIR\":true},\"sources\":{\"lib/sp1-contracts/contracts/src/ISP1Verifier.sol\":{\"keccak256\":\"0x9e3ba64860bea920772dcf16be7946de2a2900d80bd51e9c0771184138f4f4d3\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://0ec7230ca1fdd74edc6ab597d80bb345282aed3f0db4788ed96b4cc373ff46a3\",\"dweb:/ipfs/QmXPuSS5gzxMhFKWr1gsxBVu6WHh53ZZEvWkGgzrkM6Y7Q\"]},\"node_modules/@hyperbridge/core/contracts/interfaces/IConsensus.sol\":{\"keccak256\":\"0x56b093b9ca6913da8d12c54beca9ba8d970c1a1a0cf39838c2c341cd4ef23afb\",\"license\":\"Apache-2.0\",\"urls\":[\"bzz-raw://6be3495c82c3c5dd95ccc5855289b5e7079a419a9b0d09af843344ac86b6d286\",\"dweb:/ipfs/QmNQZugSBtnVcggYqnTXdcsZV3nLkGTK4VEXCnYX3fGKpV\"]},\"node_modules/@hyperbridge/core/contracts/interfaces/IConsensusV2.sol\":{\"keccak256\":\"0xa680bb1b902d419b862d155c49ae6fd2371e9b8a0a42d67cf07a6b4306300b90\",\"license\":\"Apache-2.0\",\"urls\":[\"bzz-raw://df9f403774a0fb637e331e23a599aa1cd3dc2a70baef0ebdd3b7dd4676dab81a\",\"dweb:/ipfs/QmfA14ersZ1D88DkxEaK3krNs7XsCYe5UTmTANKcGB8tE4\"]},\"node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\":{\"keccak256\":\"0x2d9dc2fe26180f74c11c13663647d38e259e45f95eb88f57b61d2160b0109d3e\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://81233d1f98060113d9922180bb0f14f8335856fe9f339134b09335e9f678c377\",\"dweb:/ipfs/QmWh6R35SarhAn4z2wH8SU456jJSYL2FgucfTFgbHJJN4E\"]},\"node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\":{\"keccak256\":\"0x8891738ffe910f0cf2da09566928589bf5d63f4524dd734fd9cedbac3274dd5c\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://971f954442df5c2ef5b5ebf1eb245d7105d9fbacc7386ee5c796df1d45b21617\",\"dweb:/ipfs/QmadRjHbkicwqwwh61raUEapaVEtaLMcYbQZWs9gUkgj3u\"]},\"node_modules/@polytope-labs/solidity-merkle-trees/src/trie/Bytes.sol\":{\"keccak256\":\"0xd305383358b93285d8fcee512795487484eadfd7b602df16ff4e9b01afbefec7\",\"license\":\"Apache-2.0\",\"urls\":[\"bzz-raw://57c86cd2fe6ab591264c5632d503d77f04748d722e4defa9c2badb238ee1f9bd\",\"dweb:/ipfs/QmTZ6xTcaYkRBshq6YZVMx2kkk94ZtJsRM6xLpC5qWT3oA\"]},\"node_modules/@polytope-labs/solidity-merkle-trees/src/trie/Memory.sol\":{\"keccak256\":\"0x59e3a56caa42c1aac30231173439817d38c7f359e40bd36e9bb418d3f82ceab7\",\"license\":\"Apache-2.0\",\"urls\":[\"bzz-raw://e060fed46c6b420624166ea02a326f0f566897941bdc322257e690ae134b8179\",\"dweb:/ipfs/QmbXW8yG2ZntjLMyUEmQGcRZroZj4dVZkBhHxK2PFKfUKB\"]},\"node_modules/@polytope-labs/solidity-merkle-trees/src/trie/Node.sol\":{\"keccak256\":\"0xca611969a68f7fe63dcdc742c9caf9bc1b26495561b68f4676c209279a4576ba\",\"license\":\"Apache-2.0\",\"urls\":[\"bzz-raw://17b7ec2cf65d484f0a2c188a7ae33430b015b3a55bf10393167f53839e2dde56\",\"dweb:/ipfs/QmTQbT8J7rBRNHFXSR7S4KbpwCteMrFt8mvrzCD1vYYTwX\"]},\"node_modules/@polytope-labs/solidity-merkle-trees/src/trie/polkadot/ScaleCodec.sol\":{\"keccak256\":\"0x9ac4df46e68718f7deaaa5b7443778533f53dc0ff3736cc386cf4991099da2aa\",\"license\":\"Apache-2.0\",\"urls\":[\"bzz-raw://85d08b00d9173358323105be975ce85b7e206ba52df2d80a14d2581dec1ddd11\",\"dweb:/ipfs/QmQCqVvSdJUqfhLH8TRBGNDGiEzkGduhRacnYhoKcm7e2a\"]},\"src/consensus/Codec.sol\":{\"keccak256\":\"0xfbda8d0aef81312f23b53eb34ba4fcd19ab886cbd010a0f100d86271eecee126\",\"license\":\"Apache-2.0\",\"urls\":[\"bzz-raw://bc4a4b1a88f702efa6727c368894b8ac13b69769efc81355b71a9a0d7a2efd7b\",\"dweb:/ipfs/QmYwLJgyCr4pPRyyk2oLYMLq5QGRhCSZKLYUEdW6U2SBzx\"]},\"src/consensus/SP1Beefy.sol\":{\"keccak256\":\"0x4b779208583580e277f7a8c5333cdefa73f1a7dd82011a4a062ddea3e92d5154\",\"license\":\"Apache-2.0\",\"urls\":[\"bzz-raw://f515bd6d9458bda42b798f58efe85b275dbe12647d283a73b8748e78007a3caf\",\"dweb:/ipfs/QmbjJx24CtuHiiqas7ouVyWV52JMN7mLdhastQeN7xoEWp\"]},\"src/consensus/Types.sol\":{\"keccak256\":\"0xcd1866064ae11c71575fefa857a7317d10e18da0c204c09ae42308c4c13a0268\",\"license\":\"Apache-2.0\",\"urls\":[\"bzz-raw://c083e149c4607f2cd5b769c1a624bbc5a861e8d5c485dd2ce06a0e23f7e762dd\",\"dweb:/ipfs/QmPMSM8S2sav9t4X2peHJnpTQhowEgEW5phYoiy3LbGAsv\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.30+commit.73712a01"},"language":"Solidity","output":{"abi":[{"inputs":[{"internalType":"contract ISP1Verifier","name":"v","type":"address"},{"internalType":"bytes32","name":"vk","type":"bytes32"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"type":"error","name":"IllegalGenesisBlock"},{"inputs":[],"type":"error","name":"TimestampNotFound"},{"inputs":[],"type":"error","name":"UnknownAuthoritySet"},{"inputs":[{"internalType":"struct SP1BeefyProof","name":"s","type":"tuple","components":[{"internalType":"struct MiniCommitment","name":"commitment","type":"tuple","components":[{"internalType":"uint256","name":"blockNumber","type":"uint256"},{"internalType":"uint256","name":"validatorSetId","type":"uint256"}]},{"internalType":"struct PartialBeefyMmrLeaf","name":"mmrLeaf","type":"tuple","components":[{"internalType":"uint8","name":"version","type":"uint8"},{"internalType":"uint32","name":"parentNumber","type":"uint32"},{"internalType":"bytes32","name":"parentHash","type":"bytes32"},{"internalType":"struct AuthoritySetCommitment","name":"nextAuthoritySet","type":"tuple","components":[{"internalType":"uint64","name":"id","type":"uint64"},{"internalType":"uint32","name":"len","type":"uint32"},{"internalType":"bytes32","name":"root","type":"bytes32"}]},{"internalType":"bytes32","name":"extra","type":"bytes32"}]},{"internalType":"struct ParachainHeader[]","name":"headers","type":"tuple[]","components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"header","type":"bytes"}]},{"internalType":"bytes","name":"proof","type":"bytes"}]},{"internalType":"struct PublicInputs","name":"p","type":"tuple","components":[{"internalType":"bytes32","name":"authorities_root","type":"bytes32"},{"internalType":"uint256","name":"authorities_len","type":"uint256"},{"internalType":"bytes32","name":"leaf_hash","type":"bytes32"},{"internalType":"uint256","name":"block_number","type":"uint256"},{"internalType":"struct ParachainHeaderHash[]","name":"headers","type":"tuple[]","components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes32","name":"hash","type":"bytes32"}]}]}],"stateMutability":"pure","type":"function","name":"noOp"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"stateMutability":"view","type":"function","name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}]},{"inputs":[],"stateMutability":"view","type":"function","name":"verificationKey","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}]},{"inputs":[],"stateMutability":"view","type":"function","name":"verifier","outputs":[{"internalType":"contract ISP1Verifier","name":"","type":"address"}]},{"inputs":[{"internalType":"bytes","name":"previousState","type":"bytes"},{"internalType":"bytes","name":"proof","type":"bytes"}],"stateMutability":"view","type":"function","name":"verify","outputs":[{"internalType":"bytes","name":"","type":"bytes"},{"internalType":"struct IntermediateState[]","name":"","type":"tuple[]","components":[{"internalType":"uint256","name":"stateMachineId","type":"uint256"},{"internalType":"uint256","name":"height","type":"uint256"},{"internalType":"struct StateCommitment","name":"commitment","type":"tuple","components":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bytes32","name":"overlayRoot","type":"bytes32"},{"internalType":"bytes32","name":"stateRoot","type":"bytes32"}]}]},{"internalType":"uint256","name":"","type":"uint256"}]},{"inputs":[{"internalType":"bytes","name":"encodedState","type":"bytes"},{"internalType":"bytes","name":"encodedProof","type":"bytes"}],"stateMutability":"view","type":"function","name":"verifyConsensus","outputs":[{"internalType":"bytes","name":"","type":"bytes"},{"internalType":"struct IntermediateState[]","name":"","type":"tuple[]","components":[{"internalType":"uint256","name":"stateMachineId","type":"uint256"},{"internalType":"uint256","name":"height","type":"uint256"},{"internalType":"struct StateCommitment","name":"commitment","type":"tuple","components":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bytes32","name":"overlayRoot","type":"bytes32"},{"internalType":"bytes32","name":"stateRoot","type":"bytes32"}]}]}]}],"devdoc":{"kind":"dev","methods":{"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."},"verify(bytes,bytes)":{"details":"IConsensusV2 entry point. Decodes the proof, verifies the SP1 ZK proof, and returns the updated state along with the latest authority set id."}},"version":1},"userdoc":{"kind":"user","methods":{},"version":1}},"settings":{"remappings":["@hyperbridge/core/=node_modules/@hyperbridge/core/contracts/","@openzeppelin/=node_modules/@openzeppelin/","@polytope-labs/=node_modules/@polytope-labs/","@sp1-contracts/=lib/sp1-contracts/contracts/src/","@uniswap/=node_modules/@uniswap/","ds-test/=lib/solidity-stringutils/lib/ds-test/src/","erc4626-tests/=lib/sp1-contracts/contracts/lib/openzeppelin-contracts/lib/erc4626-tests/","forge-std/=node_modules/forge-std/src/","openzeppelin-contracts/=lib/sp1-contracts/contracts/lib/openzeppelin-contracts/","solidity-stringutils/=lib/solidity-stringutils/","sp1-contracts/=lib/sp1-contracts/contracts/","stringutils/=lib/solidity-stringutils/src/"],"optimizer":{"enabled":true,"runs":200},"metadata":{"bytecodeHash":"ipfs"},"compilationTarget":{"src/consensus/SP1Beefy.sol":"SP1Beefy"},"evmVersion":"cancun","libraries":{},"viaIR":true},"sources":{"lib/sp1-contracts/contracts/src/ISP1Verifier.sol":{"keccak256":"0x9e3ba64860bea920772dcf16be7946de2a2900d80bd51e9c0771184138f4f4d3","urls":["bzz-raw://0ec7230ca1fdd74edc6ab597d80bb345282aed3f0db4788ed96b4cc373ff46a3","dweb:/ipfs/QmXPuSS5gzxMhFKWr1gsxBVu6WHh53ZZEvWkGgzrkM6Y7Q"],"license":"MIT"},"node_modules/@hyperbridge/core/contracts/interfaces/IConsensus.sol":{"keccak256":"0x56b093b9ca6913da8d12c54beca9ba8d970c1a1a0cf39838c2c341cd4ef23afb","urls":["bzz-raw://6be3495c82c3c5dd95ccc5855289b5e7079a419a9b0d09af843344ac86b6d286","dweb:/ipfs/QmNQZugSBtnVcggYqnTXdcsZV3nLkGTK4VEXCnYX3fGKpV"],"license":"Apache-2.0"},"node_modules/@hyperbridge/core/contracts/interfaces/IConsensusV2.sol":{"keccak256":"0xa680bb1b902d419b862d155c49ae6fd2371e9b8a0a42d67cf07a6b4306300b90","urls":["bzz-raw://df9f403774a0fb637e331e23a599aa1cd3dc2a70baef0ebdd3b7dd4676dab81a","dweb:/ipfs/QmfA14ersZ1D88DkxEaK3krNs7XsCYe5UTmTANKcGB8tE4"],"license":"Apache-2.0"},"node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol":{"keccak256":"0x2d9dc2fe26180f74c11c13663647d38e259e45f95eb88f57b61d2160b0109d3e","urls":["bzz-raw://81233d1f98060113d9922180bb0f14f8335856fe9f339134b09335e9f678c377","dweb:/ipfs/QmWh6R35SarhAn4z2wH8SU456jJSYL2FgucfTFgbHJJN4E"],"license":"MIT"},"node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol":{"keccak256":"0x8891738ffe910f0cf2da09566928589bf5d63f4524dd734fd9cedbac3274dd5c","urls":["bzz-raw://971f954442df5c2ef5b5ebf1eb245d7105d9fbacc7386ee5c796df1d45b21617","dweb:/ipfs/QmadRjHbkicwqwwh61raUEapaVEtaLMcYbQZWs9gUkgj3u"],"license":"MIT"},"node_modules/@polytope-labs/solidity-merkle-trees/src/trie/Bytes.sol":{"keccak256":"0xd305383358b93285d8fcee512795487484eadfd7b602df16ff4e9b01afbefec7","urls":["bzz-raw://57c86cd2fe6ab591264c5632d503d77f04748d722e4defa9c2badb238ee1f9bd","dweb:/ipfs/QmTZ6xTcaYkRBshq6YZVMx2kkk94ZtJsRM6xLpC5qWT3oA"],"license":"Apache-2.0"},"node_modules/@polytope-labs/solidity-merkle-trees/src/trie/Memory.sol":{"keccak256":"0x59e3a56caa42c1aac30231173439817d38c7f359e40bd36e9bb418d3f82ceab7","urls":["bzz-raw://e060fed46c6b420624166ea02a326f0f566897941bdc322257e690ae134b8179","dweb:/ipfs/QmbXW8yG2ZntjLMyUEmQGcRZroZj4dVZkBhHxK2PFKfUKB"],"license":"Apache-2.0"},"node_modules/@polytope-labs/solidity-merkle-trees/src/trie/Node.sol":{"keccak256":"0xca611969a68f7fe63dcdc742c9caf9bc1b26495561b68f4676c209279a4576ba","urls":["bzz-raw://17b7ec2cf65d484f0a2c188a7ae33430b015b3a55bf10393167f53839e2dde56","dweb:/ipfs/QmTQbT8J7rBRNHFXSR7S4KbpwCteMrFt8mvrzCD1vYYTwX"],"license":"Apache-2.0"},"node_modules/@polytope-labs/solidity-merkle-trees/src/trie/polkadot/ScaleCodec.sol":{"keccak256":"0x9ac4df46e68718f7deaaa5b7443778533f53dc0ff3736cc386cf4991099da2aa","urls":["bzz-raw://85d08b00d9173358323105be975ce85b7e206ba52df2d80a14d2581dec1ddd11","dweb:/ipfs/QmQCqVvSdJUqfhLH8TRBGNDGiEzkGduhRacnYhoKcm7e2a"],"license":"Apache-2.0"},"src/consensus/Codec.sol":{"keccak256":"0xfbda8d0aef81312f23b53eb34ba4fcd19ab886cbd010a0f100d86271eecee126","urls":["bzz-raw://bc4a4b1a88f702efa6727c368894b8ac13b69769efc81355b71a9a0d7a2efd7b","dweb:/ipfs/QmYwLJgyCr4pPRyyk2oLYMLq5QGRhCSZKLYUEdW6U2SBzx"],"license":"Apache-2.0"},"src/consensus/SP1Beefy.sol":{"keccak256":"0x4b779208583580e277f7a8c5333cdefa73f1a7dd82011a4a062ddea3e92d5154","urls":["bzz-raw://f515bd6d9458bda42b798f58efe85b275dbe12647d283a73b8748e78007a3caf","dweb:/ipfs/QmbjJx24CtuHiiqas7ouVyWV52JMN7mLdhastQeN7xoEWp"],"license":"Apache-2.0"},"src/consensus/Types.sol":{"keccak256":"0xcd1866064ae11c71575fefa857a7317d10e18da0c204c09ae42308c4c13a0268","urls":["bzz-raw://c083e149c4607f2cd5b769c1a624bbc5a861e8d5c485dd2ce06a0e23f7e762dd","dweb:/ipfs/QmPMSM8S2sav9t4X2peHJnpTQhowEgEW5phYoiy3LbGAsv"],"license":"Apache-2.0"}},"version":1},"id":151} \ No newline at end of file +{"abi":[{"type":"constructor","inputs":[{"name":"v","type":"address","internalType":"contract ISP1Verifier"},{"name":"vk","type":"bytes32","internalType":"bytes32"}],"stateMutability":"nonpayable"},{"type":"function","name":"noOp","inputs":[{"name":"s","type":"tuple","internalType":"struct SP1BeefyProof","components":[{"name":"commitment","type":"tuple","internalType":"struct MiniCommitment","components":[{"name":"blockNumber","type":"uint256","internalType":"uint256"},{"name":"validatorSetId","type":"uint256","internalType":"uint256"}]},{"name":"mmrLeaf","type":"tuple","internalType":"struct PartialBeefyMmrLeaf","components":[{"name":"version","type":"uint8","internalType":"uint8"},{"name":"parentNumber","type":"uint32","internalType":"uint32"},{"name":"parentHash","type":"bytes32","internalType":"bytes32"},{"name":"nextAuthoritySet","type":"tuple","internalType":"struct AuthoritySetCommitment","components":[{"name":"id","type":"uint64","internalType":"uint64"},{"name":"len","type":"uint32","internalType":"uint32"},{"name":"root","type":"bytes32","internalType":"bytes32"}]},{"name":"extra","type":"bytes32","internalType":"bytes32"}]},{"name":"headers","type":"tuple[]","internalType":"struct ParachainHeader[]","components":[{"name":"id","type":"uint256","internalType":"uint256"},{"name":"header","type":"bytes","internalType":"bytes"}]},{"name":"proof","type":"bytes","internalType":"bytes"},{"name":"nonce","type":"bytes32","internalType":"bytes32"}]},{"name":"p","type":"tuple","internalType":"struct PublicInputs","components":[{"name":"authorities_root","type":"bytes32","internalType":"bytes32"},{"name":"authorities_len","type":"uint256","internalType":"uint256"},{"name":"leaf_hash","type":"bytes32","internalType":"bytes32"},{"name":"block_number","type":"uint256","internalType":"uint256"},{"name":"headers","type":"tuple[]","internalType":"struct ParachainHeaderHash[]","components":[{"name":"id","type":"uint256","internalType":"uint256"},{"name":"hash","type":"bytes32","internalType":"bytes32"}]},{"name":"nonce","type":"bytes32","internalType":"bytes32"}]}],"outputs":[],"stateMutability":"pure"},{"type":"function","name":"supportsInterface","inputs":[{"name":"interfaceId","type":"bytes4","internalType":"bytes4"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"type":"function","name":"verificationKey","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"verifier","inputs":[],"outputs":[{"name":"","type":"address","internalType":"contract ISP1Verifier"}],"stateMutability":"view"},{"type":"function","name":"verify","inputs":[{"name":"previousState","type":"bytes","internalType":"bytes"},{"name":"proof","type":"bytes","internalType":"bytes"}],"outputs":[{"name":"","type":"bytes","internalType":"bytes"},{"name":"","type":"tuple[]","internalType":"struct IntermediateState[]","components":[{"name":"stateMachineId","type":"uint256","internalType":"uint256"},{"name":"height","type":"uint256","internalType":"uint256"},{"name":"commitment","type":"tuple","internalType":"struct StateCommitment","components":[{"name":"timestamp","type":"uint256","internalType":"uint256"},{"name":"overlayRoot","type":"bytes32","internalType":"bytes32"},{"name":"stateRoot","type":"bytes32","internalType":"bytes32"}]}]},{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"error","name":"IllegalGenesisBlock","inputs":[]},{"type":"error","name":"TimestampNotFound","inputs":[]},{"type":"error","name":"UnknownAuthoritySet","inputs":[]}],"bytecode":{"object":"0x60c03461008957601f611b7638819003918201601f19168301916001600160401b0383118484101761008d578084926040948552833981010312610089578051906001600160a01b038216820361008957602001519060a052608052604051611ad490816100a282396080518181816101210152610ca0015260a05181818160db0152610c5a0152f35b5f80fd5b634e487b7160e01b5f52604160045260245ffdfe60806040526004361015610011575f80fd5b5f3560e01c806301ffc9a7146100645780632b7ac3f31461005f5780637ddc907d1461005a5780639f81f883146100555763f7e83aee14610050575f80fd5b6106e9565b61053f565b61010a565b6100c6565b346100b85760203660031901126100b85760043563ffffffff60e01b81168091036100b857637bf41d7760e11b81149081156100a7575b50151560805260206080f35b6301ffc9a760e01b1490508161009b565b5f80fd5b5f9103126100b857565b346100b8575f3660031901126100b8576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b346100b8575f3660031901126100b85760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b634e487b7160e01b5f52604160045260245ffd5b604081019081106001600160401b0382111761017357604052565b610144565b606081019081106001600160401b0382111761017357604052565b60a081019081106001600160401b0382111761017357604052565b60c081019081106001600160401b0382111761017357604052565b608081019081106001600160401b0382111761017357604052565b90601f801991011681019081106001600160401b0382111761017357604052565b6040519061021460a0836101e4565b565b604051906102146040836101e4565b6040519061021460c0836101e4565b604051906102146060836101e4565b91908260409103126100b85760405161025b81610158565b6020808294803584520135910152565b359063ffffffff821682036100b857565b91908260609103126100b85760405161029481610178565b809280356001600160401b03811681036100b857604091829184526102bb6020820161026b565b60208501520135910152565b91909160e0818403126100b857604051906102e182610193565b819381359160ff831683036100b85761031f60c09260809486526103076020840161026b565b6020870152604083013560408701526060830161027c565b60608501520135910152565b6001600160401b0381116101735760051b60200190565b6001600160401b03811161017357601f01601f191660200190565b81601f820112156100b85780359061037482610342565b9261038260405194856101e4565b828452602083830101116100b857815f926020809301838601378301015290565b9080601f830112156100b8578135916103bb8361032b565b926103c960405194856101e4565b80845260208085019160051b830101918383116100b85760208101915b8383106103f557505050505090565b82356001600160401b0381116100b8578201906040828703601f1901126100b8576040519061042382610158565b602083013582526040830135916001600160401b0383116100b8576104508860208096958196010161035d565b838201528152019201916103e6565b91909160c0818403126100b85760405190610479826101ae565b81938135835260208201356020840152604082013560408401526060820135606084015260808201356001600160401b0381116100b857820181601f820112156100b8578035906104c98261032b565b926104d760405194856101e4565b82845260208085019360061b830101918183116100b857602001925b82841061050e5750505050608083015260a090810135910152565b6040848303126100b8576020604091825161052881610158565b8635815282870135838201528152019301926104f3565b346100b85760403660031901126100b8576004356001600160401b0381116100b85761018060031982360301126100b857610578610205565b906105863682600401610243565b825261059536604483016102c7565b60208301526101248101356001600160401b0381116100b8576105be90600436918401016103a3565b60408301526101448101356001600160401b0381116100b8576080916105ed610164926004369184010161035d565b606085015201359101526024356001600160401b0381116100b85761061690369060040161045f565b005b9181601f840112156100b8578235916001600160401b0383116100b857602083818601950101116100b857565b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b9392919061067f90606086526060860190610645565b908482036020860152602080825193848152019101915f5b8181106106a957505060409150930152565b9091602060a06001926040808851805184528581015186850152015180518284015284810151606084015201516080820152019401910192919092610697565b346100b85760403660031901126100b8576004356001600160401b0381116100b857610719903690600401610618565b906024356001600160401b0381116100b857610739903690600401610618565b92820190610100838303126100b8576107c0936107886107959360a060405196610762886101c9565b803588526020810135602089015261077d836040830161027c565b60408901520161027c565b6060850152810190610814565b926107a4959495929192610205565b9586526020860152604085015260608401526080830152610b56565b906108106001600160401b036108036060604051946107f4866107e68360208301610884565b03601f1981018852876101e4565b0151516001600160401b031690565b1660405193849384610669565b0390f35b9190610180838203126100b85761082b8184610243565b9261083982604083016102c7565b926101208201356001600160401b0381116100b8578361085a9184016103a3565b926101408301356001600160401b0381116100b8576101609161087e91850161035d565b92013590565b6102149092919260a0606061010083019580518452602081015160208501526108d860408201516040860190604080916001600160401b03815116845263ffffffff60208201511660208501520151910152565b0151910190604080916001600160401b03815116845263ffffffff60208201511660208501520151910152565b6040519061091282610178565b5f6040838281528260208201520152565b60405190610930826101c9565b815f81525f6020820152610942610905565b60408201526060610951610905565b910152565b604051906109656020836101e4565b5f80835282815b82811061097857505050565b60209060405161098781610178565b5f81525f83820152610997610905565b60408201528282850101520161096c565b906109b28261032b565b6109bf60405191826101e4565b82815280926109d0601f199161032b565b01905f5b8281106109e057505050565b6020906040516109ef81610178565b5f81525f838201526109ff610905565b6040820152828285010152016109d4565b90610a1a8261032b565b610a2760405191826101e4565b8281528092610a38601f199161032b565b01905f5b828110610a4857505050565b602090604051610a5781610158565b5f81525f8382015282828501015201610a3c565b634e487b7160e01b5f52603260045260245ffd5b8051821015610a935760209160051b010190565b610a6b565b6020815260e08101918051602083015260208101516040830152604081015160608301526060810151608083015260808101519260c060a08401528351809152602061010084019401905f5b818110610afb5750505060a060c091015191015290565b8251805187526020908101518188015260409096019590920191600101610ae4565b91610b3a90610b4894928452606060208501526060840190610645565b916040818403910152610645565b90565b6040513d5f823e3d90fd5b919091610b61610923565b508251815181511115610e6757610b76610905565b5060208101516060830190610ba3610b9783516001600160401b0390511690565b6001600160401b031690565b8103610e32575080515b604086019586515191610bbf83610a10565b925f5b818110610dde575050610c4f816040610be56020610c4195015163ffffffff1690565b910151908751956020860196610bfb8851610efb565b6020815191012063ffffffff608089015194610c15610225565b96875216602086015260408501526060840152608083015260a082015260405192839160208301610a98565b03601f1981018352826101e4565b606060018060a01b037f000000000000000000000000000000000000000000000000000000000000000016920151823b156100b85760405163020a49e360e51b8152925f92849283918291610cc8917f000000000000000000000000000000000000000000000000000000000000000060048501610b1d565b03915afa8015610dd957610dbf575b50855151610ce4816109a8565b965f5b828110610d49575050815160600151516001600160401b03169050908251916001600160401b03610d22610b9785516001600160401b031690565b911611610d34575b5050505181529190565b606091604086015251015190525f8080610d2a565b610d54818351610a7f565b5190610d6360208301516111bd565b916020830190815115610db057610d7b600194611309565b90519151610d87610234565b92835260208301526040820152610d9e828c610a7f565b52610da9818b610a7f565b5001610ce7565b63b4eb9e5160e01b5f5260045ffd5b80610dcd5f610dd3936101e4565b806100bc565b5f610cd7565b610b4b565b808a6020610dfc83610df36001968551610a7f565b51519351610a7f565b51015160208151910120610e0e610216565b9182526020820152610e208288610a7f565b52610e2b8187610a7f565b5001610bc2565b6040840190610e4d610b9783516001600160401b0390511690565b03610e585751610bad565b637202e68560e11b5f5260045ffd5b509150610b48610956565b805191908290602001825e015f815290565b949291969593909660405197889660208801610e9f91610e72565b9063ffffffff60e01b168152600401610eb791610e72565b916001600160401b0360c01b16825263ffffffff60e01b166008820152600c01610ee091610e72565b610ee991610e72565b03601f198101835261021490836101e4565b6110ae61108b610f38610b4893610f46610f16825160ff1690565b60405160f89190911b6001600160f81b03191660208201529283906021820190565b03601f1981018452836101e4565b610f38610f97610f5d602084015163ffffffff1690565b63ff00ff00600882811b9190911691901c62ff00ff1617601081811b63ffff00001691901c61ffff161760e01b6001600160e01b03191690565b610fb260408401516040519384916020830160209181520190565b6060830151936110bc608061105b610fd188516001600160401b031690565b67ffffffffffff000067ff00ff00ff00ff0066ff00ff00ff00ff8360081c169260081b169165ffff0000ffff65ffff0000ff0065ffffffffffff67ffff0000ffff0000861666ff0000ffff000085161760101c16941691161760101b161767ffffffff0000000063ffffffff8260201c169160201b166001600160401b0360c01b911760c01b1690565b956110996040611075610f5d60208c015163ffffffff1690565b9901516040519a8b916020830160209181520190565b03601f1981018b528a6101e4565b01516040519889916020830160209181520190565b03601f1981018952886101e4565b610e84565b604051906110ce82610193565b60606080835f81525f60208201525f60408201525f838201520152565b604051906110f882610158565b60606020835f81520152565b6040519061012082018281106001600160401b03821117610173576040525f610100838281526111326110eb565b60208201528260408201526111456110eb565b60608201528260808201526111586110eb565b60a08201528260c0820152606060e08201520152565b906111788261032b565b61118560405191826101e4565b8281528092611196601f199161032b565b01905f5b8281106111a657505050565b6020906111b1611104565b8282850101520161119a565b6111c56110c1565b506111ce610216565b9081525f60208201526111e86111e38261149c565b61154c565b906111f28161163c565b6111fe6111e38361149c565b61120a6111e38461149c565b916112148461163c565b61121d8161116e565b945f5b82811061124c57505050611232610205565b948552602085015260408401526060830152608082015290565b600190611258836117ba565b60ff611262611104565b91168061128e5750600160c08201525b61127c828a610a7f565b526112878189610a7f565b5001611220565b600481036112b25750600160408201526112a784611837565b60608201525b611272565b600581036112d55750600160808201526112cb84611837565b60a0820152611272565b600681036112f55750600181526112eb84611837565b6020820152611272565b6008036112ad576001610100820152611272565b611311610905565b505f5f925f5f5b60808501805180518310156114425760406113368461133e93610a7f565b510151151590565b8061141a575b6113d1575b6113596040611336848451610a7f565b80611398575b61136d575b50600101611318565b8192506113906020606061138660809560019551610a7f565b5101510151611972565b929150611364565b50634953544d60e01b63ffffffff60e01b6113ca60606113b9868651610a7f565b510151516001600160e01b03191690565b161461135f565b955092506113f46111e3602060606113ea878a51610a7f565b5101510151611913565b926114146111e36020606061140a858b51610a7f565b5101510151611945565b95611349565b5063049534d560e41b63ffffffff60e01b61143b60606113b9868651610a7f565b1614611344565b50505092509290821561146757611457610234565b9283526020830152604082015290565b633eba99d160e21b5f5260045ffd5b634e487b7160e01b5f52601160045260245ffd5b9190820180921161149757565b611476565b602081019081516020810180911161149757815151106100b8576020905181835182010191829101116114975760206114d4916119e9565b9080519060208201809211611497575290565b906020820191825182810180911161149757815151106100b8578115611535576020905181845182010191829101116114975781611524916119e9565b918051918201809211611497575290565b5050506040516115466020826101e4565b5f815290565b602081511061155c576020015190565b60405162461bcd60e51b8152602060048201526024808201527f42797465733a3a20746f427974657333323a206461746120697320746f20736860448201526337b93a1760e11b6064820152608490fd5b60ff60049116019060ff821161149757565b156115c657565b60405162461bcd60e51b815260206004820152602860248201527f756e657870656374656420707265666978206465636f64696e6720436f6d706160448201526731ba1e2ab4b73a1f60c11b6064820152608490fd5b906001600160401b03809116911601906001600160401b03821161149757565b611645816117ba565b60038116806116615750610b48915060021c603f165b60ff1690565b600181036116a65750610b97906116a061165b61169661168661165b610b48976117ba565b60061b67ffffffffffffffc01690565b9260021c603f1690565b9061161c565b60028103611725575061171c9061170f60ff84611700826116c9610b48986117ba565b95816116ef816116e16116db886117ba565b976117ba565b991660081b63ffffff001690565b911617921660101b63ffff00001690565b17921660181b63ff0000001690565b1760021c633fffffff1690565b63ffffffff1690565b60030361176457610b489160ff61174b61174661175f94603f9060021c1690565b6115ad565b169061175a60088311156115bf565b6114e7565b611972565b60405162461bcd60e51b815260206004820152601a60248201527f436f64652073686f756c6420626520756e726561636861626c650000000000006044820152606490fd5b908151811015610a93570160200190565b60208101908151600181018091116114975781515110611803575181516001600160f81b0319916117eb91906117a9565b511660f81c9080519060018201809211611497575290565b60405162461bcd60e51b815260206004820152600c60248201526b4f7574206f662072616e676560a01b6044820152606490fd5b61183f6110eb565b50602081019081516004810180911161149757815151106100b857602081518184518201019182910111611497576004611878916119e9565b918051906004820180921161149757525f915f905b600482106118cd575050806118a46118aa9261163c565b906114e7565b6118c56118b5610216565b6001600160e01b03199093168352565b602082015290565b90926001600160f81b03196118e285846117a9565b5116908460031b9185830460081486151715611497576001926001600160e01b0319918216901c161793019061188d565b80516020116100b857602080610b4892016119e9565b602003906020821161149757565b5f1981019190821161149757565b8051806020116100b857601f198101908111611497576040820191602001821061149757610b48916119e9565b80515f91815b61198157505090565b90915f1983018381116114975761199881846117a9565b5160f81c90600381901b906001600160fd1b038116036114975760ff8111611497576001901b90818102918183041490151715611497576119d89161148a565b918015611497575f19019081611978565b9190916119f583610342565b611a0260405191826101e4565b838152611a0e84610342565b602082019190601f1901368337939091905b6020811015611a5f5780611a4057505f19905b5182518216911916179052565b611a54611a4f611a5992611929565b611a8f565b611937565b90611a33565b909182518152602081018091116114975791602081018091116114975790601f19810190811115611a2057611476565b601f8111611497576101000a9056fea2646970667358221220dad4b510a6fbf7dce2106f46e06d1ceb55fa5defab43431f67530e8bc065634364736f6c634300081e0033","sourceMap":"1947:4892:9:-:0;;;;;;;;;;;;;-1:-1:-1;;1947:4892:9;;;;-1:-1:-1;;;;;1947:4892:9;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;1947:4892:9;;;;;;;;;2385:12;;;2407:20;;1947:4892;;;;;;;;2407:20;1947:4892;;;;;;;;;;2385:12;1947:4892;;;;;;;;;;;;-1:-1:-1;1947:4892:9;;;;;;-1:-1:-1;1947:4892:9;;;;;-1:-1:-1;1947:4892:9","linkReferences":{}},"deployedBytecode":{"object":"0x60806040526004361015610011575f80fd5b5f3560e01c806301ffc9a7146100645780632b7ac3f31461005f5780637ddc907d1461005a5780639f81f883146100555763f7e83aee14610050575f80fd5b6106e9565b61053f565b61010a565b6100c6565b346100b85760203660031901126100b85760043563ffffffff60e01b81168091036100b857637bf41d7760e11b81149081156100a7575b50151560805260206080f35b6301ffc9a760e01b1490508161009b565b5f80fd5b5f9103126100b857565b346100b8575f3660031901126100b8576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b346100b8575f3660031901126100b85760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b634e487b7160e01b5f52604160045260245ffd5b604081019081106001600160401b0382111761017357604052565b610144565b606081019081106001600160401b0382111761017357604052565b60a081019081106001600160401b0382111761017357604052565b60c081019081106001600160401b0382111761017357604052565b608081019081106001600160401b0382111761017357604052565b90601f801991011681019081106001600160401b0382111761017357604052565b6040519061021460a0836101e4565b565b604051906102146040836101e4565b6040519061021460c0836101e4565b604051906102146060836101e4565b91908260409103126100b85760405161025b81610158565b6020808294803584520135910152565b359063ffffffff821682036100b857565b91908260609103126100b85760405161029481610178565b809280356001600160401b03811681036100b857604091829184526102bb6020820161026b565b60208501520135910152565b91909160e0818403126100b857604051906102e182610193565b819381359160ff831683036100b85761031f60c09260809486526103076020840161026b565b6020870152604083013560408701526060830161027c565b60608501520135910152565b6001600160401b0381116101735760051b60200190565b6001600160401b03811161017357601f01601f191660200190565b81601f820112156100b85780359061037482610342565b9261038260405194856101e4565b828452602083830101116100b857815f926020809301838601378301015290565b9080601f830112156100b8578135916103bb8361032b565b926103c960405194856101e4565b80845260208085019160051b830101918383116100b85760208101915b8383106103f557505050505090565b82356001600160401b0381116100b8578201906040828703601f1901126100b8576040519061042382610158565b602083013582526040830135916001600160401b0383116100b8576104508860208096958196010161035d565b838201528152019201916103e6565b91909160c0818403126100b85760405190610479826101ae565b81938135835260208201356020840152604082013560408401526060820135606084015260808201356001600160401b0381116100b857820181601f820112156100b8578035906104c98261032b565b926104d760405194856101e4565b82845260208085019360061b830101918183116100b857602001925b82841061050e5750505050608083015260a090810135910152565b6040848303126100b8576020604091825161052881610158565b8635815282870135838201528152019301926104f3565b346100b85760403660031901126100b8576004356001600160401b0381116100b85761018060031982360301126100b857610578610205565b906105863682600401610243565b825261059536604483016102c7565b60208301526101248101356001600160401b0381116100b8576105be90600436918401016103a3565b60408301526101448101356001600160401b0381116100b8576080916105ed610164926004369184010161035d565b606085015201359101526024356001600160401b0381116100b85761061690369060040161045f565b005b9181601f840112156100b8578235916001600160401b0383116100b857602083818601950101116100b857565b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b9392919061067f90606086526060860190610645565b908482036020860152602080825193848152019101915f5b8181106106a957505060409150930152565b9091602060a06001926040808851805184528581015186850152015180518284015284810151606084015201516080820152019401910192919092610697565b346100b85760403660031901126100b8576004356001600160401b0381116100b857610719903690600401610618565b906024356001600160401b0381116100b857610739903690600401610618565b92820190610100838303126100b8576107c0936107886107959360a060405196610762886101c9565b803588526020810135602089015261077d836040830161027c565b60408901520161027c565b6060850152810190610814565b926107a4959495929192610205565b9586526020860152604085015260608401526080830152610b56565b906108106001600160401b036108036060604051946107f4866107e68360208301610884565b03601f1981018852876101e4565b0151516001600160401b031690565b1660405193849384610669565b0390f35b9190610180838203126100b85761082b8184610243565b9261083982604083016102c7565b926101208201356001600160401b0381116100b8578361085a9184016103a3565b926101408301356001600160401b0381116100b8576101609161087e91850161035d565b92013590565b6102149092919260a0606061010083019580518452602081015160208501526108d860408201516040860190604080916001600160401b03815116845263ffffffff60208201511660208501520151910152565b0151910190604080916001600160401b03815116845263ffffffff60208201511660208501520151910152565b6040519061091282610178565b5f6040838281528260208201520152565b60405190610930826101c9565b815f81525f6020820152610942610905565b60408201526060610951610905565b910152565b604051906109656020836101e4565b5f80835282815b82811061097857505050565b60209060405161098781610178565b5f81525f83820152610997610905565b60408201528282850101520161096c565b906109b28261032b565b6109bf60405191826101e4565b82815280926109d0601f199161032b565b01905f5b8281106109e057505050565b6020906040516109ef81610178565b5f81525f838201526109ff610905565b6040820152828285010152016109d4565b90610a1a8261032b565b610a2760405191826101e4565b8281528092610a38601f199161032b565b01905f5b828110610a4857505050565b602090604051610a5781610158565b5f81525f8382015282828501015201610a3c565b634e487b7160e01b5f52603260045260245ffd5b8051821015610a935760209160051b010190565b610a6b565b6020815260e08101918051602083015260208101516040830152604081015160608301526060810151608083015260808101519260c060a08401528351809152602061010084019401905f5b818110610afb5750505060a060c091015191015290565b8251805187526020908101518188015260409096019590920191600101610ae4565b91610b3a90610b4894928452606060208501526060840190610645565b916040818403910152610645565b90565b6040513d5f823e3d90fd5b919091610b61610923565b508251815181511115610e6757610b76610905565b5060208101516060830190610ba3610b9783516001600160401b0390511690565b6001600160401b031690565b8103610e32575080515b604086019586515191610bbf83610a10565b925f5b818110610dde575050610c4f816040610be56020610c4195015163ffffffff1690565b910151908751956020860196610bfb8851610efb565b6020815191012063ffffffff608089015194610c15610225565b96875216602086015260408501526060840152608083015260a082015260405192839160208301610a98565b03601f1981018352826101e4565b606060018060a01b037f000000000000000000000000000000000000000000000000000000000000000016920151823b156100b85760405163020a49e360e51b8152925f92849283918291610cc8917f000000000000000000000000000000000000000000000000000000000000000060048501610b1d565b03915afa8015610dd957610dbf575b50855151610ce4816109a8565b965f5b828110610d49575050815160600151516001600160401b03169050908251916001600160401b03610d22610b9785516001600160401b031690565b911611610d34575b5050505181529190565b606091604086015251015190525f8080610d2a565b610d54818351610a7f565b5190610d6360208301516111bd565b916020830190815115610db057610d7b600194611309565b90519151610d87610234565b92835260208301526040820152610d9e828c610a7f565b52610da9818b610a7f565b5001610ce7565b63b4eb9e5160e01b5f5260045ffd5b80610dcd5f610dd3936101e4565b806100bc565b5f610cd7565b610b4b565b808a6020610dfc83610df36001968551610a7f565b51519351610a7f565b51015160208151910120610e0e610216565b9182526020820152610e208288610a7f565b52610e2b8187610a7f565b5001610bc2565b6040840190610e4d610b9783516001600160401b0390511690565b03610e585751610bad565b637202e68560e11b5f5260045ffd5b509150610b48610956565b805191908290602001825e015f815290565b949291969593909660405197889660208801610e9f91610e72565b9063ffffffff60e01b168152600401610eb791610e72565b916001600160401b0360c01b16825263ffffffff60e01b166008820152600c01610ee091610e72565b610ee991610e72565b03601f198101835261021490836101e4565b6110ae61108b610f38610b4893610f46610f16825160ff1690565b60405160f89190911b6001600160f81b03191660208201529283906021820190565b03601f1981018452836101e4565b610f38610f97610f5d602084015163ffffffff1690565b63ff00ff00600882811b9190911691901c62ff00ff1617601081811b63ffff00001691901c61ffff161760e01b6001600160e01b03191690565b610fb260408401516040519384916020830160209181520190565b6060830151936110bc608061105b610fd188516001600160401b031690565b67ffffffffffff000067ff00ff00ff00ff0066ff00ff00ff00ff8360081c169260081b169165ffff0000ffff65ffff0000ff0065ffffffffffff67ffff0000ffff0000861666ff0000ffff000085161760101c16941691161760101b161767ffffffff0000000063ffffffff8260201c169160201b166001600160401b0360c01b911760c01b1690565b956110996040611075610f5d60208c015163ffffffff1690565b9901516040519a8b916020830160209181520190565b03601f1981018b528a6101e4565b01516040519889916020830160209181520190565b03601f1981018952886101e4565b610e84565b604051906110ce82610193565b60606080835f81525f60208201525f60408201525f838201520152565b604051906110f882610158565b60606020835f81520152565b6040519061012082018281106001600160401b03821117610173576040525f610100838281526111326110eb565b60208201528260408201526111456110eb565b60608201528260808201526111586110eb565b60a08201528260c0820152606060e08201520152565b906111788261032b565b61118560405191826101e4565b8281528092611196601f199161032b565b01905f5b8281106111a657505050565b6020906111b1611104565b8282850101520161119a565b6111c56110c1565b506111ce610216565b9081525f60208201526111e86111e38261149c565b61154c565b906111f28161163c565b6111fe6111e38361149c565b61120a6111e38461149c565b916112148461163c565b61121d8161116e565b945f5b82811061124c57505050611232610205565b948552602085015260408401526060830152608082015290565b600190611258836117ba565b60ff611262611104565b91168061128e5750600160c08201525b61127c828a610a7f565b526112878189610a7f565b5001611220565b600481036112b25750600160408201526112a784611837565b60608201525b611272565b600581036112d55750600160808201526112cb84611837565b60a0820152611272565b600681036112f55750600181526112eb84611837565b6020820152611272565b6008036112ad576001610100820152611272565b611311610905565b505f5f925f5f5b60808501805180518310156114425760406113368461133e93610a7f565b510151151590565b8061141a575b6113d1575b6113596040611336848451610a7f565b80611398575b61136d575b50600101611318565b8192506113906020606061138660809560019551610a7f565b5101510151611972565b929150611364565b50634953544d60e01b63ffffffff60e01b6113ca60606113b9868651610a7f565b510151516001600160e01b03191690565b161461135f565b955092506113f46111e3602060606113ea878a51610a7f565b5101510151611913565b926114146111e36020606061140a858b51610a7f565b5101510151611945565b95611349565b5063049534d560e41b63ffffffff60e01b61143b60606113b9868651610a7f565b1614611344565b50505092509290821561146757611457610234565b9283526020830152604082015290565b633eba99d160e21b5f5260045ffd5b634e487b7160e01b5f52601160045260245ffd5b9190820180921161149757565b611476565b602081019081516020810180911161149757815151106100b8576020905181835182010191829101116114975760206114d4916119e9565b9080519060208201809211611497575290565b906020820191825182810180911161149757815151106100b8578115611535576020905181845182010191829101116114975781611524916119e9565b918051918201809211611497575290565b5050506040516115466020826101e4565b5f815290565b602081511061155c576020015190565b60405162461bcd60e51b8152602060048201526024808201527f42797465733a3a20746f427974657333323a206461746120697320746f20736860448201526337b93a1760e11b6064820152608490fd5b60ff60049116019060ff821161149757565b156115c657565b60405162461bcd60e51b815260206004820152602860248201527f756e657870656374656420707265666978206465636f64696e6720436f6d706160448201526731ba1e2ab4b73a1f60c11b6064820152608490fd5b906001600160401b03809116911601906001600160401b03821161149757565b611645816117ba565b60038116806116615750610b48915060021c603f165b60ff1690565b600181036116a65750610b97906116a061165b61169661168661165b610b48976117ba565b60061b67ffffffffffffffc01690565b9260021c603f1690565b9061161c565b60028103611725575061171c9061170f60ff84611700826116c9610b48986117ba565b95816116ef816116e16116db886117ba565b976117ba565b991660081b63ffffff001690565b911617921660101b63ffff00001690565b17921660181b63ff0000001690565b1760021c633fffffff1690565b63ffffffff1690565b60030361176457610b489160ff61174b61174661175f94603f9060021c1690565b6115ad565b169061175a60088311156115bf565b6114e7565b611972565b60405162461bcd60e51b815260206004820152601a60248201527f436f64652073686f756c6420626520756e726561636861626c650000000000006044820152606490fd5b908151811015610a93570160200190565b60208101908151600181018091116114975781515110611803575181516001600160f81b0319916117eb91906117a9565b511660f81c9080519060018201809211611497575290565b60405162461bcd60e51b815260206004820152600c60248201526b4f7574206f662072616e676560a01b6044820152606490fd5b61183f6110eb565b50602081019081516004810180911161149757815151106100b857602081518184518201019182910111611497576004611878916119e9565b918051906004820180921161149757525f915f905b600482106118cd575050806118a46118aa9261163c565b906114e7565b6118c56118b5610216565b6001600160e01b03199093168352565b602082015290565b90926001600160f81b03196118e285846117a9565b5116908460031b9185830460081486151715611497576001926001600160e01b0319918216901c161793019061188d565b80516020116100b857602080610b4892016119e9565b602003906020821161149757565b5f1981019190821161149757565b8051806020116100b857601f198101908111611497576040820191602001821061149757610b48916119e9565b80515f91815b61198157505090565b90915f1983018381116114975761199881846117a9565b5160f81c90600381901b906001600160fd1b038116036114975760ff8111611497576001901b90818102918183041490151715611497576119d89161148a565b918015611497575f19019081611978565b9190916119f583610342565b611a0260405191826101e4565b838152611a0e84610342565b602082019190601f1901368337939091905b6020811015611a5f5780611a4057505f19905b5182518216911916179052565b611a54611a4f611a5992611929565b611a8f565b611937565b90611a33565b909182518152602081018091116114975791602081018091116114975790601f19810190811115611a2057611476565b601f8111611497576101000a9056fea2646970667358221220dad4b510a6fbf7dce2106f46e06d1ceb55fa5defab43431f67530e8bc065634364736f6c634300081e0033","sourceMap":"1947:4892:9:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;;;;;-1:-1:-1;;1947:4892:9;;;;;;;;;;;;;;;;-1:-1:-1;;;2609:45:9;;;:97;;;;1947:4892;;;;;;;;;2609:97;-1:-1:-1;;;829:40:2;;-1:-1:-1;2609:97:9;;;1947:4892;;;;;;;;;;;:::o;:::-;;;;;;-1:-1:-1;;1947:4892:9;;;;;;2133:38;-1:-1:-1;;;;;1947:4892:9;;;;;;;;;;;;-1:-1:-1;;1947:4892:9;;;;;;;2057:40;1947:4892;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;1947:4892:9;;;;;;;:::o;:::-;;:::i;:::-;;;;;;;-1:-1:-1;;;;;1947:4892:9;;;;;;;:::o;:::-;;;;;;;-1:-1:-1;;;;;1947:4892:9;;;;;;;:::o;:::-;;;;;;;-1:-1:-1;;;;;1947:4892:9;;;;;;;:::o;:::-;;;;;;;-1:-1:-1;;;;;1947:4892:9;;;;;;;:::o;:::-;;;;;;;;;;;;;-1:-1:-1;;;;;1947:4892:9;;;;;;;:::o;:::-;;;;;;;;:::i;:::-;:::o;:::-;4861:13;1947:4892;;;4861:13;1947:4892;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;:::i;:::-;;;;;-1:-1:-1;;;;;1947:4892:9;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;:::o;:::-;-1:-1:-1;;;;;1947:4892:9;;;;;;;;;:::o;:::-;-1:-1:-1;;;;;1947:4892:9;;;;;;-1:-1:-1;;1947:4892:9;;;;:::o;:::-;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;;;;;;-1:-1:-1;1947:4892:9;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;-1:-1:-1;;;;;1947:4892:9;;;;;;;;;;;-1:-1:-1;;1947:4892:9;;;;;;;;;;:::i;:::-;;;;;;;;;;;;-1:-1:-1;;;;;1947:4892:9;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;1947:4892:9;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;1947:4892:9;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1947:4892:9;;;;;;-1:-1:-1;;;;;1947:4892:9;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;;:::i;:::-;;;;;;;;;-1:-1:-1;;;;;1947:4892:9;;;;;;;;;;;;;:::i;:::-;;;;;;;;;-1:-1:-1;;;;;1947:4892:9;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;-1:-1:-1;;;;;1947:4892:9;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;-1:-1:-1;;;;;1947:4892:9;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;-1:-1:-1;1947:4892:9;;;;;;;;-1:-1:-1;;1947:4892:9;;;;:::o;:::-;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1947:4892:9;;;;;;-1:-1:-1;;;;;1947:4892:9;;;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;;;;1947:4892:9;;;;;;;;;;;:::i;:::-;3106:48;;;1947:4892;;;;;;;;3791:41;1947:4892;;3378:91;1947:4892;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;3378:91;;;;:::i;:::-;1947:4892;;;;;;;;;:::i;:::-;;;;;3511:175;;1947:4892;;3511:175;;1947:4892;;3511:175;;1947:4892;;3511:175;;1947:4892;3791:41;:::i;:::-;1947:4892;;-1:-1:-1;;;;;3888:28:9;1947:4892;;;3851:20;;;;;1947:4892;3851:20;;;:::i;:::-;;1947:4892;;3851:20;;;;;;:::i;:::-;3888:25;;1947:4892;-1:-1:-1;;;;;1947:4892:9;;;3888:28;1947:4892;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;-1:-1:-1;;;;;1947:4892:9;;;;;;;;;;:::i;:::-;;;;;;-1:-1:-1;;;;;1947:4892:9;;;;;;;;;;;:::i;:::-;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;1947:4892:9;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;1947:4892:9;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;1947:4892:9;;;;;;;;;;;;:::o;:::-;;;;;;;:::i;:::-;;-1:-1:-1;1947:4892:9;;-1:-1:-1;1947:4892:9;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;:::o;:::-;;;;;;;;:::i;:::-;4240:16;1947:4892;;;;4240:16;1947:4892;;;;;;;;;:::o;:::-;;;;;;;;:::i;:::-;4240:16;1947:4892;;4240:16;1947:4892;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;;;;:::i;:::-;;;-1:-1:-1;1947:4892:9;;;;;;;;;:::o;:::-;;;;;;;;:::i;:::-;-1:-1:-1;1947:4892:9;;-1:-1:-1;1947:4892:9;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;;;;:::i;:::-;;;-1:-1:-1;1947:4892:9;;;;;;;;;:::o;:::-;;;;;;;;:::i;:::-;-1:-1:-1;1947:4892:9;;-1:-1:-1;1947:4892:9;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;:::i;:::-;;:::o;:::-;;;;;;;;;;3994:2707;;;;1947:4892;;:::i;:::-;4163:26;4240:16;;1947:4892;;;;-1:-1:-1;4306:51:9;4302:131;;1947:4892;;:::i;:::-;4496:25;;;;1947:4892;;4525:29;;;4496:61;4525:32;:29;;-1:-1:-1;;;;;1947:4892:9;;;;;4525:32;-1:-1:-1;;;;;1947:4892:9;;;4496:61;;;4525:29;;4585;;;4492:337;4861:13;;;;;;1947:4892;4930:38;;;;:::i;:::-;4983:13;-1:-1:-1;4998:15:9;;;;;;5302:13;;5230:351;5302:13;4861;1947:4892;4496:25;5230:351;5302:13;;1947:4892;;;;;;5351:14;;1947:4892;;;;5505:13;4496:25;5505:13;;;5492:27;5505:13;;5492:27;:::i;:::-;4496:25;1947:4892;;;;5482:38;1947:4892;5545:11;;;1947:4892;;;;:::i;:::-;;;;;4496:25;5254:317;;1947:4892;4861:13;5254:317;;1947:4892;;5254:317;;1947:4892;5545:11;5254:317;;1947:4892;5254:317;;;1947:4892;4861:13;1947:4892;5230:351;;;4496:25;5230:351;;;:::i;:::-;;1947:4892;;5230:351;;;;;;:::i;:::-;1947:4892;;;;;;5591:8;1947:4892;5643:11;;;5591:64;;;;;4861:13;1947:4892;-1:-1:-1;;;5591:64:9;;1947:4892;-1:-1:-1;;1947:4892:9;;;;;;5591:64;;5612:15;5591:64;;;;:::i;:::-;;;;;;;;;;;4978:214;5686:13;;;1947:4892;5759:34;;;:::i;:::-;5808:13;-1:-1:-1;5823:13:9;;;;;;-1:-1:-1;;6353:13:9;;1947:4892;6353:30;;1947:4892;-1:-1:-1;;;;;1947:4892:9;;-1:-1:-1;6389:29:9;;;1947:4892;-1:-1:-1;;;;;6353:68:9;1947:4892;;;-1:-1:-1;;;;;1947:4892:9;;;6353:68;1947:4892;;6353:68;6349:239;;5803:536;1947:4892;;;;;;6658:36;3994:2707;:::o;6349:239::-;1947:4892;6437:32;4861:13;6437:32;;:64;6547:13;:30;;6515:62;;6349:239;;;;;5838:3;5887:16;:13;;;:16;:::i;:::-;;5959:11;5940:31;4496:25;5959:11;;;5940:31;:::i;:::-;5989:13;4496:25;5989:13;;1947:4892;;;5989:18;5985:52;;6093:24;1947:4892;6093:24;;:::i;:::-;1947:4892;;;;;;:::i;:::-;;;;4496:25;6187:96;;1947:4892;4861:13;6187:96;;1947:4892;6297:31;;;;:::i;:::-;;;;;;:::i;:::-;;1947:4892;5808:13;;5985:52;6016:21;;;-1:-1:-1;6016:21:9;5591:64;-1:-1:-1;6016:21:9;5591:64;;;-1:-1:-1;5591:64:9;;;:::i;:::-;;;:::i;:::-;;;;;;:::i;5015:3::-;5089:13;;4496:25;5142:16;5089:13;:16;1947:4892;5089:13;;;:16;:::i;:::-;;1947:4892;5142:13;;:16;:::i;:::-;;:23;;4496:25;1947:4892;;;;5132:34;1947:4892;;:::i;:::-;;;;4496:25;5047:134;;1947:4892;5034:147;;;;:::i;:::-;;;;;;:::i;:::-;;1947:4892;4983:13;;4492:337;4664:32;;;;4635:64;4664:35;:32;;-1:-1:-1;;;;;1947:4892:9;;;;;4635:64;;4664:32;;4727;4492:337;;4631:198;4797:21;;;-1:-1:-1;4797:21:9;;-1:-1:-1;4797:21:9;4302:131;4395:26;;;;;:::i;1947:4892::-;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;:::i;:::-;;-1:-1:-1;;;;;1947:4892:9;;;;;;;;;;;;;;;;;;:::i;:::-;;;;:::i;:::-;;;;;;;;;;;;:::i;2305:494:8:-;2754:28;2696:44;2434:30;2408:384;2305:494;2434:30;1947:4892:9;;;;;;;;;;;;;;;-1:-1:-1;;;;;;1947:4892:9;2434:30:8;;;1947:4892:9;;;;;;;;;2434:30:8;;1947:4892:9;;2434:30:8;;;;;;:::i;:::-;2530:33;2478:38;1947:4892:9;2434:30:8;2498:17;;1947:4892:9;;;;;;;;;;;;;;;;;;8200:10:7;1947:4892:9;8168:49:7;1947:4892:9;;;;;;;;;;;8266:21:7;1947:4892:9;;-1:-1:-1;;;;;;1947:4892:9;;8815:111:7;2478:38:8;2530:33;1947:4892:9;2547:15:8;;1947:4892:9;;;2530:33:8;;;2434:30;2530:33;;1947:4892:9;;;;;;;2530:33:8;2597:21;;;;1947:4892:9;2754:28:8;2771:10;2577:45;1947:4892:9;;;-1:-1:-1;;;;;1947:4892:9;;;;;7788:18:7;1947:4892:9;;;;;;;;;;7937:18:7;7933:22;1947:4892:9;7902:18:7;7898:22;;;;;;1947:4892:9;;;7932:30:7;7933:22;;;;1947:4892:9;;;7896:67:7;1947:4892:9;;;;;;8025:7:7;1947:4892:9;;;-1:-1:-1;;;;;1947:4892:9;;8012:21:7;;1947:4892:9;;;8698:111:7;;2577:45:8;2656:25;2696:44;1947:4892:9;2636:46:8;1947:4892:9;2434:30:8;2656:25;;1947:4892:9;;;;;2636:46:8;2713:26;;1947:4892:9;;;2696:44:8;;;2434:30;2696:44;;1947:4892:9;;;;;;;2696:44:8;;1947:4892:9;;2696:44:8;;;;;;:::i;:::-;2771:10;1947:4892:9;;;2754:28:8;;;2434:30;2754:28;;1947:4892:9;;;;;;;2754:28:8;;1947:4892:9;;2754:28:8;;;;;;:::i;:::-;2408:384;:::i;1947:4892:9:-;;;;;;;:::i;:::-;;;;-1:-1:-1;1947:4892:9;;-1:-1:-1;1947:4892:9;;;;-1:-1:-1;1947:4892:9;;;;-1:-1:-1;1947:4892:9;;;;;;:::o;:::-;;;;;;;:::i;:::-;;;;-1:-1:-1;1947:4892:9;;;;:::o;:::-;;;;;;;;;;-1:-1:-1;;;;;1947:4892:9;;;;;;;-1:-1:-1;1947:4892:9;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;:::o;:::-;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;;;;:::i;:::-;;;-1:-1:-1;1947:4892:9;;;;;;;;;:::o;:::-;;;;;:::i;:::-;;;;;;;;;;2849:1495:8;1947:4892:9;;:::i;:::-;;;;:::i;:::-;;;;2985:1:8;2966:21;;;1947:4892:9;3018:38:8;3034:21;;;:::i;:::-;3018:38;:::i;:::-;3088:35;;;;:::i;:::-;3153:38;3169:21;;;:::i;3153:38::-;3226;3242:21;;;:::i;3226:38::-;3292:35;;;;:::i;:::-;3363:20;;;:::i;:::-;3399:13;2985:1;3414:10;;;;;;1947:4892:9;;;;;:::i;:::-;;;;2966:21:8;4270:67;;1947:4892:9;;4270:67:8;;1947:4892:9;4270:67:8;;;1947:4892:9;4270:67:8;;;1947:4892:9;2849:1495:8;:::o;3426:3::-;1947:4892:9;3458:21:8;;;;:::i;:::-;1947:4892:9;;;:::i;:::-;;;3531:25:8;;;-1:-1:-1;1947:4892:9;3576:14:8;;;1506:1;3576:21;4223:19;;;;:::i;:::-;;;;;;:::i;:::-;;1947:4892:9;3399:13:8;;3527:683;1327:1;3622:29;;1327:1;;-1:-1:-1;1947:4892:9;;3671:18:8;;1506:1;3733:23;;;:::i;:::-;3714:16;;;:42;3618:592;3527:683;;3618:592;1377:1;3781:24;;1377:1;;-1:-1:-1;1947:4892:9;3825:13:8;;;1506:1;3877:23;;;:::i;:::-;3863:11;;;:37;3527:683;;3777:433;1433:1;3925:30;;1433:1;;-1:-1:-1;1947:4892:9;1506:1:8;;4039:23;;;:::i;:::-;2966:21;4019:17;;:43;3527:683;;3921:289;1506:1;4087:47;3777:433;4083:127;1947:4892:9;4154:34:8;;;1506:1;3527:683;;5863:967:10;1947:4892:9;;:::i;:::-;;-1:-1:-1;;6021:17:10;-1:-1:-1;;6094:3:10;6073:12;;;;;1947:4892:9;;6069:23:10;;;;;6117:27;:15;;:27;:15;;:::i;:::-;;:27;1947:4892:9;;;;;6117:27:10;:89;;;6094:3;6113:305;;6094:3;6436:27;6117;6436:15;:12;;;:15;:::i;:27::-;:89;;;6094:3;6432:196;;6094:3;-1:-1:-1;1947:4892:9;;6054:13:10;;6432:196;6582:12;;;6557:56;6582:30;:25;:15;6073:12;6582;1947:4892:9;6582:12:10;;:15;:::i;:::-;;:25;;:30;;6557:56;:::i;:::-;6432:196;;;;;6436:89;5488:14;;;;1947:4892:9;;;6467:37:10;:25;:15;:12;;;:15;:::i;:::-;;:25;;1947:4892:9;-1:-1:-1;;;;;;1947:4892:9;;;6467:37:10;1947:4892:9;6467:58:10;6436:89;;6113:305;6265:12;;;;6236:68;6252:51;6265:30;:25;:15;:12;;;:15;:::i;:::-;;:25;;:30;;6252:51;:::i;6236:68::-;6367:12;6338:65;6354:48;6265:30;:25;6367:15;:12;;;:15;:::i;:::-;;:25;;:30;;6354:48;:::i;6338:65::-;6113:305;;;6117:89;1947:4892:9;;;;;;;6148:37:10;:25;:15;:12;;;:15;:::i;:37::-;1947:4892:9;6148:58:10;6117:89;;6069:23;;;;;;;;6676:14;;6672:46;;1947:4892:9;;:::i;:::-;;;;6736:87:10;;;1947:4892:9;6117:27:10;6736:87;;1947:4892:9;5863:967:10;:::o;6672:46::-;6699:19;;;-1:-1:-1;6699:19:10;;-1:-1:-1;6699:19:10;1947:4892:9;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;:::i;2089:399:4:-;2966:21:8;2216:11:4;;1947:4892:9;;;2966:21:8;1947:4892:9;;;;;;;2237:9:4;;1947:4892:9;-1:-1:-1;1947:4892:9;;2966:21:8;2264:48:4;2351:9;1947:4892:9;;;;;;1938:75:5;;;;1947:4892:9;;;2966:21:8;2392:39:4;;;:::i;:::-;1947:4892:9;;;;2966:21:8;1947:4892:9;;;;;;;;2089:399:4;:::o;:::-;;2216:11;;;1947:4892:9;;;;;;;;;;;2237:9:4;;1947:4892:9;-1:-1:-1;1947:4892:9;;2268:8:4;;2264:48;;2216:11;2351:9;;1947:4892:9;;;;;;1938:75:5;;;;1947:4892:9;;;2392:39:4;;;;:::i;:::-;1947:4892:9;;;;;;;;;;;;2089:399:4;:::o;2264:48::-;1947:4892:9;;;;;;;;;:::i;:::-;-1:-1:-1;1947:4892:9;;2292:9:4;:::o;4543:226::-;4650:2;1947:4892:9;;4635:17:4;1947:4892:9;;4650:2:4;4703:60;;4543:226;:::o;1947:4892:9:-;;;-1:-1:-1;;;1947:4892:9;;4650:2:4;1947:4892:9;;;;;;;;;;;;;;-1:-1:-1;;;1947:4892:9;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;:::o;:::-;;;-1:-1:-1;;;1947:4892:9;;;;;;;;;;;;;;;;;-1:-1:-1;;;1947:4892:9;;;;;;;;;-1:-1:-1;;;;;1947:4892:9;;;;;;;-1:-1:-1;;;;;1947:4892:9;;;;:::o;1205:1510:7:-;1323:20;;;:::i;:::-;1947:4892:9;;;;1453:9:7;;-1:-1:-1;1501:14:7;;-1:-1:-1;1947:4892:9;;;;1509:6:7;1947:4892:9;;;;1449:1238:7;1579:1;1571:9;;1579:1;;1634:20;1782:11;1634:20;1782:11;1787:6;1740:7;1692:13;1634:20;1842:9;1634:20;;:::i;1692:13::-;1947:4892:9;;;;;;1740:7:7;1787:6;1947:4892:9;;;;;;1782:11:7;;;:::i;1567:1120::-;1880:1;1872:9;;1880:1;;1943:20;2275:8;1943:20;2243:16;1947:4892:9;1943:20:7;2194:16;1943:20;;2336:11;1943:20;;:::i;:::-;2013;;2118:15;2013:20;2058;2013;;;:::i;:::-;2058;;:::i;:::-;1947:4892:9;;;;;;;;2118:15:7;1947:4892:9;;2105:29:7;;1947:4892:9;;;;;;;2194:16:7;2188:23;;1947:4892:9;;;;;;;2243:16:7;2237:23;1947:4892:9;;;;;;2275:8:7;1947:4892:9;;;;1868:819:7;2376:1;2368:9;2376:1;;2575:34;2450:6;1947:4892:9;2449:12:7;2450:6;2589:19;2450:6;1947:4892:9;;;;;;;2450:6:7;2449:12;:::i;:::-;1947:4892:9;2503:6:7;2495:59;2508:1;2503:6;;;2495:59;:::i;:::-;2589:19;:::i;:::-;2575:34;:::i;2364:323::-;1947:4892:9;;-1:-1:-1;;;2640:36:7;;1947:4892:9;1393:1:7;2640:36;;1947:4892:9;;;;;;;;;;;;;2640:36:7;1947:4892:9;;;;;;;;;;;;;:::o;1564:269:4:-;1649:11;;;1947:4892:9;;;1663:1:4;1947:4892:9;;;;;;;1667:9:4;;1947:4892:9;-1:-1:-1;1645:87:4;;1758:9;1947:4892:9;;-1:-1:-1;;;;;;1947:4892:9;1758:22:4;;1947:4892:9;1758:22:4;:::i;:::-;1947:4892:9;;;;;;;1791:16:4;1663:1;1947:4892:9;;;;;;;;1564:269:4;:::o;1645:87::-;1947:4892:9;;-1:-1:-1;;;1699:22:4;;1649:11;1699:22;;;1947:4892:9;;;;;;-1:-1:-1;;;1947:4892:9;;;;1699:22:4;;;4445:308:8;1947:4892:9;;:::i;:::-;;2216:11:4;;;1947:4892:9;;;4586:1:8;1947:4892:9;;;;;;;2237:9:4;;1947:4892:9;-1:-1:-1;1947:4892:9;;2216:11:4;2351:9;;1947:4892:9;;;;;;1938:75:5;;;;1947:4892:9;;;4586:1:8;2392:39:4;;;:::i;:::-;1947:4892:9;;;;4586:1:8;1947:4892:9;;;;;;;;4590:1:8;5413:13:4;4590:1:8;5408:106:4;5428:5;4586:1:8;5428:5:4;;;;4619:35:8;;;;4684:25;4619:35;;:::i;:::-;4684:25;;:::i;:::-;4726:20;1947:4892:9;;:::i;:::-;-1:-1:-1;;;;;;1947:4892:9;;;;;;4726:20:8;2216:11:4;4726:20:8;;1947:4892:9;4445:308:8;:::o;5435:3:4:-;1947:4892:9;;-1:-1:-1;;;;;;5468:16:4;1947:4892:9;;5468:16:4;:::i;:::-;1947:4892:9;;;;;;;;;;5501:1:4;1947:4892:9;;;;;;;;;-1:-1:-1;;;;;;1947:4892:9;;;;;;5454:49:4;5435:3;1947:4892:9;5413:13:4;;;3313:349;1947:4892:9;;6265:30:10;3466:31:4;1947:4892:9;;6265:30:10;3512:8:4;3617:38;3512:8;1938:75:5;3617:38:4;:::i;1947:4892:9:-;;;;;;;;;:::o;:::-;-1:-1:-1;;1947:4892:9;;;;;;;;:::o;2744:313:4:-;1947:4892:9;;2876:25:4;6265:30:10;2876:25:4;1947:4892:9;;-1:-1:-1;;1947:4892:9;;;;;;;;;;;6265:30:10;1938:75:5;1947:4892:9;-1:-1:-1;1947:4892:9;;3012:38:4;;;:::i;823:320:7:-;1947:4892:9;;;;;961:5:7;;;1123:13;;823:320;:::o;968:3::-;1947:4892:9;;-1:-1:-1;;1947:4892:9;;;;;;;1051:11:7;;;;:::i;:::-;1947:4892:9;;;;;;;;;-1:-1:-1;;;;;1947:4892:9;;;;;;;;;;;;;1037:66:7;1947:4892:9;;;;;;;;;;;;;;1012:91:7;;;:::i;:::-;968:3;1947:4892:9;;;;-1:-1:-1;;1947:4892:9;;;936:23:7;;2284:287:5;;;;1947:4892:9;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;-1:-1:-1;;1947:4892:9;;;;2560:3:5;;;3244:193;3251:16;1947:4892:9;3251:16:5;;;;;3494:8;;;-1:-1:-1;;;1947:4892:9;3494:132:5;3636:173;;;;;;;;;;;2284:287::o;3494:132::-;3598:24;3606:15;3598:28;3606:15;;:::i;:::-;3598:24;:::i;:::-;:28;:::i;:::-;3494:132;;;3269:16;3301:65;;;;;;1947:4892:9;;;;;;;;;;;;;;;;;3269:16:5;-1:-1:-1;;1947:4892:9;;;;;;3244:193:5;1947:4892:9;;:::i;713:2:5:-;;;;;;;;;:::o","linkReferences":{},"immutableReferences":{"2634":[{"start":289,"length":32},{"start":3232,"length":32}],"2637":[{"start":219,"length":32},{"start":3162,"length":32}]}},"methodIdentifiers":{"noOp(((uint256,uint256),(uint8,uint32,bytes32,(uint64,uint32,bytes32),bytes32),(uint256,bytes)[],bytes,bytes32),(bytes32,uint256,bytes32,uint256,(uint256,bytes32)[],bytes32))":"9f81f883","supportsInterface(bytes4)":"01ffc9a7","verificationKey()":"7ddc907d","verifier()":"2b7ac3f3","verify(bytes,bytes)":"f7e83aee"},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.30+commit.73712a01\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract ISP1Verifier\",\"name\":\"v\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"vk\",\"type\":\"bytes32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"IllegalGenesisBlock\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TimestampNotFound\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnknownAuthoritySet\",\"type\":\"error\"},{\"inputs\":[{\"components\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"validatorSetId\",\"type\":\"uint256\"}],\"internalType\":\"struct MiniCommitment\",\"name\":\"commitment\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"parentNumber\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"parentHash\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"id\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"len\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"root\",\"type\":\"bytes32\"}],\"internalType\":\"struct AuthoritySetCommitment\",\"name\":\"nextAuthoritySet\",\"type\":\"tuple\"},{\"internalType\":\"bytes32\",\"name\":\"extra\",\"type\":\"bytes32\"}],\"internalType\":\"struct PartialBeefyMmrLeaf\",\"name\":\"mmrLeaf\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"header\",\"type\":\"bytes\"}],\"internalType\":\"struct ParachainHeader[]\",\"name\":\"headers\",\"type\":\"tuple[]\"},{\"internalType\":\"bytes\",\"name\":\"proof\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"nonce\",\"type\":\"bytes32\"}],\"internalType\":\"struct SP1BeefyProof\",\"name\":\"s\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"authorities_root\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"authorities_len\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"leaf_hash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"block_number\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"hash\",\"type\":\"bytes32\"}],\"internalType\":\"struct ParachainHeaderHash[]\",\"name\":\"headers\",\"type\":\"tuple[]\"},{\"internalType\":\"bytes32\",\"name\":\"nonce\",\"type\":\"bytes32\"}],\"internalType\":\"struct PublicInputs\",\"name\":\"p\",\"type\":\"tuple\"}],\"name\":\"noOp\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"verificationKey\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"verifier\",\"outputs\":[{\"internalType\":\"contract ISP1Verifier\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"previousState\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"proof\",\"type\":\"bytes\"}],\"name\":\"verify\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"stateMachineId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"height\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"overlayRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"stateRoot\",\"type\":\"bytes32\"}],\"internalType\":\"struct StateCommitment\",\"name\":\"commitment\",\"type\":\"tuple\"}],\"internalType\":\"struct IntermediateState[]\",\"name\":\"\",\"type\":\"tuple[]\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"author\":\"Polytope Labs (hello@polytope.technology)\",\"details\":\"The verification key is set at construction time as an immutable. Stale proofs (where the commitment block number <= the trusted latest height) are treated as no-ops and return the existing state with no intermediates.\",\"kind\":\"dev\",\"methods\":{\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"},\"verify(bytes,bytes)\":{\"details\":\"IConsensusV2 entry point. Decodes the proof, verifies the SP1 ZK proof, and returns the updated state along with the latest authority set id.\"}},\"title\":\"The SP1 BEEFY Consensus Client.\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"notice\":\"Verifies BEEFY consensus proofs using an SP1 zero-knowledge proof, offloading secp256k1 signature verification, authority set membership checks, and MMR leaf inclusion to an off-chain SP1 program. The on-chain contract only verifies the resulting proof against a fixed verification key and a set of public inputs (authority set commitment, parachain header hashes, MMR leaf hash, and block number).\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/consensus/SP1Beefy.sol\":\"SP1Beefy\"},\"evmVersion\":\"cancun\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[\":@hyperbridge/core/=node_modules/@hyperbridge/core/contracts/\",\":@openzeppelin/=node_modules/@openzeppelin/\",\":@polytope-labs/=node_modules/@polytope-labs/\",\":@sp1-contracts/=lib/sp1-contracts/contracts/src/\",\":@uniswap/=node_modules/@uniswap/\",\":ds-test/=lib/solidity-stringutils/lib/ds-test/src/\",\":erc4626-tests/=lib/sp1-contracts/contracts/lib/openzeppelin-contracts/lib/erc4626-tests/\",\":forge-std/=node_modules/forge-std/src/\",\":openzeppelin-contracts/=lib/sp1-contracts/contracts/lib/openzeppelin-contracts/\",\":solidity-stringutils/=lib/solidity-stringutils/\",\":sp1-contracts/=lib/sp1-contracts/contracts/\",\":stringutils/=lib/solidity-stringutils/src/\"],\"viaIR\":true},\"sources\":{\"lib/sp1-contracts/contracts/src/ISP1Verifier.sol\":{\"keccak256\":\"0x9e3ba64860bea920772dcf16be7946de2a2900d80bd51e9c0771184138f4f4d3\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://0ec7230ca1fdd74edc6ab597d80bb345282aed3f0db4788ed96b4cc373ff46a3\",\"dweb:/ipfs/QmXPuSS5gzxMhFKWr1gsxBVu6WHh53ZZEvWkGgzrkM6Y7Q\"]},\"node_modules/@hyperbridge/core/contracts/interfaces/IConsensusV2.sol\":{\"keccak256\":\"0x71dcb5168f8f0f95effac221bdc49e0f662011c1bf86a9369cc0db183b8ac4c3\",\"license\":\"Apache-2.0\",\"urls\":[\"bzz-raw://d84388af7b50f5f31110fe3d711930c816432f8c2ebcc7417639a727760544ff\",\"dweb:/ipfs/QmWp89jgUMhCqrGVDphLAEhJm5kPP6q1y9yid3D2a3JFZ9\"]},\"node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\":{\"keccak256\":\"0x2d9dc2fe26180f74c11c13663647d38e259e45f95eb88f57b61d2160b0109d3e\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://81233d1f98060113d9922180bb0f14f8335856fe9f339134b09335e9f678c377\",\"dweb:/ipfs/QmWh6R35SarhAn4z2wH8SU456jJSYL2FgucfTFgbHJJN4E\"]},\"node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\":{\"keccak256\":\"0x8891738ffe910f0cf2da09566928589bf5d63f4524dd734fd9cedbac3274dd5c\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://971f954442df5c2ef5b5ebf1eb245d7105d9fbacc7386ee5c796df1d45b21617\",\"dweb:/ipfs/QmadRjHbkicwqwwh61raUEapaVEtaLMcYbQZWs9gUkgj3u\"]},\"node_modules/@polytope-labs/solidity-merkle-trees/src/trie/Bytes.sol\":{\"keccak256\":\"0xd305383358b93285d8fcee512795487484eadfd7b602df16ff4e9b01afbefec7\",\"license\":\"Apache-2.0\",\"urls\":[\"bzz-raw://57c86cd2fe6ab591264c5632d503d77f04748d722e4defa9c2badb238ee1f9bd\",\"dweb:/ipfs/QmTZ6xTcaYkRBshq6YZVMx2kkk94ZtJsRM6xLpC5qWT3oA\"]},\"node_modules/@polytope-labs/solidity-merkle-trees/src/trie/Memory.sol\":{\"keccak256\":\"0x59e3a56caa42c1aac30231173439817d38c7f359e40bd36e9bb418d3f82ceab7\",\"license\":\"Apache-2.0\",\"urls\":[\"bzz-raw://e060fed46c6b420624166ea02a326f0f566897941bdc322257e690ae134b8179\",\"dweb:/ipfs/QmbXW8yG2ZntjLMyUEmQGcRZroZj4dVZkBhHxK2PFKfUKB\"]},\"node_modules/@polytope-labs/solidity-merkle-trees/src/trie/Node.sol\":{\"keccak256\":\"0xca611969a68f7fe63dcdc742c9caf9bc1b26495561b68f4676c209279a4576ba\",\"license\":\"Apache-2.0\",\"urls\":[\"bzz-raw://17b7ec2cf65d484f0a2c188a7ae33430b015b3a55bf10393167f53839e2dde56\",\"dweb:/ipfs/QmTQbT8J7rBRNHFXSR7S4KbpwCteMrFt8mvrzCD1vYYTwX\"]},\"node_modules/@polytope-labs/solidity-merkle-trees/src/trie/polkadot/ScaleCodec.sol\":{\"keccak256\":\"0x9ac4df46e68718f7deaaa5b7443778533f53dc0ff3736cc386cf4991099da2aa\",\"license\":\"Apache-2.0\",\"urls\":[\"bzz-raw://85d08b00d9173358323105be975ce85b7e206ba52df2d80a14d2581dec1ddd11\",\"dweb:/ipfs/QmQCqVvSdJUqfhLH8TRBGNDGiEzkGduhRacnYhoKcm7e2a\"]},\"src/consensus/Codec.sol\":{\"keccak256\":\"0xfbda8d0aef81312f23b53eb34ba4fcd19ab886cbd010a0f100d86271eecee126\",\"license\":\"Apache-2.0\",\"urls\":[\"bzz-raw://bc4a4b1a88f702efa6727c368894b8ac13b69769efc81355b71a9a0d7a2efd7b\",\"dweb:/ipfs/QmYwLJgyCr4pPRyyk2oLYMLq5QGRhCSZKLYUEdW6U2SBzx\"]},\"src/consensus/SP1Beefy.sol\":{\"keccak256\":\"0x1e86a7901ca775cfee8eed4d062e6a708a5119c77f880841641675a782839fa9\",\"license\":\"Apache-2.0\",\"urls\":[\"bzz-raw://cabf37dd8b1dc6e9f7abf1b0bc7f5e8774e17220c092b5e6a198b0bfc14683b7\",\"dweb:/ipfs/QmPZnKWfiWLkAhXfQNpgHiqP7DcyUxLznJNaY2v56UnekB\"]},\"src/consensus/Types.sol\":{\"keccak256\":\"0x0cd4baf67eddc51c6564b61a15941fa7ad2f3eb62c8de660d7170ccf9bab3aa5\",\"license\":\"Apache-2.0\",\"urls\":[\"bzz-raw://011966e9ec3a053cb886823fbde5236712811426111c532bf34eef8426627ba1\",\"dweb:/ipfs/QmXZkViui7DGVswUtpQuCoXv3xWTppEBZmsx5rgXmti63F\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.30+commit.73712a01"},"language":"Solidity","output":{"abi":[{"inputs":[{"internalType":"contract ISP1Verifier","name":"v","type":"address"},{"internalType":"bytes32","name":"vk","type":"bytes32"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"type":"error","name":"IllegalGenesisBlock"},{"inputs":[],"type":"error","name":"TimestampNotFound"},{"inputs":[],"type":"error","name":"UnknownAuthoritySet"},{"inputs":[{"internalType":"struct SP1BeefyProof","name":"s","type":"tuple","components":[{"internalType":"struct MiniCommitment","name":"commitment","type":"tuple","components":[{"internalType":"uint256","name":"blockNumber","type":"uint256"},{"internalType":"uint256","name":"validatorSetId","type":"uint256"}]},{"internalType":"struct PartialBeefyMmrLeaf","name":"mmrLeaf","type":"tuple","components":[{"internalType":"uint8","name":"version","type":"uint8"},{"internalType":"uint32","name":"parentNumber","type":"uint32"},{"internalType":"bytes32","name":"parentHash","type":"bytes32"},{"internalType":"struct AuthoritySetCommitment","name":"nextAuthoritySet","type":"tuple","components":[{"internalType":"uint64","name":"id","type":"uint64"},{"internalType":"uint32","name":"len","type":"uint32"},{"internalType":"bytes32","name":"root","type":"bytes32"}]},{"internalType":"bytes32","name":"extra","type":"bytes32"}]},{"internalType":"struct ParachainHeader[]","name":"headers","type":"tuple[]","components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"header","type":"bytes"}]},{"internalType":"bytes","name":"proof","type":"bytes"},{"internalType":"bytes32","name":"nonce","type":"bytes32"}]},{"internalType":"struct PublicInputs","name":"p","type":"tuple","components":[{"internalType":"bytes32","name":"authorities_root","type":"bytes32"},{"internalType":"uint256","name":"authorities_len","type":"uint256"},{"internalType":"bytes32","name":"leaf_hash","type":"bytes32"},{"internalType":"uint256","name":"block_number","type":"uint256"},{"internalType":"struct ParachainHeaderHash[]","name":"headers","type":"tuple[]","components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes32","name":"hash","type":"bytes32"}]},{"internalType":"bytes32","name":"nonce","type":"bytes32"}]}],"stateMutability":"pure","type":"function","name":"noOp"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"stateMutability":"view","type":"function","name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}]},{"inputs":[],"stateMutability":"view","type":"function","name":"verificationKey","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}]},{"inputs":[],"stateMutability":"view","type":"function","name":"verifier","outputs":[{"internalType":"contract ISP1Verifier","name":"","type":"address"}]},{"inputs":[{"internalType":"bytes","name":"previousState","type":"bytes"},{"internalType":"bytes","name":"proof","type":"bytes"}],"stateMutability":"view","type":"function","name":"verify","outputs":[{"internalType":"bytes","name":"","type":"bytes"},{"internalType":"struct IntermediateState[]","name":"","type":"tuple[]","components":[{"internalType":"uint256","name":"stateMachineId","type":"uint256"},{"internalType":"uint256","name":"height","type":"uint256"},{"internalType":"struct StateCommitment","name":"commitment","type":"tuple","components":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bytes32","name":"overlayRoot","type":"bytes32"},{"internalType":"bytes32","name":"stateRoot","type":"bytes32"}]}]},{"internalType":"uint256","name":"","type":"uint256"}]}],"devdoc":{"kind":"dev","methods":{"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."},"verify(bytes,bytes)":{"details":"IConsensusV2 entry point. Decodes the proof, verifies the SP1 ZK proof, and returns the updated state along with the latest authority set id."}},"version":1},"userdoc":{"kind":"user","methods":{},"version":1}},"settings":{"remappings":["@hyperbridge/core/=node_modules/@hyperbridge/core/contracts/","@openzeppelin/=node_modules/@openzeppelin/","@polytope-labs/=node_modules/@polytope-labs/","@sp1-contracts/=lib/sp1-contracts/contracts/src/","@uniswap/=node_modules/@uniswap/","ds-test/=lib/solidity-stringutils/lib/ds-test/src/","erc4626-tests/=lib/sp1-contracts/contracts/lib/openzeppelin-contracts/lib/erc4626-tests/","forge-std/=node_modules/forge-std/src/","openzeppelin-contracts/=lib/sp1-contracts/contracts/lib/openzeppelin-contracts/","solidity-stringutils/=lib/solidity-stringutils/","sp1-contracts/=lib/sp1-contracts/contracts/","stringutils/=lib/solidity-stringutils/src/"],"optimizer":{"enabled":true,"runs":200},"metadata":{"bytecodeHash":"ipfs"},"compilationTarget":{"src/consensus/SP1Beefy.sol":"SP1Beefy"},"evmVersion":"cancun","libraries":{},"viaIR":true},"sources":{"lib/sp1-contracts/contracts/src/ISP1Verifier.sol":{"keccak256":"0x9e3ba64860bea920772dcf16be7946de2a2900d80bd51e9c0771184138f4f4d3","urls":["bzz-raw://0ec7230ca1fdd74edc6ab597d80bb345282aed3f0db4788ed96b4cc373ff46a3","dweb:/ipfs/QmXPuSS5gzxMhFKWr1gsxBVu6WHh53ZZEvWkGgzrkM6Y7Q"],"license":"MIT"},"node_modules/@hyperbridge/core/contracts/interfaces/IConsensusV2.sol":{"keccak256":"0x71dcb5168f8f0f95effac221bdc49e0f662011c1bf86a9369cc0db183b8ac4c3","urls":["bzz-raw://d84388af7b50f5f31110fe3d711930c816432f8c2ebcc7417639a727760544ff","dweb:/ipfs/QmWp89jgUMhCqrGVDphLAEhJm5kPP6q1y9yid3D2a3JFZ9"],"license":"Apache-2.0"},"node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol":{"keccak256":"0x2d9dc2fe26180f74c11c13663647d38e259e45f95eb88f57b61d2160b0109d3e","urls":["bzz-raw://81233d1f98060113d9922180bb0f14f8335856fe9f339134b09335e9f678c377","dweb:/ipfs/QmWh6R35SarhAn4z2wH8SU456jJSYL2FgucfTFgbHJJN4E"],"license":"MIT"},"node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol":{"keccak256":"0x8891738ffe910f0cf2da09566928589bf5d63f4524dd734fd9cedbac3274dd5c","urls":["bzz-raw://971f954442df5c2ef5b5ebf1eb245d7105d9fbacc7386ee5c796df1d45b21617","dweb:/ipfs/QmadRjHbkicwqwwh61raUEapaVEtaLMcYbQZWs9gUkgj3u"],"license":"MIT"},"node_modules/@polytope-labs/solidity-merkle-trees/src/trie/Bytes.sol":{"keccak256":"0xd305383358b93285d8fcee512795487484eadfd7b602df16ff4e9b01afbefec7","urls":["bzz-raw://57c86cd2fe6ab591264c5632d503d77f04748d722e4defa9c2badb238ee1f9bd","dweb:/ipfs/QmTZ6xTcaYkRBshq6YZVMx2kkk94ZtJsRM6xLpC5qWT3oA"],"license":"Apache-2.0"},"node_modules/@polytope-labs/solidity-merkle-trees/src/trie/Memory.sol":{"keccak256":"0x59e3a56caa42c1aac30231173439817d38c7f359e40bd36e9bb418d3f82ceab7","urls":["bzz-raw://e060fed46c6b420624166ea02a326f0f566897941bdc322257e690ae134b8179","dweb:/ipfs/QmbXW8yG2ZntjLMyUEmQGcRZroZj4dVZkBhHxK2PFKfUKB"],"license":"Apache-2.0"},"node_modules/@polytope-labs/solidity-merkle-trees/src/trie/Node.sol":{"keccak256":"0xca611969a68f7fe63dcdc742c9caf9bc1b26495561b68f4676c209279a4576ba","urls":["bzz-raw://17b7ec2cf65d484f0a2c188a7ae33430b015b3a55bf10393167f53839e2dde56","dweb:/ipfs/QmTQbT8J7rBRNHFXSR7S4KbpwCteMrFt8mvrzCD1vYYTwX"],"license":"Apache-2.0"},"node_modules/@polytope-labs/solidity-merkle-trees/src/trie/polkadot/ScaleCodec.sol":{"keccak256":"0x9ac4df46e68718f7deaaa5b7443778533f53dc0ff3736cc386cf4991099da2aa","urls":["bzz-raw://85d08b00d9173358323105be975ce85b7e206ba52df2d80a14d2581dec1ddd11","dweb:/ipfs/QmQCqVvSdJUqfhLH8TRBGNDGiEzkGduhRacnYhoKcm7e2a"],"license":"Apache-2.0"},"src/consensus/Codec.sol":{"keccak256":"0xfbda8d0aef81312f23b53eb34ba4fcd19ab886cbd010a0f100d86271eecee126","urls":["bzz-raw://bc4a4b1a88f702efa6727c368894b8ac13b69769efc81355b71a9a0d7a2efd7b","dweb:/ipfs/QmYwLJgyCr4pPRyyk2oLYMLq5QGRhCSZKLYUEdW6U2SBzx"],"license":"Apache-2.0"},"src/consensus/SP1Beefy.sol":{"keccak256":"0x1e86a7901ca775cfee8eed4d062e6a708a5119c77f880841641675a782839fa9","urls":["bzz-raw://cabf37dd8b1dc6e9f7abf1b0bc7f5e8774e17220c092b5e6a198b0bfc14683b7","dweb:/ipfs/QmPZnKWfiWLkAhXfQNpgHiqP7DcyUxLznJNaY2v56UnekB"],"license":"Apache-2.0"},"src/consensus/Types.sol":{"keccak256":"0x0cd4baf67eddc51c6564b61a15941fa7ad2f3eb62c8de660d7170ccf9bab3aa5","urls":["bzz-raw://011966e9ec3a053cb886823fbde5236712811426111c532bf34eef8426627ba1","dweb:/ipfs/QmXZkViui7DGVswUtpQuCoXv3xWTppEBZmsx5rgXmti63F"],"license":"Apache-2.0"}},"version":1},"id":9} \ No newline at end of file diff --git a/evm/rust/src/conversions.rs b/evm/rust/src/conversions.rs index eb684da6c..312c96201 100644 --- a/evm/rust/src/conversions.rs +++ b/evm/rust/src/conversions.rs @@ -409,6 +409,7 @@ mod beefy { mmr_leaf: value.mmrLeaf.into(), headers: value.headers.into_iter().map(Into::into).collect(), proof: value.proof.to_vec(), + nonce: H256(value.nonce.0), } } } diff --git a/evm/script/DeployIsmp.s.sol b/evm/script/DeployIsmp.s.sol index a133a2834..b6588e54c 100644 --- a/evm/script/DeployIsmp.s.sol +++ b/evm/script/DeployIsmp.s.sol @@ -5,7 +5,7 @@ import "forge-std/Script.sol"; import "stringutils/strings.sol"; -import {SP1Verifier} from "@sp1-contracts/v5.0.0/SP1VerifierGroth16.sol"; +import {SP1Verifier} from "@sp1-contracts/v6.1.0/SP1VerifierGroth16.sol"; import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import {UniV4UniswapV2Wrapper} from "../src/utils/uniswapv2/UniV4UniswapV2Wrapper.sol"; import {IConsensusV2} from "@hyperbridge/core/interfaces/IConsensusV2.sol"; diff --git a/evm/src/consensus/SP1Beefy.sol b/evm/src/consensus/SP1Beefy.sol index f9cd2d380..3c404b7fe 100644 --- a/evm/src/consensus/SP1Beefy.sol +++ b/evm/src/consensus/SP1Beefy.sol @@ -86,10 +86,16 @@ contract SP1Beefy is IConsensusV2, ERC165 { MiniCommitment memory commitment, PartialBeefyMmrLeaf memory leaf, ParachainHeader[] memory headers, - bytes memory proofBytes - ) = abi.decode(proof, (MiniCommitment, PartialBeefyMmrLeaf, ParachainHeader[], bytes)); - SP1BeefyProof memory sp1Proof = - SP1BeefyProof({commitment: commitment, mmrLeaf: leaf, headers: headers, proof: proofBytes}); + bytes memory proofBytes, + bytes32 nonce + ) = abi.decode(proof, (MiniCommitment, PartialBeefyMmrLeaf, ParachainHeader[], bytes, bytes32)); + SP1BeefyProof memory sp1Proof = SP1BeefyProof({ + commitment: commitment, + mmrLeaf: leaf, + headers: headers, + proof: proofBytes, + nonce: nonce + }); (BeefyConsensusState memory newState, IntermediateState[] memory intermediates) = verifyConsensus(consensusState, sp1Proof); @@ -135,7 +141,8 @@ contract SP1Beefy is IConsensusV2, ERC165 { authorities_root: authority.root, headers: headers, block_number: commitment.blockNumber, - leaf_hash: keccak256(Codec.Encode(proof.mmrLeaf)) + leaf_hash: keccak256(Codec.Encode(proof.mmrLeaf)), + nonce: proof.nonce }) ); verifier.verifyProof(verificationKey, publicInputs, proof.proof); diff --git a/evm/src/consensus/Types.sol b/evm/src/consensus/Types.sol index 836067f0f..fcb3d025e 100644 --- a/evm/src/consensus/Types.sol +++ b/evm/src/consensus/Types.sol @@ -33,6 +33,10 @@ struct SP1BeefyProof { ParachainHeader[] headers; // SP1 plonk proof for BEEFY consensus bytes proof; + // Prover-chosen nonce committed into the proof's public values. Carried verbatim so the + // verifier can reconstruct the committed public inputs; rewarding verifiers bind it to the + // submission account to make a proof non-transferable. + bytes32 nonce; } struct MiniCommitment { @@ -66,6 +70,8 @@ struct PublicInputs { uint256 block_number; // Parachain header hashes ParachainHeaderHash[] headers; + // Prover-chosen nonce, committed verbatim by the SP1 program + bytes32 nonce; } struct Payload { diff --git a/evm/tests/foundry/SP1BeefyForkTest.sol b/evm/tests/foundry/SP1BeefyForkTest.sol index aaaa0aeb3..05ee80aaf 100644 --- a/evm/tests/foundry/SP1BeefyForkTest.sol +++ b/evm/tests/foundry/SP1BeefyForkTest.sol @@ -8,14 +8,22 @@ import {IntermediateState} from "@hyperbridge/core/interfaces/IConsensusV2.sol"; import {SP1Beefy} from "../../src/consensus/SP1Beefy.sol"; import {BeefyConsensusState} from "../../src/consensus/Types.sol"; +import {ISP1Verifier} from "@sp1-contracts/ISP1Verifier.sol"; -/// @notice Verifies an SP1Beefy proof generated by tesseract-prover (zk-beefy) -/// against the production SP1Beefy contract deployed on ethereum mainnet. +/// @notice Verifies an SP1Beefy proof generated by tesseract-prover (zk-beefy) on an ethereum +/// mainnet fork. This change rotates the SP1 program vkey, so the proof can no longer be verified +/// by the production SP1Beefy (which is pinned to the previous vkey as an immutable) until it is +/// redeployed. We therefore reuse the *live* SP1 verifier but point a fresh SP1Beefy at the new +/// vkey — still exercising the real on-chain verifier against the regenerated proof. /// contract SP1BeefyForkTest is Test { /// SP1Beefy deployed by DeployHostUpdates.s.sol — same CREATE2 address on all chains. + /// Used only to read the live SP1 verifier address; redeploy carries the new vkey. address internal constant SP1_BEEFY = 0x82582f85cf370adCB61D97dab3068c0C4102Ccb6; + /// sp1-beefy v1.1.0 program vkey (public values now include the committed prover nonce). + bytes32 internal constant VKEY = bytes32(0x007d1720c695842ed647a1a72e981751f9b5e26fc5ca038523b23430a1292f08); + /// Fixture committed under tests/foundry/fixtures/. Regenerate with the zk-beefy test: /// cargo test --release -p zk-beefy --lib tests::test_sp1_beefy -- --ignored --nocapture /// (See FIXTURE_OUT env var in tesseract/consensus/beefy/zk/src/tests.rs.) @@ -32,7 +40,7 @@ contract SP1BeefyForkTest is Test { vm.selectFork(mainnetFork); } - function testVerifyMainnetProof() public view { + function testVerifyMainnetProof() public { string memory json = vm.readFile(FIXTURE_PATH); bytes memory previousState = vm.parseJsonBytes(json, ".previous_state"); @@ -47,8 +55,12 @@ contract SP1BeefyForkTest is Test { console.log("prev.latestHeight:", prev.latestHeight); console.log("prev.currentAuthoritySet.id:", prev.currentAuthoritySet.id); + // Reuse the live SP1 verifier from the production deployment, but with the new vkey. + ISP1Verifier verifier = SP1Beefy(SP1_BEEFY).verifier(); + SP1Beefy beefy = new SP1Beefy(verifier, VKEY); + (bytes memory newStateEnc, IntermediateState[] memory intermediates, uint256 nextAuthId) = - SP1Beefy(SP1_BEEFY).verify(previousState, proof); + beefy.verify(previousState, proof); BeefyConsensusState memory newState = abi.decode(newStateEnc, (BeefyConsensusState)); console.log("new.latestHeight:", newState.latestHeight); diff --git a/evm/tests/foundry/SP1BeefyTest.sol b/evm/tests/foundry/SP1BeefyTest.sol index 3ae9e1eca..e3aa36545 100644 --- a/evm/tests/foundry/SP1BeefyTest.sol +++ b/evm/tests/foundry/SP1BeefyTest.sol @@ -23,7 +23,7 @@ import "../../src/consensus/SP1Beefy.sol"; contract SP1BeefyTest is Test { SP1Verifier internal sp1; SP1Beefy internal beefy; - bytes32 internal verificationKey = bytes32(0x0095a067623354f4cc98faa79652b2d1e0e6c11ac235abe65ad7e45a5135ead0); + bytes32 internal verificationKey = bytes32(0x007d1720c695842ed647a1a72e981751f9b5e26fc5ca038523b23430a1292f08); function setUp() public virtual { sp1 = new SP1Verifier(); @@ -79,13 +79,13 @@ contract SP1BeefyTest is Test { // Initial trusted consensus state (previous_state) captured from Polkadot // mainnet when the proof below was generated against sp1-beefy v1.0.0. bytes memory state = - hex"0000000000000000000000000000000000000000000000000000000001de0e3500000000000000000000000000000000000000000000000000000000012a53180000000000000000000000000000000000000000000000000000000000001344000000000000000000000000000000000000000000000000000000000000025831dc27bc79c0e5fc4e99d8900d13573d668a472e1d0e1ce53729448fa82512c00000000000000000000000000000000000000000000000000000000000001345000000000000000000000000000000000000000000000000000000000000025831dc27bc79c0e5fc4e99d8900d13573d668a472e1d0e1ce53729448fa82512c0"; + hex"0000000000000000000000000000000000000000000000000000000001df6bd100000000000000000000000000000000000000000000000000000000012a5318000000000000000000000000000000000000000000000000000000000000136a00000000000000000000000000000000000000000000000000000000000002582cd28e2a83ddf10dbcc7da45533a44c70d5bc52be1868649ab8c30f7ec6dc741000000000000000000000000000000000000000000000000000000000000136b00000000000000000000000000000000000000000000000000000000000002582cd28e2a83ddf10dbcc7da45533a44c70d5bc52be1868649ab8c30f7ec6dc741"; BeefyConsensusState memory initial = abi.decode(state, (BeefyConsensusState)); // ABI-encoded SP1BeefyProof (abi_encode_params output; no outer offset). bytes memory proof = - hex"0000000000000000000000000000000000000000000000000000000001de0e3d000000000000000000000000000000000000000000000000000000000000134400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001de0e3ce74b53a94acbdcc4aeece36a4c0785c6a2d2646f3f65bc7cb19a78d4840788440000000000000000000000000000000000000000000000000000000000001345000000000000000000000000000000000000000000000000000000000000025831dc27bc79c0e5fc4e99d8900d13573d668a472e1d0e1ce53729448fa82512c064298798662bb0861e07e05dfc74f7a83ed106f73fb90625089170cb8e1c3e1e00000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000d2700000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000139412d4391f1a149646243282eb12ad535048e899da224f4fdc3845897389473d5527974022ba08c7cd425cb6bab3b2d35acae88d3a6bf6fab235795ac03df6ec3e8c9effcb028ed52db3ca8c912f4e0b6fb2c7421ee9dcc7d6d2330ae1e3fe45b56c91543140661757261204992d60800000000045250535290681565089c893fd0952438961dc6c1cef3fb59a2351d0c094c0bb7bbbdcdbf39e63878070449534d5001010000000000000000000000000000000000000000000000000000000000000000bc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a044953544d2072db0e6a000000000561757261010140131f77567ddaa5e89f190abf466473c7d6254bc3ac1bb0d81a0595a353a6305cfd249460e628250f79da53a951eea20233bf840af2f4ddecce784847dabd820000000000000000000000000000000000000000000000000000000000000000000000000001644388a21c0000000000000000000000000000000000000000000000000000000000000000002f850ee998974d6cc00e50cd0814b098c05bfade466d28573240d057f25352000000000000000000000000000000000000000000000000000000000000000020b467bd1a1907e2951b90149711e993984c3b28dba9ff2f57b52d298b848c45267700a9ad82cedeba582dda1348f53f3e1e13b959092212a04db546a441551f1bfd01282476c2e2d3f0003dddf4446b182affb5c3de0113b26f4cda8abf7b77078051434cd45a1a37fcf11512df9d632ad0999df50b8b359a364eb2bd83d63e0b2d2bb5b50e73b300063d0f74ca7b7aeb5c784395784a5a3dcfccd167562482100c9ef96bd609318278de308a7c15838c0a7da26f5cc145a5d1434a4df89ead07647eba40127e056fd622957e13e746a5ff1b6540951bd4293d0d838b6fc69c2a180738486efb2bda0f6e39c7ceb7b50c1466e224e3e3a17efba358215f306c00000000000000000000000000000000000000000000000000000000"; + hex"0000000000000000000000000000000000000000000000000000000001df6bd9000000000000000000000000000000000000000000000000000000000000136a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001df6bd8b06c82d25b39550a06ab64cf89004fce1f913b27190ab108320812295591fa89000000000000000000000000000000000000000000000000000000000000136b00000000000000000000000000000000000000000000000000000000000002582cd28e2a83ddf10dbcc7da45533a44c70d5bc52be1868649ab8c30f7ec6dc741ed96e512661b155ef81e590ca5ad1bacf2ccce06e7e822ca521daa71efb4ff91000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000003608eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000d2700000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000139557ed2657ce1e450327c6006e17e64425bb2154a7e6a55514e3d37fc7fd5d9884697790283bf3e632f74afab019365ed730a6deb0bc3e70bb229635fcf769d28febdf61f520234bde985bfdd18c0b04baf50ddae8f48860b9546184888ce393886265396140661757261209441d70800000000045250535290b43da1ab3f398f7008b0bd1374925ba70102ff77f33c1acce60e98a4e40fb8cf56af7d070449534d500101af5c78d7d0420a25ee6b68dc946d9919da3799b923cff420aa27ab1b646f355794a54ad343c04bc95bb013d63caecc98e97b65edb739cacc2c6e97f7d5aba5c9044953544d20f612176a000000000561757261010162f8da99803bec263b758f801ed06717d9af6178ac74e3c5ecba6e9cf6ab5c33e4daf9b75a18945bc3bb2221e1aceef06b67c87a0c6756872789dffbcd747b810000000000000000000000000000000000000000000000000000000000000000000000000001644388a21c0000000000000000000000000000000000000000000000000000000000000000002f850ee998974d6cc00e50cd0814b098c05bfade466d28573240d057f2535200000000000000000000000000000000000000000000000000000000000000002607774c88245bcad79f2414d5829f9b61771e86fb92366a5d224ba9a42cea9b16e91bc69ca90c8f455e8973ca2d522e460b371e95a8cdd298e00558bb25e39c1046ac2fb71dfc17f57e39ae5309c9522d97cc181e836aa679be1c168e25180b1556c8c21b6537ff21a57ecb73d497301f5fc9fe8f8d312d03720e401684da5e16440efe811bc61f2bfa210171efc4745d1b7461ce5593c8bcd9a9b2f6489f6e0c8cfbf59f1489e3e9a93143084cd57df0bf06cbf1fce9a7098154abcfb984a90fd4708053142c7043ce767492db2f5c0055f8791ef0cfb31173e9cac6ab47600e3953c2efe616bbd960b6048026dd1e0bb8bba4a29f3ccdb5ac21ce3899751300000000000000000000000000000000000000000000000000000000"; (bytes memory newState, IntermediateState[] memory intermediates,) = beefy.verify(state, proof); @@ -98,14 +98,14 @@ contract SP1BeefyTest is Test { assertEq(intermediates.length, 1, "expected one intermediate state"); IntermediateState memory nexus = intermediates[0]; assertEq(nexus.stateMachineId, 3367, "state machine id"); - assertEq(nexus.height, 10296916, "height"); + assertEq(nexus.height, 10380753, "height"); // Timestamp (seconds) is read from the ISMP `ISTM` timestamp digest. - assertEq(nexus.commitment.timestamp, 1779358578, "timestamp"); + assertEq(nexus.commitment.timestamp, 1779897078, "timestamp"); assertEq( nexus.commitment.stateRoot, - bytes32(0xbc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a), + bytes32(0x94a54ad343c04bc95bb013d63caecc98e97b65edb739cacc2c6e97f7d5aba5c9), "state root" ); - assertEq(nexus.commitment.overlayRoot, bytes32(0x0000000000000000000000000000000000000000000000000000000000000000), "overlay root"); + assertEq(nexus.commitment.overlayRoot, bytes32(0xaf5c78d7d0420a25ee6b68dc946d9919da3799b923cff420aa27ab1b646f3557), "overlay root"); } } diff --git a/evm/tests/foundry/fixtures/sp1_beefy_fixture.json b/evm/tests/foundry/fixtures/sp1_beefy_fixture.json index c2aad346f..ee024685c 100644 --- a/evm/tests/foundry/fixtures/sp1_beefy_fixture.json +++ b/evm/tests/foundry/fixtures/sp1_beefy_fixture.json @@ -1,16 +1,16 @@ { - "block_number": 31213559, + "block_number": 31419353, "intermediates_expected": [ { - "height": 10184385, - "overlay_root": "0xdb5a2025cacc6a30cb8359a594d7d5cd3b001b060efc658775c43dd9febee19f", + "height": 10380753, + "overlay_root": "0xaf5c78d7d0420a25ee6b68dc946d9919da3799b923cff420aa27ab1b646f3557", "state_machine_id": 3367, - "state_root": "0x9b04637257e1a28fb87a12795e7c1f4bb4f43c5c03f904dbda1b6dcbd63883ae", - "timestamp": 1778658960000 + "state_root": "0x94a54ad343c04bc95bb013d63caecc98e97b65edb739cacc2c6e97f7d5aba5c9", + "timestamp": 1779897078 } ], "para_id": 3367, - "previous_state": "0x0000000000000000000000000000000000000000000000000000000001dc47ef00000000000000000000000000000000000000000000000000000000012a53180000000000000000000000000000000000000000000000000000000000001314000000000000000000000000000000000000000000000000000000000000025880af94e4aabe6b11819d8e50059b73693140c4e781a3380311ffd1334d3685800000000000000000000000000000000000000000000000000000000000001315000000000000000000000000000000000000000000000000000000000000025880af94e4aabe6b11819d8e50059b73693140c4e781a3380311ffd1334d368580", - "proof": "0x0000000000000000000000000000000000000000000000000000000001dc47f7000000000000000000000000000000000000000000000000000000000000131400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001dc47f626de324920a139adbcfec37592c3d5d4f1c5d47be3c962da23f54de266b6b7af0000000000000000000000000000000000000000000000000000000000001315000000000000000000000000000000000000000000000000000000000000025880af94e4aabe6b11819d8e50059b73693140c4e781a3380311ffd1334d368580dd392bcf43ae0ec709e1b092c8104422611665975c6cd579c30dd08e9b087b8700000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000d2700000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000139371a10acc61519dfb7f41332f5b20fe72f320506c47091aaaf4210d4f078dec7069b6d028d87933c5237ba98c8dca60d753a1053494e6c11df7c23cba900e0cf54797f2a008138fa61940fae7e4f1ec58907ccc57eced453b3d00b29c7f7eaa999e03e09140661757261208caed508000000000452505352906934e5099eb4a44dfb23d258d0510adb4e9a427fc7499b8870130457d826ad10ce1f71070449534d500101db5a2025cacc6a30cb8359a594d7d5cd3b001b060efc658775c43dd9febee19f9b04637257e1a28fb87a12795e7c1f4bb4f43c5c03f904dbda1b6dcbd63883ae044953544d20902e046a0000000005617572610101367b70f2da76391f7f810ab08a393987460cff2d2e290fc689ff6fccc30807568f8e57226898192ad284ee82e6187e07bd3864988c29a905d4f108323d38f18b0000000000000000000000000000000000000000000000000000000000000000000000000001644388a21c0000000000000000000000000000000000000000000000000000000000000000002f850ee998974d6cc00e50cd0814b098c05bfade466d28573240d057f2535200000000000000000000000000000000000000000000000000000000000000001e42a064240ad4f396a1db358a97274a6b43b143323c70ccb064463c51f620ae18cdd61384fb99d6440bde7472eac01b5441502a7ae704ad89bb1708640b138e228e12adc1afa827f2fa3de02243430dec1f4c9eb55cf7c7d1a0e764ac7b76540f8544daaa4e46e81227c73b6dbb99e60bc412100b588b6d00178b37943a43b2262ecd4e750cf44b41b95b306a24e408cc1b1549b3087717f57660b23eca45de121714e2e0045462d3ce7aa03700daf7842ca59126f6b30819523e3eabc8ad9c0db273840c5d6bf2468b8925dcd6e8aee857e3197ef280dcf0a8d5369be964822b4b0f8508f24277738b1f4c9ca06d2f2166f42f9f9b470bc5968526d55bbbc300000000000000000000000000000000000000000000000000000000", - "validator_set_id": 4884 + "previous_state": "0x0000000000000000000000000000000000000000000000000000000001df6bd100000000000000000000000000000000000000000000000000000000012a5318000000000000000000000000000000000000000000000000000000000000136a00000000000000000000000000000000000000000000000000000000000002582cd28e2a83ddf10dbcc7da45533a44c70d5bc52be1868649ab8c30f7ec6dc741000000000000000000000000000000000000000000000000000000000000136b00000000000000000000000000000000000000000000000000000000000002582cd28e2a83ddf10dbcc7da45533a44c70d5bc52be1868649ab8c30f7ec6dc741", + "proof": "0x0000000000000000000000000000000000000000000000000000000001df6bd9000000000000000000000000000000000000000000000000000000000000136a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001df6bd8b06c82d25b39550a06ab64cf89004fce1f913b27190ab108320812295591fa89000000000000000000000000000000000000000000000000000000000000136b00000000000000000000000000000000000000000000000000000000000002582cd28e2a83ddf10dbcc7da45533a44c70d5bc52be1868649ab8c30f7ec6dc741ed96e512661b155ef81e590ca5ad1bacf2ccce06e7e822ca521daa71efb4ff91000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000003608eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000d2700000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000139557ed2657ce1e450327c6006e17e64425bb2154a7e6a55514e3d37fc7fd5d9884697790283bf3e632f74afab019365ed730a6deb0bc3e70bb229635fcf769d28febdf61f520234bde985bfdd18c0b04baf50ddae8f48860b9546184888ce393886265396140661757261209441d70800000000045250535290b43da1ab3f398f7008b0bd1374925ba70102ff77f33c1acce60e98a4e40fb8cf56af7d070449534d500101af5c78d7d0420a25ee6b68dc946d9919da3799b923cff420aa27ab1b646f355794a54ad343c04bc95bb013d63caecc98e97b65edb739cacc2c6e97f7d5aba5c9044953544d20f612176a000000000561757261010162f8da99803bec263b758f801ed06717d9af6178ac74e3c5ecba6e9cf6ab5c33e4daf9b75a18945bc3bb2221e1aceef06b67c87a0c6756872789dffbcd747b810000000000000000000000000000000000000000000000000000000000000000000000000001644388a21c0000000000000000000000000000000000000000000000000000000000000000002f850ee998974d6cc00e50cd0814b098c05bfade466d28573240d057f2535200000000000000000000000000000000000000000000000000000000000000002607774c88245bcad79f2414d5829f9b61771e86fb92366a5d224ba9a42cea9b16e91bc69ca90c8f455e8973ca2d522e460b371e95a8cdd298e00558bb25e39c1046ac2fb71dfc17f57e39ae5309c9522d97cc181e836aa679be1c168e25180b1556c8c21b6537ff21a57ecb73d497301f5fc9fe8f8d312d03720e401684da5e16440efe811bc61f2bfa210171efc4745d1b7461ce5593c8bcd9a9b2f6489f6e0c8cfbf59f1489e3e9a93143084cd57df0bf06cbf1fce9a7098154abcfb984a90fd4708053142c7043ce767492db2f5c0055f8791ef0cfb31173e9cac6ab47600e3953c2efe616bbd960b6048026dd1e0bb8bba4a29f3ccdb5ac21ce3899751300000000000000000000000000000000000000000000000000000000", + "validator_set_id": 4970 } \ No newline at end of file diff --git a/modules/consensus/beefy/primitives/src/lib.rs b/modules/consensus/beefy/primitives/src/lib.rs index e9f31ea04..cf0609d2d 100644 --- a/modules/consensus/beefy/primitives/src/lib.rs +++ b/modules/consensus/beefy/primitives/src/lib.rs @@ -139,6 +139,11 @@ pub struct Sp1BeefyProof { pub headers: Vec, /// SP1 proof bytes pub proof: Vec, + /// Prover-chosen nonce committed into the SP1 public values. The verifier reconstructs the + /// committed public inputs with this value, so the proof is only valid for this exact nonce. + /// Rewarding verifiers (`pallet-beefy-consensus-proofs`) bind it to the extrinsic submission + /// account, making the proof non-transferable. + pub nonce: H256, } /// finality proof diff --git a/modules/consensus/beefy/verifier/src/sp1.rs b/modules/consensus/beefy/verifier/src/sp1.rs index be2e68646..317e84ca9 100644 --- a/modules/consensus/beefy/verifier/src/sp1.rs +++ b/modules/consensus/beefy/verifier/src/sp1.rs @@ -39,6 +39,7 @@ sol! { bytes32 leaf_hash; uint256 block_number; ParachainHeaderHash[] headers; + bytes32 nonce; } } @@ -81,6 +82,7 @@ pub fn verify_sp1_consensus( leaf_hash: FixedBytes::from(Into::<[u8; 32]>::into(H::keccak256(&proof.mmr_leaf.encode()))), block_number: U256::from(proof.block_number), headers, + nonce: FixedBytes::from(proof.nonce.0), } .abi_encode(); diff --git a/modules/consensus/beefy/verifier/src/test.rs b/modules/consensus/beefy/verifier/src/test.rs index 3541c3c9b..46f7e6d5f 100644 --- a/modules/consensus/beefy/verifier/src/test.rs +++ b/modules/consensus/beefy/verifier/src/test.rs @@ -269,6 +269,9 @@ fn dump_sp1_fixture_scale_bytes() { mmr_leaf: leaf.into(), headers: headers.into_iter().map(Into::into).collect(), proof: plonk_proof.to_vec(), + // REGEN: fixtures predate the committed-nonce public input; regenerate with the + // rebuilt ELF/vkey and set this to the fixture's committed nonce. + nonce: Default::default(), }; let mut wire = vec![PROOF_TYPE_SP1]; @@ -301,13 +304,13 @@ fn test_sp1_verify_consensus_accepts_solidity_fixture() { sp1_beefy::SP1Beefy::{MiniCommitment, ParachainHeader, PartialBeefyMmrLeaf}, }; - // Fixture: Polkadot relay block 31213559, Nexus parachain height 10184385. - // Generated against SP1 program vkey 0x009ce9c8...cddcf (the mainnet deployment). + // Fixture: evm/tests/foundry/fixtures/sp1_beefy_fixture.json (committed nonce = Bob). + // Generated against SP1 program vkey 0x007d1720 (v1.1.0, committed nonce = Bob). let state_bytes = hex!( - "0000000000000000000000000000000000000000000000000000000001dc47ef00000000000000000000000000000000000000000000000000000000012a53180000000000000000000000000000000000000000000000000000000000001314000000000000000000000000000000000000000000000000000000000000025880af94e4aabe6b11819d8e50059b73693140c4e781a3380311ffd1334d3685800000000000000000000000000000000000000000000000000000000000001315000000000000000000000000000000000000000000000000000000000000025880af94e4aabe6b11819d8e50059b73693140c4e781a3380311ffd1334d368580" + "0000000000000000000000000000000000000000000000000000000001df6bd100000000000000000000000000000000000000000000000000000000012a5318000000000000000000000000000000000000000000000000000000000000136a00000000000000000000000000000000000000000000000000000000000002582cd28e2a83ddf10dbcc7da45533a44c70d5bc52be1868649ab8c30f7ec6dc741000000000000000000000000000000000000000000000000000000000000136b00000000000000000000000000000000000000000000000000000000000002582cd28e2a83ddf10dbcc7da45533a44c70d5bc52be1868649ab8c30f7ec6dc741" ); let proof_bytes = hex!( - "0000000000000000000000000000000000000000000000000000000001dc47f7000000000000000000000000000000000000000000000000000000000000131400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001dc47f626de324920a139adbcfec37592c3d5d4f1c5d47be3c962da23f54de266b6b7af0000000000000000000000000000000000000000000000000000000000001315000000000000000000000000000000000000000000000000000000000000025880af94e4aabe6b11819d8e50059b73693140c4e781a3380311ffd1334d368580dd392bcf43ae0ec709e1b092c8104422611665975c6cd579c30dd08e9b087b8700000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000d2700000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000139371a10acc61519dfb7f41332f5b20fe72f320506c47091aaaf4210d4f078dec7069b6d028d87933c5237ba98c8dca60d753a1053494e6c11df7c23cba900e0cf54797f2a008138fa61940fae7e4f1ec58907ccc57eced453b3d00b29c7f7eaa999e03e09140661757261208caed508000000000452505352906934e5099eb4a44dfb23d258d0510adb4e9a427fc7499b8870130457d826ad10ce1f71070449534d500101db5a2025cacc6a30cb8359a594d7d5cd3b001b060efc658775c43dd9febee19f9b04637257e1a28fb87a12795e7c1f4bb4f43c5c03f904dbda1b6dcbd63883ae044953544d20902e046a0000000005617572610101367b70f2da76391f7f810ab08a393987460cff2d2e290fc689ff6fccc30807568f8e57226898192ad284ee82e6187e07bd3864988c29a905d4f108323d38f18b0000000000000000000000000000000000000000000000000000000000000000000000000001644388a21c0000000000000000000000000000000000000000000000000000000000000000002f850ee998974d6cc00e50cd0814b098c05bfade466d28573240d057f2535200000000000000000000000000000000000000000000000000000000000000001e42a064240ad4f396a1db358a97274a6b43b143323c70ccb064463c51f620ae18cdd61384fb99d6440bde7472eac01b5441502a7ae704ad89bb1708640b138e228e12adc1afa827f2fa3de02243430dec1f4c9eb55cf7c7d1a0e764ac7b76540f8544daaa4e46e81227c73b6dbb99e60bc412100b588b6d00178b37943a43b2262ecd4e750cf44b41b95b306a24e408cc1b1549b3087717f57660b23eca45de121714e2e0045462d3ce7aa03700daf7842ca59126f6b30819523e3eabc8ad9c0db273840c5d6bf2468b8925dcd6e8aee857e3197ef280dcf0a8d5369be964822b4b0f8508f24277738b1f4c9ca06d2f2166f42f9f9b470bc5968526d55bbbc300000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000001df6bd9000000000000000000000000000000000000000000000000000000000000136a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001df6bd8b06c82d25b39550a06ab64cf89004fce1f913b27190ab108320812295591fa89000000000000000000000000000000000000000000000000000000000000136b00000000000000000000000000000000000000000000000000000000000002582cd28e2a83ddf10dbcc7da45533a44c70d5bc52be1868649ab8c30f7ec6dc741ed96e512661b155ef81e590ca5ad1bacf2ccce06e7e822ca521daa71efb4ff91000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000003608eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000d2700000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000139557ed2657ce1e450327c6006e17e64425bb2154a7e6a55514e3d37fc7fd5d9884697790283bf3e632f74afab019365ed730a6deb0bc3e70bb229635fcf769d28febdf61f520234bde985bfdd18c0b04baf50ddae8f48860b9546184888ce393886265396140661757261209441d70800000000045250535290b43da1ab3f398f7008b0bd1374925ba70102ff77f33c1acce60e98a4e40fb8cf56af7d070449534d500101af5c78d7d0420a25ee6b68dc946d9919da3799b923cff420aa27ab1b646f355794a54ad343c04bc95bb013d63caecc98e97b65edb739cacc2c6e97f7d5aba5c9044953544d20f612176a000000000561757261010162f8da99803bec263b758f801ed06717d9af6178ac74e3c5ecba6e9cf6ab5c33e4daf9b75a18945bc3bb2221e1aceef06b67c87a0c6756872789dffbcd747b810000000000000000000000000000000000000000000000000000000000000000000000000001644388a21c0000000000000000000000000000000000000000000000000000000000000000002f850ee998974d6cc00e50cd0814b098c05bfade466d28573240d057f2535200000000000000000000000000000000000000000000000000000000000000002607774c88245bcad79f2414d5829f9b61771e86fb92366a5d224ba9a42cea9b16e91bc69ca90c8f455e8973ca2d522e460b371e95a8cdd298e00558bb25e39c1046ac2fb71dfc17f57e39ae5309c9522d97cc181e836aa679be1c168e25180b1556c8c21b6537ff21a57ecb73d497301f5fc9fe8f8d312d03720e401684da5e16440efe811bc61f2bfa210171efc4745d1b7461ce5593c8bcd9a9b2f6489f6e0c8cfbf59f1489e3e9a93143084cd57df0bf06cbf1fce9a7098154abcfb984a90fd4708053142c7043ce767492db2f5c0055f8791ef0cfb31173e9cac6ab47600e3953c2efe616bbd960b6048026dd1e0bb8bba4a29f3ccdb5ac21ce3899751300000000000000000000000000000000000000000000000000000000" ); let sol_state = @@ -316,8 +319,8 @@ fn test_sp1_verify_consensus_accepts_solidity_fixture() { // Proof payload matches SP1Beefy.sol:verifyConsensus's `abi.decode(...)` call: // a sequence of four top-level types, not a struct wrapper. - type ProofTuple = sol! { (MiniCommitment, PartialBeefyMmrLeaf, ParachainHeader[], bytes) }; - let (commitment, leaf, headers, plonk_proof) = + type ProofTuple = sol! { (MiniCommitment, PartialBeefyMmrLeaf, ParachainHeader[], bytes, bytes32) }; + let (commitment, leaf, headers, plonk_proof, nonce) = ::abi_decode_sequence(&proof_bytes).expect("decode proof tuple"); let sp1_proof = Sp1BeefyProof { block_number: commitment.blockNumber.try_into().expect("block number out of bounds"), @@ -328,11 +331,12 @@ fn test_sp1_verify_consensus_accepts_solidity_fixture() { mmr_leaf: leaf.into(), headers: headers.into_iter().map(Into::into).collect(), proof: plonk_proof.to_vec(), + nonce: H256(nonce.0), }; // Mainnet SP1Beefy verification key — matches `SP1_VERIFICATION_KEY` in // `0x82582f85cf370adCB61D97dab3068c0C4102Ccb6`. - let vkey_hash = "0x009ce9c86546ac790c9e694519e16e59ff34b633c309fe4d6a4f850b886cddcf"; + let vkey_hash = "0x007d1720c695842ed647a1a72e981751f9b5e26fc5ca038523b23430a1292f08"; let result = sp_io::TestExternalities::default().execute_with(|| { crate::sp1::verify_sp1_consensus::(trusted.clone(), sp1_proof, vkey_hash) }); diff --git a/modules/pallets/beefy-consensus-proofs/src/benchmarking.rs b/modules/pallets/beefy-consensus-proofs/src/benchmarking.rs index b7c498d31..4ecb1c583 100644 --- a/modules/pallets/beefy-consensus-proofs/src/benchmarking.rs +++ b/modules/pallets/beefy-consensus-proofs/src/benchmarking.rs @@ -24,27 +24,27 @@ use sp_core::{Get, H256}; /// SCALE-encoded `beefy_verifier_primitives::ConsensusState` for the SP1 Groth16 fixture /// produced by `zk-beefy::tests::test_sp1_beefy` and committed under /// `evm/tests/foundry/fixtures/sp1_beefy_fixture.json`. The first 4 bytes -/// (`latest_beefy_height` LE) decode to 31_213_551 = 0x01dc47ef, which is below the -/// fixture proof's `blockNumber = 0x01dc47f7`. Used as the pre-proof snapshot in +/// (`latest_beefy_height` LE) decode to 31_419_345 = 0x01df6bd1, which is below the +/// fixture proof's `blockNumber = 0x01df6bd9`. Used as the pre-proof snapshot in /// `ProofContext` so `settle_uncle_proof`'s SP1 verifier sees a valid trusted state. -const TRUSTED_STATE_SCALE: [u8; 128] = hex_literal::hex!("ef47dc0118532a01000000000000000000000000000000000000000000000000000000000000000014130000000000005802000080af94e4aabe6b11819d8e50059b73693140c4e781a3380311ffd1334d36858015130000000000005802000080af94e4aabe6b11819d8e50059b73693140c4e781a3380311ffd1334d368580"); +const TRUSTED_STATE_SCALE: [u8; 128] = hex_literal::hex!("d16bdf0118532a0100000000000000000000000000000000000000000000000000000000000000006a13000000000000580200002cd28e2a83ddf10dbcc7da45533a44c70d5bc52be1868649ab8c30f7ec6dc7416b13000000000000580200002cd28e2a83ddf10dbcc7da45533a44c70d5bc52be1868649ab8c30f7ec6dc741"); /// Same fixture as `TRUSTED_STATE_SCALE` but with `latest_beefy_height` bumped to -/// 31_213_559 = 0x01dc47f7, which equals the fixture proof's `blockNumber`. +/// 31_419_353 = 0x01df6bd9, which equals the fixture proof's `blockNumber`. /// Used as the live consensus state so the SP1 verifier inside /// `BeefyConsensusClient::verify_consensus` returns `StaleHeight` cheaply (its own /// upfront check, before any cryptographic work). The pallet maps that to `StaleProof`, /// dispatch routes to `settle_uncle_proof`, and SP1 runs once there. Net cost on the /// measured path: one SP1 verification + uncle storage writes. -const LIVE_STATE_SCALE: [u8; 128] = hex_literal::hex!("f747dc0118532a01000000000000000000000000000000000000000000000000000000000000000014130000000000005802000080af94e4aabe6b11819d8e50059b73693140c4e781a3380311ffd1334d36858015130000000000005802000080af94e4aabe6b11819d8e50059b73693140c4e781a3380311ffd1334d368580"); +const LIVE_STATE_SCALE: [u8; 128] = hex_literal::hex!("d96bdf0118532a0100000000000000000000000000000000000000000000000000000000000000006a13000000000000580200002cd28e2a83ddf10dbcc7da45533a44c70d5bc52be1868649ab8c30f7ec6dc7416b13000000000000580200002cd28e2a83ddf10dbcc7da45533a44c70d5bc52be1868649ab8c30f7ec6dc741"); /// Wire-format proof: `[PROOF_TYPE_SP1] ++ abi_encode_params(SP1BeefyProof)`. /// ABI bytes lifted verbatim from `evm/tests/foundry/fixtures/sp1_beefy_fixture.json`, /// which is the same fixture consumed by `SP1BeefyForkTest`. -const WIRE_PROOF: [u8; 1249] = hex_literal::hex!("010000000000000000000000000000000000000000000000000000000001dc47f7000000000000000000000000000000000000000000000000000000000000131400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001dc47f626de324920a139adbcfec37592c3d5d4f1c5d47be3c962da23f54de266b6b7af0000000000000000000000000000000000000000000000000000000000001315000000000000000000000000000000000000000000000000000000000000025880af94e4aabe6b11819d8e50059b73693140c4e781a3380311ffd1334d368580dd392bcf43ae0ec709e1b092c8104422611665975c6cd579c30dd08e9b087b8700000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000d2700000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000139371a10acc61519dfb7f41332f5b20fe72f320506c47091aaaf4210d4f078dec7069b6d028d87933c5237ba98c8dca60d753a1053494e6c11df7c23cba900e0cf54797f2a008138fa61940fae7e4f1ec58907ccc57eced453b3d00b29c7f7eaa999e03e09140661757261208caed508000000000452505352906934e5099eb4a44dfb23d258d0510adb4e9a427fc7499b8870130457d826ad10ce1f71070449534d500101db5a2025cacc6a30cb8359a594d7d5cd3b001b060efc658775c43dd9febee19f9b04637257e1a28fb87a12795e7c1f4bb4f43c5c03f904dbda1b6dcbd63883ae044953544d20902e046a0000000005617572610101367b70f2da76391f7f810ab08a393987460cff2d2e290fc689ff6fccc30807568f8e57226898192ad284ee82e6187e07bd3864988c29a905d4f108323d38f18b0000000000000000000000000000000000000000000000000000000000000000000000000001644388a21c0000000000000000000000000000000000000000000000000000000000000000002f850ee998974d6cc00e50cd0814b098c05bfade466d28573240d057f2535200000000000000000000000000000000000000000000000000000000000000001e42a064240ad4f396a1db358a97274a6b43b143323c70ccb064463c51f620ae18cdd61384fb99d6440bde7472eac01b5441502a7ae704ad89bb1708640b138e228e12adc1afa827f2fa3de02243430dec1f4c9eb55cf7c7d1a0e764ac7b76540f8544daaa4e46e81227c73b6dbb99e60bc412100b588b6d00178b37943a43b2262ecd4e750cf44b41b95b306a24e408cc1b1549b3087717f57660b23eca45de121714e2e0045462d3ce7aa03700daf7842ca59126f6b30819523e3eabc8ad9c0db273840c5d6bf2468b8925dcd6e8aee857e3197ef280dcf0a8d5369be964822b4b0f8508f24277738b1f4c9ca06d2f2166f42f9f9b470bc5968526d55bbbc300000000000000000000000000000000000000000000000000000000"); +const WIRE_PROOF: [u8; 1281] = hex_literal::hex!("010000000000000000000000000000000000000000000000000000000001df6bd9000000000000000000000000000000000000000000000000000000000000136a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001df6bd8b06c82d25b39550a06ab64cf89004fce1f913b27190ab108320812295591fa89000000000000000000000000000000000000000000000000000000000000136b00000000000000000000000000000000000000000000000000000000000002582cd28e2a83ddf10dbcc7da45533a44c70d5bc52be1868649ab8c30f7ec6dc741ed96e512661b155ef81e590ca5ad1bacf2ccce06e7e822ca521daa71efb4ff91000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000003608eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000d2700000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000139557ed2657ce1e450327c6006e17e64425bb2154a7e6a55514e3d37fc7fd5d9884697790283bf3e632f74afab019365ed730a6deb0bc3e70bb229635fcf769d28febdf61f520234bde985bfdd18c0b04baf50ddae8f48860b9546184888ce393886265396140661757261209441d70800000000045250535290b43da1ab3f398f7008b0bd1374925ba70102ff77f33c1acce60e98a4e40fb8cf56af7d070449534d500101af5c78d7d0420a25ee6b68dc946d9919da3799b923cff420aa27ab1b646f355794a54ad343c04bc95bb013d63caecc98e97b65edb739cacc2c6e97f7d5aba5c9044953544d20f612176a000000000561757261010162f8da99803bec263b758f801ed06717d9af6178ac74e3c5ecba6e9cf6ab5c33e4daf9b75a18945bc3bb2221e1aceef06b67c87a0c6756872789dffbcd747b810000000000000000000000000000000000000000000000000000000000000000000000000001644388a21c0000000000000000000000000000000000000000000000000000000000000000002f850ee998974d6cc00e50cd0814b098c05bfade466d28573240d057f2535200000000000000000000000000000000000000000000000000000000000000002607774c88245bcad79f2414d5829f9b61771e86fb92366a5d224ba9a42cea9b16e91bc69ca90c8f455e8973ca2d522e460b371e95a8cdd298e00558bb25e39c1046ac2fb71dfc17f57e39ae5309c9522d97cc181e836aa679be1c168e25180b1556c8c21b6537ff21a57ecb73d497301f5fc9fe8f8d312d03720e401684da5e16440efe811bc61f2bfa210171efc4745d1b7461ce5593c8bcd9a9b2f6489f6e0c8cfbf59f1489e3e9a93143084cd57df0bf06cbf1fce9a7098154abcfb984a90fd4708053142c7043ce767492db2f5c0055f8791ef0cfb31173e9cac6ab47600e3953c2efe616bbd960b6048026dd1e0bb8bba4a29f3ccdb5ac21ce3899751300000000000000000000000000000000000000000000000000000000"); const FIXTURE_VKEY: H256 = - H256(hex_literal::hex!("009ce9c86546ac790c9e694519e16e59ff34b633c309fe4d6a4f850b886cddcf")); + H256(hex_literal::hex!("007d1720c695842ed647a1a72e981751f9b5e26fc5ca038523b23430a1292f08")); #[benchmarks( where @@ -89,9 +89,10 @@ mod benchmarks { // `blockNumber` so the SP1 verifier accepts the proof here. pallet::ProofContext::::insert(0u64, TRUSTED_STATE_SCALE.to_vec()); - // Any 32-byte AccountId works. The signed origin doesn't need a keystore entry - // for the actual signature, just a usable AccountId for reward payout. - let submitter: T::AccountId = [1u8; 32].into(); + // The committed nonce in the fixture is Bob's account, so the signer must be Bob for + // the `nonce == signer` check to pass. + let submitter: T::AccountId = + hex_literal::hex!("8eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48").into(); let proof = frame_support::BoundedVec::::truncate_from(WIRE_PROOF.to_vec()); @@ -99,9 +100,9 @@ mod benchmarks { #[extrinsic_call] _(RawOrigin::Signed(submitter), proof); - // Uncle accepted at position 0; one hash recorded under height 0. + // Uncle accepted at position 0; one submitter account recorded under height 0. assert_eq!(pallet::ProverCount::::get(0u64), 1); - assert_eq!(pallet::AcceptedProofHashes::::get(0u64).len(), 1); + assert_eq!(pallet::AcceptedProvers::::get(0u64).len(), 1); } #[benchmark] @@ -125,16 +126,17 @@ mod benchmarks { #[benchmark] fn set_reward_curve() { - // Suggested mainnet defaults: 100%, 80%, 60%, 40%, 20%. The curve is bounded by - // `MaxStoredProvers` (`MaxUncleProvers + 1`), covering position 0 plus every - // uncle slot. + // Mainnet curve: 100%, 50%, 30%, 20%, 10%, 5% — the first prover (position 0) earns the + // full reward and each successive uncle a decreasing share. The curve is bounded by + // `MaxStoredProvers` (`MaxUncleProvers + 1`), covering position 0 plus every uncle slot. let curve: frame_support::BoundedVec<(u32, u32), pallet::MaxStoredProvers> = frame_support::BoundedVec::truncate_from(alloc::vec![ (1u32, 1u32), - (4, 5), - (3, 5), - (2, 5), + (1, 2), + (3, 10), (1, 5), + (1, 10), + (1, 20), ]); #[extrinsic_call] diff --git a/modules/pallets/beefy-consensus-proofs/src/lib.rs b/modules/pallets/beefy-consensus-proofs/src/lib.rs index 6f9441f6c..4c92c418a 100644 --- a/modules/pallets/beefy-consensus-proofs/src/lib.rs +++ b/modules/pallets/beefy-consensus-proofs/src/lib.rs @@ -30,15 +30,24 @@ //! //! Multiple SP1 provers running independently can each get rewarded for the same //! finality target via decreasing-curve uncle rewards. The first prover to land a -//! proof advances state and gets position 0; subsequent independent provers -//! (different proof bytes thanks to SP1 Groth16 witness randomization) for the +//! proof advances state and gets position 0; subsequent independent provers for the //! same target are accepted as uncles, up to `MaxUncleProvers`, and rewarded at //! decreasing positions. //! //! Uncle verification reuses the consensus state snapshot taken before the first //! proof mutated it, so uncle proofs are checked cryptographically against the -//! same trusted state the first prover used. `keccak256(proof)` is recorded per -//! parachain height to reject re-submission of bytes that were already accepted. +//! same trusted state the first prover used. +//! +//! ## Prover-bound proofs & deduplication +//! +//! Each SP1 proof commits a prover-chosen nonce into its public values, and the pallet +//! requires that nonce to equal the extrinsic signer (the reward payee). This binds a proof +//! to its submitter: a copied proof verifies cryptographically but cannot be claimed by a +//! different account, so proofs cannot be stolen from the mempool. The committed account is +//! also the dedup key — recorded per parachain height in [`pallet::AcceptedProvers`] — so an +//! account is rewarded at most once per height. Because the nonce is committed (not derived +//! from the proof bytes), Groth16 re-randomization or re-proving cannot mint extra reward +//! slots: every variant a single prover can produce carries the same committed account. #![cfg_attr(not(feature = "std"), no_std)] @@ -86,7 +95,7 @@ pub mod pallet { /// `Get` adapter that yields `MaxUncleProvers + 1`, the total number of provers /// (one first + `MaxUncleProvers` uncles) that may be rewarded per parachain height. - /// Used as the bound for `AcceptedProofHashes` and `RewardCurve`. + /// Used as the bound for `AcceptedProvers` and `RewardCurve`. pub struct MaxStoredProvers(core::marker::PhantomData); impl Get for MaxStoredProvers { fn get() -> u32 { @@ -95,7 +104,7 @@ pub mod pallet { } /// Current storage version. - const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); + const STORAGE_VERSION: StorageVersion = StorageVersion::new(2); #[pallet::pallet] #[pallet::without_storage_info] @@ -193,12 +202,14 @@ pub mod pallet { #[pallet::storage] pub type ProverCount = StorageMap<_, Blake2_128Concat, u64, u32, ValueQuery>; - /// `keccak256(proof_bytes)` for every proof accepted at a given parachain height. - /// SP1 Groth16 randomizes the witness so independent provers produce different - /// bytes; re-submission of the exact same bytes hits this set and is rejected. - /// Bounded by `MaxUncleProvers + 1` (one first + `MaxUncleProvers` uncles). + /// Submission accounts (the prover-chosen nonce committed into each SP1 proof, which the + /// pallet binds to the extrinsic signer) accepted at a given parachain height. Dedup is + /// per-account: a second proof from an account already present here is rejected, so an + /// account claims at most one reward slot per height regardless of how many distinct proof + /// bytes it produces (Groth16 re-randomization / re-proving). Bounded by `MaxUncleProvers + + /// 1` (one first + `MaxUncleProvers` uncles). #[pallet::storage] - pub type AcceptedProofHashes = + pub type AcceptedProvers = StorageMap<_, Blake2_128Concat, u64, BoundedVec>, ValueQuery>; /// Reward fractions `(numerator, denominator)` indexed by prover position. The base @@ -221,8 +232,10 @@ pub mod pallet { UnknownProofType, /// ABI decoding or conversion failed. AbiDecodeFailed, - /// The submitted proof is not in canonical ABI form (e.g. trailing padding). - MalformedProof, + /// The nonce committed into the SP1 proof does not match the extrinsic signer. The proof + /// is bound to its committed account, so it can only be submitted by that account — this + /// rejects a copied/mempool-sniped proof being claimed under a different account. + UnauthorizedProof, /// The BEEFY verifier rejected the proof. VerificationFailed, /// Rotation proof did not rotate to `NextAuthoritySetId`. @@ -238,7 +251,7 @@ pub mod pallet { NoNewWork, /// `MaxUncleProvers` already accepted at this height. UncleSlotsFull, - /// This exact proof has already been accepted at this height. + /// This account has already been rewarded for a proof at this height. ProofAlreadySubmitted, /// No first proof has been seen at this height, so no uncle slot exists. NoUncleContext, @@ -309,7 +322,7 @@ pub mod pallet { challenge_periods: Default::default(), state_machine_commitments: vec![( StateMachineId { - consensus_state_id: ismp_beefy::BEEFY_CONSENSUS_ID, + consensus_state_id: T::ConsensusStateId::get(), state_id: host.host_state_machine(), }, StateCommitmentHeight { @@ -435,49 +448,39 @@ pub mod pallet { // `submit_proof` — oversized payloads fail SCALE decoding inside the txpool // and never reach this dispatch. // The set of accepted proof types is gated by `ismp-beefy`'s - // `BeefyClientConfig::allowed_proof_types` during `verify_and_apply`; here we only - // need the type byte to drive canonical re-encoding. Unknown bytes still fall - // through to the `_ => UnknownProofType` arm of the match below. + // `BeefyClientConfig::allowed_proof_types` during `verify_and_apply`. Unknown bytes + // fall through to the `_ => UnknownProofType` arm below. let proof_type = *proof.first().ok_or(Error::::UnknownProofType)?; - // Decode the ABI payload then re-encode it canonically and hash *that* instead - // of the raw input. `alloy_sol_types::abi_decode_params` silently ignores - // trailing bytes after the encoded sequence ends, so without this a submitter - // could pad a valid proof with junk to mint a fresh `keccak256(proof)` and - // bypass the `AcceptedProofHashes` dedup. Hashing the canonical re-encoding - // collapses every ABI-equivalent input to the same hash by construction. - let abi_payload = &proof[1..]; - let canonical_payload = match proof_type { + // For SP1 proofs, decode the committed nonce and require it to equal the extrinsic + // signer. The nonce is committed into the proof's public values, so it can only be + // changed by re-running the SP1 program — a copied proof verifies cryptographically + // but is bound to the *original* prover's account, so a different signer cannot claim + // it. This is the anti-theft gate and also the dedup key: see [`AcceptedProvers`]. + // + // Binding to the committed nonce also makes dedup robust without canonical + // re-encoding: Groth16 re-randomization (or re-proving) yields different proof bytes + // for the same statement, but all of them carry the same committed nonce, so they + // collapse to a single per-account slot regardless of trailing padding or alternate + // encodings. + let account = match proof_type { types::PROOF_TYPE_SP1 => { let p = ::abi_decode_params( - abi_payload, - ) - .map_err(|_| Error::::AbiDecodeFailed)?; - ::abi_encode_params(&p) - }, - types::PROOF_TYPE_NAIVE => { - let p = - ::abi_decode_params( - abi_payload, + &proof[1..], ) .map_err(|_| Error::::AbiDecodeFailed)?; - ::abi_encode_params(&p) + let nonce = H256(p.nonce.0); + // `T::AccountId` is `AccountId32` in hyperbridge runtimes, which SCALE-encodes + // to its 32 raw bytes; compare those against the committed nonce. + if submitter.encode().as_slice() != nonce.as_bytes() { + Err(Error::::UnauthorizedProof)? + } + Some(nonce) }, + types::PROOF_TYPE_NAIVE => None, _ => Err(Error::::UnknownProofType)?, }; - let mut canonical_proof = Vec::with_capacity(1 + canonical_payload.len()); - canonical_proof.push(proof_type); - canonical_proof.extend_from_slice(&canonical_payload); - let proof_hash: H256 = sp_io::hashing::keccak_256(&canonical_proof).into(); - - // Reject any submission that isn't already in canonical form. If the raw input - // hashes differently from its canonical re-encoding it carries non-canonical - // bytes (trailing padding, alternate encodings), so it is malformed. - let submitted_hash: H256 = sp_io::hashing::keccak_256(&proof).into(); - if submitted_hash != proof_hash { - Err(Error::::MalformedProof)? - } // Read the pre-proof consensus state before `verify_and_apply` mutates it. // Used to seed `ProofContext` for the first-proof path. @@ -486,11 +489,11 @@ pub mod pallet { .consensus_state(ismp_beefy::BEEFY_CONSENSUS_ID) .map_err(|_| Error::::NotInitialized)?; - match Self::verify_and_apply(&canonical_proof) { + match Self::verify_and_apply(&proof) { Ok(outcome) => Self::settle_first_proof( submitter, - canonical_proof, - proof_hash, + proof, + account, proof_type, prev_state_bytes, outcome, @@ -500,20 +503,26 @@ pub mod pallet { // which is exactly the legitimate-uncle case. Other failures (corrupt // bytes, bad signatures, wrong vkey) propagate so the submitter pays the // fee instead of paying for a wasted second SP1 verification. - Err(Error::::StaleProof) if proof_type == types::PROOF_TYPE_SP1 => - Self::settle_uncle_proof(submitter, canonical_proof, proof_hash), + Err(Error::::StaleProof) if proof_type == types::PROOF_TYPE_SP1 => { + // SP1 always yields `Some(account)` above. + let account = account.ok_or(Error::::UnknownProofType)?; + Self::settle_uncle_proof(submitter, proof, account) + }, Err(e) => Err(e.into()), } } /// First-proof path: state has been advanced inside `verify_and_apply`. Save the - /// pre-proof snapshot, record the proof hash, pay the reward at position 0, and + /// pre-proof snapshot, record the submitter account, pay the reward at position 0, and /// run ring-buffer eviction across `MessagingProofs`/`RotationProofs`. When an /// entry falls off either ring, prune the matching uncle rows. + /// + /// `account` is the committed nonce (== signer) for SP1 proofs, and `None` for naive + /// proofs (which are ineligible for uncle rewards). fn settle_first_proof( submitter: T::AccountId, proof: Vec, - proof_hash: H256, + account: Option, proof_type: u8, prev_state_bytes: Vec, outcome: VerifyOutcome, @@ -524,7 +533,8 @@ pub mod pallet { // Record uncle metadata for SP1 proofs only. Naive proofs are ineligible. if proof_type == types::PROOF_TYPE_SP1 { - Self::record_uncle_metadata(outcome.latest_height, prev_state_bytes, proof_hash)?; + let account = account.ok_or(Error::::UnknownProofType)?; + Self::record_uncle_metadata(outcome.latest_height, prev_state_bytes, account)?; } let reward_paid = Self::pay_position_reward(&submitter, 0)?; @@ -552,7 +562,7 @@ pub mod pallet { sp_io::offchain_index::clear(&types::offchain_key(height)); ProofContext::::remove(height); ProverCount::::remove(height); - AcceptedProofHashes::::remove(height); + AcceptedProvers::::remove(height); } Self::deposit_event(Event::ProofAccepted { @@ -571,7 +581,7 @@ pub mod pallet { fn settle_uncle_proof( submitter: T::AccountId, proof: Vec, - proof_hash: H256, + account: H256, ) -> DispatchResultWithPostInfo { // The first proof for the most-recent finality target advanced state to // `latest_height` and snapshotted the pre-state under that key. Uncles that @@ -593,8 +603,11 @@ pub mod pallet { Err(Error::::UncleSlotsFull)? } - let hashes = AcceptedProofHashes::::get(parachain_height); - if hashes.contains(&proof_hash) { + // Dedup on the submitter account: an account that already landed a proof (first or + // uncle) at this height cannot claim a second slot, regardless of how many distinct + // proof bytes it can produce for the same target via Groth16 re-randomization. + let accounts = AcceptedProvers::::get(parachain_height); + if accounts.contains(&account) { Err(Error::::ProofAlreadySubmitted)? } @@ -629,7 +642,7 @@ pub mod pallet { let reward_paid = Self::pay_position_reward(&submitter, position)?; - AcceptedProofHashes::::try_mutate(parachain_height, |vec| vec.try_push(proof_hash)) + AcceptedProvers::::try_mutate(parachain_height, |vec| vec.try_push(account)) .map_err(|_| Error::::UncleSlotsFull)?; ProverCount::::insert(parachain_height, position.saturating_add(1)); @@ -643,17 +656,17 @@ pub mod pallet { Ok(PostDispatchInfo { actual_weight: None, pays_fee: Pays::No }) } - /// Save the pre-proof snapshot keyed by `parachain_height` and register the - /// first proof's hash. Uncles for this height land in the same rows; eviction + /// Save the pre-proof snapshot keyed by `parachain_height` and register the first + /// proof's submitter account. Uncles for this height land in the same rows; eviction /// from `MessagingProofs`/`RotationProofs` removes them in lockstep. fn record_uncle_metadata( parachain_height: u64, prev_state_bytes: Vec, - proof_hash: H256, + account: H256, ) -> Result<(), Error> { ProofContext::::insert(parachain_height, prev_state_bytes); - AcceptedProofHashes::::try_mutate(parachain_height, |vec| vec.try_push(proof_hash)) + AcceptedProvers::::try_mutate(parachain_height, |vec| vec.try_push(account)) .map_err(|_| Error::::UncleSlotsFull)?; ProverCount::::mutate(parachain_height, |c| *c = c.saturating_add(1)); diff --git a/modules/pallets/beefy-consensus-proofs/src/migrations.rs b/modules/pallets/beefy-consensus-proofs/src/migrations.rs index b3e644812..bc37832d0 100644 --- a/modules/pallets/beefy-consensus-proofs/src/migrations.rs +++ b/modules/pallets/beefy-consensus-proofs/src/migrations.rs @@ -58,3 +58,47 @@ pub type ClearSp1VkeyHash = VersionedMigration< Pallet, ::DbWeight, >; + +mod v2 { + use super::*; + use frame_support::traits::{Get, PalletInfoAccess}; + + /// Clears the old `AcceptedProofHashes` map. Uncle dedup moved from `keccak256(proof)` to + /// the prover-bound submission account (stored under the new `AcceptedProvers` prefix), so + /// the old entries are dead storage under a prefix the runtime no longer reads or evicts. + pub struct ClearAcceptedProofHashes(PhantomData); + + impl UncheckedOnRuntimeUpgrade for ClearAcceptedProofHashes { + fn on_runtime_upgrade() -> Weight { + // `AcceptedProofHashes` was a `StorageMap`, so clear the whole prefix. + let result = frame_support::migration::clear_storage_prefix( + as PalletInfoAccess>::name().as_bytes(), + b"AcceptedProofHashes", + b"", + None, + None, + ); + + log::info!( + target: "pallet-beefy-consensus-proofs", + "ClearAcceptedProofHashes: cleared {} old uncle-dedup entries; dedup is now per submission account", + result.unique, + ); + + T::DbWeight::get().writes(result.unique.into()) + } + } +} + +/// Migration that clears the old `AcceptedProofHashes` map (v1 → v2). +/// +/// Uncle deduplication changed from hashing proof bytes to keying on the prover-bound +/// submission account (the new `AcceptedProvers` storage). The old entries are orphaned and +/// cleared here. +pub type ClearAcceptedProofHashes = VersionedMigration< + 1, + 2, + v2::ClearAcceptedProofHashes, + Pallet, + ::DbWeight, +>; diff --git a/parachain/runtimes/gargantua/src/lib.rs b/parachain/runtimes/gargantua/src/lib.rs index 112db35b3..e8bbdd193 100644 --- a/parachain/runtimes/gargantua/src/lib.rs +++ b/parachain/runtimes/gargantua/src/lib.rs @@ -187,6 +187,7 @@ pub type Migrations = ( ismp_optimism::migrations::SeedDisputeGameConfigs, pallet_ismp_host_executive::migrations::ClearLegacyHostParams, pallet_beefy_consensus_proofs::migrations::ClearSp1VkeyHash, + pallet_beefy_consensus_proofs::migrations::ClearAcceptedProofHashes, ); /// Handles converting a weight scalar to a fee value, based on the scale and granularity of the diff --git a/parachain/runtimes/nexus/src/lib.rs b/parachain/runtimes/nexus/src/lib.rs index 880553197..cf97e443e 100644 --- a/parachain/runtimes/nexus/src/lib.rs +++ b/parachain/runtimes/nexus/src/lib.rs @@ -173,6 +173,7 @@ pub type Migrations = ( pallet_mmr_tree::migrations::ResetMmrTree, ismp_optimism::migrations::SeedDisputeGameConfigs, pallet_ismp_host_executive::migrations::ClearLegacyHostParams, + pallet_beefy_consensus_proofs::migrations::ClearAcceptedProofHashes, ); /// Handles converting a weight scalar to a fee value, based on the scale and granularity of the diff --git a/parachain/simtests/src/pallet_beefy_consensus_proofs.rs b/parachain/simtests/src/pallet_beefy_consensus_proofs.rs index 8501c4102..dfebdd5ac 100644 --- a/parachain/simtests/src/pallet_beefy_consensus_proofs.rs +++ b/parachain/simtests/src/pallet_beefy_consensus_proofs.rs @@ -17,10 +17,12 @@ //! `settle_uncle_proof` end-to-end. Forces the live BEEFY consensus state ahead of the SP1 //! fixture proof's block number (so the verifier returns `StaleHeight`), seeds `ProofContext` //! with the older snapshot the SP1 verifier accepts, then submits the fixture proof from Bob -//! (uncle accept at position 0) and re-submits the identical bytes from Ferdie (rejected by -//! `AcceptedProofHashes` dedup with `ProofAlreadySubmitted`). The multi-position fan-out is -//! covered by the bench rather than here — generating multiple distinct valid SP1 proofs -//! requires running `polytope-labs/sp1-beefy` once per fixture. No live network access. +//! (uncle accept at position 0, recorded in `AcceptedProvers` by account) and re-submits the +//! identical bytes from Ferdie (rejected by the anti-theft `nonce == signer` check with +//! `UnauthorizedProof`, since the proof is bound to Bob's committed account). The +//! multi-position fan-out is covered by the bench rather than here — generating multiple +//! distinct valid SP1 proofs requires running `polytope-labs/sp1-beefy` once per fixture. No +//! live network access. REGEN: the SP1 fixture must commit Bob's account as its nonce. #![cfg(test)] @@ -142,10 +144,10 @@ fn sp1_wire_proof() -> Vec { out } -/// SP1 verification key the fixture proof was generated against — matches the mainnet -/// SP1Beefy deployment at `0x82582f85cf370adCB61D97dab3068c0C4102Ccb6`. +/// SP1 verification key the fixture proof was generated against — sp1-beefy v1.1.0 program vkey +/// (public values include the committed prover nonce). const SP1_FIXTURE_VKEY: [u8; 32] = - hex_literal::hex!("009ce9c86546ac790c9e694519e16e59ff34b633c309fe4d6a4f850b886cddcf"); + hex_literal::hex!("007d1720c695842ed647a1a72e981751f9b5e26fc5ca038523b23430a1292f08"); /// Storage-key builder for a `Twox64Concat` map (`twox_128(pallet) ++ twox_128(item) ++ /// twox_64(key) ++ key`). @@ -658,33 +660,26 @@ async fn test_naive_proof_happy_path() -> Result<(), anyhow::Error> { /// pre-seeded with the older `trusted_state_scale()` snapshot so SP1 verification inside /// the uncle path actually succeeds. /// -/// Multi-uncle accumulation is exercised by appending unique suffix bytes to the SP1 -/// fixture for each successive submitter. `alloy-sol-types` 1.5.7's -/// `SP1BeefyProof::abi_decode_params` reads only the bytes the encoded struct needs and -/// silently ignores any trailing junk, so each `WIRE_PROOF ++ ` decodes to the -/// same `SP1BeefyProof` (verifies against the same Groth16 commitment + public inputs) -/// while producing a distinct `keccak256(proof)` — distinct enough to land in fresh -/// `AcceptedProofHashes` slots without tripping dedup. This is a test-only trick; in -/// production every relayer's SP1 prover already produces independently-randomised -/// proof bytes. +/// Deduplication keys on the committed submission account (the proof's nonce, bound to the +/// extrinsic signer), not the proof bytes. Each SP1 proof commits the submitter's account into +/// its public values, so distinct provers produce proofs bound to distinct accounts; multi-uncle +/// fan-out across accounts is covered by the bench, since each genuinely independent uncle needs +/// its own SP1 Groth16 proof committing a different account (`polytope-labs/sp1-beefy`). /// -/// Four sequential submissions cover the uncle outcomes the pallet exposes: +/// Two sequential submissions exercise the surface here: /// -/// 1. Bob (`WIRE_PROOF`): SP1 verifies, uncle accepted at position 0. `ProverCount` becomes 1 and -/// the proof hash is recorded. -/// 2. Charlie (`WIRE_PROOF ++ [0xAA]`): distinct hash, SP1 verifies again, uncle accepted at -/// position 1. `ProverCount` becomes 2. -/// 3. Dave (`WIRE_PROOF ++ [0xBB, 0xBB]`): distinct hash, uncle accepted at position 2. -/// `ProverCount` becomes 3. -/// 4. Ferdie (`WIRE_PROOF`, same bytes Bob already submitted): same hash as (1) → trips the -/// `AcceptedProofHashes` dedup inside `settle_uncle_proof` and the dispatch fails with -/// `ProofAlreadySubmitted`. State invariants must hold: `ProverCount` stays at 3 and -/// `AcceptedProofHashes` retains exactly the three accepted hashes. +/// 1. Bob (`WIRE_PROOF`, committing Bob's account): SP1 verifies, uncle accepted at position 0. +/// `ProverCount` becomes 1 and Bob's account is recorded in `AcceptedProvers`. +/// 2. Ferdie (Bob's exact bytes): the committed nonce is Bob's account, so the anti-theft +/// `nonce == signer` check in `do_submit_proof` rejects it with `UnauthorizedProof` before any +/// uncle work. State invariants hold: `ProverCount` stays at 1 and `AcceptedProvers` still +/// holds only Bob's account. (Re-submission by the *same* account — the `ProofAlreadySubmitted` +/// account-dedup path — needs a second proof committing Bob's account, so it is covered by the +/// bench rather than here.) /// -/// Together these prove the uncle dispatch surface is wired up end-to-end on the live -/// runtime, that `ProverCount` advances correctly across multiple accepts, and that -/// dedup keeps rejecting after several successful uncles. No live network access is -/// required — the SP1 fixture is static. +/// Together these prove the uncle dispatch surface is wired up end-to-end on the live runtime and +/// that a proof cannot be claimed by an account other than the one it commits. No live network +/// access is required — the SP1 fixture is static. REGEN: the fixture must commit Bob's account. #[tokio::test] #[ignore] async fn test_sp1_uncle_proof_dispatch_path() -> Result<(), anyhow::Error> { @@ -765,24 +760,27 @@ async fn test_sp1_uncle_proof_dispatch_path() -> Result<(), anyhow::Error> { submit_sudo(&client, &rpc_client, set_storage_call).await?; eprintln!("[stage] consensus + uncle snapshot seeded"); - // Bob lands the only valid SP1 fixture; Ferdie resubmits identical bytes to exercise - // dedup. We can't cook multiple distinct uncles cheaply (each needs its own SP1 - // Groth16 proof from `polytope-labs/sp1-beefy`), so the multi-position fan-out is - // covered by the bench instead. Trailing-byte malleability is now rejected at the - // extrinsic boundary by `do_submit_proof`'s round-trip check. + // Bob lands the only valid SP1 fixture; Ferdie resubmits Bob's identical bytes to exercise + // the anti-theft gate. We can't cook multiple distinct uncles cheaply (each needs its own + // SP1 Groth16 proof from `polytope-labs/sp1-beefy`), so the multi-position fan-out is + // covered by the bench instead. + // + // REGEN: this fixture must commit Bob's account as its nonce (see `BeefyCommitment::nonce`), + // otherwise `do_submit_proof`'s `nonce == signer` check rejects Bob's own submission. let bob_proof = sp1_wire_proof(); let ferdie_proof = bob_proof.clone(); let proof_context_key = blake2_128_concat_key(b"BeefyConsensusProofs", b"ProofContext", ¶chain_height.encode()); let prover_count_key = blake2_128_concat_key(b"BeefyConsensusProofs", b"ProverCount", ¶chain_height.encode()); - let accepted_hashes_key = blake2_128_concat_key( + let accepted_provers_key = blake2_128_concat_key( b"BeefyConsensusProofs", - b"AcceptedProofHashes", + b"AcceptedProvers", ¶chain_height.encode(), ); - let bob_hash: H256 = keccak_256(&bob_proof).into(); + // Dedup now keys on the submission account (the committed nonce), not the proof bytes. + let bob_account: H256 = H256::from_slice(Keyring::Bob.to_account_id().as_ref()); // 5. Bob: WIRE_PROOF as-is. Position 0. eprintln!("[stage] submit (Bob) — expect uncle accept at position 0"); @@ -798,19 +796,18 @@ async fn test_sp1_uncle_proof_dispatch_path() -> Result<(), anyhow::Error> { ) .await?; let count: u32 = fetch_storage_by_key::(&client, &prover_count_key).await?.unwrap_or(0); - let hashes: Vec = fetch_storage_by_key::>(&client, &accepted_hashes_key) + let provers: Vec = fetch_storage_by_key::>(&client, &accepted_provers_key) .await? .unwrap_or_default(); let ctx: Option> = fetch_storage_by_key::>(&client, &proof_context_key).await?; assert_eq!(count, 1, "Bob's uncle should set ProverCount to 1"); - assert_eq!(hashes, vec![bob_hash], "AcceptedProofHashes should record Bob's hash"); + assert_eq!(provers, vec![bob_account], "AcceptedProvers should record Bob's account"); assert!(ctx.is_some(), "ProofContext snapshot must persist across uncle accepts"); - // 6. Ferdie: WIRE_PROOF (same bytes as Bob). Same hash → `AcceptedProofHashes` dedup fires - // inside `settle_uncle_proof`, dispatch errors with `ProofAlreadySubmitted`. - eprintln!( - "[stage] submit (Ferdie) — expect ProofAlreadySubmitted (Bob's hash already recorded)" - ); + // 6. Ferdie: Bob's exact bytes. The committed nonce is Bob's account, not Ferdie's, so the + // anti-theft `nonce == signer` check in `do_submit_proof` rejects it with + // `UnauthorizedProof` — a sniped proof cannot be claimed by another account. + eprintln!("[stage] submit (Ferdie) — expect UnauthorizedProof (proof bound to Bob's account)"); let ferdie_result = submit_signed( &client, &rpc_client, @@ -824,17 +821,17 @@ async fn test_sp1_uncle_proof_dispatch_path() -> Result<(), anyhow::Error> { .await; assert!( ferdie_result.is_err(), - "duplicate uncle submission must be rejected by AcceptedProofHashes dedup", + "a proof bound to Bob's account must be rejected when submitted by Ferdie", ); - // State invariants across the failed dispatch — dedup short-circuits before - // `ProverCount` is bumped or another hash is appended. + // State invariants across the failed dispatch — the anti-theft check short-circuits before + // `ProverCount` is bumped or another account is appended. let count: u32 = fetch_storage_by_key::(&client, &prover_count_key).await?.unwrap_or(0); - let hashes: Vec = fetch_storage_by_key::>(&client, &accepted_hashes_key) + let provers: Vec = fetch_storage_by_key::>(&client, &accepted_provers_key) .await? .unwrap_or_default(); - assert_eq!(count, 1, "rejected duplicate must not bump ProverCount past 1"); - assert_eq!(hashes, vec![bob_hash], "rejected duplicate must not mutate AcceptedProofHashes",); + assert_eq!(count, 1, "rejected submission must not bump ProverCount past 1"); + assert_eq!(provers, vec![bob_account], "rejected submission must not mutate AcceptedProvers",); Ok(()) } diff --git a/tesseract/consensus/beefy/Cargo.toml b/tesseract/consensus/beefy/Cargo.toml index 66776540b..94f60c8ab 100644 --- a/tesseract/consensus/beefy/Cargo.toml +++ b/tesseract/consensus/beefy/Cargo.toml @@ -61,3 +61,8 @@ new-consensus-state = [] [dev-dependencies] # crates.io serde = { workspace = true, default-features = false, features = ["derive", "alloc"] } +dotenv = { workspace = true } +anyhow = "1.0.75" +hex = { workspace = true } +tokio = { workspace = true, features = ["full", "sync"] } +alloy = { workspace = true, features = ["provider-http", "rpc-types", "contract", "signer-local", "network", "providers", "transports", "reqwest", "reqwest-default-tls"] } diff --git a/tesseract/consensus/beefy/src/lib.rs b/tesseract/consensus/beefy/src/lib.rs index 4af15f7ba..7f6a71465 100644 --- a/tesseract/consensus/beefy/src/lib.rs +++ b/tesseract/consensus/beefy/src/lib.rs @@ -67,7 +67,14 @@ impl BeefyConfig { H256: From>, { let client = SubstrateClient::

::new(self.substrate).await?; - let prover = Prover::::new(self.prover.clone()).await?; + // The SP1 nonce must equal the account that signs `submit_proof`, which is this client's + // signer. Commit it into every proof so the pallet's `nonce == signer` check passes. + // `SubstrateClient::address` is the signer's 32-byte sr25519 public key. + let account: H256 = <[u8; 32]>::try_from(client.address.as_slice()) + .map_err(|_| anyhow!("beefy submission signer account must be 32 bytes"))? + .into(); + let prover = + Prover::::new(self.prover.clone(), account).await?; let backend: Arc = match self.prover_config.backend.clone() { backend::ProofBackendConfig::Redis { config } => { diff --git a/tesseract/consensus/beefy/src/prover.rs b/tesseract/consensus/beefy/src/prover.rs index 56db2642c..3a7446651 100644 --- a/tesseract/consensus/beefy/src/prover.rs +++ b/tesseract/consensus/beefy/src/prover.rs @@ -608,7 +608,7 @@ where R: subxt::Config, P: subxt::Config, { - pub async fn new(config: ProverConfig) -> Result { + pub async fn new(config: ProverConfig, account: H256) -> Result { let max_rpc_payload_size = config.max_rpc_payload_size.unwrap_or(15 * 1024 * 1024); let (relay_chain, relay_rpc_client) = subxt_utils::client::ws_client::(&config.relay_rpc_ws, max_rpc_payload_size).await?; @@ -653,7 +653,7 @@ where let prover = match config.proof_variant { ProofVariant::Sp1 => { let sp1_prover = zk_beefy::LocalProver::new().await?; - Prover::Sp1(zk_beefy::Prover::new(prover, sp1_prover)) + Prover::Sp1(zk_beefy::Prover::new(prover, sp1_prover, account)) }, ProofVariant::Ecdsa => Prover::Ecdsa(prover, PhantomData), }; diff --git a/tesseract/consensus/beefy/tests/mainnet_rotation.rs b/tesseract/consensus/beefy/tests/mainnet_rotation.rs new file mode 100644 index 000000000..902fdef39 --- /dev/null +++ b/tesseract/consensus/beefy/tests/mainnet_rotation.rs @@ -0,0 +1,399 @@ +// Copyright (C) Polytope Labs Ltd. +// SPDX-License-Identifier: Apache-2.0 +// +//! Live mainnet relayer test: generate naive (ECDSA) BEEFY consensus proofs that rotate the +//! authority set and submit them to the deployed `HandlerV2.handleConsensus` on all 9 mainnet +//! chains, asserting each succeeds before moving on. +//! +//! All chains were initialized with the same BEEFY consensus state, so the loop reads the +//! genesis state from one chain, then walks Polkadot's authority-set handovers (exactly like +//! `BeefyProver::run`: `query_next_finalized_epoch` -> `epoch_justification_for`), builds the +//! rotation proof, and fans the same wire bytes out to every chain. The on-chain Handler reads +//! each host's own stored state, so identical genesis + identical proof keeps all 9 in lockstep. +//! +//! Config comes from `evm/.env.mainnet` (`PRIVATE_KEY`, per-chain `*_RPC_URL`, `PARA_ID`, +//! and `POLKADOT_URL` = the EVM RPC for chain 420420419 / Polkadot Hub). The Polkadot **relay** +//! and Nexus **parachain** substrate endpoints come from `RELAY_WS_URL` / `PARA_WS_URL`. +//! +//! Marked `#[ignore]` — it sends real mainnet transactions (real gas). Run with: +//! cargo test -p tesseract-beefy --test mainnet_rotation -- --ignored --nocapture + +use std::{collections::BTreeSet, sync::Arc, time::Duration}; + +use alloy::{ + eips::eip2718::Encodable2718, + network::{EthereumWallet, TransactionBuilder}, + primitives::{address, Address, Bytes}, + providers::{DynProvider, Provider, ProviderBuilder}, + rpc::types::{TransactionReceipt, TransactionRequest}, + signers::local::PrivateKeySigner, +}; +use alloy_sol_types::SolValue; +use anyhow::{anyhow, Context}; +use beefy_prover::relay::fetch_latest_beefy_justification; +use ismp_abi::{ecdsa_beefy::BeefyConsensusState, evm_host::EvmHost, handler::handler_v2::HandlerV2}; +use sp_consensus_beefy::{ecdsa_crypto::Signature, SignedCommitment}; +use subxt::{backend::legacy::LegacyRpcMethods, config::Header as _}; +use tesseract_beefy::{ + backend::{InMemoryProofBackend, ProofBackend}, + prover::{BeefyProver, BeefyProverConfig, Prover, ProverConfig, ProverConsensusState, ProofVariant}, + ConsensusState, +}; +use tesseract_substrate::{ + config::{Blake2SubstrateChain, KeccakSubstrateChain}, + SubstrateClient, SubstrateConfig, +}; + +/// Shared CREATE2 addresses across every mainnet deployment (config.mainnet.toml). +const HOST: Address = address!("620128E2B19193d6Bd244a3AC8D3bBa0541B19c3"); +const HANDLER: Address = address!("2a18AB35DEa43474882E05A661e2F20fe89c0535"); + +/// Arbitrum rejects the ~96 KB naive proof at the public RPC ("oversized data"); pushing the +/// signed tx straight to the sequencer bypasses that node-level txpool size check. +const ARBITRUM_SEQUENCER: &str = "https://arb1-sequencer.arbitrum.io/rpc"; + +/// The 9 mainnet chains: (chain id, label, env var holding the EVM RPC url, optional submit +/// endpoint). When the submit endpoint is set, the tx is filled+signed against the RPC and the +/// raw signed tx is sent there instead. Chain 420420419 (Polkadot Hub) uses `POLKADOT_URL`. +const CHAINS: &[(u64, &str, &str, Option<&str>)] = &[ + (1, "ethereum", "ETHEREUM_RPC_URL", None), + (42161, "arbitrum", "ARBITRUM_RPC_URL", Some(ARBITRUM_SEQUENCER)), + (10, "optimism", "OPTIMISM_RPC_URL", None), + (8453, "base", "BASE_RPC_URL", None), + (56, "bsc", "BSC_RPC_URL", None), + (100, "gnosis", "GNOSIS_RPC_URL", None), + (1868, "soneium", "SONEIUM_RPC_URL", None), + (137, "polygon", "POLYGON_RPC_URL", None), + (420420419, "polkadot-hub", "POLKADOT_URL", None), +]; + +fn env_or(key: &str, default: &str) -> String { + std::env::var(key).unwrap_or_else(|_| default.to_string()) +} + +/// Read a host's stored BEEFY consensus state and decode it to the prover's `ConsensusState`. +async fn read_consensus_state(provider: &DynProvider) -> anyhow::Result { + let host = EvmHost::new(HOST, provider.clone()); + let bytes = host.consensusState().call().await.context("host.consensusState()")?; + let sol = BeefyConsensusState::abi_decode(&bytes).context("decode BeefyConsensusState")?; + Ok(sol.into()) +} + +/// Fill + sign a `handleConsensus` tx against `read`, push the raw signed tx to `sequencer` +/// (which doesn't enforce the public node's oversized-tx limit), then poll `read` for the +/// receipt (sequencer endpoints don't serve reads). +async fn submit_via_sequencer( + read: &DynProvider, + sequencer: &DynProvider, + wallet: &EthereumWallet, + from: Address, + proof: Bytes, +) -> anyhow::Result { + // `DynProvider` erases the filler layer, so populate the tx fields explicitly against the + // read RPC, sign locally, and push the raw signed tx to the sequencer. + let calldata = + HandlerV2::new(HANDLER, read.clone()).handleConsensus(HOST, proof).calldata().clone(); + let base = + TransactionRequest::default().with_from(from).with_to(HANDLER).with_input(calldata); + let chain_id = read.get_chain_id().await.context("get_chain_id")?; + let nonce = read.get_transaction_count(from).await.context("get_transaction_count")?; + let gas = read.estimate_gas(base.clone()).await.context("estimate_gas")?; + let fees = read.estimate_eip1559_fees().await.context("estimate_eip1559_fees")?; + let request = base + .with_chain_id(chain_id) + .with_nonce(nonce) + .with_gas_limit(gas) + .with_max_fee_per_gas(fees.max_fee_per_gas) + .with_max_priority_fee_per_gas(fees.max_priority_fee_per_gas); + let envelope = request.build(wallet).await?; + let raw = envelope.encoded_2718(); + let pending = sequencer + .send_raw_transaction(&raw) + .await + .context("sequencer eth_sendRawTransaction")?; + let hash = *pending.tx_hash(); + for _ in 0..90 { + if let Some(receipt) = read.get_transaction_receipt(hash).await? { + return Ok(receipt); + } + tokio::time::sleep(Duration::from_secs(2)).await; + } + Err(anyhow!("timed out waiting for receipt of {hash:?} after sequencer submit")) +} + +#[tokio::test(flavor = "multi_thread")] +#[ignore = "sends real mainnet transactions; run with --ignored and a funded PRIVATE_KEY"] +async fn rotate_authorities_across_all_chains() -> anyhow::Result<()> { + // Load EVM-submission config from evm/.env.mainnet (PRIVATE_KEY, *_RPC_URL, PARA_ID, + // POLKADOT_URL). Relay/parachain substrate endpoints come from RELAY_WS_URL/PARA_WS_URL. + let env_path = concat!(env!("CARGO_MANIFEST_DIR"), "/../../../evm/.env.mainnet"); + let _ = dotenv::from_path(env_path); + + let relay_url = env_or("RELAY_WS_URL", ""); + let para_url = env_or("PARA_WS_URL", ""); + let para_id: u32 = env_or("PARA_ID", "3367").parse().context("PARA_ID")?; + + // --- EVM side: one signer (relayer), one provider per chain. -------------------------------- + let pk = std::env::var("PRIVATE_KEY").context("PRIVATE_KEY missing from env/.env.mainnet")?; + let signer: PrivateKeySigner = + pk.trim_start_matches("0x").parse().context("invalid PRIVATE_KEY")?; + let from = signer.address(); + let wallet = EthereumWallet::from(signer); + + let mut chains: Vec<(String, DynProvider, Option)> = Vec::with_capacity(CHAINS.len()); + println!("EVM RPC endpoints:"); + for (id, name, rpc_env, submit_url) in CHAINS { + let url = std::env::var(rpc_env) + .with_context(|| format!("missing {rpc_env} for chain {id} ({name})"))?; + println!(" {name} (chain {id}) <- ${rpc_env} = {url}"); + let read = ProviderBuilder::new() + .wallet(wallet.clone()) + .connect(&url) + .await + .with_context(|| format!("connect {name} @ {url}"))? + .erased(); + let submit = match submit_url { + Some(s) => { + println!(" {name} raw-tx submit -> {s}"); + Some( + ProviderBuilder::new() + .connect(s) + .await + .with_context(|| format!("connect {name} sequencer @ {s}"))? + .erased(), + ) + }, + None => None, + }; + chains.push((name.to_string(), read, submit)); + } + + // --- Starting anchor: the most-behind chain's consensus state. ----------------------------- + // Chains can diverge (a prior run/relayer advanced some and not others), so the loop always + // drives from the laggard. Read every chain and log THAT anchor, not whichever is first. + let start_anchor = { + let mut best: Option<(String, ConsensusState)> = None; + for (name, read, _submit) in &chains { + let s = read_consensus_state(read) + .await + .with_context(|| format!("consensusState() on {name}"))?; + println!( + " {name}: height={} current_set={} next_set={}", + s.latest_beefy_height, s.current_authorities.id, s.next_authorities.id, + ); + if best.as_ref().map_or(true, |(_, b)| s.latest_beefy_height < b.latest_beefy_height) { + best = Some((name.clone(), s)); + } + } + best.expect("at least one chain") + }; + println!( + "starting anchor: most-behind chain {} @ height={} current_set={} next_set={}", + start_anchor.0, + start_anchor.1.latest_beefy_height, + start_anchor.1.current_authorities.id, + start_anchor.1.next_authorities.id, + ); + let genesis = start_anchor.1; + + // --- Relay/prover side: build a BeefyProver (Ecdsa) over an in-memory backend. -------------- + let prover_config = ProverConfig { + relay_rpc_ws: relay_url.clone(), + para_rpc_ws: para_url.clone(), + para_ids: vec![para_id], + proof_variant: ProofVariant::Ecdsa, + max_rpc_payload_size: None, + query_batch_size: None, + }; + // ECDSA proof submitted to the EVM handler, which does not enforce the SP1 committed- + // nonce binding, so a zero account is fine here. + let prover: Prover = + Prover::new(prover_config, Default::default()).await?; + + let substrate = SubstrateClient::::new( + SubstrateConfig { + state_machine: None, + hashing: None, + consensus_state_id: None, + rpc_ws: para_url.clone(), + max_rpc_payload_size: None, + signer: None, + initial_height: None, + max_concurent_queries: None, + poll_interval: None, + fee_token_decimals: None, + } + .resolve() + .await?, + ) + .await?; + + // Seed the in-memory backend with the genesis state read from the chains. + let backend: Arc = Arc::new(InMemoryProofBackend::new(ProverConsensusState { + inner: genesis.clone(), + finalized_parachain_height: 0, + })); + + let beefy_config = BeefyProverConfig { + consensus_state_id: *b"DOT0", + minimum_finalization_height: 0, + state_machines: vec![], + backend: Default::default(), + }; + + let beefy = BeefyProver::::new( + beefy_config, + substrate, + prover, + backend, + ) + .await?; + + // A second relay connection for the auxiliary queries the helpers don't expose (resolving + // the epoch-change block number, the live finalized head). + let (_relay, relay_rpc_client) = + subxt_utils::client::ws_client::(&relay_url, u32::MAX).await?; + let relay_rpc = LegacyRpcMethods::::new(relay_rpc_client.clone()); + + // --- The catch-up loop: one rotation proof per authority-set handover. ---------------------- + let _ = genesis; // genesis was only needed to seed the backend; per-iteration we read live state. + + // Chains that can't accept a naive proof (e.g. Arbitrum rejects the ~96 KB calldata as + // "oversized data") are recorded here and excluded from *both* submission and the anchor — + // otherwise a permanently-failing chain stays the most-behind chain forever and stalls the + // rest. Submission errors never abort the run; the chain is skipped and we keep going. + let mut failed: BTreeSet = BTreeSet::new(); + let mut rotations = 0u32; + loop { + // Look up the consensus state on every chain up front. They may diverge (an earlier + // run/relayer can advance some chains and not others), so anchor proof generation to the + // most-behind *active* chain — that produces a proof whose validator set the laggards + // still accept, while any chain already at/past the target height is skipped below. + let mut states: Vec<(String, DynProvider, Option, ConsensusState)> = + Vec::with_capacity(chains.len()); + for (name, read, submit) in &chains { + let s = read_consensus_state(read) + .await + .with_context(|| format!("consensusState() on {name}"))?; + states.push((name.clone(), read.clone(), submit.clone(), s)); + } + + let Some(anchor) = states + .iter() + .filter(|(name, _, _, _)| !failed.contains(name)) + .min_by_key(|(_, _, _, s)| s.latest_beefy_height) + .map(|(_, _, _, s)| s.clone()) + else { + println!("\nNo active chains left to advance (all skipped)."); + break; + }; + println!( + "\n--- anchor (most-behind active chain): height={} current_set={} next_set={} ---", + anchor.latest_beefy_height, anchor.current_authorities.id, anchor.next_authorities.id, + ); + + let pcs = ProverConsensusState { inner: anchor.clone(), finalized_parachain_height: 0 }; + let (update, live_header) = beefy.query_next_finalized_epoch(&pcs).await?; + + let commitment: SignedCommitment = match update { + Some((epoch_hash, next_set_id)) => { + assert_eq!( + next_set_id, anchor.next_authorities.id, + "next epoch must be the anchor's next set", + ); + let epoch_header = relay_rpc + .chain_get_header(Some(epoch_hash)) + .await? + .ok_or_else(|| anyhow!("epoch-change header missing"))?; + beefy + .epoch_justification_for(epoch_header.number().into()) + .await? + .ok_or_else(|| anyhow!("no BEEFY justification found for epoch {next_set_id}"))? + }, + None => { + // Sets are caught up. Do a final height advance to the live head, then stop. + if live_header.number <= anchor.latest_beefy_height { + println!("\nActive chains caught up at height {} set {}", anchor.latest_beefy_height, anchor.current_authorities.id); + break; + } + let head = live_header.hash(); + let (sc, _) = fetch_latest_beefy_justification(&relay_rpc, head.into()).await?; + sc + }, + }; + + let block = commitment.commitment.block_number; + let set_id = commitment.commitment.validator_set_id; + println!("=== proof @ block={block} set_id={set_id} ==="); + + // Reuse the daemon's encoder: returns `0x00 ++ abi_encode_params(BeefyConsensusProof)`. + let wire = beefy.consensus_proof(commitment.clone(), anchor.clone()).await?; + let proof = Bytes::from(wire); + + let failed_before = failed.len(); + let mut advanced_any = false; + for (name, read, submit, before) in &states { + if failed.contains(name) { + continue; + } + if before.latest_beefy_height >= block { + println!(" - {name}: already at height {} (skip)", before.latest_beefy_height); + continue; + } + // Submission errors (oversized tx, RPC rejection) and reverts are non-fatal: log, + // mark the chain skipped, and continue with the rest. Chains with a dedicated submit + // endpoint (Arbitrum sequencer) take the raw-tx path; the rest use a normal send. + let result: anyhow::Result = match submit { + Some(sequencer) => submit_via_sequencer(read, sequencer, &wallet, from, proof.clone()).await, + None => { + let handler = HandlerV2::new(HANDLER, read.clone()); + async { + Ok(handler.handleConsensus(HOST, proof.clone()).send().await?.get_receipt().await?) + } + .await + }, + }; + match result { + Ok(receipt) if receipt.status() => { + let after = read_consensus_state(read).await?; + println!( + " ✓ {name}: height {} -> {} | set {} -> {} | tx {:?}", + before.latest_beefy_height, + after.latest_beefy_height, + before.current_authorities.id, + after.current_authorities.id, + receipt.transaction_hash, + ); + advanced_any = true; + }, + Ok(receipt) => { + println!(" ✗ {name}: reverted (tx {:?}) — skipping this chain.", receipt.transaction_hash); + failed.insert(name.clone()); + }, + Err(e) => { + println!(" ✗ {name}: submission failed — skipping this chain. {e:#}"); + failed.insert(name.clone()); + }, + } + } + + // Progress guard: stop only if this round neither advanced a chain nor newly skipped one + // (i.e. nothing changed and we'd loop forever). A fresh skip moves the anchor next round. + if !advanced_any && failed.len() == failed_before { + println!("\nNo progress this round; stopping."); + break; + } + if advanced_any { + rotations += 1; + } + } + + let advanced: Vec<&str> = + chains.iter().map(|(n, _, _)| n.as_str()).filter(|n| !failed.contains(*n)).collect(); + println!("\nDone — {rotations} rotation(s)."); + println!(" advanced: {advanced:?}"); + if !failed.is_empty() { + println!(" skipped (could not submit): {:?}", failed); + } + Ok(()) +} diff --git a/tesseract/consensus/beefy/zk/Cargo.toml b/tesseract/consensus/beefy/zk/Cargo.toml index c84f7916f..6817c2ec4 100644 --- a/tesseract/consensus/beefy/zk/Cargo.toml +++ b/tesseract/consensus/beefy/zk/Cargo.toml @@ -26,11 +26,11 @@ hex-literal = "0.4.1" [dependencies.sp1-beefy] git = "ssh://git@github.com/polytope-labs/sp1-beefy.git" -tag = "v1.0.0" +tag = "v1.1.0" [dependencies.sp1-beefy-primitives] git = "ssh://git@github.com/polytope-labs/sp1-beefy.git" -tag = "v1.0.0" +tag = "v1.1.0" [dev-dependencies] alloy-sol-types = { workspace = true } diff --git a/tesseract/consensus/beefy/zk/src/lib.rs b/tesseract/consensus/beefy/zk/src/lib.rs index b92bdf377..ce43d2f9e 100644 --- a/tesseract/consensus/beefy/zk/src/lib.rs +++ b/tesseract/consensus/beefy/zk/src/lib.rs @@ -31,6 +31,10 @@ mod tests; pub struct Prover { pub inner: beefy_prover::Prover, pub sp1_beefy: Arc, + /// The extrinsic submission account (the `submit_proof` signer). Committed verbatim into + /// each SP1 proof as its nonce, so `pallet-beefy-consensus-proofs` can bind the proof to + /// this account and reject it if submitted by anyone else. + pub account: H256, } impl Clone for Prover @@ -41,7 +45,11 @@ where beefy_prover::Prover: Clone, { fn clone(&self) -> Self { - Self { inner: self.inner.clone(), sp1_beefy: self.sp1_beefy.clone() } + Self { + inner: self.inner.clone(), + sp1_beefy: self.sp1_beefy.clone(), + account: self.account, + } } } @@ -51,8 +59,8 @@ where P: subxt::Config, B: BeefyProver, { - pub fn new(prover: beefy_prover::Prover, sp1_beefy: B) -> Self { - Self { inner: prover, sp1_beefy: Arc::new(sp1_beefy) } + pub fn new(prover: beefy_prover::Prover, sp1_beefy: B, account: H256) -> Self { + Self { inner: prover, sp1_beefy: Arc::new(sp1_beefy), account } } pub async fn consensus_proof( @@ -60,6 +68,10 @@ where signed_commitment: sp_consensus_beefy::SignedCommitment, consensus_state: ConsensusState, ) -> Result { + // Submission account committed into the proof as its nonce (see struct field docs). + // Use the raw bytes at each commit site so the conversion is agnostic to the exact + // `H256`/`FixedBytes` type each consumer expects. + let account: [u8; 32] = self.account.0; let authority = match signed_commitment.commitment.validator_set_id { id if id == consensus_state.current_authorities.id => consensus_state.current_authorities, @@ -170,6 +182,10 @@ where proof: para_header_witness, total_count: paras_len, }, + // Commit our submission account as the proof's nonce. `pallet-beefy-consensus-proofs` + // requires this to equal the `submit_proof` signer, binding the proof to us so it + // can't be sniped from the mempool and submitted under another account. + nonce: account.into(), }; let proof = self.sp1_beefy.prove(commitment).await?; @@ -182,6 +198,8 @@ where mmrLeaf: message.mmr.latest_mmr_leaf.into(), proof: proof.bytes().into(), headers: message.parachain.parachains.into_iter().map(|i| i.into()).collect(), + // Carry the committed nonce so the verifier reconstructs matching public inputs. + nonce: account.into(), }) } } diff --git a/tesseract/consensus/beefy/zk/src/tests.rs b/tesseract/consensus/beefy/zk/src/tests.rs index 5991c9e55..6e8317ed9 100644 --- a/tesseract/consensus/beefy/zk/src/tests.rs +++ b/tesseract/consensus/beefy/zk/src/tests.rs @@ -159,6 +159,10 @@ async fn test_sp1_beefy() -> Result<(), anyhow::Error> { query_batch_size: None, }, sp1_prover, + // Commit Bob's well-known sr25519 dev account as the nonce so the generated fixture is + // usable by the pallet tests, which require `committed nonce == submit_proof signer` + // (the simtest signs as Bob). + primitive_types::H256(hex!("8eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48")), ); // Get initial consensus state — also the "previousState" the on-chain verify() consumes. diff --git a/tesseract/consensus/config/src/lib.rs b/tesseract/consensus/config/src/lib.rs index 19b67029f..9643cfcd3 100644 --- a/tesseract/consensus/config/src/lib.rs +++ b/tesseract/consensus/config/src/lib.rs @@ -239,8 +239,13 @@ impl HyperbridgeHostConfig { let host = match self.host { ConsensusHost::Beefy { substrate, prover, beefy, redis } => { let client = SubstrateClient::

::new(substrate).await?; + // Commit the submission signer as the SP1 nonce (see `pallet-beefy-consensus-proofs`). + // `SubstrateClient::address` is the signer's 32-byte sr25519 public key. + let account: H256 = <[u8; 32]>::try_from(client.address.as_slice()) + .map_err(|_| anyhow!("beefy submission signer account must be 32 bytes"))? + .into(); let prover_instance = - Prover::::new(prover.clone()).await?; + Prover::::new(prover.clone(), account).await?; let backend = Arc::new(tesseract_beefy::backend::RedisProofBackend::new(redis).await?); diff --git a/tesseract/prover/Cargo.toml b/tesseract/prover/Cargo.toml index e1d6d6c5a..76106528b 100644 --- a/tesseract/prover/Cargo.toml +++ b/tesseract/prover/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tesseract-prover" -version = "2.0.2" +version = "2.1.0" edition = "2021" description = "Standalone BEEFY consensus prover daemon" authors = ["Polytope Labs "] @@ -16,6 +16,7 @@ clap = { version = "4.3.5", features = ["derive"] } tokio = { workspace = true, features = ["full"] } tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } rustls = { version = "0.23.23", features = ["ring"] } +primitive-types = { workspace = true } subxt-utils = { workspace = true } tesseract-beefy = { workspace = true } diff --git a/tesseract/prover/src/main.rs b/tesseract/prover/src/main.rs index bde311cf0..537ff64bf 100644 --- a/tesseract/prover/src/main.rs +++ b/tesseract/prover/src/main.rs @@ -16,6 +16,7 @@ use anyhow::anyhow; use clap::Parser; +use primitive_types::H256; use std::sync::Arc; use tesseract_beefy::prover::{BeefyProver, Prover}; use tesseract_primitives::IsmpProvider; @@ -47,13 +48,6 @@ async fn main() -> Result<(), anyhow::Error> { let mut config = tokio::fs::read_to_string(cli.config).await?.parse::()?; - let prover = { - let prover_config = config - .remove("prover") - .ok_or_else(|| anyhow!("Substrate config missing; qed"))?; - Prover::new(prover_config.try_into()?).await? - }; - let substrate = { let substrate_config: tesseract_substrate::SubstrateConfig = config .remove("substrate") @@ -63,6 +57,20 @@ async fn main() -> Result<(), anyhow::Error> { SubstrateClient::new(substrate_config.resolve().await?).await? }; + // The SP1 nonce committed into each proof must equal the account that submits it, which is + // this prover's substrate signer (see `pallet-beefy-consensus-proofs`). `address` is the + // signer's 32-byte sr25519 public key. + let account: H256 = <[u8; 32]>::try_from(substrate.address.as_slice()) + .map_err(|_| anyhow!("beefy submission signer account must be 32 bytes"))? + .into(); + + let prover = { + let prover_config = config + .remove("prover") + .ok_or_else(|| anyhow!("Substrate config missing; qed"))?; + Prover::new(prover_config.try_into()?, account).await? + }; + let beefy_prover = { let beefy_config: tesseract_beefy::prover::BeefyProverConfig = config .remove("beefy")