您正在查看: Optimism 分类下的文章

op-succinct 实测和流程相关代码分析

Clone op-succinct

https://github.com/succinctlabs/op-succinct.git

更新项目submodule

git submodule update --init --recursive

创建 .env

在op-succinct根目录新建.env文件,并填写自己的配置信息

L1_RPC=https://eth-sepolia.g.alchemy.com/v2/mQz ...
L1_BEACON_RPC=https://ethereum-sepolia-beacon-api.publicnode.com
L2_RPC=http://...:8545
L2_NODE_RPC=http://....:4000
PRIVATE_KEY=0xa7d....
ETHERSCAN_API_KEY=2BY57NTWCW...

L2_RPC需要开启debug,否则会在启动时debug_chainConfig报错

安装just

sudo apt update
sudo apt install snapd
sudo snap install just --classic

安装rust

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

安装OpenSSL

sudo apt update
sudo apt install libssl-dev

安装 RocksDB

sudo apt update
sudo apt install librocksdb-dev build-essential cmake libclang-dev

部署一个SP1MockVerifier用于验证模拟证明的

https://succinctlabs.github.io/op-succinct/quick-start/mock.html

just deploy-mock-verifier

注:如果出错,多重试几次

执行日志

[⠊] Compiling...
No files changed, compilation skipped
Script ran successfully.

== Return ==
0: address 0xe31B339d16697105Bc7EF9faf474CF7528557fF0

## Setting up 1 EVM.

==========================

Chain 11155111

Estimated gas price: 48.919307822 gwei

Estimated total gas used for script: 170454

Estimated amount required: 0.008338491695491188 ETH

修改.env

VERIFIER_ADDRESS=0xe31B339d16697105Bc7EF9faf474CF7528557fF0

部署地址:https://sepolia.etherscan.io/address/0x7C44E2970b17fE5BA823fEF5a3f60e38DDBb19d4

部署OPSuccinctL2outputOracle合约

just deploy-oracle

注:如果报交易发送失败等问题,就多尝试几次

执行日志

== Return ==
0: address 0x050FDc19d469ACc9e9A20761A565bEcE0cDD5879

## Setting up 1 EVM.

==========================

Chain 11155111

Estimated gas price: 62.822606964 gwei

Estimated total gas used for script: 3676931

Estimated amount required: 0.230994391046747484 ETH

==========================

##### sepolia
✅  [Success]Hash: 0xbd7ac1497869e49a110d0a85c9bd2b9ce3addc2328d89a9388125580825ae64b
Contract Address: 0xA9F8DEc334a35a99B7eFaca5C0a55b3e3706774A
Block: 7443868
Paid: 0.058773015956194648 ETH (1951822 gas * 30.111872884 gwei)


##### sepolia
✅  [Success]Hash: 0x925e583251914e0554cc4eb6076682817c11330c6eabbb5969fba2397988fd3f
Contract Address: 0x050FDc19d469ACc9e9A20761A565bEcE0cDD5879
Block: 7443868
Paid: 0.013220527454101548 ETH (439047 gas * 30.111872884 gwei)


##### sepolia
✅  [Success]Hash: 0x67a663442dfacf19296aa51b03fc6dddf9e66c254b93d6e2f64898ee15e0957b
Block: 7443868
Paid: 0.012419521523514264 ETH (412446 gas * 30.111872884 gwei)

✅ Sequence #1 on sepolia | Total Paid: 0.08441306493381046 ETH (2803315 gas * avg 30.111872884 gwei)


==========================

ONCHAIN EXECUTION COMPLETE & SUCCESSFUL.
##
Start verification for (2) contracts
Start verifying contract `0xA9F8DEc334a35a99B7eFaca5C0a55b3e3706774A` deployed on sepolia

Submitting verification for [src/OPSuccinctL2OutputOracle.sol:OPSuccinctL2OutputOracle] 0xA9F8DEc334a35a99B7eFaca5C0a55b3e3706774A.

Submitting verification for [src/OPSuccinctL2OutputOracle.sol:OPSuccinctL2OutputOracle] 0xA9F8DEc334a35a99B7eFaca5C0a55b3e3706774A.

Submitting verification for [src/OPSuccinctL2OutputOracle.sol:OPSuccinctL2OutputOracle] 0xA9F8DEc334a35a99B7eFaca5C0a55b3e3706774A.

Submitting verification for [src/OPSuccinctL2OutputOracle.sol:OPSuccinctL2OutputOracle] 0xA9F8DEc334a35a99B7eFaca5C0a55b3e3706774A.

Submitting verification for [src/OPSuccinctL2OutputOracle.sol:OPSuccinctL2OutputOracle] 0xA9F8DEc334a35a99B7eFaca5C0a55b3e3706774A.
Submitted contract for verification:
        Response: `OK`
        GUID: `brpptxuzsp3nan5cgtjqviyfnpj4tveeqam2slyg4z3aapjvav`
        URL: https://sepolia.etherscan.io/address/0xa9f8dec334a35a99b7efaca5c0a55b3e3706774a
Contract verification status:
Response: `NOTOK`
Details: `Pending in queue`
Contract verification status:
Response: `NOTOK`
Details: `Already Verified`
Contract source code already verified
Start verifying contract `0x050FDc19d469ACc9e9A20761A565bEcE0cDD5879` deployed on sepolia

Submitting verification for [lib/optimism/packages/contracts-bedrock/src/universal/Proxy.sol:Proxy] 0x050FDc19d469ACc9e9A20761A565bEcE0cDD5879.
Submitted contract for verification:
        Response: `OK`
        GUID: `2mvuftsib5mqxxaqyza4aumdmxfp6y5dwxtiiwvuaibutet6qb`
        URL: https://sepolia.etherscan.io/address/0x050fdc19d469acc9e9a20761a565bece0cdd5879
Contract verification status:
Response: `NOTOK`
Details: `Already Verified`
Contract source code already verified
All (2) contracts were verified!

Transactions saved to: /mnt/md0/saas/sp1/op-succinct/contracts/broadcast/OPSuccinctDeployer.s.sol/11155111/run-latest.json

Sensitive values saved to: /mnt/md0/saas/sp1/op-succinct/contracts/cache/OPSuccinctDeployer.s.sol/11155111/run-latest.json

run-latest.json

root@204185:/mnt/md0/saas/sp1/op-succinct# cat contracts/broadcast/OPSuccinctDeployer.s.sol/11155111/run-latest.json

{
  "transactions": [
    {
      "hash": "0xbd7ac1497869e49a110d0a85c9bd2b9ce3addc2328d89a9388125580825ae64b",
      "transactionType": "CREATE",
      "contractName": "OPSuccinctL2OutputOracle",
      "contractAddress": "0xa9f8dec334a35a99b7efaca5c0a55b3e3706774a",
      "function": null,
      "arguments": null,
      "transaction": {
        "from": "0xc2df13b6ad0753e0547a318f65f99ac62aec6e2b",
        "gas": "0x26b4c3",
        "value": "0x0",
        "input": "0x608060405234801561001057600080fd5b5061001961001e565b6100de565b600054610100900460ff161561008a5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff90811610156100dc576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b6121d880620000ee6000396000f3fe6080604052600436106102715760003560e01c806389c44cbb1161014f578063bffa7f0f116100c1578063d46512761161007a578063d465127614610758578063db1470f514610788578063dcec3348146107a8578063e1a41bcf146107bd578063f2fde38b146107d3578063f4daa291146107f357600080fd5b8063bffa7f0f146106ae578063c32e4e3e146106cc578063c4cb03ec146106e2578063ce5db8d614610702578063cf8e5cf014610718578063d1de856c1461073857600080fd5b80639ad84880116101135780639ad84880146105bb578063a196b525146105ce578063a25ae557146105fb578063a8e4fb901461064e578063b03cd4181461066e578063bc91ce331461068e57600080fd5b806389c44cbb146105325780638da5cb5b1461055257806393991af31461057257806397fc007c146105885780639aaab648146105a857600080fd5b8063534db0e2116101e85780636b4d98dd116101ac5780636b4d98dd1461048b5780636d9a1c8b146104a957806370872aa5146104bf5780637f006420146104d55780637f01ea68146104f5578063887862721461051c57600080fd5b8063534db0e2146103d457806354fd4d50146103f457806360caf7a01461043757806369f16eec146104615780636abcf5631461047657600080fd5b80632b7ac3f31161023a5780632b7ac3f3146103125780632c6979611461034a578063336c9e811461036a5780634599c7881461038a5780634ab309ac1461039f578063529933df146103bf57600080fd5b80622134cc1461027657806309d632d31461029a5780631bdd450c146102bc5780631e856800146102dc5780632b31841e146102fc575b600080fd5b34801561028257600080fd5b506005545b6040519081526020015b60405180910390f35b3480156102a657600080fd5b506102ba6102b5366004611c2f565b610808565b005b3480156102c857600080fd5b506102ba6102d7366004611c51565b610891565b3480156102e857600080fd5b506102ba6102f7366004611c51565b6108ef565b34801561030857600080fd5b50610287600a5481565b34801561031e57600080fd5b50600b54610332906001600160a01b031681565b6040516001600160a01b039091168152602001610291565b34801561035657600080fd5b506102ba610365366004611c51565b610921565b34801561037657600080fd5b506102ba610385366004611c51565b6109b3565b34801561039657600080fd5b50610287610a1e565b3480156103ab57600080fd5b506102ba6103ba366004611c51565b610a7b565b3480156103cb57600080fd5b50600454610287565b3480156103e057600080fd5b50600654610332906001600160a01b031681565b34801561040057600080fd5b5061042a6040518060400160405280600a8152602001693b189718171816b9319960b11b81525081565b6040516102919190611cb7565b34801561044357600080fd5b506010546104519060ff1681565b6040519015158152602001610291565b34801561046d57600080fd5b50610287610b09565b34801561048257600080fd5b50600354610287565b34801561049757600080fd5b506006546001600160a01b0316610332565b3480156104b557600080fd5b50610287600c5481565b3480156104cb57600080fd5b5061028760015481565b3480156104e157600080fd5b506102876104f0366004611c51565b610b1b565b34801561050157600080fd5b5061050a600181565b60405160ff9091168152602001610291565b34801561052857600080fd5b5061028760025481565b34801561053e57600080fd5b506102ba61054d366004611c51565b610cb9565b34801561055e57600080fd5b50600d54610332906001600160a01b031681565b34801561057e57600080fd5b5061028760055481565b34801561059457600080fd5b506102ba6105a3366004611c2f565b610ebe565b6102ba6105b6366004611cca565b610f44565b6102ba6105c9366004611d6d565b61120b565b3480156105da57600080fd5b506102876105e9366004611c51565b600f6020526000908152604090205481565b34801561060757600080fd5b5061061b610616366004611c51565b6115a5565b60408051825181526020808401516001600160801b03908116918301919091529282015190921690820152606001610291565b34801561065a57600080fd5b50600754610332906001600160a01b031681565b34801561067a57600080fd5b506102ba610689366004611c2f565b611623565b34801561069a57600080fd5b506102ba6106a9366004611c51565b6116a4565b3480156106ba57600080fd5b506007546001600160a01b0316610332565b3480156106d857600080fd5b5061028760095481565b3480156106ee57600080fd5b506102ba6106fd366004611c51565b611702565b34801561070e57600080fd5b5061028760085481565b34801561072457600080fd5b5061061b610733366004611c51565b611760565b34801561074457600080fd5b50610287610753366004611c51565b611798565b34801561076457600080fd5b50610451610773366004611c2f565b600e6020526000908152604090205460ff1681565b34801561079457600080fd5b506102ba6107a3366004611e1f565b6117c8565b3480156107b457600080fd5b50610287611b76565b3480156107c957600080fd5b5061028760045481565b3480156107df57600080fd5b506102ba6107ee366004611c2f565b611b8d565b3480156107ff57600080fd5b50600854610287565b600d546001600160a01b0316331461083b5760405162461bcd60e51b815260040161083290611ee2565b60405180910390fd5b6001600160a01b0381166000818152600e60209081526040808320805460ff19169055519182527f5df38d395edc15b669d646569bd015513395070b5b4deb8a16300abb060d1b5a91015b60405180910390a250565b600d546001600160a01b031633146108bb5760405162461bcd60e51b815260040161083290611ee2565b600c546040518291907f5d9ebe9f09b0810b3546b30781ba9a51092b37dd6abada4b830ce54a41ac6a4b90600090a3600c55565b80408061090f576040516321301a1960e21b815260040160405180910390fd5b6000918252600f602052604090912055565b600d546001600160a01b0316331461094b5760405162461bcd60e51b815260040161083290611ee2565b60105460ff161561096e5760405162461bcd60e51b815260040161083290611f29565b60088190556010805460ff191660019081179091556040518281527f1f5c872f1ea93c57e43112ea449ee19ef5754488b87627b4c52456b0e5a4109a90602001610886565b600d546001600160a01b031633146109dd5760405162461bcd60e51b815260040161083290611ee2565b60045460408051918252602082018390527fc1bf9abfb57ea01ed9ecb4f45e9cefa7ba44b2e6778c3ce7281409999f1af1b2910160405180910390a1600455565b60035460009015610a725760038054610a3990600190611f89565b81548110610a4957610a49611fa0565b6000918252602090912060029091020160010154600160801b90046001600160801b0316919050565b6001545b905090565b600d546001600160a01b03163314610aa55760405162461bcd60e51b815260040161083290611ee2565b60105460ff16610ac75760405162461bcd60e51b815260040161083290611fb6565b60088190556010805460ff191690556040518181526000907f1f5c872f1ea93c57e43112ea449ee19ef5754488b87627b4c52456b0e5a4109a90602001610886565b600354600090610a7690600190611f89565b6000610b25610a1e565b821115610bab5760405162461bcd60e51b815260206004820152604860248201527f4c324f75747075744f7261636c653a2063616e6e6f7420676574206f7574707560448201527f7420666f72206120626c6f636b207468617420686173206e6f74206265656e206064820152671c1c9bdc1bdcd95960c21b608482015260a401610832565b600354610c2f5760405162461bcd60e51b815260206004820152604660248201527f4c324f75747075744f7261636c653a2063616e6e6f7420676574206f7574707560448201527f74206173206e6f206f7574707574732068617665206265656e2070726f706f736064820152651959081e595d60d21b608482015260a401610832565b6003546000905b80821015610cb25760006002610c4c8385612004565b610c56919061201c565b90508460038281548110610c6c57610c6c611fa0565b6000918252602090912060029091020160010154600160801b90046001600160801b03161015610ca857610ca1816001612004565b9250610cac565b8091505b50610c36565b5092915050565b6006546001600160a01b03163314610d395760405162461bcd60e51b815260206004820152603e60248201527f4c324f75747075744f7261636c653a206f6e6c7920746865206368616c6c656e60448201527f67657220616464726573732063616e2064656c657465206f75747075747300006064820152608401610832565b6003548110610dbc5760405162461bcd60e51b815260206004820152604360248201527f4c324f75747075744f7261636c653a2063616e6e6f742064656c657465206f7560448201527f747075747320616674657220746865206c6174657374206f757470757420696e6064820152620c8caf60eb1b608482015260a401610832565b60085460038281548110610dd257610dd2611fa0565b6000918252602090912060016002909202010154610df9906001600160801b031642611f89565b10610e7b5760405162461bcd60e51b815260206004820152604660248201527f4c324f75747075744f7261636c653a2063616e6e6f742064656c657465206f7560448201527f74707574732074686174206861766520616c7265616479206265656e2066696e606482015265185b1a5e995960d21b608482015260a401610832565b6000610e8660035490565b90508160035581817f4ee37ac2c786ec85e87592d3c5c8a1dd66f8496dda3f125d9ea8ca5f657629b660405160405180910390a35050565b600d546001600160a01b03163314610ee85760405162461bcd60e51b815260040161083290611ee2565b600b546040516001600160a01b038084169216907f0243549a92b2412f7a3caf7a2e56d65b8821b91345363faa5f57195384065fcc90600090a3600b80546001600160a01b0319166001600160a01b0392909216919091179055565b60105460ff16610f665760405162461bcd60e51b815260040161083290611fb6565b336000908152600e602052604090205460ff1680610fae575060008052600e6020527fe710864318d4a32f37d6ce54cb3fadbef648dd12d8dbdf53973564d56b7f881c5460ff165b610fca5760405162461bcd60e51b81526004016108329061203e565b610fd2611b76565b83146110575760405162461bcd60e51b815260206004820152604860248201527f4c324f75747075744f7261636c653a20626c6f636b206e756d626572206d757360448201527f7420626520657175616c20746f206e65787420657870656374656420626c6f636064820152673590373ab6b132b960c11b608482015260a401610832565b4261106184611798565b1061107e5760405162461bcd60e51b81526004016108329061209b565b8361109b5760405162461bcd60e51b8152600401610832906120f1565b811561112957818140146111295760405162461bcd60e51b815260206004820152604960248201527f4c324f75747075744f7261636c653a20626c6f636b206861736820646f65732060448201527f6e6f74206d6174636820746865206861736820617420746865206578706563746064820152681959081a195a59da1d60ba1b608482015260a401610832565b8261113360035490565b857fa7aaf2512769da4e444e3de247be2564225c2e7a8f74cfe528e46e17d24868e24260405161116591815260200190565b60405180910390a45050604080516060810182529283526001600160801b034281166020850190815292811691840191825260038054600181018255600091909152935160029094027fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b810194909455915190518216600160801b029116177fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85c90910155565b60105460ff161561122e5760405162461bcd60e51b815260040161083290611f29565b336000908152600e602052604090205460ff1680611276575060008052600e6020527fe710864318d4a32f37d6ce54cb3fadbef648dd12d8dbdf53973564d56b7f881c5460ff165b6112925760405162461bcd60e51b81526004016108329061203e565b61129a611b76565b8310156113355760405162461bcd60e51b815260206004820152605860248201527f4c324f75747075744f7261636c653a20626c6f636b206e756d626572206d757360448201527f742062652067726561746572207468616e206f7220657175616c20746f206e6560648201527f787420657870656374656420626c6f636b206e756d6265720000000000000000608482015260a401610832565b4261133f84611798565b1061135c5760405162461bcd60e51b81526004016108329061209b565b836113795760405162461bcd60e51b8152600401610832906120f1565b6000828152600f6020526040902054806113a657604051630455475360e31b815260040160405180910390fd5b60006040518060c0016040528083815260200160036113c3610b09565b815481106113d3576113d3611fa0565b60009182526020918290206002909102015482528181018990526040808301899052600c54606080850191909152600a54608094850152600b5460095483518751818701529487015185850152928601518483015290850151838501529284015160a08084019190915284015160c08301529293506001600160a01b03909116916341493c609160e001604051602081830303815290604052866040518463ffffffff1660e01b815260040161148b9392919061214e565b60006040518083038186803b1580156114a357600080fd5b505afa1580156114b7573d6000803e3d6000fd5b50505050846114c560035490565b877fa7aaf2512769da4e444e3de247be2564225c2e7a8f74cfe528e46e17d24868e2426040516114f791815260200190565b60405180910390a45050604080516060810182529485526001600160801b034281166020870190815294811691860191825260038054600181018255600091909152955160029096027fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b810196909655935190518416600160801b029316929092177fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85c909301929092555050565b6040805160608101825260008082526020820181905291810191909152600382815481106115d5576115d5611fa0565b600091825260209182902060408051606081018252600290930290910180548352600101546001600160801b0380821694840194909452600160801b90049092169181019190915292915050565b600d546001600160a01b0316331461164d5760405162461bcd60e51b815260040161083290611ee2565b6001600160a01b0381166000818152600e6020908152604091829020805460ff1916600190811790915591519182527f5df38d395edc15b669d646569bd015513395070b5b4deb8a16300abb060d1b5a9101610886565b600d546001600160a01b031633146116ce5760405162461bcd60e51b815260040161083290611ee2565b600a546040518291907fbf8cab6317796bfa97fea82b6d27c9542a08fa0821813cf2a57e7cff7fdc815690600090a3600a55565b600d546001600160a01b0316331461172c5760405162461bcd60e51b815260040161083290611ee2565b6009546040518291907f390b73b2b067afcef04d30b573e4590c6e565519e370927dd777ca0ce8a55db090600090a3600955565b6040805160608101825260008082526020820181905291810191909152600361178883610b1b565b815481106115d5576115d5611fa0565b6000600554600154836117ab9190611f89565b6117b59190612183565b6002546117c29190612004565b92915050565b600054600190610100900460ff161580156117ea575060005460ff8083169116105b61184d5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610832565b6000805461ffff191660ff8316176101001790556101608201516118d95760405162461bcd60e51b815260206004820152603a60248201527f4c324f75747075744f7261636c653a207375626d697373696f6e20696e74657260448201527f76616c206d7573742062652067726561746572207468616e20300000000000006064820152608401610832565b600082608001511161194a5760405162461bcd60e51b815260206004820152603460248201527f4c324f75747075744f7261636c653a204c3220626c6f636b2074696d65206d75604482015273073742062652067726561746572207468616e20360641b6064820152608401610832565b4282610140015111156119d35760405162461bcd60e51b8152602060048201526044602482018190527f4c324f75747075744f7261636c653a207374617274696e67204c322074696d65908201527f7374616d70206d757374206265206c657373207468616e2063757272656e742060648201526374696d6560e01b608482015260a401610832565b6101608201516004556080820151600555600354600003611aaa57604080516060810182526101008401518152610140840180516001600160801b03908116602084019081526101208701805183169585019586526003805460018181018355600092909252955160029687027fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b810191909155925196518416600160801b0296909316959095177fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85c909101559251909255905190555b8151600680546001600160a01b03199081166001600160a01b0393841617909155606084015160085560208085015183166000908152600e82526040808220805460ff1916600117905560a087015160095560c0870151600a55610180870151600b8054861691871691909117905560e0870151600c5580870151600d8054909516951694909417909255815461ff001916909155905160ff831681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498910160405180910390a15050565b6000600454611b83610a1e565b610a769190612004565b600d546001600160a01b03163314611bb75760405162461bcd60e51b815260040161083290611ee2565b600d546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600d80546001600160a01b0319166001600160a01b0392909216919091179055565b80356001600160a01b0381168114611c2a57600080fd5b919050565b600060208284031215611c4157600080fd5b611c4a82611c13565b9392505050565b600060208284031215611c6357600080fd5b5035919050565b6000815180845260005b81811015611c9057602081850181015186830182015201611c74565b81811115611ca2576000602083870101525b50601f01601f19169290920160200192915050565b602081526000611c4a6020830184611c6a565b60008060008060808587031215611ce057600080fd5b5050823594602084013594506040840135936060013592509050565b634e487b7160e01b600052604160045260246000fd5b6040516101a0810167ffffffffffffffff81118282101715611d3657611d36611cfc565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715611d6557611d65611cfc565b604052919050565b60008060008060808587031215611d8357600080fd5b84359350602080860135935060408601359250606086013567ffffffffffffffff80821115611db157600080fd5b818801915088601f830112611dc557600080fd5b813581811115611dd757611dd7611cfc565b611de9601f8201601f19168501611d3c565b91508082528984828501011115611dff57600080fd5b808484018584013760008482840101525080935050505092959194509250565b60006101a08284031215611e3257600080fd5b611e3a611d12565b611e4383611c13565b8152611e5160208401611c13565b6020820152611e6260408401611c13565b6040820152606083013560608201526080830135608082015260a083013560a082015260c083013560c082015260e083013560e0820152610100808401358183015250610120808401358183015250610140808401358183015250610160808401358183015250610180611ed7818501611c13565b908201529392505050565b60208082526027908201527f4c324f75747075744f7261636c653a2063616c6c6572206973206e6f74207468604082015266329037bbb732b960c91b606082015260800190565b6020808252602a908201527f4c324f75747075744f7261636c653a206f7074696d6973746963206d6f6465206040820152691a5cc8195b98589b195960b21b606082015260800190565b634e487b7160e01b600052601160045260246000fd5b600082821015611f9b57611f9b611f73565b500390565b634e487b7160e01b600052603260045260246000fd5b6020808252602e908201527f4c324f75747075744f7261636c653a206f7074696d6973746963206d6f64652060408201526d1a5cc81b9bdd08195b98589b195960921b606082015260800190565b6000821982111561201757612017611f73565b500190565b60008261203957634e487b7160e01b600052601260045260246000fd5b500490565b6020808252603f908201527f4c324f75747075744f7261636c653a206f6e6c7920617070726f76656420707260408201527f6f706f736572732063616e2070726f706f7365206e6577206f75747075747300606082015260800190565b60208082526036908201527f4c324f75747075744f7261636c653a2063616e6e6f742070726f706f7365204c60408201527532206f757470757420696e207468652066757475726560501b606082015260800190565b6020808252603a908201527f4c324f75747075744f7261636c653a204c32206f75747075742070726f706f7360408201527f616c2063616e6e6f7420626520746865207a65726f2068617368000000000000606082015260800190565b8381526060602082015260006121676060830185611c6a565b82810360408401526121798185611c6a565b9695505050505050565b600081600019048311821515161561219d5761219d611f73565b50029056fea26469706673582212205e369ad4437dabea1f1be6283d955e7638d425f8b17b82e789370710917ca6f664736f6c634300080f0033",
        "nonce": "0x4a",
        "chainId": "0xaa36a7"
      },
      "additionalContracts": [],
      "isFixedGasLimit": false
    },
    {
      "hash": "0x925e583251914e0554cc4eb6076682817c11330c6eabbb5969fba2397988fd3f",
      "transactionType": "CREATE",
      "contractName": "Proxy",
      "contractAddress": "0x050fdc19d469acc9e9a20761a565bece0cdd5879",
      "function": null,
      "arguments": [
        "0xC2Df13b6AD0753E0547A318F65F99aC62AEC6E2b"
      ],
      "transaction": {
        "from": "0xc2df13b6ad0753e0547a318f65f99ac62aec6e2b",
        "gas": "0x8b4e7",
        "value": "0x0",
        "input": "0x608060405234801561001057600080fd5b5060405161078e38038061078e83398101604081905261002f916100b5565b6100388161003e565b506100e5565b600061005660008051602061076e8339815191525490565b60008051602061076e833981519152838155604080516001600160a01b0380851682528616602082015292935090917f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f910160405180910390a1505050565b6000602082840312156100c757600080fd5b81516001600160a01b03811681146100de57600080fd5b9392505050565b61067a806100f46000396000f3fe60806040526004361061004e5760003560e01c80633659cfe6146100655780634f1ef286146100855780635c60da1b146100ae5780638f283970146100db578063f851a440146100fb5761005d565b3661005d5761005b610110565b005b61005b610110565b34801561007157600080fd5b5061005b610080366004610521565b6101c8565b61009861009336600461053c565b61020e565b6040516100a591906105bf565b60405180910390f35b3480156100ba57600080fd5b506100c361033e565b6040516001600160a01b0390911681526020016100a5565b3480156100e757600080fd5b5061005b6100f6366004610521565b6103a9565b34801561010757600080fd5b506100c36103e4565b600061013a7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b90506001600160a01b0381166101a55760405162461bcd60e51b815260206004820152602560248201527f50726f78793a20696d706c656d656e746174696f6e206e6f7420696e697469616044820152641b1a5e995960da1b60648201526084015b60405180910390fd5b3660008037600080366000845af43d6000803e806101c2573d6000fd5b503d6000f35b600080516020610625833981519152546001600160a01b0316336001600160a01b031614806101f5575033155b156102065761020381610432565b50565b610203610110565b60606102266000805160206106258339815191525490565b6001600160a01b0316336001600160a01b03161480610243575033155b1561032f5761025184610432565b600080856001600160a01b0316858560405161026e929190610614565b600060405180830381855af49150503d80600081146102a9576040519150601f19603f3d011682016040523d82523d6000602084013e6102ae565b606091505b5091509150816103265760405162461bcd60e51b815260206004820152603960248201527f50726f78793a2064656c656761746563616c6c20746f206e657720696d706c6560448201527f6d656e746174696f6e20636f6e7472616374206661696c656400000000000000606482015260840161019c565b91506103379050565b610337610110565b9392505050565b60006103566000805160206106258339815191525490565b6001600160a01b0316336001600160a01b03161480610373575033155b1561039e57507f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b6103a6610110565b90565b600080516020610625833981519152546001600160a01b0316336001600160a01b031614806103d6575033155b15610206576102038161048e565b60006103fc6000805160206106258339815191525490565b6001600160a01b0316336001600160a01b03161480610419575033155b1561039e57506000805160206106258339815191525490565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8181556040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a25050565b60006104a66000805160206106258339815191525490565b600080516020610625833981519152838155604080516001600160a01b0380851682528616602082015292935090917f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f910160405180910390a1505050565b80356001600160a01b038116811461051c57600080fd5b919050565b60006020828403121561053357600080fd5b61033782610505565b60008060006040848603121561055157600080fd5b61055a84610505565b9250602084013567ffffffffffffffff8082111561057757600080fd5b818601915086601f83011261058b57600080fd5b81358181111561059a57600080fd5b8760208285010111156105ac57600080fd5b6020830194508093505050509250925092565b600060208083528351808285015260005b818110156105ec578581018301518582016040015282016105d0565b818111156105fe576000604083870101525b50601f01601f1916929092016040019392505050565b818382376000910190815291905056feb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103a2646970667358221220318caf201f2a8916e5df0b75205914e02ed0e95fa1304e2b2510e3499a9c88f164736f6c634300080f0033b53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103000000000000000000000000c2df13b6ad0753e0547a318f65f99ac62aec6e2b",
        "nonce": "0x4b",
        "chainId": "0xaa36a7"
      },
      "additionalContracts": [],
      "isFixedGasLimit": false
    },
    {
      "hash": "0x67a663442dfacf19296aa51b03fc6dddf9e66c254b93d6e2f64898ee15e0957b",
      "transactionType": "CALL",
      "contractName": "Proxy",
      "contractAddress": "0x050fdc19d469acc9e9a20761a565bece0cdd5879",
      "function": "upgradeToAndCall(address,bytes)",
      "arguments": [
        "0xA9F8DEc334a35a99B7eFaca5C0a55b3e3706774A",
        "0xdb1470f5000000000000000000000000c2df13b6ad0753e0547a318f65f99ac62aec6e2b000000000000000000000000c2df13b6ad0753e0547a318f65f99ac62aec6e2b000000000000000000000000c2df13b6ad0753e0547a318f65f99ac62aec6e2b0000000000000000000000000000000000000000000000000000000000000e10000000000000000000000000000000000000000000000000000000000000000200d4e72bc998d0528b0722a53bedd9c6f0143c9157af194ad4bb2502e37a496f33e3678015df481724af3aac49d000923caeec277027610b1490f857769f9459ae480336b576abf09a25c2a05c88aea3449a0a8d799175eb5b8d1e164f1af100e985c9bd50994b5a7c672caf4d0db7045cd0ab3bd324f1463886b5cb1073f205000000000000000000000000000000000000000000000000000000000005b97b00000000000000000000000000000000000000000000000000000000677dddf600000000000000000000000000000000000000000000000000000000000003e8000000000000000000000000e31b339d16697105bc7ef9faf474cf7528557ff0"
      ],
      "transaction": {
        "from": "0xc2df13b6ad0753e0547a318f65f99ac62aec6e2b",
        "to": "0x050fdc19d469acc9e9a20761a565bece0cdd5879",
        "gas": "0x8b159",
        "value": "0x0",
        "input": "0x4f1ef286000000000000000000000000a9f8dec334a35a99b7efaca5c0a55b3e3706774a000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001a4db1470f5000000000000000000000000c2df13b6ad0753e0547a318f65f99ac62aec6e2b000000000000000000000000c2df13b6ad0753e0547a318f65f99ac62aec6e2b000000000000000000000000c2df13b6ad0753e0547a318f65f99ac62aec6e2b0000000000000000000000000000000000000000000000000000000000000e10000000000000000000000000000000000000000000000000000000000000000200d4e72bc998d0528b0722a53bedd9c6f0143c9157af194ad4bb2502e37a496f33e3678015df481724af3aac49d000923caeec277027610b1490f857769f9459ae480336b576abf09a25c2a05c88aea3449a0a8d799175eb5b8d1e164f1af100e985c9bd50994b5a7c672caf4d0db7045cd0ab3bd324f1463886b5cb1073f205000000000000000000000000000000000000000000000000000000000005b97b00000000000000000000000000000000000000000000000000000000677dddf600000000000000000000000000000000000000000000000000000000000003e8000000000000000000000000e31b339d16697105bc7ef9faf474cf7528557ff000000000000000000000000000000000000000000000000000000000",
        "nonce": "0x4c",
        "chainId": "0xaa36a7"
      },
      "additionalContracts": [],
      "isFixedGasLimit": false
    }
  ],
  "receipts": [
    {
      "status": "0x1",
      "cumulativeGasUsed": "0x9d85f8",
      "logs": [
        {
          "address": "0xa9f8dec334a35a99b7efaca5c0a55b3e3706774a",
          "topics": [
            "0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498"
          ],
          "data": "0x00000000000000000000000000000000000000000000000000000000000000ff",
          "blockHash": "0x730c7d63af79783184946d8790b62a2d32490e27c1459780af534a01cf70390e",
          "blockNumber": "0x71959c",
          "transactionHash": "0xbd7ac1497869e49a110d0a85c9bd2b9ce3addc2328d89a9388125580825ae64b",
          "transactionIndex": "0x47",
          "logIndex": "0x90",
          "removed": false
        }
      ],
      "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000",
      "type": "0x2",
      "transactionHash": "0xbd7ac1497869e49a110d0a85c9bd2b9ce3addc2328d89a9388125580825ae64b",
      "transactionIndex": "0x47",
      "blockHash": "0x730c7d63af79783184946d8790b62a2d32490e27c1459780af534a01cf70390e",
      "blockNumber": "0x71959c",
      "gasUsed": "0x1dc84e",
      "effectiveGasPrice": "0x702ceb774",
      "from": "0xc2df13b6ad0753e0547a318f65f99ac62aec6e2b",
      "to": null,
      "contractAddress": "0xa9f8dec334a35a99b7efaca5c0a55b3e3706774a"
    },
    {
      "status": "0x1",
      "cumulativeGasUsed": "0xa438ff",
      "logs": [
        {
          "address": "0x050fdc19d469acc9e9a20761a565bece0cdd5879",
          "topics": [
            "0x7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f"
          ],
          "data": "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c2df13b6ad0753e0547a318f65f99ac62aec6e2b",
          "blockHash": "0x730c7d63af79783184946d8790b62a2d32490e27c1459780af534a01cf70390e",
          "blockNumber": "0x71959c",
          "transactionHash": "0x925e583251914e0554cc4eb6076682817c11330c6eabbb5969fba2397988fd3f",
          "transactionIndex": "0x48",
          "logIndex": "0x91",
          "removed": false
        }
      ],
      "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800004000000000000000000000008000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
      "type": "0x2",
      "transactionHash": "0x925e583251914e0554cc4eb6076682817c11330c6eabbb5969fba2397988fd3f",
      "transactionIndex": "0x48",
      "blockHash": "0x730c7d63af79783184946d8790b62a2d32490e27c1459780af534a01cf70390e",
      "blockNumber": "0x71959c",
      "gasUsed": "0x6b307",
      "effectiveGasPrice": "0x702ceb774",
      "from": "0xc2df13b6ad0753e0547a318f65f99ac62aec6e2b",
      "to": null,
      "contractAddress": "0x050fdc19d469acc9e9a20761a565bece0cdd5879"
    },
    {
      "status": "0x1",
      "cumulativeGasUsed": "0xaa841d",
      "logs": [
        {
          "address": "0x050fdc19d469acc9e9a20761a565bece0cdd5879",
          "topics": [
            "0xbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b",
            "0x000000000000000000000000a9f8dec334a35a99b7efaca5c0a55b3e3706774a"
          ],
          "data": "0x",
          "blockHash": "0x730c7d63af79783184946d8790b62a2d32490e27c1459780af534a01cf70390e",
          "blockNumber": "0x71959c",
          "transactionHash": "0x67a663442dfacf19296aa51b03fc6dddf9e66c254b93d6e2f64898ee15e0957b",
          "transactionIndex": "0x49",
          "logIndex": "0x92",
          "removed": false
        },
        {
          "address": "0x050fdc19d469acc9e9a20761a565bece0cdd5879",
          "topics": [
            "0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498"
          ],
          "data": "0x0000000000000000000000000000000000000000000000000000000000000001",
          "blockHash": "0x730c7d63af79783184946d8790b62a2d32490e27c1459780af534a01cf70390e",
          "blockNumber": "0x71959c",
          "transactionHash": "0x67a663442dfacf19296aa51b03fc6dddf9e66c254b93d6e2f64898ee15e0957b",
          "transactionIndex": "0x49",
          "logIndex": "0x93",
          "removed": false
        }
      ],
      "logsBloom": "0x00000000000000000000000000000000400080000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000008000000000000000000000000000000000000000080000000000000000000000000000000000000000000000400000000000000000000000000000000000040000020000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
      "type": "0x2",
      "transactionHash": "0x67a663442dfacf19296aa51b03fc6dddf9e66c254b93d6e2f64898ee15e0957b",
      "transactionIndex": "0x49",
      "blockHash": "0x730c7d63af79783184946d8790b62a2d32490e27c1459780af534a01cf70390e",
      "blockNumber": "0x71959c",
      "gasUsed": "0x64b1e",
      "effectiveGasPrice": "0x702ceb774",
      "from": "0xc2df13b6ad0753e0547a318f65f99ac62aec6e2b",
      "to": "0x050fdc19d469acc9e9a20761a565bece0cdd5879",
      "contractAddress": null
    }
  ],
  "libraries": [],
  "pending": [],
  "returns": {
    "0": {
      "internal_type": "address",
      "value": "0x050FDc19d469ACc9e9A20761A565bEcE0cDD5879"
    }
  },
  "timestamp": 1736304388,
  "chain": 11155111,
  "commit": "519e7c8"
}

地址交易

https://sepolia.etherscan.io/tx/0xbd7ac1497869e49a110d0a85c9bd2b9ce3addc2328d89a9388125580825ae64b
https://sepolia.etherscan.io/tx/0x925e583251914e0554cc4eb6076682817c11330c6eabbb5969fba2397988fd3f
https://sepolia.etherscan.io/tx/0x67a663442dfacf19296aa51b03fc6dddf9e66c254b93d6e2f64898ee15e0957b

设置op-succinct服务环境变量

修改.env,在前面配置前提下,增加以下配置

  • L2OO_ADDRESS OPSuccinctL2OutputOracle上一步中的合约地址。(执行日志中,最开始return的地址)
  • OP_SUCCINCT_MOCK 设置为true模拟模式。
L2OO_ADDRESS=0x050FDc19d469ACc9e9A20761A565bEcE0cDD5879
OP_SUCCINCT_MOCK=true

op-succinct已模拟器方式启动

构建 Docker Compose 设置。

docker compose build
CONTAINER ID   IMAGE                                            COMMAND                  CREATED              STATUS              PORTS                                                                                                                                                                                     NAMES
516e7d420adb   op-succinct-op-succinct-proposer                 "/usr/local/bin/op_p…"   About a minute ago   Up About a minute   0.0.0.0:7300->7300/tcp, :::7300->7300/tcp                                                                                                                                                 op-succinct-op-succinct-proposer-1
5c9def1ff705   op-succinct-op-succinct-server                   "/usr/local/bin/serv…"   About a minute ago   Up About a minute   0.0.0.0:3000->3000/tcp, :::3000->3000/tcp                                                                                                                                                 op-succinct-op-succinct-server-1

运行提议器

docker compose up -d

此命令在后台启动op-succinct 服务。它会启动两个容器:一个容器管理证明生成,另一个容器是原始 op-proposer 服务的一个小分支。
几分钟后,您应该会看到 op-succinct-proposer 服务开始生成模拟范围证明。一旦生成了足够的范围证明,就会创建一个模拟聚合证明并提交给 L1。

查看日志

docker compose logs -f
op-succinct-op-succinct-proposer-1  | t=2025-01-08T03:46:54+0000 lvl=info msg="Proposer status" metrics="{L2UnsafeHeadBlock:378134 L2FinalizedBlock:376987 LatestContractL2Block:375163 HighestProvenContiguousL2Block:376963 MinBlockToProveToAgg:376163 NumProving:0 NumWitnessgen:0 NumUnrequested:0}"
op-succinct-op-succinct-proposer-1  | t=2025-01-08T03:46:54+0000 lvl=info msg="Stage 1: Getting Range Proof Boundaries..."
op-succinct-op-succinct-proposer-1  | t=2025-01-08T03:46:54+0000 lvl=info msg="Stage 2: Processing PROVING requests..."
op-succinct-op-succinct-proposer-1  | t=2025-01-08T03:46:54+0000 lvl=info msg="Stage 3: Processing WITNESSGEN requests..."
op-succinct-op-succinct-proposer-1  | t=2025-01-08T03:46:54+0000 lvl=info msg="Stage 3: Deriving Agg Proofs..."
op-succinct-op-succinct-proposer-1  | t=2025-01-08T03:46:55+0000 lvl=info msg="created new AGG proof" from=375163 to=376963
op-succinct-op-succinct-proposer-1  | t=2025-01-08T03:46:55+0000 lvl=info msg="Stage 4: Requesting Queued Proofs..."
op-succinct-op-succinct-proposer-1  | t=2025-01-08T03:46:55+0000 lvl=info msg="Publishing transaction" service=proposer tx=0xd314db1133eb1a6948a030c4d6d1d5eb438783c4d702740871fdbaebb67e8e02 nonce=77 gasTipCap=1000000000 gasFeeCap=40045868604 gasLimit=49166 tx=0xd314db1133eb1a6948a030c4d6d1d5eb438783c4d702740871fdbaebb67e8e02
op-succinct-op-succinct-proposer-1  | t=2025-01-08T03:46:55+0000 lvl=info msg="Transaction successfully published" service=proposer tx=0xd314db1133eb1a6948a030c4d6d1d5eb438783c4d702740871fdbaebb67e8e02 nonce=77 gasTipCap=1000000000 gasFeeCap=40045868604 gasLimit=49166 tx=0xd314db1133eb1a6948a030c4d6d1d5eb438783c4d702740871fdbaebb67e8e02
op-succinct-op-succinct-proposer-1  | t=2025-01-08T03:49:19+0000 lvl=info msg="Transaction confirmed" service=proposer tx=0xd314db1133eb1a6948a030c4d6d1d5eb438783c4d702740871fdbaebb67e8e02 block=0x7453cd10c2109e64833eba6157f18ff5190721435f20fa12255e2c60d5fb1abc:7444153 effectiveGasPrice=20301622776
op-succinct-op-succinct-proposer-1  | t=2025-01-08T03:49:19+0000 lvl=info msg="checkpoint blockhash tx successfully published" tx_hash=0xd314db1133eb1a6948a030c4d6d1d5eb438783c4d702740871fdbaebb67e8e02
op-succinct-op-succinct-proposer-1  | t=2025-01-08T03:49:19+0000 lvl=info msg="Stage 5: Submitting Agg Proofs..."
op-succinct-op-succinct-proposer-1  | t=2025-01-08T03:49:20+0000 lvl=info msg="Proposer status" metrics="{L2UnsafeHeadBlock:378207 L2FinalizedBlock:376987 LatestContractL2Block:375163 HighestProvenContiguousL2Block:376963 MinBlockToProveToAgg:376163 NumProving:0 NumWitnessgen:0 NumUnrequested:1}"
op-succinct-op-succinct-proposer-1  | t=2025-01-08T03:49:20+0000 lvl=info msg="Stage 1: Getting Range Proof Boundaries..."
op-succinct-op-succinct-proposer-1  | t=2025-01-08T03:49:20+0000 lvl=info msg="Stage 2: Processing PROVING requests..."
op-succinct-op-succinct-proposer-1  | t=2025-01-08T03:49:20+0000 lvl=info msg="Stage 3: Processing WITNESSGEN requests..."
op-succinct-op-succinct-proposer-1  | t=2025-01-08T03:49:20+0000 lvl=info msg="Stage 3: Deriving Agg Proofs..."
op-succinct-op-succinct-proposer-1  | t=2025-01-08T03:49:20+0000 lvl=info msg="Stage 4: Requesting Queued Proofs..."
op-succinct-op-succinct-proposer-1  | t=2025-01-08T03:49:20+0000 lvl=info msg="found agg proof with already checkpointed l1 block info"
op-succinct-op-succinct-proposer-1  | t=2025-01-08T03:49:20+0000 lvl=info msg="Stage 5: Submitting Agg Proofs..."
op-succinct-op-succinct-proposer-1  | t=2025-01-08T03:49:20+0000 lvl=info msg="requesting proof from server" type=AGG start=375163 end=376963 id=7
op-succinct-op-succinct-server-1    | stdout: WARNING: Using insecure random number generator.
op-succinct-op-succinct-proposer-1  | t=2025-01-08T03:49:33+0000 lvl=info msg="Proposer status" metrics="{L2UnsafeHeadBlock:378214 L2FinalizedBlock:376987 LatestContractL2Block:375163 HighestProvenContiguousL2Block:376963 MinBlockToProveToAgg:376163 NumProving:0 NumWitnessgen:0 NumUnrequested:0}"
op-succinct-op-succinct-proposer-1  | t=2025-01-08T03:49:33+0000 lvl=info msg="Stage 1: Getting Range Proof Boundaries..."
op-succinct-op-succinct-proposer-1  | t=2025-01-08T03:49:33+0000 lvl=info msg="Stage 2: Processing PROVING requests..."
op-succinct-op-succinct-proposer-1  | t=2025-01-08T03:49:33+0000 lvl=info msg="Stage 3: Processing WITNESSGEN requests..."
op-succinct-op-succinct-proposer-1  | t=2025-01-08T03:49:33+0000 lvl=info msg="Stage 3: Deriving Agg Proofs..."
op-succinct-op-succinct-proposer-1  | t=2025-01-08T03:49:33+0000 lvl=info msg="Stage 4: Requesting Queued Proofs..."
op-succinct-op-succinct-proposer-1  | t=2025-01-08T03:49:33+0000 lvl=info msg="Stage 5: Submitting Agg Proofs..."
op-succinct-op-succinct-proposer-1  | t=2025-01-08T03:49:53+0000 lvl=info msg="Proposing output root" output=0xc9400255dc53cf40ab7f44249bb8178d54b670a7d82a3605e98174361e09fe2f block=0x41c1f7ceea6b1ab0731587a60083e9700d13f00cef2313fdb1ce7fd2eaf96572:376963
op-succinct-op-succinct-proposer-1  | t=2025-01-08T03:49:53+0000 lvl=info msg="Publishing transaction" service=proposer tx=0x00ca0165505b68ba746238e38c392bb4a3893619dcc2583425fac81a333b460c nonce=78 gasTipCap=1000000000 gasFeeCap=45304698768 gasLimit=115535 tx=0x00ca0165505b68ba746238e38c392bb4a3893619dcc2583425fac81a333b460c
op-succinct-op-succinct-proposer-1  | t=2025-01-08T03:49:53+0000 lvl=info msg="Transaction successfully published" service=proposer tx=0x00ca0165505b68ba746238e38c392bb4a3893619dcc2583425fac81a333b460c nonce=78 gasTipCap=1000000000 gasFeeCap=45304698768 gasLimit=115535 tx=0x00ca0165505b68ba746238e38c392bb4a3893619dcc2583425fac81a333b460c
op-succinct-op-succinct-proposer-1  | t=2025-01-08T03:51:53+0000 lvl=info msg="Transaction confirmed" service=proposer tx=0x00ca0165505b68ba746238e38c392bb4a3893619dcc2583425fac81a333b460c block=0xbb06380707e28390e051c9b6678b5502ffdb8a76ae1d90d28a73c81cc28140f5:7444166 effectiveGasPrice=21571495890
op-succinct-op-succinct-proposer-1  | t=2025-01-08T03:51:53+0000 lvl=info msg="Proposer tx successfully published" tx_hash=0x00ca0165505b68ba746238e38c392bb4a3893619dcc2583425fac81a333b460c
op-succinct-op-succinct-proposer-1  | t=2025-01-08T03:51:53+0000 lvl=info msg="AGG proof submitted on-chain" end=376963
op-succinct-op-succinct-proposer-1  | t=2025-01-08T03:51:54+0000 lvl=info msg="Slack notifications disabled, token not set"

当前提交的Proposing output root: 0xc9400255dc53cf40ab7f44249bb8178d54b670a7d82a3605e98174361e09fe2f

交易分析

# Name Type Data
0 _blockNumber uint256 7444413

https://github.com/succinctlabs/op-succinct/blob/c4eef1ac5f11b5b1d2750d4ee5cbff5e57fa5cc2/contracts/src/OPSuccinctL2OutputOracle.sol#L430C3-L437C6

/// @notice Checkpoints a block hash at a given block number.
    /// @param _blockNumber Block number to checkpoint the hash at.
    /// @dev If the block hash is not available, this will revert.
    function checkpointBlockHash(uint256 _blockNumber) external {
        bytes32 blockHash = blockhash(_blockNumber);
        if (blockHash == bytes32(0)) {
            revert L1BlockHashNotAvailable();
        }
        historicBlockHashes[_blockNumber] = blockHash;
    }

注:检查存储对应L1高度的区块hash,作为检查点,会在后续verifyProof时作为proof验证源数据

# Name Type Data
0 _outputRoot bytes32 0xc9400255dc53cf40ab7f44249bb8178d54b670a7d82a3605e98174361e09fe2f
1 _l2BlockNumber uint256 376963
2 _l1BlockNumber uint256 7444151
3 _proof bytes

注:当前_proof为Mock数据,数据空(length == 0)

contracts/src/OPSuccinctL2OutputOracle.sol

https://github.com/succinctlabs/op-succinct/blob/c4eef1ac5f11b5b1d2750d4ee5cbff5e57fa5cc2/contracts/src/OPSuccinctL2OutputOracle.sol#L349-L358

AggregationOutputs memory publicValues = AggregationOutputs({
    l1Head: l1BlockHash,
    l2PreRoot: l2Outputs[latestOutputIndex()].outputRoot,
    claimRoot: _outputRoot,
    claimBlockNum: _l2BlockNumber,
    rollupConfigHash: rollupConfigHash,
    rangeVkeyCommitment: rangeVkeyCommitment
});

ISP1Verifier(verifier).verifyProof(aggregationVkey, abi.encode(publicValues), _proof);

contracts/src/SP1MockVerifier.sol

https://github.com/succinctlabs/sp1-contracts/blob/90d99052cf7880fe521f5fb0974b9c51056f9619/contracts/src/SP1MockVerifier.sol#L12

contract SP1MockVerifier is ISP1Verifier {
    /// @notice Verifies a mock proof with given public values and vkey.
    /// @param proofBytes The proof of the program execution the SP1 zkVM encoded as bytes.
    function verifyProof(bytes32, bytes calldata, bytes calldata proofBytes) external pure {
        assert(proofBytes.length == 0);
    }
}

浏览器截图

使用真实Proof

具体最终配置在 contracts/opsuccinctl2ooconfig.json

{
  "challenger": "0xC2Df13b6AD0753E0547A318F65F99aC62AEC6E2b",
  "finalizationPeriod": 3600,
  "l2BlockTime": 2,
  "owner": "0xC2Df13b6AD0753E0547A318F65F99aC62AEC6E2b",
  "proposer": "0xC2Df13b6AD0753E0547A318F65F99aC62AEC6E2b",
  "rollupConfigHash": "0xae480336b576abf09a25c2a05c88aea3449a0a8d799175eb5b8d1e164f1af100",
  "startingBlockNumber": 375163,
  "startingOutputRoot": "0xe985c9bd50994b5a7c672caf4d0db7045cd0ab3bd324f1463886b5cb1073f205",
  "startingTimestamp": 1736302070,
  "submissionInterval": 1000,
  "verifier": "0xe31B339d16697105Bc7EF9faf474CF7528557fF0",
  "aggregationVkey": "0x00d4e72bc998d0528b0722a53bedd9c6f0143c9157af194ad4bb2502e37a496f",
  "rangeVkeyCommitment": "0x33e3678015df481724af3aac49d000923caeec277027610b1490f857769f9459"
}

verifier对应的就是节点验证合约地址,通过.env 中的VERIFIER_ADDRESS进行设置
官方版本对应的地址为:https://sepolia.etherscan.io/address/0x397A5f7f3dBd538f23DE225B51f532c34448dA9B#code
部署的合约为:https://github.com/succinctlabs/sp1-contracts/blob/90d99052cf7880fe521f5fb0974b9c51056f9619/contracts/src/SP1VerifierGateway.sol

注:支持PLONK和Groth16两种类型的SP1 验证器网关,官方默认为Groth16

Clone sp1-contracts

git clone https://github.com/succinctlabs/sp1-contracts.git
cd sp1-contracts/
git checkout v3.0.0
git submodule update --init --recursive

参考文档:https://github.com/succinctlabs/sp1-contracts/blob/v3.0.0/README.md

修改.env

cd contracts/ && cp .env.example .env && vi .env

### Salt used to deploy the contracts. Recommended to use the same salt across different chains.
CREATE2_SALT=0x0000000000000000000000000000000000000000000000000000000000000000

### The owner of the SP1 Verifier Gateway. This is the account that will be able to add and freeze routes.
OWNER=0xC2Df13b6AD0753E0547A318F65F99aC62AEC6E2b

### The chains to deploy to, specified by chain name (e.g. CHAINS=mainnet,sepolia,arbitrum_sepolia)
CHAINS=sepolia

### RPCs for each chain ID
RPC_SEPOLIA=http://....:8545

# Etherscan API keys for each chain ID
ETHERSCAN_API_KEY_SEPOLIA=2BY57NTWCWIWN....

## Contract Deployer Private Key
PRIVATE_KEY=0xa7da3c790f48.....

部署合约

source .env
FOUNDRY_PROFILE=deploy forge script ./script/deploy/SP1VerifierGateway.s.sol:SP1VerifierGatewayScript --private-key $PRIVATE_KEY --verify --verifier etherscan --multi --broadcast

部署地址:https://sepolia.etherscan.io/address/0x88C89693758CD526cB9F5897865a2644eEbBCd1E#code

注:在v4.0.0+版本,去除了统一的SP1VerifierGateway,分别使用SP1VerifierGatewayPlonk和SP1VerifierGatewayGroth16,目前还是rc版本,目前优先使用v3.0.0 release 版本

添加验证者地址

FOUNDRY_PROFILE=deploy forge script ./script/deploy/v3.0.0/SP1VerifierPlonk.s.sol:SP1VerifierScript --private-key $PRIVATE_KEY --verify --verifier etherscan --multi --broadcast

部署地址:https://sepolia.etherscan.io/address/0x339319bBCfDEa130E9642028684dB85d430230E8#code

完整模式下启动op-succinct

修改op-succinct .env

VERIFIER_ADDRESS=0x88C89693758CD526cB9F5897865a2644eEbBCd1E

部署OPSuccinctL2outputOracle合约

just deploy-oracle

部署地址:https://sepolia.etherscan.io/address/0x6360f7e2c222153365d4479d55484cbed5165df3

设置op-succinct服务环境变量

修改变量,并新增两个配置

  • SP1_PRIVATE_KEY:将向 L1 提交证明的账户的私钥。
  • PROVER_NETWORK_RPC:默认是作为三方加入Succinct官方,需要审核访问权限。默认端点 ( https://rpc.succinct.xyz) ,对于自搭建的环境,直接填prover 服务地址,例如 http://172.18.36.185:3000
L2OO_ADDRESS=0x6360f7e2c222153365d4479d55484cbed5165df3
OP_SUCCINCT_MOCK=false
SP1_PRIVATE_KEY=0x....
PROVER_NETWORK_RPC=http://172.18.36.185:3000

构建 Docker Compose 设置。

docker compose build

运行提议器

docker compose up -d

查看日志

docker compose logs -f

参考文档

https://succinctlabs.github.io/op-succinct/

op-stack + zk + DA 方案测试 TODO

空余看SP1,顺便想了下,目前主流的几个L2,都有些不足?

  • zk类的 prover 运行成本高,或者 EVM兼容性,RPC 性能低
  • op 类的,有个7天
  • 必要的DA支持,降低提交成本

zkSync,Polygon cdk,arbitrum, op-stack 等主流的项目代码大部分都看过了
从代码实现,Evm兼容性,代码架构,稳定性,功能定制复杂度,op-stack 是最合适的?

目前各个方案综合来看,最优的组合是 op-stack + zk + DA ?

方案组成调研

TODO

  1. op-succinct的部署,prover 实际机器成本,产出性能
  2. EigenDA私有化部署

op-succinct 代码分析- proposer succinct server

代码分析

proposer/succinct/bin/server.rs

let app = Router::new()
    .route("/request_span_proof", post(request_span_proof)) // 请求对一系列区块的证明。
    .route("/request_agg_proof", post(request_agg_proof)) // 请求一组子证明的聚合证明。
    .route("/request_mock_span_proof", post(request_mock_span_proof)) // 请求对一系列区块的Mock证明。
    .route("/request_mock_agg_proof", post(request_mock_agg_proof))// 请求一组子证明的Mock聚合证明。
    .route("/status/:proof_id", get(get_proof_status)) // 获取证明的状态。
    .route("/validate_config", post(validate_config)) // 验证 L2 输出 Oracle 的配置
    .layer(DefaultBodyLimit::disable())
    .layer(RequestBodyLimitLayer::new(102400 * 1024 * 1024))
    .with_state(global_hashes);

let port = env::var("PORT").unwrap_or_else(|_| "3000".to_string());
let listener = tokio::net::TcpListener::bind(format!("0.0.0.0:{}", port))
.await
.unwrap();

info!("Server listening on {}", listener.local_addr().unwrap());

request_span_proof

async fn request_span_proof(
    State(state): State<ContractConfig>,
    Json(payload): Json<SpanProofRequest>,
) -> Result<(StatusCode, Json<ProofResponse>), AppError> {
    info!("Received span proof request: {:?}", payload);
    let fetcher = match OPSuccinctDataFetcher::new_with_rollup_config(RunContext::Docker).await { // get_rpcs() 通过环境变量 L1_RPC L1_BEACON_RPC L2_RPC L2_NODE_RPC 获取相应配置,并通过fetch_and_save_rollup_config 获取L2的rollup_config
        Ok(f) => f,
        Err(e) => {
            error!("Failed to create data fetcher: {}", e);
            return Err(AppError(e));
        }
    };

    let host_cli = match fetcher
        .get_host_cli_args( // 获取给定块号的 L2 输出数据,并将启动信息保存到数据目录中带有 block_number 的文件中。返回要传递给 datagen 的本机主机的参数。
            payload.start,
            payload.end,
            ProgramType::Multi,
            CacheMode::DeleteCache,
        )
        .await
    {
        Ok(cli) => cli,
        Err(e) => {
            error!("Failed to get host CLI args: {}", e);
            return Err(AppError(anyhow::anyhow!(
                "Failed to get host CLI args: {}",
                e
            )));
        }
    };

    // 启动服务器和本机客户端并设置超时时间。
    // 注意:理想情况下,服务器应调用执行本机的单独进程
    // 主机,并返回客户端可以轮询以检查证明是否已提交的 ID。
    let mut witnessgen_executor = WitnessGenExecutor::new(WITNESSGEN_TIMEOUT, RunContext::Docker);
    if let Err(e) = witnessgen_executor.spawn_witnessgen(&host_cli).await { // 为给定的主机 CLI 生成见证生成进程,并将其添加到正在进行的进程列表中。
        error!("Failed to spawn witness generation: {}", e);
        return Err(AppError(anyhow::anyhow!(
            "Failed to spawn witness generation: {}",
            e
        )));
    }
    // 记录运行见证生成过程时出现的任何错误。
    if let Err(e) = witnessgen_executor.flush().await {
        error!("Failed to generate witness: {}", e);
        return Err(AppError(anyhow::anyhow!(
            "Failed to generate witness: {}",
            e
        )));
    }

    let sp1_stdin = match get_proof_stdin(&host_cli) { // 获取标准输入来为给定的 L2 声明生成证明。
        Ok(stdin) => stdin,
        Err(e) => {
            error!("Failed to get proof stdin: {}", e);
            return Err(AppError(anyhow::anyhow!(
                "Failed to get proof stdin: {}",
                e
            )));
        }
    };

    let private_key = match env::var("SP1_PRIVATE_KEY") {
        Ok(private_key) => private_key,
        Err(e) => {
            error!("Failed to get SP1 private key: {}", e);
            return Err(AppError(anyhow::anyhow!(
                "Failed to get SP1 private key: {}",
                e
            )));
        }
    };
    let rpc_url = match env::var("PROVER_NETWORK_RPC") {
        Ok(rpc_url) => rpc_url,
        Err(e) => {
            error!("Failed to get PROVER_NETWORK_RPC: {}", e);
            return Err(AppError(anyhow::anyhow!(
                "Failed to get PROVER_NETWORK_RPC: {}",
                e
            )));
        }
    };
    let mut prover = NetworkProverV2::new(&private_key, Some(rpc_url.to_string()), false); // 根据private key和rpc 创建prover
    // 使用预留策略路由到特定集群。
    prover.with_strategy(FulfillmentStrategy::Reserved);

    // 由于范围证明很大,因此将模拟设置为 false。
    env::set_var("SKIP_SIMULATION", "true");
    let vk_hash = match prover.register_program(&state.range_vk, RANGE_ELF).await { // 注册elf/range-elf
        Ok(vk_hash) => vk_hash,
        Err(e) => {
            error!("Failed to register program: {}", e);
            return Err(AppError(anyhow::anyhow!(
                "Failed to register program: {}",
                e
            )));
        }
    };
    let proof_id = match prover
        .request_proof( // 向证明者网络请求证明,并返回请求 ID。
            &vk_hash,
            &sp1_stdin,
            ProofMode::Compressed, // 压缩证明模式。还支持 Core,Plonk,Groth16
            1_000_000_000_000,
            None,
        )
        .await
    {
        Ok(proof_id) => proof_id,
        Err(e) => {
            error!("Failed to request proof: {}", e);
            return Err(AppError(anyhow::anyhow!("Failed to request proof: {}", e)));
        }
    };
    env::set_var("SKIP_SIMULATION", "false");

    Ok((StatusCode::OK, Json(ProofResponse { proof_id })))
}
pub async fn request_proof(
        &self,
        vk_hash: &[u8],
        stdin: &SP1Stdin,
        mode: ProofMode,
        cycle_limit: u64,
        timeout: Option<Duration>,
    ) -> Result<Vec<u8>> {
        // Get the timeout.
        let timeout_secs = timeout.map(|dur| dur.as_secs()).unwrap_or(TIMEOUT_SECS);

        log::info!("Requesting proof with cycle limit: {}", cycle_limit);

        // Request the proof with retries.
        let response = with_retry(
            || async {
                self.client
                    .request_proof(
                        vk_hash,
                        stdin,
                        mode,
                        SP1_CIRCUIT_VERSION,
                        self.strategy,
                        timeout_secs,
                        cycle_limit,
                    )
                    .await
            },
            timeout,
            "requesting proof",
        )
        .await?;

        // 记录请求 ID 和交易哈希。
        let tx_hash_hex = "0x".to_string() + &hex::encode(response.tx_hash);
        let request_id = response.body.unwrap().request_id;
        let request_id_hex = "0x".to_string() + &hex::encode(request_id.clone());
        log::info!("Created request {} in transaction {}", request_id_hex, tx_hash_hex);

        if self.client.rpc_url() == DEFAULT_PROVER_NETWORK_RPC { // "https://rpc.production.succinct.tools/"
            log::info!("View in explorer: https://network.succinct.xyz/request/{}", request_id_hex);
        }

        Ok(request_id)
    }
// 使用给定的验证密钥哈希和标准输入创建证明请求。
pub async fn request_proof(
        &self,
        vk_hash: &[u8],
        stdin: &SP1Stdin,
        mode: ProofMode,
        version: &str,
        strategy: FulfillmentStrategy,
        timeout_secs: u64,
        cycle_limit: u64,
    ) -> Result<RequestProofResponse> {
        // 计算截止期限。
        let start = SystemTime::now();
        let since_the_epoch = start.duration_since(UNIX_EPOCH).expect("Invalid start time");
        let deadline = since_the_epoch.as_secs() + timeout_secs;

        // 创建 stdin artifact.
        let mut store = self.get_store().await?;
        let stdin_uri = self.create_artifact_with_content(&mut store, &stdin).await?;

        // 发送请求
        let mut rpc = self.get_rpc().await?; // 获取 ProverNetwork rpc
        let nonce = self.get_nonce().await?; // 从ProverNetwork中获取nonce
        let request_body = RequestProofRequestBody { // 组装请求体
            nonce,
            version: format!("sp1-{}", version),
            vk_hash: vk_hash.to_vec(),
            mode: mode.into(),
            strategy: strategy.into(),
            stdin_uri,
            deadline,
            cycle_limit,
        };
        let request_response = rpc
            .request_proof(RequestProofRequest { // 调用的为sp1客户端服务 /network.ProverNetwork/RequestProof
                format: MessageFormat::Binary.into(),
                signature: request_body.sign(&self.signer).into(), // 使用私钥进行签名
                body: Some(request_body),
            })
            .await?
            .into_inner();

        Ok(request_response)
    }

https://github.com/succinctlabs/sp1/blob/bfb0c6d8e045b5f40422b9c06cb0e9ee21b3c19c/crates/sdk/src/network/proto/network.rs#L3

// This file is @generated by prost-build.
#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)]
pub struct RequestProofRequest {
    /// The message format of the body.
    #[prost(enumeration = "MessageFormat", tag = "1")]
    pub format: i32,
    /// The signature of the sender.
    #[prost(bytes = "vec", tag = "2")]
    pub signature: ::prost::alloc::vec::Vec<u8>,
    /// The body of the request.
    #[prost(message, optional, tag = "3")]
    pub body: ::core::option::Option<RequestProofRequestBody>,
}

具体SP1服务相关逻辑,后续文章单独分析

request_agg_proof

// 请求一组子证明的聚合证明。

async fn request_agg_proof(
    State(state): State<ContractConfig>,
    Json(payload): Json<AggProofRequest>,
) -> Result<(StatusCode, Json<ProofResponse>), AppError> {
    info!("Received agg proof request");
    let mut proofs_with_pv: Vec<SP1ProofWithPublicValues> = payload
        .subproofs
        .iter()
        .map(|sp| bincode::deserialize(sp).unwrap())
        .collect();

    let boot_infos: Vec<BootInfoStruct> = proofs_with_pv
        .iter_mut()
        .map(|proof| proof.public_values.read())
        .collect();

    let proofs: Vec<SP1Proof> = proofs_with_pv // 从payload中获取多个证明
        .iter_mut()
        .map(|proof| proof.proof.clone())
        .collect();

    let l1_head_bytes = hex::decode(
        payload
            .head
            .strip_prefix("0x")
            .expect("Invalid L1 head, no 0x prefix."),
    )?;
    let l1_head: [u8; 32] = l1_head_bytes.try_into().unwrap();

    let fetcher = match OPSuccinctDataFetcher::new_with_rollup_config(RunContext::Docker).await {
        Ok(f) => f,
        Err(e) => return Err(AppError(anyhow::anyhow!("Failed to create fetcher: {}", e))),
    };

    let headers = match fetcher
        .get_header_preimages(&boot_infos, l1_head.into()) // 获取与启动信息对应的标头的原映像。具体来说,获取与启动信息和最新的 L1 头对应的标头。 通过get_earliest_l1_head_in_batch从boot_infos中获取最早的L1 Head 作为start, get_l1_header 获取最新的 L1 Head(在链上验证)的完整标头, 通过fetch_headers_in_range获取start到end多个区块的headers
        .await
    {
        Ok(h) => h,
        Err(e) => {
            error!("Failed to get header preimages: {}", e);
            return Err(AppError(anyhow::anyhow!(
                "Failed to get header preimages: {}",
                e
            )));
        }
    };

    let private_key = env::var("SP1_PRIVATE_KEY")?;
    let rpc_url = env::var("PROVER_NETWORK_RPC")?;
    let mut prover = NetworkProverV2::new(&private_key, Some(rpc_url.to_string()), false);
    // 使用预留策略路由到特定集群。
    prover.with_strategy(FulfillmentStrategy::Reserved);

    let stdin =
        match get_agg_proof_stdin(proofs, boot_infos, headers, &state.range_vk, l1_head.into()) { // 获取聚合证明的标准输入。
            Ok(s) => s,
            Err(e) => {
                error!("Failed to get agg proof stdin: {}", e);
                return Err(AppError(anyhow::anyhow!(
                    "Failed to get agg proof stdin: {}",
                    e
                )));
            }
        };

    let vk_hash = match prover.register_program(&state.agg_vk, AGG_ELF).await { // 注册elf/aggregation-elf
        Ok(vk_hash) => vk_hash,
        Err(e) => {
            error!("Failed to register program: {}", e);
            return Err(AppError(anyhow::anyhow!(
                "Failed to register program: {}",
                e
            )));
        }
    };
    let proof_id = match prover
        .request_proof( // 使用给定的验证密钥哈希和标准输入创建证明请求。具体看上面的request_span_proof->request_proof
            &vk_hash,
            &stdin,
            ProofMode::Groth16, // 和request_span_proof有区别,ProofMode::Compressed,
            1_000_000_000_000,
            None,
        )
        .await
    {
        Ok(id) => id,
        Err(e) => {
            error!("Failed to request proof: {}", e);
            return Err(AppError(anyhow::anyhow!("Failed to request proof: {}", e)));
        }
    };

    Ok((StatusCode::OK, Json(ProofResponse { proof_id })))
}
pub fn get_agg_proof_stdin(
    proofs: Vec<SP1Proof>,
    boot_infos: Vec<BootInfoStruct>,
    headers: Vec<Header>,
    multi_block_vkey: &sp1_sdk::SP1VerifyingKey,
    latest_checkpoint_head: B256,
) -> Result<SP1Stdin> {
    let mut stdin = SP1Stdin::new();
    for proof in proofs {
        let SP1Proof::Compressed(compressed_proof) = proof else {
            panic!();
        };
        stdin.write_proof(*compressed_proof, multi_block_vkey.vk.clone());
    }

    // 将聚合输入写入标准输入。
    stdin.write(&AggregationInputs {
        boot_infos,
        latest_l1_checkpoint_head: latest_checkpoint_head,
        multi_block_vkey: multi_block_vkey.hash_u32(),
    });
    // Head在使用 bincode 序列化时存在问题,因此请改用 serde_json。
    let headers_bytes = serde_cbor::to_vec(&headers).unwrap();
    stdin.write_vec(headers_bytes);

    Ok(stdin)
}

总结

  • request_span_proof:通过get_proof_stdin获取证明所需参数,使用ProofMode::Compressed压缩证明模式,通过request_proof向sp1服务申请生成proof
  • request_agg_proof: 将获取到的多个proof,使用ProofMode::Groth16证明模式,通过request_proof向sp1服务申请生成聚合proof

op-succinct 代码分析- proposer

代码分析

1. 启动

proposer/op/proposer/service.go

func (ps *ProposerService) Start(_ context.Context) error {
    ps.Log.Info("Starting Proposer")
    return ps.driver.StartL2OutputSubmitting()
}

proposer/op/proposer/driver.go

func (l *L2OutputSubmitter) StartL2OutputSubmitting() error {
    ...
    // 当使用缓存数据库重新启动提议者时,我们需要将处于见证生成状态的所有证明标记为失败,然后重试。
    witnessGenReqs, err := l.db.GetAllProofsWithStatus(proofrequest.StatusWITNESSGEN)
    if err != nil {
        return fmt.Errorf("failed to get witness generation pending proofs: %w", err)
    }
    for _, req := range witnessGenReqs {
        err = l.RetryRequest(req, ProofStatusResponse{})
        if err != nil {
            return fmt.Errorf("failed to retry request: %w", err)
        }
    }

    // 验证合约的聚合和范围验证密钥的配置以及汇总配置哈希。
    err = l.ValidateConfig(l.Cfg.L2OutputOracleAddr.Hex()) // 向 l.Cfg.OPSuccinctServerUrl+"/validate_config" 配置的proposer/succinct/bin/server.rs 去请求数据
    ...
    go l.loop() // loop 负责创建和提交下一个输出

2. 循环检查和提交

proposer/op/proposer/driver.go

// loopL2OO 定期轮询 L2OO 以提出下一个区块,如果当前最终确定(或安全)的区块超过了下一个区块,则它会提出该区块。
func (l *L2OutputSubmitter) loopL2OO(ctx context.Context) {
    ticker := time.NewTicker(l.Cfg.PollInterval) // 检查间隔
    for {
        select {
        case <-ticker.C:
            // 获取提议者的当前指标。
            metrics, err := l.GetProposerMetrics(ctx)
            if err != nil {
                l.Log.Error("failed to get metrics", "err", err)
                continue
            }
            l.Log.Info("Proposer status", "metrics", metrics)

            // 1) 将准备好进行证明的范围证明放入队列中。根据最新的 L2 最终区块和当前的 L2 不安全头来确定这些范围证明。
            l.Log.Info("Stage 1: Getting Range Proof Boundaries...")
            err = l.GetRangeProofBoundaries(ctx)
            if err != nil {
                l.Log.Error("failed to get range proof boundaries", "err", err)
                continue
            }

            // 2) 检查 PROVING 请求的状态。如果成功返回,我们将验证其是否已保存在磁盘上,并将状态设置为“COMPLETE”。如果失败或超时,我们将状态设置为“FAILED”(如果是跨度证明,则将请求分成两半以重试)。
            l.Log.Info("Stage 2: Processing PROVING requests...")
            err = l.ProcessProvingRequests()
            if err != nil {
                l.Log.Error("failed to update PROVING requests", "err", err)
                continue
            }

            // 3) 检查 WITNESSGEN 请求的状态。如果见证生成请求处于 WITNESSGEN 状态的时间超过超时时间,则将状态设置为 FAILED 并重试。
            l.Log.Info("Stage 3: Processing WITNESSGEN requests...")
            err = l.ProcessWitnessgenRequests()
            if err != nil {
                l.Log.Error("failed to update WITNESSGEN requests", "err", err)
                continue
            }

            // 4) 确定从 L2OO 合约上的最新区块开始,是否存在连续的跨度证明链。如果有,则为所有跨度证明排队一个聚合证明。
            l.Log.Info("Stage 3: Deriving Agg Proofs...")
            err = l.DeriveAggProofs(ctx)
            if err != nil {
                l.Log.Error("failed to generate pending agg proofs", "err", err)
                continue
            }

            // 5) 从证明者网络请求所有未请求的证明。任何状态为“UNREQ”的数据库条目都表示它已排队并准备就绪。我们从证明者网络请求所有这些(span 和 agg)。对于 agg 证明,我们还会提前检查区块哈希。
            l.Log.Info("Stage 4: Requesting Queued Proofs...")
            err = l.RequestQueuedProofs(ctx)
            if err != nil {
                l.Log.Error("failed to request unrequested proofs", "err", err)
                continue
            }

            // 6) 在链上提交聚合证明。如果我们在数据库中有一个完整的聚合证明等待处理,我们会将其提交到链上。
            l.Log.Info("Stage 5: Submitting Agg Proofs...")
            err = l.SubmitAggProofs(ctx)
            if err != nil {
                l.Log.Error("failed to submit agg proofs", "err", err)
            }

2.1 GetRangeProofBoundaries

proposer/op/proposer/range.go

// 将准备好进行证明的范围证明放入队列中。根据最新的 L2 最终区块和当前的 L2 不安全头来确定这些范围证明。
func (l *L2OutputSubmitter) GetRangeProofBoundaries(ctx context.Context) error {
    // nextBlock 等于 DB 的 `EndBlock` 列中的最高值加 1。
    latestL2EndBlock, err := l.db.GetLatestEndBlock()
    if err != nil {
        if ent.IsNotFound(err) {
            latestEndBlockU256, err := l.l2ooContract.LatestBlockNumber(&bind.CallOpts{Context: ctx}) // 如果本地没有记录,则从合约读取
            if err != nil {
                return fmt.Errorf("failed to get latest output index: %w", err)
            } else {
                latestL2EndBlock = latestEndBlockU256.Uint64()
            }
        } else {
            l.Log.Error("failed to get latest end requested", "err", err)
            return err
        }
    }
    newL2StartBlock := latestL2EndBlock

    rollupClient, err := dial.DialRollupClientWithTimeout(ctx, dial.DefaultDialTimeout, l.Log, l.Cfg.RollupRpc) // 连接L2
    if err != nil {
        return err
    }

    // 获取最新的最终确定的 L2 区块。
    status, err := rollupClient.SyncStatus(ctx) // optimism_syncStatus
    if err != nil {
        l.Log.Error("proposer unable to get sync status", "err", err)
        return err
    }
    // 注意:最初,这使用的是 L1 最终区块。但为了满足新 API,我们现在使用 L2 最终区块。
    newL2EndBlock := status.FinalizedL2.Number

    spans := l.SplitRangeBasic(newL2StartBlock, newL2EndBlock)

    // 将每个跨度添加到数据库。如果没有跨度,我们将不会创建任何证明。
    for _, span := range spans {
        err := l.db.NewEntry(proofrequest.TypeSPAN, span.Start, span.End)
        l.Log.Info("New range proof request.", "start", span.Start, "end", span.End)
        if err != nil {
            l.Log.Error("failed to add span to db", "err", err)
            return err
        }
    }

    return nil
}
// CreateSpans 创建一个从开始到结束大小为 MaxBlockRangePerSpanProof 的跨度列表。注意:跨度 i 的结束 = 跨度 i+1 的开始。
func (l *L2OutputSubmitter) SplitRangeBasic(start, end uint64) []Span {
    spans := []Span{}
    // 从开始到结束创建大小为 MaxBlockRangePerSpanProof 的跨度。每个跨度都从前一个跨度结束的地方开始。继续,直到我们在到达终点之前无法再容纳另一个完整的跨度。
    for i := start; i+l.Cfg.MaxBlockRangePerSpanProof <= end; i += l.Cfg.MaxBlockRangePerSpanProof {
        spans = append(spans, Span{Start: i, End: i + l.Cfg.MaxBlockRangePerSpanProof})
    }
    return spans
}
总结

GetRangeProofBoundaries 根据初始高度(本地记录优先,否则查找合约记录)和当前L2最终区块高度,根据设置参数MaxBlockRangePerSpanProof拆分跨度区块,创建对应的Proof任务

2.2 ProcessProvingRequests

proposer/op/proposer/prove.go

// 检查 PROVING 请求的状态。如果成功返回,我们将验证其是否已保存在磁盘上,并将状态设置为“COMPLETE”。如果失败或超时,我们将状态设置为“FAILED”(如果是跨度证明,则将请求分成两半,以重试)。
func (l *L2OutputSubmitter) ProcessProvingRequests() error {
    reqs, err := l.db.GetAllProofsWithStatus(proofrequest.StatusPROVING) // 获取所有当前处于 PROVING 状态的证明请求
    if err != nil {
        return err
    }
    for _, req := range reqs {
        proofStatus, err := l.GetProofStatus(req.ProverRequestID)
        if err != nil {
            l.Log.Error("failed to get proof status for ID", "id", req.ProverRequestID, "err", err)
            l.Metr.RecordError("get_proof_status", 1) // 记录获取证明状态调用的错误。
            return err
        }
        if proofStatus.FulfillmentStatus == SP1FulfillmentStatusFulfilled {
            l.Log.Info("Fulfilled Proof", "id", req.ProverRequestID)
            err = l.db.AddFulfilledProof(req.ID, proofStatus.Proof) // 更新数据库中的证明并将状态更新为完成。
            if err != nil {
                l.Log.Error("failed to update completed proof status", "err", err)
                return err
            }
            continue
        }

        if proofStatus.FulfillmentStatus == SP1FulfillmentStatusUnfulfillable {
            // 记录失败原因。
            l.Log.Info("Proof is unfulfillable", "id", req.ProverRequestID)
            l.Metr.RecordProveFailure("unfulfillable")

            err = l.RetryRequest(req, proofStatus) // 如果为区间,则拆分成2个
            if err != nil {
                return fmt.Errorf("failed to retry request: %w", err)
            }
        }
    }

    return nil
}
func (l *L2OutputSubmitter) RetryRequest(req *ent.ProofRequest, status ProofStatusResponse) error {
    err := l.db.UpdateProofStatus(req.ID, proofrequest.StatusFAILED)
    if err != nil {
        l.Log.Error("failed to update proof status", "err", err)
        return err
    }

    // // 如果出现执行错误,且请求是 SPAN 证明,且区块范围 > 1,则将请求拆分为两个请求。这可能是由于 SP1 OOM 造成的,因为区块范围较大且交易较多。
    // TODO:一旦使用嵌入式分配器,就可以删除此解决方案,因为这样程序就永远不会出现 OOM。
    if req.Type == proofrequest.TypeSPAN && status.ExecutionStatus == SP1ExecutionStatusUnexecutable && req.EndBlock-req.StartBlock > 1 {
        // 将请求拆分为两个请求。
        midBlock := (req.StartBlock + req.EndBlock) / 2
        err = l.db.NewEntry(req.Type, req.StartBlock, midBlock)
        if err != nil {
            l.Log.Error("failed to retry first half of proof request", "err", err)
            return err
        }
        err = l.db.NewEntry(req.Type, midBlock+1, req.EndBlock)
        if err != nil {
            l.Log.Error("failed to retry second half of proof request", "err", err)
            return err
        }
    } else {
        // 重试同一请求。
        err = l.db.NewEntry(req.Type, req.StartBlock, req.EndBlock)
        if err != nil {
            l.Log.Error("failed to retry proof request", "err", err)
            return err
        }
    }

    return nil
}
总结

ProcessProvingRequests 根据本地db记录,依次向服务端l.Cfg.OPSuccinctServerUrl+"/status/"+proofId获取所有当前处于PROVING的任务最新状态,如果SP1已生成完成,则更新本地数据为完成,如果失败则进行重试(如果为区间,则拆分成2个)

2.3 ProcessWitnessgenRequests

proposer/op/proposer/prove.go

func (l *L2OutputSubmitter) ProcessWitnessgenRequests() error {
    // 获取当前处于 WITNESSGEN 状态的所有证明请求。
    reqs, err := l.db.GetAllProofsWithStatus(proofrequest.StatusWITNESSGEN)
    if err != nil {
        return err
    }
    for _, req := range reqs {
        // 如果请求处于 WITNESSGEN 状态的时间超过超时时间(20分钟),则将状态设置为 FAILED。
        if req.LastUpdatedTime+uint64(WITNESSGEN_TIMEOUT.Seconds()) < uint64(time.Now().Unix()) {
            l.RetryRequest(req, ProofStatusResponse{}) // 如果超时,重试请求
        }
    }

    return nil
}

2.4 DeriveAggProofs

proposer/op/proposer/prove.go

// 使用 L2OO 合约查找下一个证明必须覆盖的区块范围。检查数据库以查看我们是否有足够的跨度证明来请求覆盖此范围的聚合证明。如果是,则将聚合证明排队在数据库中以供稍后请求。
func (l *L2OutputSubmitter) DeriveAggProofs(ctx context.Context) error {
    latest, err := l.l2ooContract.LatestBlockNumber(&bind.CallOpts{Context: ctx})
    if err != nil {
        return fmt.Errorf("failed to get latest L2OO output: %w", err)
    }

    // 这将获取下一个块号,即 currentBlock + submissionInterval。
    minTo, err := l.l2ooContract.NextBlockNumber(&bind.CallOpts{Context: ctx})
    if err != nil {
        return fmt.Errorf("failed to get next L2OO output: %w", err)
    }

    created, end, err := l.db.TryCreateAggProofFromSpanProofs(latest.Uint64(), minTo.Uint64()) // 尝试从覆盖范围 [from, minTo) 的跨度证明中创建 AGG 证明。 如果创建了新的 AGG 证明,则返回 true,否则返回 false。
    if err != nil {
        return fmt.Errorf("failed to create agg proof from span proofs: %w", err)
    }
    if created {
        l.Log.Info("created new AGG proof", "from", latest.Uint64(), "to", end)
    }

    return nil
}

2.5 RequestQueuedProofs

// proposer/op/proposer/driver.go

// 从证明者网络请求所有未请求的证明。任何状态为“UNREQ”的数据库条目都表示它已排队并准备就绪。我们从证明者网络请求所有这些(span 和 agg)。对于 agg 证明,我们还会提前检查区块哈希。
func (l *L2OutputSubmitter) RequestQueuedProofs(ctx context.Context) error {
    nextProofToRequest, err := l.db.GetNextUnrequestedProof()
    if err != nil {
        return fmt.Errorf("failed to get unrequested proofs: %w", err)
    }
    if nextProofToRequest == nil {
        return nil
    }

    if nextProofToRequest.Type == proofrequest.TypeAGG {
        if nextProofToRequest.L1BlockHash == "" {
            blockNumber, blockHash, err := l.checkpointBlockHash(ctx) // 获取L1最新区块-1的head, 并把区块高度通过sendCheckpointTransaction方法发送交易,l.Cfg.L2OutputOracleAddr->checkpointBlockHash 写入合约
            if err != nil {
                l.Log.Error("failed to checkpoint block hash", "err", err)
                return err
            }
            nextProofToRequest, err = l.db.AddL1BlockInfoToAggRequest(nextProofToRequest.StartBlock, nextProofToRequest.EndBlock, blockNumber, blockHash.Hex()) // 创建新Proof任务
            if err != nil {
                l.Log.Error("failed to add L1 block info to AGG request", "err", err)
            }

            // 等待下一次循环,这样我们就有了添加了块信息的版本
            return nil
        } else {
            l.Log.Info("found agg proof with already checkpointed l1 block info")
        }
    } else {
        witnessGenProofs, err := l.db.GetNumberOfRequestsWithStatuses(proofrequest.StatusWITNESSGEN)
        if err != nil {
            return fmt.Errorf("failed to count witnessgen proofs: %w", err)
        }
        provingProofs, err := l.db.GetNumberOfRequestsWithStatuses(proofrequest.StatusPROVING)
        if err != nil {
            return fmt.Errorf("failed to count proving proofs: %w", err)
        }

        // 见证生成请求的数量上限为 MAX_CONCURRENT_WITNESS_GEN。这可以防止见证生成服务器产生的进程使机器过载。一旦 https://github.com/anton-rs/kona/issues/553 修复,我们可能就可以删除此检查。
        if witnessGenProofs >= MAX_CONCURRENT_WITNESS_GEN {
            l.Log.Info("max witness generation reached, waiting for next cycle")
            return nil
        }

        // 并发证明的总数上限为 MAX_CONCURRENT_PROOF_REQUESTS。
        if (witnessGenProofs + provingProofs) >= int(l.Cfg.MaxConcurrentProofRequests) {
            l.Log.Info("max concurrent proof requests reached, waiting for next cycle")
            return nil
        }
    }
    go func(p ent.ProofRequest) {
        l.Log.Info("requesting proof from server", "type", p.Type, "start", p.StartBlock, "end", p.EndBlock, "id", p.ID)
        // 将证明状态设置为 WITNESSGEN。
        err = l.db.UpdateProofStatus(p.ID, proofrequest.StatusWITNESSGEN)
        if err != nil {
            l.Log.Error("failed to update proof status", "err", err)
            return
        }

        // 根据模拟配置请求证明类型。
        err = l.RequestProof(p, l.Cfg.Mock)
        if err != nil {
            // 如果证明请求失败,我们应该将其添加到队列中以待重试。
            err = l.RetryRequest(nextProofToRequest, ProofStatusResponse{})
            if err != nil {
                l.Log.Error("failed to retry request", "err", err)
            }

        }
    }(*nextProofToRequest)

    return nil
}
// RequestProof 处理模拟和真实证明请求
func (l *L2OutputSubmitter) RequestProof(p ent.ProofRequest, isMock bool) error {
    jsonBody, err := l.prepareProofRequest(p)
    if err != nil {
        return err
    }

    if isMock { // 开启Mock
        proofData, err := l.requestMockProof(p.Type, jsonBody)
        if err != nil {
            return fmt.Errorf("mock proof request failed: %w", err)
        }

        // 对于模拟证明,一旦生成了“模拟证明”,就将状态设置为 PROVING。AddFulfilledProof 期望证明处于 PROVING 状态。
        err = l.db.UpdateProofStatus(p.ID, proofrequest.StatusPROVING)
        if err != nil {
            return fmt.Errorf("failed to set proof status to proving: %w", err)
        }
        return l.db.AddFulfilledProof(p.ID, proofData)
    }

    // 向见证生成服务器请求真实证明。从网络返回证明 ID。
    proofID, err := l.requestRealProof(p.Type, jsonBody)
    if err != nil {
        return fmt.Errorf("real proof request failed: %w", err)
    }

    // 检索到证明者 ID 后,将证明状态设置为 PROVING。只有状态为 PROVING、SUCCESS 或 FAILED 的证明才有证明者请求 ID。
    err = l.db.UpdateProofStatus(p.ID, proofrequest.StatusPROVING)
    if err != nil {
        return fmt.Errorf("failed to set proof status to proving: %w", err)
    }

    return l.db.SetProverRequestID(p.ID, proofID)
}

2.6 SubmitAggProofs

// 在链上提交聚合证明。如果我们在数据库中有一个完整的聚合证明等待处理,我们会将其提交到链上。
func (l *L2OutputSubmitter) SubmitAggProofs(ctx context.Context) error {
    // 从 L2OutputOracle 合约获取最新的输出索引
    latestBlockNumber, err := l.l2ooContract.LatestBlockNumber(&bind.CallOpts{Context: ctx})
    if err != nil {
        return fmt.Errorf("failed to get latest output index: %w", err)
    }

    // 从下一个索引开始检查已完成的 AGG 证明
    completedAggProofs, err := l.db.GetAllCompletedAggProofs(latestBlockNumber.Uint64())
    if err != nil {
        return fmt.Errorf("failed to query for completed AGG proof: %w", err)
    }

    if len(completedAggProofs) == 0 {
        return nil
    }

    // 选择具有最高 L2 块编号的聚合证明。
    sort.Slice(completedAggProofs, func(i, j int) bool {
        return completedAggProofs[i].EndBlock > completedAggProofs[j].EndBlock
    })

    // 提交具有最高 L2 块编号的聚合证明。
    aggProof := completedAggProofs[0]
    output, err := l.FetchOutput(ctx, aggProof.EndBlock) // 通过optimism_outputAtBlock 健全性检查,例如在出现不良 RPC 缓存的情况下
    if err != nil {
        return fmt.Errorf("failed to fetch output at block %d: %w", aggProof.EndBlock, err)
    }
    err = l.proposeOutput(ctx, output, aggProof.Proof, aggProof.L1BlockNumber)// 通过proposeOutput 进行Proof的提交
    if err != nil {
        return fmt.Errorf("failed to propose output: %w", err)
    }

    return nil
}

op-succinct - 使用SP1 将OP stack转换成type-1 zkEVM Rollup

简介

OP Succinct 使用 SP1 在 1 小时内将任何 OP 堆栈汇总转换为完整的 type-1 zkEVM Rollup。

文章介绍:https://blog.succinct.xyz/op-succinct/
github: https://github.com/succinctlabs/op-succinct
docs: https://succinctlabs.github.io/op-succinct/introduction.html
SP1介绍:https://blog.succinct.xyz/introducing-sp1/
客户用例:https://blog.conduit.xyz/op-succinct-zk-rollups/