diff --git a/CHANGELOG.md b/CHANGELOG.md index bd62fd2c56..4ef1d8d6c3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,673 @@ Because this is workspace with multi libraries, tags will be simplified, and with this document you can match version of project with git tag. + +# v83 +date: 23.07.2025 + +Fusaka devnet-3 support. Performance regresion fixes. + +`revm-primitives`: 20.0.0 -> 20.1.0 (✓ API compatible changes) +`revm-bytecode`: 6.0.1 -> 6.1.0 (✓ API compatible changes) +`revm-database-interface`: 7.0.1 -> 7.0.2 (✓ API compatible changes) +`revm-context-interface`: 8.0.1 -> 9.0.0 (⚠ API breaking changes) +`revm-context`: 8.0.3 -> 8.0.4 (✓ API compatible changes) +`revm-interpreter`: 23.0.2 -> 24.0.0 (⚠ API breaking changes) +`revm-precompile`: 24.0.1 -> 25.0.0 (⚠ API breaking changes) +`revm-handler`: 8.0.3 -> 8.1.0 (✓ API compatible changes) +`revm-inspector`: 8.0.3 -> 8.1.0 (✓ API compatible changes) +`revm`: 27.0.3 -> 27.1.0 (✓ API compatible changes) +`revme`: 7.0.4 -> 7.1.0 (✓ API compatible changes) +`op-revm`: 8.0.3 -> 8.1.0 (✓ API compatible changes) +`revm-state`: 7.0.1 -> 7.0.2 +`revm-database`: 7.0.1 -> 7.0.2 +`revm-statetest-types`: 8.0.4 -> 8.0.5 + +# v82 +date 14.07.2025 + +Fix for inspector not calling `step_end`. + +* `revm-context`: 8.0.2 -> 8.0.3 (✓ API compatible changes) +* `revm-interpreter`: 23.0.1 -> 23.0.2 (✓ API compatible changes) +* `revm-precompile`: 24.0.0 -> 24.0.1 (✓ API compatible changes) +* `revm-handler`: 8.0.2 -> 8.0.3 (✓ API compatible changes) +* `revm-inspector`: 8.0.2 -> 8.0.3 (✓ API compatible changes) +* `revme`: 7.0.3 -> 7.0.4 (✓ API compatible changes) +* `op-revm`: 8.0.2 -> 8.0.3 (✓ API compatible changes) +* `custom_precompile_journal`: 0.1.0 +* `revm`: 27.0.2 -> 27.0.3 +* `revm-statetest-types`: 8.0.3 -> 8.0.4 + +# v81 +date: 03.07.2025 + +Fix inspector step_end panic for opcode fn. + +* `revm-bytecode`: 6.0.0 -> 6.0.1 (✓ API compatible changes) +* `revm-handler`: 8.0.1 -> 8.0.2 (✓ API compatible changes) +* `revm-inspector`: 8.0.1 -> 8.0.2 (✓ API compatible changes) +* `revme`: 7.0.2 -> 7.0.3 (✓ API compatible changes) +* `custom_precompile_journal`: 0.1.0 +* `revm-state`: 7.0.0 -> 7.0.1 +* `revm-database-interface`: 7.0.0 -> 7.0.1 +* `revm-context-interface`: 8.0.0 -> 8.0.1 +* `revm-context`: 8.0.1 -> 8.0.2 +* `revm-database`: 7.0.0 -> 7.0.1 +* `revm-interpreter`: 23.0.0 -> 23.0.1 +* `revm`: 27.0.1 -> 27.0.2 +* `revm-statetest-types`: 8.0.2 -> 8.0.3 +* `op-revm`: 8.0.1 -> 8.0.2 + +# v80 +date 01.07.2025 + +Fix `build` and `build_fill` for OpTransactionBuilder + +* `revm-context`: 8.0.0 -> 8.0.1 (✓ API compatible changes) +* `revm-handler`: 8.0.0 -> 8.0.1 (✓ API compatible changes) +* `revm-inspector`: 8.0.0 -> 8.0.1 (✓ API compatible changes) +* `revm`: 27.0.0 -> 27.0.1 (✓ API compatible changes) +* `op-revm`: 8.0.0 -> 8.0.1 (✓ API compatible changes) + +# v79 +date: 01.07.2025 + +Fix for bytecode eq operation. + +* `revm-bytecode`: 5.0.0 -> 6.0.0 (⚠ API breaking changes) +* `revm-state`: 6.0.0 -> 7.0.0 (✓ API compatible changes) +* `revm-database-interface`: 6.0.0 -> 7.0.0 (✓ API compatible changes) +* `revm-context-interface`: 7.0.1 -> 8.0.0 (⚠ API breaking changes) +* `revm-context`: 7.0.1 -> 8.0.0 (✓ API compatible changes) +* `revm-interpreter`: 22.0.1 -> 23.0.0 (✓ API compatible changes) +* `revm-precompile`: 23.0.0 -> 24.0.0 (✓ API compatible changes) +* `revm-handler`: 7.0.1 -> 8.0.0 (⚠ API breaking changes) +* `revm-inspector`: 7.0.1 -> 8.0.0 (✓ API compatible changes) +* `revm`: 26.0.1 -> 27.0.0 (✓ API compatible changes) +* `revm-statetest-types`: 8.0.1 -> 8.0.2 (✓ API compatible changes) +* `revme`: 7.0.1 -> 7.0.2 (✓ API compatible changes) +* `op-revm`: 7.0.1 -> 8.0.0 (⚠ API breaking changes) +* `revm-database`: 6.0.0 -> 7.0.0 + +# v78 +date: 20.05.2025 + +Quick fix for not calling `frame_stack.clear()` https://github.com/bluealloy/revm/pull/2656 + +* `revm-context`: 7.0.0 -> 7.0.1 (✓ API compatible changes) +* `revm-interpreter`: 22.0.0 -> 22.0.1 (✓ API compatible changes) +* `revm-precompile`: 23.0.0 -> 23.0.1 (✓ API compatible changes) +* `revm-handler`: 7.0.0 -> 7.0.1 (✓ API compatible changes) +* `revm-inspector`: 7.0.0 -> 7.0.1 +* `revm`: 26.0.0 -> 26.0.1 +* `revm-statetest-types`: 8.0.0 -> 8.0.1 +* `revme`: 7.0.0 -> 7.0.1 +* `op-revm`: 7.0.0 -> 7.0.1 + +# v77 +date: 19.05.2025 + +Perf upgrade and support for osaka devnet-2 EIPs. + +* `revm-primitives`: 19.2.0 -> 20.0.0 (⚠ API breaking changes) +* `revm-bytecode`: 4.1.0 -> 5.0.0 (⚠ API breaking changes) +* `revm-state`: 5.0.0 -> 6.0.0 (✓ API compatible changes) +* `revm-database-interface`: 5.0.0 -> 6.0.0 (✓ API compatible changes) +* `revm-context-interface`: 6.0.0 -> 7.0.0 (⚠ API breaking changes) +* `revm-context`: 6.0.0 -> 7.0.0 (⚠ API breaking changes) +* `revm-database`: 5.0.0 -> 6.0.0 (✓ API compatible changes) +* `revm-interpreter`: 21.0.0 -> 22.0.0 (⚠ API breaking changes) +* `revm-precompile`: 22.0.0 -> 23.0.0 (⚠ API breaking changes) +* `revm-handler`: 6.0.0 -> 7.0.0 (⚠ API breaking changes) +* `revm-inspector`: 6.0.0 -> 7.0.0 (⚠ API breaking changes) +* `revm`: 25.0.0 -> 26.0.0 (⚠ API breaking changes) +* `revm-statetest-types`: 7.0.0 -> 8.0.0 (✓ API compatible changes) +* `revme`: 6.0.0 -> 7.0.0 (⚠ API breaking changes) +* `op-revm`: 6.0.0 -> 7.0.0 (✓ API compatible changes) + + +# v76 +date: 06.05.2025 + +Introduction of multi transaction. + +* `revm-primitives`: 19.1.0 -> 19.2.0 (✓ API compatible changes) +* `revm-bytecode`: 4.0.1 -> 4.1.0 (✓ API compatible changes) +* `revm-state`: 4.0.1 -> 5.0.0 (⚠ API breaking changes) +* `revm-database-interface`: 4.0.1 -> 5.0.0 (✓ API compatible changes) +* `revm-context-interface`: 5.0.0 -> 6.0.0 (⚠ API breaking changes) +* `revm-context`: 5.0.1 -> 6.0.0 (⚠ API breaking changes) +* `revm-database`: 4.0.1 -> 5.0.0 (⚠ API breaking changes) +* `revm-interpreter`: 20.0.0 -> 21.0.0 (⚠ API breaking changes) +* `revm-precompile`: 21.0.0 -> 22.0.0 (✓ API compatible changes) +* `revm-handler`: 5.0.1 -> 6.0.0 (⚠ API breaking changes) +* `revm-inspector`: 5.0.1 -> 6.0.0 (⚠ API breaking changes) +* `revm`: 24.0.1 -> 25.0.0 (✓ API compatible changes) +* `revm-statetest-types`: 6.0.0 -> 7.0.0 (✓ API compatible changes) +* `revme`: 5.1.1 -> 6.0.0 (⚠ API breaking changes) +* `op-revm`: 5.0.1 -> 6.0.0 (⚠ API breaking changes) + +# v75 tag +date: 31.05.2025 + +Maintainance release. + +* `revm-context`: 5.0.0 -> 5.0.1 +* `revm-handler`: 5.0.0 -> 5.0.1 +* `revm-inspector`: 5.0.0 -> 5.0.1 +* `revm`: 24.0.0 -> 24.0.1 +* `revm-statetest-type`: 5.0.0 -> 6.0.0 +* `op-revm`: 5.0.0 -> 5.0.1 + +# v74 tag +date 23.05.2025 + +Osaka devnet-0 support + +* `revm-primitives`: 19.0.0 -> 19.1.0 (✓ API compatible changes) +* `revm-bytecode`: 4.0.0 -> 4.0.1 (✓ API compatible changes) +* `revm-state`: 4.0.0 -> 4.0.1 (✓ API compatible changes) +* `revm-database-interface`: 4.0.0 -> 4.0.1 (✓ API compatible changes) +* `revm-context-interface`: 4.1.0 -> 5.0.0 (⚠ API breaking changes) +* `revm-context`: 4.1.0 -> 5.0.0 (⚠ API breaking changes) +* `revm-database`: 4.0.0 -> 4.0.1 (✓ API compatible changes) +* `revm-interpreter`: 19.1.0 -> 20.0.0 (✓ API compatible changes) +* `revm-precompile`: 20.1.0 -> 21.0.0 (⚠ API breaking changes) +* `revm-handler`: 4.1.0 -> 5.0.0 (✓ API compatible changes) +* `revm-inspector`: 4.1.0 -> 5.0.0 (✓ API compatible changes) +* `revm`: 23.1.0 -> 24.0.0 (✓ API compatible changes) +* `revm-statetest-types`: 4.1.0 -> 5.0.0 (✓ API compatible changes) +* `revme`: 5.0.0 -> 5.1.0 (✓ API compatible changes) +* `op-revm`: 4.0.2 -> 5.0.0 (✓ API compatible changes) + +# v71 tag +date: 09.05.2025 + +op-revm fix: deposit nonce bump + +* `op-revm`: 4.0.1 -> 4.0.2 (✓ API compatible changes) + + +# v71 tag +date: 09.05.2025 + +op-revm fix. + +* `op-revm`: 4.0.0 -> 4.0.1 (✓ API compatible changes) + +# v71 tag +date: 07.05.2025 + +Maintanance release that fixes last v70 version bump. + + +* `revm-state`: 3.0.1 -> 4.0.0 +* `revm-database-interface`: 3.0.1 -> 4.0.0 +* `revm-database`: 3.1.0 -> 4.0.0 +* `revm-context-interface`: 4.0.0 -> 4.1.0 +* `revm-context`: 4.0.0 -> 4.1.0 +* `revm-interpreter`: 19.0.0 -> 19.1.0 +* `revm-precompile`: 20.0.0 -> 20.1.0 +* `revm-handler`: 4.0.0 -> 4.1.0 +* `revm-inspector`: 4.0.0 -> 4.1.0 +* `revm`: 23.0.0 -> 23.1.0 +* `revm-statetest-types`: 4.0.0 -> 4.1.0 +* `revme`: 4.1.0 -> 5.0.0 +* `op-revm`: 3.0.2 -> 3.1.0 + +# v70 tag +date: 07.05.2025 + +Yanked release as dependency bump was done incorrectly. Maintanance release. + +* `revm-primitives`: 18.0.0 -> 19.0.0 (⚠️ API breaking changes) +* `revm-bytecode`: 3.0.0 -> 4.0.0 (⚠️ API breaking changes) +* `revm-state`: 3.0.0 -> 3.0.1 (✓ API compatible changes) +* `revm-database-interface`: 3.0.0 -> 3.0.1 (✓ API compatible changes) +* `revm-context-interface`: 3.0.0 -> 4.0.0 (⚠️ API breaking changes) +* `revm-context`: 3.0.1 -> 4.0.0 (⚠️ API breaking changes) +* `revm-database`: 3.0.0 -> 3.1.0 (✓ API compatible changes) +* `revm-interpreter`: 18.0.0 -> 19.0.0 (⚠️ API breaking changes) +* `revm-precompile`: 19.0.0 -> 20.0.0 (⚠️ API breaking changes) +* `revm-handler`: 3.0.1 -> 4.0.0 (⚠️ API breaking changes) +* `revm-inspector`: 3.0.1 -> 4.0.0 (⚠️ API breaking changes) +* `revm`: 22.0.1 -> 23.0.0 (✓ API compatible changes) +* `revm-statetest-types`: 3.0.1 -> 4.0.0 (⚠️ API breaking changes) +* `revme`: 4.0.2 -> 4.1.0 (✓ API compatible changes) +* `op-revm`: 3.0.2 -> 3.1.0 (✓ API compatible changes) + +# v69 tag +date: 14.04.2025 + +op-revm bug fix for bls precompiles + +* `op-revm`: 3.0.0 -> 3.0.1 (✓ API compatible changes) + +# v68 tag +date: 09.04.2025 + +Bump to alloy-primitives, this warants major bump on all libs. No breaking changes + +* `revm-primitives`: 17.0.0 -> 18.0.0 (✓ API compatible changes) +* `revm-bytecode`: 2.0.0 -> 3.0.0 (✓ API compatible changes) +* `revm-state`: 2.0.0 -> 3.0.0 (✓ API compatible changes) +* `revm-database-interface`: 2.0.0 -> 3.0.0 (✓ API compatible changes) +* `revm-context-interface`: 2.0.0 -> 3.0.0 (✓ API compatible changes) +* `revm-context`: 2.0.0 -> 3.0.0 (✓ API compatible changes) +* `revm-database`: 2.0.0 -> 3.0.0 (✓ API compatible changes) +* `revm-interpreter`: 17.0.0 -> 18.0.0 (✓ API compatible changes) +* `revm-precompile`: 18.0.0 -> 19.0.0 (✓ API compatible changes) +* `revm-handler`: 2.0.0 -> 3.0.0 (⚠️ API breaking changes) + * Two traits reexported in different mod +* `revm-inspector`: 2.0.0 -> 3.0.0 (✓ API compatible changes) +* `revm`: 21.0.0 -> 22.0.0 (✓ API compatible changes) +* `revme`: 4.0.0 -> 4.0.1 (✓ API compatible changes) +* `op-revm`: 2.0.0 -> 3.0.0 (✓ API compatible changes) +* `revm-statetest-types`: 2.0.0 -> 3.0.0 + + +# v67 tag +date: 28.03.2025 + +op-revm isthum fix. + +* `revm-primitives`: 16.0.0 -> 17.0.0 (⚠ API breaking changes) +* `revm-bytecode`: 1.0.0 -> 2.0.0 (⚠ API breaking changes) +* `revm-database-interface`: 1.0.0 -> 2.0.0 (✓ API compatible changes) +* `revm-context-interface`: 1.0.0 -> 2.0.0 (✓ API compatible changes) +* `revm-context`: 1.0.0 -> 2.0.0 (⚠ API breaking changes) +* `revm-database`: 1.0.0 -> 2.0.0 (✓ API compatible changes) +* `revm-interpreter`: 16.0.0 -> 17.0.0 (✓ API compatible changes) +* `revm-precompile`: 17.0.0 -> 18.0.0 (⚠ API breaking changes) +* `revm-handler`: 1.0.0 -> 2.0.0 (⚠ API breaking changes) +* `revm-inspector`: 1.0.0 -> 2.0.0 (✓ API compatible changes) +* `revm`: 20.0.0 -> 21.0.0 (✓ API compatible changes) +* `revme`: 3.0.0 -> 4.0.0 (⚠ API breaking changes) +* `op-revm`: 1.0.0 -> 2.0.0 (⚠ API breaking changes) +* `revm-state`: 1.0.0 -> 2.0.0 +* `revm-statetest-types`: 1.0.0 -> 2.0.0 + +# v66 tag +date: 24.03.205 + +Stable release of Revm new Execution API and Evm Framework. + +* `revm-primitives`: 16.0.0-alpha.5 -> 16.0.0 +* `revm-context-interface`: 1.0.0-alpha.6 -> 1.0.0 +* `revm-context`: 1.0.0-alpha.6 -> 1.0.0 +* `revm-database`: 1.0.0-alpha.5 -> 1.0.0 +* `revm-interpreter`: 16.0.0-alpha.7 -> 16.0.0 +* `revm-precompile`: 17.0.0-alpha.7 -> 17.0.0 +* `revm-handler`: 1.0.0-alpha.7 -> 1.0.0 +* `revm-inspector`: 1.0.0-alpha.7 -> 1.0.0 +* `revme`: 3.0.0-alpha.6 -> 3.0.0 +* `op-revm`: 1.0.0-alpha.6 -> 1.0.0 +* `revm-bytecode`: 1.0.0-alpha.5 -> 1.0.0 +* `revm-state`: 1.0.0-alpha.5 -> 1.0.0 +* `revm-database-interface`: 1.0.0-alpha.5 -> 1.0.0 +* `revm`: 20.0.0-alpha.7 -> 20.0.0 + +# v65 tag +date 23.03.2025 + +Optimism fixes, preo for release v20.0.0 release. +Breaking changes related to EVMError, more about this here: https://github.com/bluealloy/revm/pull/2280 + +* `revm-primitives`: 16.0.0-alpha.4 -> 16.0.0-alpha.5 (⚠ API breaking changes) +* `revm-context-interface`: 1.0.0-alpha.5 -> 1.0.0-alpha.6 (⚠ API breaking changes) +* `revm-context`: 1.0.0-alpha.5 -> 1.0.0-alpha.6 (⚠ API breaking changes) +* `revm-database`: 1.0.0-alpha.4 -> 1.0.0-alpha.5 (✓ API compatible changes) +* `revm-interpreter`: 16.0.0-alpha.6 -> 16.0.0-alpha.7 (✓ API compatible changes) +* `revm-precompile`: 17.0.0-alpha.6 -> 17.0.0-alpha.7 (⚠ API breaking changes) +* `revm-handler`: 1.0.0-alpha.6 -> 1.0.0-alpha.7 (✓ API compatible changes) +* `revm-inspector`: 1.0.0-alpha.6 -> 1.0.0-alpha.7 (⚠ API breaking changes) +* `revme`: 3.0.0-alpha.6 -> 3.0.0-alpha.7 (✓ API compatible changes) +* `op-revm`: 1.0.0-alpha.5 -> 1.0.0-alpha.6 (⚠ API breaking changes) +* `revm-bytecode`: 1.0.0-alpha.4 -> 1.0.0-alpha.5 +* `revm-state`: 1.0.0-alpha.4 -> 1.0.0-alpha.5 +* `revm-database-interface`: 1.0.0-alpha.4 -> 1.0.0-alpha.5 +* `revm`: 20.0.0-alpha.6 -> 20.0.0-alpha.7 + +# v63 tag +date: 16.03.2025 + +Docs, prep for v20.0.0 release. + +* `revm-primitives`: 16.0.0-alpha.3 -> 16.0.0-alpha.4 (✓ API compatible changes) +* `revm-bytecode`: 1.0.0-alpha.3 -> 1.0.0-alpha.4 (⚠️ API breaking changes) +* `revm-context-interface`: 1.0.0-alpha.4 -> 1.0.0-alpha.5 (✓ API compatible changes) +* `revm-context`: 1.0.0-alpha.4 -> 1.0.0-alpha.5 (✓ API compatible changes) +* `revm-precompile`: 17.0.0-alpha.5 -> 17.0.0-alpha.6 (✓ API compatible changes) +* `revm-handler`: 1.0.0-alpha.5 -> 1.0.0-alpha.6 (✓ API compatible changes) +* `revm-inspector`: 1.0.0-alpha.5 -> 1.0.0-alpha.6 (✓ API compatible changes) +* `op-revm`: 1.0.0-alpha.4 -> 1.0.0-alpha.5 (⚠️ API breaking changes) +* `revm-state`: 1.0.0-alpha.3 -> 1.0.0-alpha.4 +* `revm-database-interface`: 1.0.0-alpha.3 -> 1.0.0-alpha.4 +* `revm-database`: 1.0.0-alpha.3 -> 1.0.0-alpha.4 +* `revm-interpreter`: 16.0.0-alpha.5 -> 16.0.0-alpha.6 +* `revm`: 20.0.0-alpha.5 -> 20.0.0-alpha.6 +* `revme`: 3.0.0-alpha.5 -> 3.0.0-alpha.6 + +# v62 tag +date: 12.03.2025 + +A few small breaking changed in preparation for v20.0.0. + +* `revm-context-interface`: 1.0.0-alpha.3 -> 1.0.0-alpha.4 +* `revm-context`: 1.0.0-alpha.3 -> 1.0.0-alpha.4 +* `revm-interpreter`: 16.0.0-alpha.4 -> 16.0.0-alpha.5 +* `revm-handler`: 1.0.0-alpha.4 -> 1.0.0-alpha.5 +* `revm-inspector`: 1.0.0-alpha.4 -> 1.0.0-alpha.5 +* `revme`: 3.0.0-alpha.4 -> 3.0.0-alpha.5 +* `op-revm`: 1.0.0-alpha.3 -> 1.0.0-alpha.4 +* `revm-precompile`: 17.0.0-alpha.4 -> 17.0.0-alpha.5 +* `revm`: 20.0.0-alpha.4 -> 20.0.0-alpha.5 + +# v61 tag +date: 11.03.2025 + +Bug fixes for op-revm. + +* `revm-primitives`: 16.0.0-alpha.2 -> 16.0.0-alpha.3 +* `revm-bytecode`: 1.0.0-alpha.2 -> 1.0.0-alpha.3 +* `revm-state`: 1.0.0-alpha.2 -> 1.0.0-alpha.3 +* `revm-database-interface`: 1.0.0-alpha.2 -> 1.0.0-alpha.3 +* `revm-context-interface`: 1.0.0-alpha.2 -> 1.0.0-alpha.3 +* `revm-context`: 1.0.0-alpha.2 -> 1.0.0-alpha.3 +* `revm-database`: 1.0.0-alpha.2 -> 1.0.0-alpha.3 +* `revm-interpreter`: 16.0.0-alpha.3 -> 16.0.0-alpha.4 +* `revm-precompile`: 17.0.0-alpha.3 -> 17.0.0-alpha.4 +* `revm-handler`: 1.0.0-alpha.3 -> 1.0.0-alpha.4 +* `revm-inspector`: 1.0.0-alpha.3 -> 1.0.0-alpha.4 +* `revm`: 20.0.0-alpha.3 -> 20.0.0-alpha.4 +* `revme`: 3.0.0-alpha.3 -> 3.0.0-alpha.4 +* `op-revm`: 1.0.0-alpha.2 -> 1.0.0-alpha.3 +* `revm-statetest-types`: 1.0.0-alpha.3 -> 1.0.0-alpha.4 + +# v60 tag +date: 10.03.2025 + +Bug fix on blockhash opcode. + +* `revm-interpreter`: 16.0.0-alpha.2 -> 16.0.0-alpha.3 +* `revm-precompile`: 17.0.0-alpha.2 -> 17.0.0-alpha.3 +* `revm`: 20.0.0-alpha.2 -> 20.0.0-alpha.3 +* `revm-handler`: 1.0.0-alpha.2 -> 1.0.0-alpha.3 +* `revm-inspector`: 1.0.0-alpha.2 -> 1.0.0-alpha.3 +* `revm-statetest-types`: 1.0.0-alpha.2 -> 1.0.0-alpha.3 +* `revme`: 3.0.0-alpha.2 -> 3.0.0-alpha.3 +* `op-revm`: 1.0.0-alpha.1 -> 1.0.0-alpha.2 + + +# v59 tag +date: 10.03.2025 + +* Few bugs fixes mostly for optimism crate. +* remv-optimism renamed to op-revm. +* revm-specification files moved to revm-primitives +* docs, initial book and cleanup. + +Versions: + +* `revm-primitives`: 16.0.0-alpha.1 -> 16.0.0-alpha.2 +* `revm-bytecode`: 1.0.0-alpha.1 -> 1.0.0-alpha.2 +* `revm-state`: 1.0.0-alpha.1 -> 1.0.0-alpha.2 +* `revm-database-interface`: 1.0.0-alpha.1 -> 1.0.0-alpha.2 +* `revm-context-interface`: 1.0.0-alpha.1 -> 1.0.0-alpha.2 +* `revm-context`: 1.0.0-alpha.1 -> 1.0.0-alpha.2 +* `revm-database`: 1.0.0-alpha.1 -> 1.0.0-alpha.2 +* `revm-interpreter`: 16.0.0-alpha.1 -> 16.0.0-alpha.2 +* `revm-precompile`: 17.0.0-alpha.1 -> 17.0.0-alpha.2 +* `revm-handler`: 1.0.0-alpha.1 -> 1.0.0-alpha.2 +* `revm-inspector`: 1.0.0-alpha.1 -> 1.0.0-alpha.2 +* `revm`: 20.0.0-alpha.1 -> 20.0.0-alpha.2 +* `revm-statetest-types`: 1.0.0-alpha.1 -> 1.0.0-alpha.2 +* `revme`: 3.0.0-alpha.1 -> 3.0.0-alpha.2 +* `op-revm`: 1.0.0-alpha.1 + +# v57 tag +date 16.02.2025 + +Big refactor of the code. +Introduction of Revm Framework a way to extend evm without forking. + +* `revm` = 19.5.0 -> 20.0.0-alpha.1 +* `revm-primitives` = 15.2.0 -> 16.0.0-alpha.1 +* `revm-interpreter` = 15.2.0 -> 16.0.0-alpha.1 +* `revm-precompile` = 16.1.0 -> 17.0.0-alpha.1 +* `revme` = 2.5.0 -> 3.0.0-alpha.1 + +New crates: +* `revm-bytecode` = 1.0.0-alpha.1 +* `revm-database` = 1.0.0-alpha.1 +* `revm-database-interface` = 1.0.0-alpha.1 +* `revm-specification` = 1.0.0-alpha.1 +* `revm-state` = 1.0.0-alpha.1 +* `revm-inspector` = 1.0.0-alpha.1 +* `revm-statetest-types` = 1.0.0-alpha.1 +* `revm-context` = 1.0.0-alpha.1 +* `revm-context-interface` = 1.0.0-alpha.1 +* `revm-handler` = 1.0.0-alpha.1 + + + +# v56 tag +date: 11.02.2025 + +Optimism fixes and improvements. + +* `revm`: 19.4.0 -> 19.5.0 +* `revm-interpreter`: 15.1.0 -> 15.2.0 +* `revm-primitives`: 15.1.0 -> 15.2.0 +* `revm-precompile`: 16.0.0 -> 16.1.0 +* `revme`: 2.4.0 -> 2.5.0 + +# v55 tag + +date: 28.01.2025 + +Small release for Prague devnet-6 network. + +* `revme`: 2.3.0 -> 2.4.0 +* `revm`: 19.3.0 -> 19.4.0 + +# v54 tag + +date: 13.01.2025 + +Changes for Prague devnet-5 network. + +* `revme`: 2.2.0 -> 2.3.0 +* `revm`: 19.2.0 -> 19.3.0 + +# v53 tag + +date: 06.01.2025 + +Fix for previous release related to Optimism. + +* `revm`: 19.1.0 -> 19.2.0 + +# v52 tag + +date: 06.01.2025 + +Optimism isthmus spec added. + +* `revm`: 19.0.0 -> 19.1.0 + +# v51 tag +date 26.12.2024 +devnet-5 release. + +* `revme`: 2.1.0 -> 2.2.0 +* `revm`: 18.0.0 -> 19.0.0 +* `revm-interpreter`: 14.0.0 -> 15.0.0 +* `revm-primitives`: 14.0.0 -> 15.1.0 +* `revm-precompile`: 15.0.0 -> 16.0.0 + +# v50 tag +date 06.11.2024 +Maintenance release. Bump alloy-primitives deps, few utilities. + +* `revme`: 2.0.0 -> 2.1.0 +* `revm`: 17.1.0 -> 18.0.0 +* `revm-interpreter`: 13.0.0 -> 14.0.0 +* `revm-primitives`: 13.0.0 -> 14.0.0 +* `revm-precompile`: 14.0.0 -> 15.0.0 + +# v49 tag +date 23.10.2024 +Maintenance release. Bump alloydb deps. + +* `revm`: 17.0.0 -> 17.1.0 (✓ API compatible changes) + +# v48 tag +date 23.10.2024 +Maintenance release. Bug fix for EIP-7702. + +* `revm`: 16.0.0 -> 17.0.0 (✓ API compatible changes) +* `revm-primitives`: 12.0.0 -> 13.0.0 (✓ API compatible changes) +* `revme`: 1.0.0 -> 2.0.0 +* `revm-interpreter`: 12.0.0 -> 13.0.0 +* `revm-precompile`: 13.0.0 -> 14.0.0 + +# v47 tag +date: 17.10.2024 +Maintenance release. bumping new alloy-eip7702 + +* `revme`: 0.11.0 -> 1.0.0 +* `revm`: 15.0.0 -> 16.0.0 +* `revm-primitives`: 11.0.0 -> 12.0.0 +* `revm-precompile`: 12.0.0 -> 13.0.0 +* `revm-interpreter`: 11.0.0 -> 12.0.0 + +# v46 tag +date: 17.10.2024 +Maintenance release. EIP-7702 newest changes, alloy-primitives bump. + +* `revme`: 0.10.3 -> 0.11.0 +* `revm`: 14.0.3 -> 15.0.0 +* `revm-primitives`: 10.0.0 -> 11.0.0 +* `revm-precompile`: 11.0.3 -> 12.0.0 +* `revm-interpreter`: 10.0.3 -> 11.0.0 + +# v45 tag +date: 26.09.2024 + +Maintenance release. + +* `revme`: 0.10.2 -> 0.10.3 +* `revm`: 14.0.2 -> 14.0.3 +* `revm-primitives`: 9.0.2 -> 10.0.0 +* `revm-interpreter`: 10.0.2 -> 10.0.3 +* `revm-precompile`: 11.0.2 -> 11.0.3 + +# v44 tag +date: 18.09.2024 + +Small maintenance release. +Code can be found in release/v44 branch. +Fixes bug with Inspector selfdestruct not called every time, and enabled PRAGUE_EOF in statetest for PRAGUE tests. + +* `revme`: 0.10.1 -> 0.10.2 +* `revm`: 14.0.1 -> 14.0.2 +* `revm-interpreter`: 10.0.1 -> 10.0.2 +* `revm-primitives`: 9.0.1 -> 9.0.2 +* `revm-precompile`: 11.0.1 -> 11.0.2 +* `revm-test`: 0.1.0 + +# v43 tag +date: 30.08.2024 + +Logo change and doc fix. + +* `revm`: 14.0.0 -> 14.0.1 +* `revm-interpreter`: 10.0.0 -> 10.0.1 +* `revm-primitives`: 9.0.0 -> 9.0.1 +* `revm-precompile`: 11.0.0 -> 11.0.1 +* `revme`: 0.10.0 -> 0.10.1 + +# v42 tag +date: 29.08.2024 + +new EIP-7702 implemented. Passing all EOF and EIP-7702 tests. +Preparation for devnet-3. + +* `revme`: 0.9.0 -> 0.10.0 +* `revm`: 13.0.0 -> 14.0.0 +* `revm-interpreter`: 9.0.0 -> 10.0.0 +* `revm-primitives`: 8.0.0 -> 9.0.0 +* `revm-precompile`: 10.0.0 -> 11.0.0 + +# v41 tag +date: 08.08.2024 + +EOF fixes and improvements. +Optimism Granite fork support. + +* `revme`: 0.8.0 -> 0.9.0 +* `revm`: 12.1.0 -> 13.0.0 +* `revm-interpreter`: 8.1.0 -> 9.0.0 +* `revm-primitives`: 7.1.0 -> 8.0.0 +* `revm-precompile`: 9.2.0 -> 10.0.0 +* `revm-test`: 0.1.0 + +# v40 tag +date 17.07.2024 + +EOF bugfix. + +* revm: 12.0.0 -> 12.1.0 +* revm-interpreter: 8.0.0 -> 8.1.0 +* revm-primitives: 7.0.0 -> 7.1.0 +* revm-precompile: 9.1.0 -> 8.2.0 + +# v39 tag +date: 16.07.2024 + +Fixes for eip7702 and EOF. Kzg precompile alternative kzg-rs added. + +* revme: 0.7.0 -> 0.8.0 +* revm: 11.0.0 -> 12.0.0 +* revm-interpreter: 7.0.0 -> 8.0.0 +* revm-primitives: 6.0.0 -> 7.0.0 +* revm-precompile: 9.0.0 -> 9.1.0 + +# v38 tag +date: 08.07.2024 + +* Add EIP-7702 for Prague. +* Import AccessList from alloy-eips repo. +* EOF fixes +* Utility changes. + +Versions +* revme: 0.6.0 -> 0.7.0 +* revm: 10.0.0 -> 11.0.0 +* revm-interpreter: 6.0.0 -> 7.0.0 +* revm-primitives: 5.0.0 -> 6.0.0 +* revm-precompile: 8.0.0 -> 9.0.0 + +# v37 tag +date: 20.06.2024 + +Audit of the codebase announced: https://hackmd.io/G7zazTX4TtekCnj6xlgctQ +secp256r1 precompile added. + +Prague changes: +* EOF bugs squashed. +* Introducing PragueEOF hardfork. +* EIP-2935 (blockhashes) modified for devnet-1. +* Fixed for BLS12-381 curve. + +Versions: +* revme: 0.5.0 -> 0.6.0 +* revm: 9.0.0 -> 10.0.0 +* revm-interpreter: 5.0.0 -> 6.0.0 +* revm-primitives: 4.0.0 -> 5.0.0 +* revm-precompile: 7.0.0 -> 8.0.0 + # v36 tag date: 12.05.2024 @@ -10,35 +678,35 @@ Support for prague EIPs. EOF removed BytecodeLocked, OpCode table got changed, and CallInputs got refactored. -revme: 0.4.0 -> 0.5.0 (⚠️ API breaking changes) -revm: 8.0.0 -> 9.0.0 (⚠️ API breaking changes) -revm-interpreter: 4.0.0 -> 5.0.0 (⚠️ API breaking changes) -revm-primitives: 3.1.1 -> 4.0.0 (⚠️ API breaking changes) -revm-precompile: 6.0.0 -> 7.0.0 (⚠️ API breaking changes) -revm-test: 0.1.0 +* revme: 0.4.0 -> 0.5.0 (⚠️ API breaking changes) +* revm: 8.0.0 -> 9.0.0 (⚠️ API breaking changes) +* revm-interpreter: 4.0.0 -> 5.0.0 (⚠️ API breaking changes) +* revm-primitives: 3.1.1 -> 4.0.0 (⚠️ API breaking changes) +* revm-precompile: 6.0.0 -> 7.0.0 (⚠️ API breaking changes) +* revm-test: 0.1.0 # v35 tag date: 02.04.2024 Small release. Alloy bump. Small refactors and deprecated functions removed. -revme: 0.3.1 -> 0.4.0 (✓ API compatible changes) -revm: 7.2.0 -> 8.0.0 (⚠️ API breaking changes) -revm-interpreter: 3.4.0 -> 4.0.0 (⚠️ API breaking changes) -revm-primitives: 3.1.0 -> 3.1.1 (✓ API compatible changes) -revm-precompile: 5.1.0 -> 6.0.0 (⚠️ API breaking changes) -revm-test: 0.1.0 +* revme: 0.3.1 -> 0.4.0 (✓ API compatible changes) +* revm: 7.2.0 -> 8.0.0 (⚠️ API breaking changes) +* revm-interpreter: 3.4.0 -> 4.0.0 (⚠️ API breaking changes) +* revm-primitives: 3.1.0 -> 3.1.1 (✓ API compatible changes) +* revm-precompile: 5.1.0 -> 6.0.0 (⚠️ API breaking changes) +* revm-test: 0.1.0 # v34 tag date: 20.03.2024 Small release, few utilities and refactoring, precompiles fn and Interpreter helper macros are made public. -revme: 0.3.0 -> 0.3.1 (✓ API compatible changes) -revm: 7.1.0 -> 7.2.0 (✓ API compatible changes) -revm-interpreter: 3.3.0 -> 3.4.0 (✓ API compatible changes) -revm-primitives: 3.0.0 -> 3.1.0 (✓ API compatible changes) -revm-precompile: 5.0.0 -> 5.1.0 (✓ API compatible changes) +* revme: 0.3.0 -> 0.3.1 (✓ API compatible changes) +* revm: 7.1.0 -> 7.2.0 (✓ API compatible changes) +* revm-interpreter: 3.3.0 -> 3.4.0 (✓ API compatible changes) +* revm-primitives: 3.0.0 -> 3.1.0 (✓ API compatible changes) +* revm-precompile: 5.0.0 -> 5.1.0 (✓ API compatible changes) # v33 tag TODO @@ -130,7 +798,7 @@ Bigger release. Cancun support, revm State added and some cleanup refactoring. # v24 tag date: 03.05.2023 -Cosnensus bug inside journal and some small changes. +Consensus bug inside journal and some small changes. * revm: v3.3.0 * revm-precompile: v2.0.3 diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000000..7e192850f5 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,93 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +REVM is a highly efficient Rust implementation of the Ethereum Virtual Machine (EVM). It serves both as: +1. A standard EVM for executing Ethereum transactions +2. A framework for building custom EVM variants (like Optimism's op-revm) + +The project is used by major Ethereum infrastructure including Reth, Foundry, Hardhat, Optimism, Scroll, and many zkVMs. + +## Build and Development Commands + +### Essential Commands +```bash +# Build the project +cargo build +cargo build --release + +# Run all tests +cargo nexttest run --workspace + +# Lint and format +cargo clippy --workspace --all-targets --all-features +cargo fmt --all + +# Check no_std compatibility +cargo check --target riscv32imac-unknown-none-elf --no-default-features + +# Run Ethereum state tests +cargo run -p revme statetest legacytests/Cancun/GeneralStateTests +``` + +### Test Scripts +```bash +# Download and run ethereum tests +./scripts/run-tests.sh + +# Clean test fixtures and re-run +./scripts/run-tests.sh clean + +# Run with specific profile +./scripts/run-tests.sh release +``` + +## Architecture + +The workspace consists of these core crates: + +- **revm**: Main crate that re-exports all others +- **revm-primitives**: Constants, primitive types, and core data structures +- **revm-interpreter**: EVM opcode implementations and execution engine +- **revm-context**: Execution context, environment, and journaled state +- **revm-handler**: Execution flow control and call frame management +- **revm-database**: State database traits and implementations +- **revm-precompile**: Ethereum precompiled contracts +- **revm-inspector**: Tracing and debugging framework +- **op-revm**: Example of custom EVM variant (Optimism) + +### Key Design Patterns + +1. **Trait-based Architecture**: Core functionality is defined through traits, allowing custom implementations +2. **Handler Pattern**: Execution flow is controlled through customizable handlers +3. **no_std Support**: All core crates support no_std environments +4. **Feature Flags**: Extensive use of feature flags for optional functionality + +### Important Interfaces + +1. **Database Trait** (`revm-database`): Defines how state is accessed +2. **Inspector Trait** (`revm-inspector`): Hooks for transaction tracing +3. **Handler Interface** (`revm-handler`): Customizable execution logic +4. **Context** (`revm-context`): Manages execution state and environment + +## Current Development Context + +When working on the `frame_stack` branch, note that significant refactoring is happening around: +- Frame and FrameData structures (moved from handler to context) +- Execution loop simplification +- Inspector trait cleanup + +## Testing Strategy + +1. Unit tests in each crate +2. Integration tests using Ethereum official test suite +3. Example projects demonstrating features +4. Benchmarking with CodSpeed + +When adding new features: +- Ensure no_std compatibility +- Add appropriate feature flags +- Include tests for new functionality +- Update relevant examples if needed \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 8250353bfa..8e674436fd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,27 +1,38 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 + +[[package]] +name = "addchain" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b2e69442aa5628ea6951fa33e24efe8313f4321a91bd729fc2f75bdfc858570" +dependencies = [ + "num-bigint 0.3.3", + "num-integer", + "num-traits", +] [[package]] name = "addr2line" -version = "0.21.0" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" dependencies = [ "gimli", ] [[package]] -name = "adler" -version = "1.0.2" +name = "adler2" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "ahash" -version = "0.8.11" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" dependencies = [ "cfg-if", "once_cell", @@ -40,54 +51,138 @@ dependencies = [ [[package]] name = "allocator-api2" -version = "0.2.18" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "alloy-chains" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" +checksum = "19a9cc9d81ace3da457883b0bdf76776e55f1b84219a9e9d55c27ad308548d3f" +dependencies = [ + "alloy-primitives", + "num_enum", + "strum", +] [[package]] name = "alloy-consensus" -version = "0.1.0" -source = "git+https://github.com/alloy-rs/alloy.git?rev=44b8a6d#44b8a6da656602fd9fd2c52f28ecffa4acaed96c" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bcb57295c4b632b6b3941a089ee82d00ff31ff9eb3eac801bf605ffddc81041" dependencies = [ "alloy-eips", "alloy-primitives", "alloy-rlp", "alloy-serde", + "alloy-trie", + "alloy-tx-macros", + "auto_impl", "c-kzg", + "derive_more", + "either", + "k256", + "once_cell", + "rand 0.8.5", + "secp256k1 0.30.0", + "serde", + "serde_with", + "thiserror", +] + +[[package]] +name = "alloy-consensus-any" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ab669be40024565acb719daf1b2a050e6dc065fc0bec6050d97a81cdb860bd7" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-primitives", + "alloy-rlp", + "alloy-serde", + "serde", +] + +[[package]] +name = "alloy-eip2124" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "741bdd7499908b3aa0b159bba11e71c8cddd009a2c2eb7a06e825f1ec87900a5" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "crc", + "serde", + "thiserror", +] + +[[package]] +name = "alloy-eip2930" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b82752a889170df67bbb36d42ca63c531eb16274f0d7299ae2a680facba17bd" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "serde", +] + +[[package]] +name = "alloy-eip7702" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d4769c6ffddca380b0070d71c8b7f30bed375543fe76bb2f74ec0acf4b7cd16" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "k256", "serde", + "thiserror", ] [[package]] name = "alloy-eips" -version = "0.1.0" -source = "git+https://github.com/alloy-rs/alloy.git?rev=44b8a6d#44b8a6da656602fd9fd2c52f28ecffa4acaed96c" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f853de9ca1819f54de80de5d03bfc1bb7c9fafcf092b480a654447141bc354d" dependencies = [ + "alloy-eip2124", + "alloy-eip2930", + "alloy-eip7702", "alloy-primitives", "alloy-rlp", "alloy-serde", + "auto_impl", "c-kzg", - "once_cell", + "derive_more", + "either", "serde", - "sha2", + "sha2 0.10.9", ] [[package]] -name = "alloy-genesis" -version = "0.1.0" -source = "git+https://github.com/alloy-rs/alloy.git?rev=44b8a6d#44b8a6da656602fd9fd2c52f28ecffa4acaed96c" +name = "alloy-json-abi" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b26fdd571915bafe857fccba4ee1a4f352965800e46a53e4a5f50187b7776fa" dependencies = [ "alloy-primitives", - "alloy-serde", + "alloy-sol-type-parser", "serde", "serde_json", ] [[package]] name = "alloy-json-rpc" -version = "0.1.0" -source = "git+https://github.com/alloy-rs/alloy.git?rev=44b8a6d#44b8a6da656602fd9fd2c52f28ecffa4acaed96c" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4997a9873c8639d079490f218e50e5fa07e70f957e9fc187c0a0535977f482f" dependencies = [ "alloy-primitives", + "alloy-sol-types", + "http", "serde", "serde_json", "thiserror", @@ -96,26 +191,48 @@ dependencies = [ [[package]] name = "alloy-network" -version = "0.1.0" -source = "git+https://github.com/alloy-rs/alloy.git?rev=44b8a6d#44b8a6da656602fd9fd2c52f28ecffa4acaed96c" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0306e8d148b7b94d988615d367443c1b9d6d2e9fecd2e1f187ac5153dce56f5" dependencies = [ "alloy-consensus", + "alloy-consensus-any", "alloy-eips", "alloy-json-rpc", + "alloy-network-primitives", "alloy-primitives", - "alloy-rpc-types", + "alloy-rpc-types-any", + "alloy-rpc-types-eth", + "alloy-serde", "alloy-signer", "alloy-sol-types", "async-trait", + "auto_impl", + "derive_more", "futures-utils-wasm", + "serde", + "serde_json", "thiserror", ] +[[package]] +name = "alloy-network-primitives" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eef189583f4c53d231dd1297b28a675ff842b551fb34715f562868a1937431a" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-primitives", + "alloy-serde", + "serde", +] + [[package]] name = "alloy-primitives" -version = "0.7.4" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db8aa973e647ec336810a9356af8aea787249c9d00b1525359f3db29a68d231b" +checksum = "a326d47106039f38b811057215a92139f46eef7983a4b77b10930a0ea5685b1e" dependencies = [ "alloy-rlp", "arbitrary", @@ -124,53 +241,69 @@ dependencies = [ "const-hex", "derive_arbitrary", "derive_more", - "ethereum_ssz", - "getrandom", - "hex-literal", + "foldhash", + "getrandom 0.3.3", + "hashbrown 0.15.4", + "indexmap 2.9.0", "itoa", "k256", "keccak-asm", + "paste", "proptest", "proptest-derive", - "rand", + "rand 0.9.1", "ruint", + "rustc-hash", "serde", + "sha3", "tiny-keccak", ] [[package]] name = "alloy-provider" -version = "0.1.0" -source = "git+https://github.com/alloy-rs/alloy.git?rev=44b8a6d#44b8a6da656602fd9fd2c52f28ecffa4acaed96c" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea624ddcdad357c33652b86aa7df9bd21afd2080973389d3facf1a221c573948" dependencies = [ + "alloy-chains", + "alloy-consensus", "alloy-eips", "alloy-json-rpc", "alloy-network", + "alloy-network-primitives", "alloy-primitives", "alloy-rpc-client", - "alloy-rpc-types", - "alloy-rpc-types-trace", + "alloy-rpc-types-eth", + "alloy-signer", + "alloy-sol-types", "alloy-transport", "alloy-transport-http", "async-stream", "async-trait", "auto_impl", "dashmap", + "either", "futures", "futures-utils-wasm", + "http", "lru", - "reqwest 0.12.4", + "parking_lot", + "pin-project", + "reqwest", + "serde", "serde_json", + "thiserror", "tokio", "tracing", "url", + "wasmtimer", ] [[package]] name = "alloy-rlp" -version = "0.3.5" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b155716bab55763c95ba212806cf43d05bcc70e5f35b02bad20cf5ec7fe11fed" +checksum = "5f70d83b765fdc080dbcd4f4db70d8d23fe4761f2f02ebfa9146b833900634b4" dependencies = [ "alloy-rlp-derive", "arrayvec", @@ -179,267 +312,464 @@ dependencies = [ [[package]] name = "alloy-rlp-derive" -version = "0.3.5" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8037e03c7f462a063f28daec9fda285a9a89da003c552f8637a80b9c8fd96241" +checksum = "64b728d511962dda67c1bc7ea7c03736ec275ed2cf4c35d9585298ac9ccf3b73" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.103", ] [[package]] name = "alloy-rpc-client" -version = "0.1.0" -source = "git+https://github.com/alloy-rs/alloy.git?rev=44b8a6d#44b8a6da656602fd9fd2c52f28ecffa4acaed96c" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e43d00b4de38432304c4e4b01ae6a3601490fd9824c852329d158763ec18663c" dependencies = [ "alloy-json-rpc", + "alloy-primitives", "alloy-transport", "alloy-transport-http", + "async-stream", "futures", "pin-project", - "reqwest 0.12.4", + "reqwest", "serde", "serde_json", "tokio", "tokio-stream", "tower", "tracing", + "tracing-futures", "url", + "wasmtimer", ] [[package]] -name = "alloy-rpc-types" -version = "0.1.0" -source = "git+https://github.com/alloy-rs/alloy.git?rev=44b8a6d#44b8a6da656602fd9fd2c52f28ecffa4acaed96c" +name = "alloy-rpc-types-any" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5958f2310d69f4806e6f6b90ceb4f2b781cc5a843517a7afe2e7cfec6de3cfb9" +dependencies = [ + "alloy-consensus-any", + "alloy-rpc-types-eth", + "alloy-serde", +] + +[[package]] +name = "alloy-rpc-types-eth" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1826285e4ffc2372a8c061d5cc145858e67a0be3309b768c5b77ddb6b9e6cbc7" dependencies = [ "alloy-consensus", + "alloy-consensus-any", "alloy-eips", - "alloy-genesis", + "alloy-network-primitives", "alloy-primitives", "alloy-rlp", "alloy-serde", "alloy-sol-types", - "itertools 0.12.1", + "itertools 0.14.0", "serde", "serde_json", "thiserror", ] [[package]] -name = "alloy-rpc-types-trace" -version = "0.1.0" -source = "git+https://github.com/alloy-rs/alloy.git?rev=44b8a6d#44b8a6da656602fd9fd2c52f28ecffa4acaed96c" +name = "alloy-serde" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "906ce0190afeded19cb2e963cb8507c975a7862216b9e74f39bf91ddee6ae74b" dependencies = [ "alloy-primitives", - "alloy-rpc-types", - "alloy-serde", "serde", "serde_json", ] [[package]] -name = "alloy-serde" -version = "0.1.0" -source = "git+https://github.com/alloy-rs/alloy.git?rev=44b8a6d#44b8a6da656602fd9fd2c52f28ecffa4acaed96c" +name = "alloy-signer" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c89baab06195c4be9c5d66f15c55e948013d1aff3ec1cfb0ed469e1423313fce" dependencies = [ "alloy-primitives", - "serde", - "serde_json", + "async-trait", + "auto_impl", + "either", + "elliptic-curve", + "k256", + "thiserror", ] [[package]] -name = "alloy-signer" -version = "0.1.0" -source = "git+https://github.com/alloy-rs/alloy.git?rev=44b8a6d#44b8a6da656602fd9fd2c52f28ecffa4acaed96c" +name = "alloy-signer-local" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a249a923e302ac6db932567c43945392f0b6832518aab3c4274858f58756774" dependencies = [ + "alloy-consensus", + "alloy-network", "alloy-primitives", + "alloy-signer", "async-trait", - "auto_impl", - "elliptic-curve", "k256", + "rand 0.8.5", "thiserror", ] [[package]] name = "alloy-sol-macro" -version = "0.7.4" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dbd17d67f3e89478c8a634416358e539e577899666c927bc3d2b1328ee9b6ca" +checksum = "d4be1ce1274ddd7fdfac86e5ece1b225e9bba1f2327e20fbb30ee6b9cc1423fe" dependencies = [ "alloy-sol-macro-expander", "alloy-sol-macro-input", - "proc-macro-error", + "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.103", ] [[package]] name = "alloy-sol-macro-expander" -version = "0.7.4" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c6da95adcf4760bb4b108fefa51d50096c5e5fdd29ee72fed3e86ee414f2e34" +checksum = "01e92f3708ea4e0d9139001c86c051c538af0146944a2a9c7181753bd944bf57" dependencies = [ "alloy-sol-macro-input", "const-hex", - "heck 0.4.1", - "indexmap", - "proc-macro-error", + "heck", + "indexmap 2.9.0", + "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.103", "syn-solidity", "tiny-keccak", ] [[package]] name = "alloy-sol-macro-input" -version = "0.7.4" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32c8da04c1343871fb6ce5a489218f9c85323c8340a36e9106b5fc98d4dd59d5" +checksum = "9afe1bd348a41f8c9b4b54dfb314886786d6201235b0b3f47198b9d910c86bb2" dependencies = [ "const-hex", "dunce", - "heck 0.5.0", + "heck", + "macro-string", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.103", "syn-solidity", ] +[[package]] +name = "alloy-sol-type-parser" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6195df2acd42df92a380a8db6205a5c7b41282d0ce3f4c665ecf7911ac292f1" +dependencies = [ + "serde", + "winnow", +] + [[package]] name = "alloy-sol-types" -version = "0.7.4" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40a64d2d2395c1ac636b62419a7b17ec39031d6b2367e66e9acbf566e6055e9c" +checksum = "6185e98a79cf19010722f48a74b5a65d153631d2f038cabd250f4b9e9813b8ad" dependencies = [ + "alloy-json-abi", "alloy-primitives", "alloy-sol-macro", - "const-hex", "serde", ] [[package]] name = "alloy-transport" -version = "0.1.0" -source = "git+https://github.com/alloy-rs/alloy.git?rev=44b8a6d#44b8a6da656602fd9fd2c52f28ecffa4acaed96c" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d1ae10b1bc77fde38161e242749e41e65e34000d05da0a3d3f631e03bfcb19e" dependencies = [ "alloy-json-rpc", - "base64 0.22.1", - "futures-util", + "alloy-primitives", + "base64", + "derive_more", + "futures", "futures-utils-wasm", + "parking_lot", "serde", "serde_json", "thiserror", "tokio", "tower", + "tracing", "url", - "wasm-bindgen-futures", + "wasmtimer", ] [[package]] name = "alloy-transport-http" -version = "0.1.0" -source = "git+https://github.com/alloy-rs/alloy.git?rev=44b8a6d#44b8a6da656602fd9fd2c52f28ecffa4acaed96c" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b234272ee449e32c9f1afbbe4ee08ea7c4b52f14479518f95c844ab66163c545" dependencies = [ "alloy-json-rpc", "alloy-transport", - "reqwest 0.12.4", + "reqwest", "serde_json", "tower", + "tracing", "url", ] [[package]] -name = "anes" -version = "0.1.6" +name = "alloy-trie" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" +checksum = "983d99aa81f586cef9dae38443245e585840fcf0fc58b09aee0b1f27aed1d500" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "arrayvec", + "derive_more", + "nybbles", + "serde", + "smallvec", + "tracing", +] [[package]] -name = "ansi_term" -version = "0.12.1" +name = "alloy-tx-macros" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +checksum = "b75ef8609ea2b31c799b0a56c724dca4c73105c5ccc205d9dfeb1d038df6a1da" dependencies = [ - "winapi", + "alloy-primitives", + "darling", + "proc-macro2", + "quote", + "syn 2.0.103", ] [[package]] -name = "anstyle" -version = "1.0.7" +name = "android-tzdata" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" [[package]] -name = "anyhow" -version = "1.0.86" +name = "android_system_properties" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] [[package]] -name = "arbitrary" -version = "1.3.2" +name = "anes" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" +checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] -name = "ark-ff" -version = "0.3.0" +name = "anstream" +version = "0.6.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b3235cc41ee7a12aaaf2c575a2ad7b46713a8a50bda2fc3b003a04845c05dd6" +checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933" dependencies = [ - "ark-ff-asm 0.3.0", - "ark-ff-macros 0.3.0", - "ark-serialize 0.3.0", - "ark-std 0.3.0", - "derivative", - "num-bigint", - "num-traits", - "paste", - "rustc_version 0.3.3", - "zeroize", + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", ] [[package]] -name = "ark-ff" -version = "0.4.2" +name = "anstyle" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" -dependencies = [ - "ark-ff-asm 0.4.2", - "ark-ff-macros 0.4.2", - "ark-serialize 0.4.2", - "ark-std 0.4.0", - "derivative", - "digest 0.10.7", - "itertools 0.10.5", - "num-bigint", - "num-traits", - "paste", - "rustc_version 0.4.0", - "zeroize", -] +checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" [[package]] -name = "ark-ff-asm" -version = "0.3.0" +name = "anstyle-parse" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db02d390bf6643fb404d3d22d31aee1c4bc4459600aef9113833d17e786c6e44" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" dependencies = [ - "quote", - "syn 1.0.109", + "utf8parse", ] [[package]] -name = "ark-ff-asm" -version = "0.4.2" +name = "anstyle-query" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" +checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9" dependencies = [ - "quote", - "syn 1.0.109", + "windows-sys 0.59.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys 0.59.0", +] + +[[package]] +name = "anyhow" +version = "1.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" + +[[package]] +name = "arbitrary" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" + +[[package]] +name = "ark-bls12-381" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3df4dcc01ff89867cd86b0da835f23c3f02738353aaee7dde7495af71363b8d5" +dependencies = [ + "ark-ec", + "ark-ff 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", +] + +[[package]] +name = "ark-bn254" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d69eab57e8d2663efa5c63135b2af4f396d66424f88954c21104125ab6b3e6bc" +dependencies = [ + "ark-ec", + "ark-ff 0.5.0", + "ark-r1cs-std", + "ark-std 0.5.0", +] + +[[package]] +name = "ark-ec" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d68f2d516162846c1238e755a7c4d131b892b70cc70c471a8e3ca3ed818fce" +dependencies = [ + "ahash", + "ark-ff 0.5.0", + "ark-poly", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "educe", + "fnv", + "hashbrown 0.15.4", + "itertools 0.13.0", + "num-bigint 0.4.6", + "num-integer", + "num-traits", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b3235cc41ee7a12aaaf2c575a2ad7b46713a8a50bda2fc3b003a04845c05dd6" +dependencies = [ + "ark-ff-asm 0.3.0", + "ark-ff-macros 0.3.0", + "ark-serialize 0.3.0", + "ark-std 0.3.0", + "derivative", + "num-bigint 0.4.6", + "num-traits", + "paste", + "rustc_version 0.3.3", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" +dependencies = [ + "ark-ff-asm 0.4.2", + "ark-ff-macros 0.4.2", + "ark-serialize 0.4.2", + "ark-std 0.4.0", + "derivative", + "digest 0.10.7", + "itertools 0.10.5", + "num-bigint 0.4.6", + "num-traits", + "paste", + "rustc_version 0.4.1", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a177aba0ed1e0fbb62aa9f6d0502e9b46dad8c2eab04c14258a1212d2557ea70" +dependencies = [ + "ark-ff-asm 0.5.0", + "ark-ff-macros 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "arrayvec", + "digest 0.10.7", + "educe", + "itertools 0.13.0", + "num-bigint 0.4.6", + "num-traits", + "paste", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db02d390bf6643fb404d3d22d31aee1c4bc4459600aef9113833d17e786c6e44" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-asm" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-asm" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60" +dependencies = [ + "quote", + "syn 2.0.103", ] [[package]] @@ -448,7 +778,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db2fd794a08ccb318058009eefdf15bcaaaaf6f8161eb3345f907222bac38b20" dependencies = [ - "num-bigint", + "num-bigint 0.4.6", "num-traits", "quote", "syn 1.0.109", @@ -460,13 +790,70 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" dependencies = [ - "num-bigint", + "num-bigint 0.4.6", "num-traits", "proc-macro2", "quote", "syn 1.0.109", ] +[[package]] +name = "ark-ff-macros" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09be120733ee33f7693ceaa202ca41accd5653b779563608f1234f78ae07c4b3" +dependencies = [ + "num-bigint 0.4.6", + "num-traits", + "proc-macro2", + "quote", + "syn 2.0.103", +] + +[[package]] +name = "ark-poly" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "579305839da207f02b89cd1679e50e67b4331e2f9294a57693e5051b7703fe27" +dependencies = [ + "ahash", + "ark-ff 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "educe", + "fnv", + "hashbrown 0.15.4", +] + +[[package]] +name = "ark-r1cs-std" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "941551ef1df4c7a401de7068758db6503598e6f01850bdb2cfdb614a1f9dbea1" +dependencies = [ + "ark-ec", + "ark-ff 0.5.0", + "ark-relations", + "ark-std 0.5.0", + "educe", + "num-bigint 0.4.6", + "num-integer", + "num-traits", + "tracing", +] + +[[package]] +name = "ark-relations" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec46ddc93e7af44bcab5230937635b06fb5744464dd6a7e7b083e80ebd274384" +dependencies = [ + "ark-ff 0.5.0", + "ark-std 0.5.0", + "tracing", + "tracing-subscriber", +] + [[package]] name = "ark-serialize" version = "0.3.0" @@ -485,7 +872,31 @@ checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" dependencies = [ "ark-std 0.4.0", "digest 0.10.7", - "num-bigint", + "num-bigint 0.4.6", +] + +[[package]] +name = "ark-serialize" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f4d068aaf107ebcd7dfb52bc748f8030e0fc930ac8e360146ca54c1203088f7" +dependencies = [ + "ark-serialize-derive", + "ark-std 0.5.0", + "arrayvec", + "digest 0.10.7", + "num-bigint 0.4.6", +] + +[[package]] +name = "ark-serialize-derive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213888f660fddcca0d257e88e54ac05bca01885f258ccdf695bafd77031bb69d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.103", ] [[package]] @@ -495,7 +906,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c" dependencies = [ "num-traits", - "rand", + "rand 0.8.5", ] [[package]] @@ -505,20 +916,39 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" dependencies = [ "num-traits", - "rand", + "rand 0.8.5", +] + +[[package]] +name = "ark-std" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "246a225cc6131e9ee4f24619af0f19d67761fff15d7ccc22e42b80846e69449a" +dependencies = [ + "num-traits", + "rand 0.8.5", ] +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + [[package]] name = "arrayvec" -version = "0.7.4" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" +dependencies = [ + "serde", +] [[package]] name = "async-stream" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" dependencies = [ "async-stream-impl", "futures-core", @@ -527,59 +957,31 @@ dependencies = [ [[package]] name = "async-stream-impl" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.103", ] [[package]] name = "async-trait" -version = "0.1.80" +version = "0.1.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" +checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", -] - -[[package]] -name = "async_io_stream" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6d7b9decdf35d8908a7e3ef02f64c5e9b1695e230154c0e8de3969142d9b94c" -dependencies = [ - "futures", - "pharos", - "rustc_version 0.4.0", -] - -[[package]] -name = "atomic-waker" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" - -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi 0.1.19", - "libc", - "winapi", + "syn 2.0.103", ] [[package]] name = "aurora-engine-modexp" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0aef7712851e524f35fbbb74fa6599c5cd8692056a1c36f9ca0d2001b670e7e5" +checksum = "518bc5745a6264b5fd7b09dffb9667e400ee9e2bbe18555fac75e1fe9afa0df9" dependencies = [ "hex", "num", @@ -587,34 +989,40 @@ dependencies = [ [[package]] name = "auto_impl" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" +checksum = "ffdcb70bdbc4d478427380519163274ac86e52916e10f0a8889adf0f96d3fee7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.103", ] [[package]] name = "autocfg" -version = "1.3.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "az" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b7e4c2464d97fe331d41de9d5db0def0a96f4d823b8b32a2efd503578988973" [[package]] name = "backtrace" -version = "0.3.71" +version = "0.3.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" +checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" dependencies = [ "addr2line", - "cc", "cfg-if", "libc", "miniz_oxide", "object", "rustc-demangle", + "windows-targets", ] [[package]] @@ -623,18 +1031,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" -[[package]] -name = "base64" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" - -[[package]] -name = "base64" -version = "0.21.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" - [[package]] name = "base64" version = "0.22.1" @@ -643,9 +1039,9 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "base64ct" -version = "1.6.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" +checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba" [[package]] name = "bincode" @@ -656,34 +1052,63 @@ dependencies = [ "serde", ] +[[package]] +name = "bincode" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36eaf5d7b090263e8150820482d5d93cd964a81e4019913c972f4edcc6edb740" +dependencies = [ + "bincode_derive", + "serde", + "unty", +] + +[[package]] +name = "bincode_derive" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf95709a440f45e986983918d0e8a1f30a9b1df04918fc828670606804ac3c09" +dependencies = [ + "virtue", +] + [[package]] name = "bit-set" -version = "0.5.3" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" dependencies = [ "bit-vec", ] [[package]] name = "bit-vec" -version = "0.6.3" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" [[package]] -name = "bitflags" -version = "1.3.2" +name = "bitcoin-io" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +checksum = "0b47c4ab7a93edb0c7198c5535ed9b52b63095f4e9b45279c6736cec4b856baf" + +[[package]] +name = "bitcoin_hashes" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb18c03d0db0247e147a21a6faafd5a7eb851c743db062de72018b6b7e8e4d16" +dependencies = [ + "bitcoin-io", + "hex-conservative", +] [[package]] name = "bitflags" -version = "2.5.0" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" dependencies = [ - "arbitrary", "serde", ] @@ -700,6 +1125,28 @@ dependencies = [ "wyz", ] +[[package]] +name = "blake3" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3888aaa89e4b2a40fca9848e400f6a658a5a3978de7be858e209cafa8be9a4a0" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", +] + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + [[package]] name = "block-buffer" version = "0.10.4" @@ -711,9 +1158,9 @@ dependencies = [ [[package]] name = "blst" -version = "0.3.11" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c94087b935a822949d3291a9989ad2b2051ea141eda0fd4e478a75f6aa3e604b" +checksum = "4fd49896f12ac9b6dcd7a5998466b9b58263a695a3dd1ecc1aaca2e12a90b080" dependencies = [ "cc", "glob", @@ -723,15 +1170,15 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.16.0" +version = "3.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +checksum = "793db76d6187cd04dff33004d8e6c9cc4e05cd330500379d2394209271b4aeee" [[package]] name = "byte-slice-cast" -version = "1.2.2" +version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" +checksum = "7575182f7272186991736b70173b0ea045398f984bf5ebbb3804736ce1330c9d" [[package]] name = "byteorder" @@ -741,24 +1188,25 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.6.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" dependencies = [ "serde", ] [[package]] name = "c-kzg" -version = "1.0.2" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdf100c4cea8f207e883ff91ca886d621d8a166cb04971dfaa9bb8fd99ed95df" +checksum = "7318cfa722931cb5fe0838b98d3ce5621e75f6a6408abc21721d80de9223f2e4" dependencies = [ "blst", "cc", "glob", "hex", "libc", + "once_cell", "serde", ] @@ -770,23 +1218,30 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.0.98" +version = "1.2.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41c270e7540d725e65ac7f1b212ac8ce349719624d7bcff99f8e2e488e8cf03f" +checksum = "d487aa071b5f64da6f19a3e848e3578944b726ee5a4854b82172f02aa876bfdc" +dependencies = [ + "shlex", +] [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" [[package]] name = "chrono" -version = "0.4.38" +version = "0.4.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" dependencies = [ + "android-tzdata", + "iana-time-zone", "num-traits", + "serde", + "windows-link", ] [[package]] @@ -818,62 +1273,129 @@ dependencies = [ [[package]] name = "clap" -version = "2.34.0" +version = "4.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40b6887a1d8685cebccf115538db5c0efe625ccac9696ad45c409d96566e910f" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" +checksum = "e0c66c08ce9f0c698cbce5c0279d0bb6ac936d8674174fe48f736533b964f59e" dependencies = [ - "ansi_term", - "atty", - "bitflags 1.3.2", + "anstream", + "anstyle", + "clap_lex", "strsim", - "textwrap", - "unicode-width", - "vec_map", ] [[package]] -name = "clap" -version = "4.5.4" +name = "clap_derive" +version = "4.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2c7947ae4cc3d851207c1adb5b5e260ff0cca11446b1d6d1423788e442257ce" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.103", +] + +[[package]] +name = "clap_lex" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" + +[[package]] +name = "codspeed" +version = "2.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93f4cce9c27c49c4f101fffeebb1826f41a9df2e7498b7cd4d95c0658b796c6c" +dependencies = [ + "colored", + "libc", + "serde", + "serde_json", + "uuid", +] + +[[package]] +name = "codspeed-criterion-compat" +version = "2.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3c23d880a28a2aab52d38ca8481dd7a3187157d0a952196b6db1db3c8499725" +dependencies = [ + "codspeed", + "codspeed-criterion-compat-walltime", + "colored", +] + +[[package]] +name = "codspeed-criterion-compat-walltime" +version = "2.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b0a2f7365e347f4f22a67e9ea689bf7bc89900a354e22e26cf8a531a42c8fbb" +dependencies = [ + "anes", + "cast", + "ciborium", + "clap", + "codspeed", + "criterion-plot", + "is-terminal", + "itertools 0.10.5", + "num-traits", + "once_cell", + "oorandom", + "plotters", + "rayon", + "regex", + "serde", + "serde_derive", + "serde_json", + "tinytemplate", + "walkdir", +] + +[[package]] +name = "colorchoice" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" -dependencies = [ - "clap_builder", -] +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" [[package]] -name = "clap_builder" -version = "4.5.2" +name = "colored" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c" dependencies = [ - "anstyle", - "clap_lex", + "lazy_static", + "windows-sys 0.59.0", ] -[[package]] -name = "clap_lex" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" - [[package]] name = "console" -version = "0.15.8" +version = "0.15.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" +checksum = "054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8" dependencies = [ "encode_unicode", - "lazy_static", "libc", + "once_cell", "unicode-width", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "const-hex" -version = "1.11.4" +version = "1.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ff96486ccc291d36a958107caf2c0af8c78c0af7d31ae2f35ce055130de1a6" +checksum = "83e22e0ed40b96a48d3db274f72fd365bd78f67af39b6bbd47e8a15e1c6207ff" dependencies = [ "cfg-if", "cpufeatures", @@ -889,10 +1411,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] -name = "convert_case" -version = "0.4.0" +name = "const_format" +version = "0.2.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "126f97965c8ad46d6d9163268ff28432e8f6a1196a55578867832e3049df63dd" +dependencies = [ + "const_format_proc_macros", +] + +[[package]] +name = "const_format_proc_macros" +version = "0.2.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" +checksum = "1d57c2eccfb16dbac1f4e61e206105db5820c9d26c3c472bc17c774259ef7744" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "constant_time_eq" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" [[package]] name = "core-foundation" @@ -906,45 +1448,34 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.12" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" dependencies = [ "libc", ] [[package]] -name = "criterion" -version = "0.5.1" +name = "crc" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f" +checksum = "9710d3b3739c2e349eb44fe848ad0b7c8cb1e42bd87ee49371df2f7acaf3e675" dependencies = [ - "anes", - "cast", - "ciborium", - "clap 4.5.4", - "criterion-plot", - "is-terminal", - "itertools 0.10.5", - "num-traits", - "once_cell", - "oorandom", - "plotters", - "rayon", - "regex", - "serde", - "serde_derive", - "serde_json", - "tinytemplate", - "walkdir", + "crc-catalog", ] +[[package]] +name = "crc-catalog" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" + [[package]] name = "criterion-plot" version = "0.5.0" @@ -957,9 +1488,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" dependencies = [ "crossbeam-epoch", "crossbeam-utils", @@ -976,15 +1507,15 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.20" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crunchy" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" [[package]] name = "crypto-bigint" @@ -993,7 +1524,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ "generic-array", - "rand_core", + "rand_core 0.6.4", "subtle", "zeroize", ] @@ -1008,30 +1539,89 @@ dependencies = [ "typenum", ] +[[package]] +name = "csv" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acdc4883a9c96732e4733212c01447ebd805833b7275a73ca3ee080fd77afdaf" +dependencies = [ + "csv-core", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "csv-core" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d02f3b0da4c6504f86e9cd789d8dbafab48c2321be74e9987593de5a894d93d" +dependencies = [ + "memchr", +] + +[[package]] +name = "custom_precompile_journal" +version = "0.1.0" +dependencies = [ + "anyhow", + "revm", +] + +[[package]] +name = "darling" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.103", +] + +[[package]] +name = "darling_macro" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.103", +] + [[package]] name = "dashmap" -version = "5.5.3" +version = "6.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" +checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" dependencies = [ "cfg-if", - "hashbrown", + "crossbeam-utils", + "hashbrown 0.14.5", "lock_api", "once_cell", "parking_lot_core", ] -[[package]] -name = "data-encoding" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" - [[package]] name = "der" -version = "0.7.9" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" dependencies = [ "const-oid", "zeroize", @@ -1039,11 +1629,12 @@ dependencies = [ [[package]] name = "deranged" -version = "0.3.11" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" dependencies = [ "powerfmt", + "serde", ] [[package]] @@ -1057,28 +1648,47 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "derive-where" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "510c292c8cf384b1a340b816a9a6cf2599eb8f566a44949024af88418000c50b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.103", +] + [[package]] name = "derive_arbitrary" -version = "1.3.2" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" +checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.103", ] [[package]] name = "derive_more" -version = "0.99.17" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" dependencies = [ - "convert_case", "proc-macro2", "quote", - "rustc_version 0.4.0", - "syn 1.0.109", + "syn 2.0.103", + "unicode-xid", ] [[package]] @@ -1096,23 +1706,34 @@ version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer", + "block-buffer 0.10.4", "const-oid", "crypto-common", "subtle", ] +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.103", +] + [[package]] name = "dunce" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" [[package]] name = "dyn-clone" -version = "1.0.17" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" +checksum = "1c7a8fb8a9fbf66c1f703fe16184d10ca0ee9d23be5b4436400408ba54a95005" [[package]] name = "ecdsa" @@ -1124,15 +1745,31 @@ dependencies = [ "digest 0.10.7", "elliptic-curve", "rfc6979", + "serdect", "signature", "spki", ] +[[package]] +name = "educe" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7bc049e1bd8cdeb31b68bbd586a9464ecf9f3944af3958a7a9d0f8b9799417" +dependencies = [ + "enum-ordinalize", + "proc-macro2", + "quote", + "syn 2.0.103", +] + [[package]] name = "either" -version = "1.12.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +dependencies = [ + "serde", +] [[package]] name = "elliptic-curve" @@ -1147,227 +1784,147 @@ dependencies = [ "generic-array", "group", "pkcs8", - "rand_core", + "rand_core 0.6.4", "sec1", + "serdect", "subtle", "zeroize", ] [[package]] name = "encode_unicode" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" - -[[package]] -name = "encoding_rs" -version = "0.8.34" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" -dependencies = [ - "cfg-if", -] +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" [[package]] -name = "enr" -version = "0.10.0" +name = "enum-ordinalize" +version = "4.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a3d8dc56e02f954cac8eb489772c552c473346fc34f67412bb6244fd647f7e4" +checksum = "fea0dcfa4e54eeb516fe454635a95753ddd39acda650ce703031c6973e315dd5" dependencies = [ - "base64 0.21.7", - "bytes", - "hex", - "k256", - "log", - "rand", - "rlp", - "serde", - "sha3", - "zeroize", + "enum-ordinalize-derive", ] [[package]] -name = "enumn" -version = "0.1.13" +name = "enum-ordinalize-derive" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fd000fd6988e73bbe993ea3db9b1aa64906ab88766d654973924340c8cddb42" +checksum = "0d28318a75d4aead5c4db25382e8ef717932d0346600cacae6357eb5941bc5ff" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.103", ] [[package]] name = "equivalent" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.9" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] -name = "ethabi" -version = "18.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7413c5f74cc903ea37386a8965a936cbeb334bd270862fdece542c1b2dcbc898" +name = "example-block-traces" +version = "0.0.0" dependencies = [ - "ethereum-types", - "hex", - "once_cell", - "regex", - "serde", - "serde_json", - "sha3", - "thiserror", - "uint", + "alloy-consensus", + "alloy-eips", + "alloy-provider", + "anyhow", + "indicatif", + "revm", + "tokio", ] [[package]] -name = "ethbloom" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" +name = "example-cheatcode-inspector" +version = "0.0.0" dependencies = [ - "crunchy", - "fixed-hash", - "impl-codec", - "impl-rlp", - "impl-serde", - "scale-info", - "tiny-keccak", + "anyhow", + "revm", ] [[package]] -name = "ethereum-types" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee" +name = "example-contract-deployment" +version = "0.0.0" dependencies = [ - "ethbloom", - "fixed-hash", - "impl-codec", - "impl-rlp", - "impl-serde", - "primitive-types", - "scale-info", - "uint", + "anyhow", + "revm", ] [[package]] -name = "ethereum_ssz" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e61ffea29f26e8249d35128a82ec8d3bd4fbc80179ea5f5e5e3daafef6a80fcb" +name = "example-custom-opcodes" +version = "0.0.0" dependencies = [ - "ethereum-types", - "itertools 0.10.5", - "smallvec", + "revm", ] [[package]] -name = "ethers-contract" -version = "2.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fceafa3578c836eeb874af87abacfb041f92b4da0a78a5edd042564b8ecdaaa" +name = "example-database-components" +version = "0.0.0" dependencies = [ - "const-hex", - "ethers-core", - "futures-util", - "once_cell", - "pin-project", - "serde", - "serde_json", + "auto_impl", + "revm", "thiserror", ] [[package]] -name = "ethers-core" -version = "2.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82d80cc6ad30b14a48ab786523af33b37f28a8623fc06afd55324816ef18fb1f" +name = "example-erc20-gas" +version = "0.0.0" dependencies = [ - "arrayvec", - "bytes", - "chrono", - "const-hex", - "elliptic-curve", - "ethabi", - "generic-array", - "k256", - "num_enum", - "open-fastrlp", - "rand", - "rlp", - "serde", - "serde_json", - "strum", - "tempfile", - "thiserror", - "tiny-keccak", - "unicode-xid", + "alloy-provider", + "alloy-sol-types", + "anyhow", + "revm", + "tokio", ] -[[package]] -name = "ethers-providers" -version = "2.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6434c9a33891f1effc9c75472e12666db2fa5a0fec4b29af6221680a6fe83ab2" -dependencies = [ - "async-trait", - "auto_impl", - "base64 0.21.7", - "bytes", - "const-hex", - "enr", - "ethers-core", - "futures-channel", - "futures-core", - "futures-timer", - "futures-util", - "hashers", - "http 0.2.12", - "instant", - "jsonwebtoken", - "once_cell", - "pin-project", - "reqwest 0.11.27", - "serde", - "serde_json", - "thiserror", +[[package]] +name = "example-my-evm" +version = "0.0.0" +dependencies = [ + "revm", +] + +[[package]] +name = "example-uniswap-get-reserves" +version = "0.0.0" +dependencies = [ + "alloy-eips", + "alloy-provider", + "alloy-sol-types", + "anyhow", + "revm", "tokio", - "tokio-tungstenite", - "tracing", - "tracing-futures", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "ws_stream_wasm", ] [[package]] -name = "eyre" -version = "0.6.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec" +name = "example-uniswap-v2-usdc-swap" +version = "0.0.0" dependencies = [ - "indenter", - "once_cell", + "alloy-eips", + "alloy-provider", + "alloy-sol-types", + "anyhow", + "revm", + "tokio", ] [[package]] name = "fastrand" -version = "2.1.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "fastrlp" @@ -1380,25 +1937,52 @@ dependencies = [ "bytes", ] +[[package]] +name = "fastrlp" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce8dba4714ef14b8274c371879b175aa55b16b30f269663f19d576f380018dc4" +dependencies = [ + "arrayvec", + "auto_impl", + "bytes", +] + [[package]] name = "ff" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" dependencies = [ - "rand_core", + "byteorder", + "ff_derive", + "rand_core 0.6.4", "subtle", ] +[[package]] +name = "ff_derive" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f10d12652036b0e99197587c6ba87a8fc3031986499973c030d8b44fcc151b60" +dependencies = [ + "addchain", + "num-bigint 0.3.3", + "num-integer", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "fixed-hash" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" dependencies = [ - "arbitrary", "byteorder", - "rand", + "rand 0.8.5", "rustc-hex", "static_assertions", ] @@ -1409,6 +1993,12 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + [[package]] name = "foreign-types" version = "0.3.2" @@ -1441,9 +2031,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ "futures-channel", "futures-core", @@ -1456,9 +2046,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", "futures-sink", @@ -1466,15 +2056,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ "futures-core", "futures-task", @@ -1483,48 +2073,44 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-macro" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.103", ] [[package]] name = "futures-sink" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-timer" version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" -dependencies = [ - "gloo-timers", - "send_wrapper 0.4.0", -] [[package]] name = "futures-util" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-channel", "futures-core", @@ -1545,13 +2131,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42012b0f064e01aa58b545fe3727f90f7dd4020f4a3ea735b50344965f5a57e9" [[package]] -name = "fxhash" -version = "0.2.1" +name = "gcd" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" -dependencies = [ - "byteorder", -] +checksum = "1d758ba1b47b00caf47f24925c0074ecb20d6dfcffe7f6d53395c0465674841a" [[package]] name = "generic-array" @@ -1566,37 +2149,47 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.15" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.11.1+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" dependencies = [ "cfg-if", "libc", - "wasi", + "r-efi", + "wasi 0.14.2+wasi-0.2.4", ] [[package]] name = "gimli" -version = "0.28.1" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "glob" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" [[package]] -name = "gloo-timers" -version = "0.2.6" +name = "gmp-mpfr-sys" +version = "1.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" +checksum = "c66d61197a68f6323b9afa616cf83d55d69191e1bf364d4eb7d35ae18defe776" dependencies = [ - "futures-channel", - "futures-core", - "js-sys", - "wasm-bindgen", + "libc", + "windows-sys 0.59.0", ] [[package]] @@ -1606,53 +2199,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ "ff", - "rand_core", + "rand_core 0.6.4", "subtle", ] -[[package]] -name = "h2" -version = "0.3.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http 0.2.12", - "indexmap", - "slab", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "h2" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa82e28a107a8cc405f0839610bdc9b15f1e25ec7d696aa5cf173edbcb1486ab" -dependencies = [ - "atomic-waker", - "bytes", - "fnv", - "futures-core", - "futures-sink", - "http 1.1.0", - "indexmap", - "slab", - "tokio", - "tokio-util", - "tracing", -] - [[package]] name = "half" -version = "2.4.1" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +checksum = "459196ed295495a68f7d7fe1d84f6c4b7ff0e21fe3017b2f283c6fac3ad803c9" dependencies = [ "cfg-if", "crunchy", @@ -1666,39 +2221,28 @@ checksum = "d23bd4e7b5eda0d0f3a307e8b381fdc8ba9000f26fbe912250c0a4cc3956364a" [[package]] name = "hashbrown" -version = "0.14.5" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" -dependencies = [ - "ahash", - "allocator-api2", - "serde", -] +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] -name = "hashers" -version = "1.0.1" +name = "hashbrown" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2bca93b15ea5a746f220e56587f71e73c6165eab783df9e26590069953e3c30" -dependencies = [ - "fxhash", -] +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" [[package]] -name = "heck" -version = "0.3.3" +name = "hashbrown" +version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" dependencies = [ - "unicode-segmentation", + "allocator-api2", + "equivalent", + "foldhash", + "serde", ] -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - [[package]] name = "heck" version = "0.5.0" @@ -1707,18 +2251,9 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - -[[package]] -name = "hermit-abi" -version = "0.3.9" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" [[package]] name = "hex" @@ -1730,10 +2265,13 @@ dependencies = [ ] [[package]] -name = "hex-literal" -version = "0.4.1" +name = "hex-conservative" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" +checksum = "5313b072ce3c597065a808dbf612c4c8e8590bdbf8b579508bf7a762c5eae6cd" +dependencies = [ + "arrayvec", +] [[package]] name = "hmac" @@ -1746,20 +2284,9 @@ dependencies = [ [[package]] name = "http" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "http" -version = "1.1.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" dependencies = [ "bytes", "fnv", @@ -1768,86 +2295,44 @@ dependencies = [ [[package]] name = "http-body" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" -dependencies = [ - "bytes", - "http 0.2.12", - "pin-project-lite", -] - -[[package]] -name = "http-body" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http 1.1.0", + "http", ] [[package]] name = "http-body-util" -version = "0.1.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0475f8b2ac86659c21b64320d5d653f9efe42acd2a4e560073ec61a155a34f1d" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ "bytes", "futures-core", - "http 1.1.0", - "http-body 1.0.0", + "http", + "http-body", "pin-project-lite", ] [[package]] name = "httparse" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" - -[[package]] -name = "httpdate" -version = "1.0.3" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" - -[[package]] -name = "hyper" -version = "0.14.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" -dependencies = [ - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "h2 0.3.26", - "http 0.2.12", - "http-body 0.4.6", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "socket2", - "tokio", - "tower-service", - "tracing", - "want", -] +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" [[package]] name = "hyper" -version = "1.3.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe575dd17d0862a9a33781c8c4696a55c320909004a67a00fb286ba8b1bc496d" +checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" dependencies = [ "bytes", "futures-channel", "futures-util", - "h2 0.4.5", - "http 1.1.0", - "http-body 1.0.0", + "http", + "http-body", "httparse", "itoa", "pin-project-lite", @@ -1856,20 +2341,6 @@ dependencies = [ "want", ] -[[package]] -name = "hyper-rustls" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" -dependencies = [ - "futures-util", - "http 0.2.12", - "hyper 0.14.28", - "rustls", - "tokio", - "tokio-rustls", -] - [[package]] name = "hyper-tls" version = "0.6.0" @@ -1878,7 +2349,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ "bytes", "http-body-util", - "hyper 1.3.1", + "hyper", "hyper-util", "native-tls", "tokio", @@ -1888,127 +2359,254 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.3" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca38ef113da30126bbff9cd1705f9273e15d45498615d138b0c20279ac7a76aa" +checksum = "dc2fdfdbff08affe55bb779f33b053aa1fe5dd5b54c257343c17edfa55711bdb" dependencies = [ + "base64", "bytes", "futures-channel", + "futures-core", "futures-util", - "http 1.1.0", - "http-body 1.0.0", - "hyper 1.3.1", + "http", + "http-body", + "hyper", + "ipnet", + "libc", + "percent-encoding", "pin-project-lite", "socket2", "tokio", - "tower", "tower-service", "tracing", ] [[package]] -name = "idna" -version = "0.5.0" +name = "iana-time-zone" +version = "0.1.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "icu_collections" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" + +[[package]] +name = "icu_properties" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "potential_utf", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" + +[[package]] +name = "icu_provider" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "displaydoc", + "icu_locale_core", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", ] [[package]] -name = "impl-codec" -version = "0.6.0" +name = "ident_case" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" dependencies = [ - "parity-scale-codec", + "idna_adapter", + "smallvec", + "utf8_iter", ] [[package]] -name = "impl-rlp" -version = "0.3.0" +name = "idna_adapter" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f28220f89297a075ddc7245cd538076ee98b01f2a9c23a53a4f1105d5a322808" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" dependencies = [ - "rlp", + "icu_normalizer", + "icu_properties", ] [[package]] -name = "impl-serde" -version = "0.4.0" +name = "impl-codec" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc88fc67028ae3db0c853baa36269d398d5f45b6982f95549ff5def78c935cd" +checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" dependencies = [ - "serde", + "parity-scale-codec", ] [[package]] name = "impl-trait-for-tuples" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.103", ] [[package]] -name = "indenter" -version = "0.3.3" +name = "indexmap" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] [[package]] name = "indexmap" -version = "2.2.6" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" dependencies = [ + "arbitrary", "equivalent", - "hashbrown", + "hashbrown 0.15.4", + "serde", ] [[package]] name = "indicatif" -version = "0.17.8" +version = "0.17.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "763a5a8f45087d6bcea4222e7b72c291a054edf80e4ef6efd2a4979878c7bea3" +checksum = "183b3088984b400f4cfac3620d5e076c84da5364016b4f49473de574b2586235" dependencies = [ "console", - "instant", "number_prefix", "portable-atomic", "unicode-width", + "web-time", ] [[package]] -name = "instant" -version = "0.1.13" +name = "ipnet" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" -dependencies = [ - "cfg-if", -] +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" [[package]] -name = "ipnet" -version = "2.9.0" +name = "iri-string" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" +dependencies = [ + "memchr", + "serde", +] [[package]] name = "is-terminal" -version = "0.4.12" +version = "0.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" +checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9" dependencies = [ - "hermit-abi 0.3.9", + "hermit-abi", "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + [[package]] name = "itertools" version = "0.10.5" @@ -2028,46 +2626,51 @@ dependencies = [ ] [[package]] -name = "itoa" -version = "1.0.11" +name = "itertools" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] [[package]] -name = "js-sys" -version = "0.3.69" +name = "itertools" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" dependencies = [ - "wasm-bindgen", + "either", ] [[package]] -name = "jsonwebtoken" -version = "8.3.0" +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "js-sys" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6971da4d9c3aa03c3d8f3ff0f4155b534aad021292003895a469716b2a230378" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" dependencies = [ - "base64 0.21.7", - "pem", - "ring 0.16.20", - "serde", - "serde_json", - "simple_asn1", + "once_cell", + "wasm-bindgen", ] [[package]] name = "k256" -version = "0.13.3" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "956ff9b67e26e1a6a866cb758f12c6f8746208489e3e4a4b5580802f2f0a587b" +checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" dependencies = [ "cfg-if", "ecdsa", "elliptic-curve", "once_cell", - "sha2", - "signature", + "serdect", + "sha2 0.10.9", ] [[package]] @@ -2081,46 +2684,112 @@ dependencies = [ [[package]] name = "keccak-asm" -version = "0.1.1" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47a3633291834c4fbebf8673acbc1b04ec9d151418ff9b8e26dcd79129928758" +checksum = "505d1856a39b200489082f90d897c3f07c455563880bc5952e38eabf731c83b6" dependencies = [ "digest 0.10.7", "sha3-asm", ] +[[package]] +name = "kzg-rs" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9201effeea3fcc93b587904ae2df9ce97e433184b9d6d299e9ebc9830a546636" +dependencies = [ + "ff", + "hex", + "serde_arrays", + "sha2 0.10.9", + "sp1_bls12_381", + "spin", +] + [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" dependencies = [ - "spin 0.5.2", + "spin", ] [[package]] name = "libc" -version = "0.2.155" +version = "0.2.174" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" [[package]] name = "libm" -version = "0.2.8" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" + +[[package]] +name = "libsecp256k1" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e79019718125edc905a079a70cfa5f3820bc76139fc91d6f9abc27ea2a887139" +dependencies = [ + "arrayref", + "base64", + "digest 0.9.0", + "libsecp256k1-core", + "libsecp256k1-gen-ecmult", + "libsecp256k1-gen-genmult", + "rand 0.8.5", + "serde", + "sha2 0.9.9", +] + +[[package]] +name = "libsecp256k1-core" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be9b9bb642d8522a44d533eab56c16c738301965504753b03ad1de3425d5451" +dependencies = [ + "crunchy", + "digest 0.9.0", + "subtle", +] + +[[package]] +name = "libsecp256k1-gen-ecmult" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3038c808c55c87e8a172643a7d87187fc6c4174468159cb3090659d55bcb4809" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "libsecp256k1-gen-genmult" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" +checksum = "3db8d6ba2cec9eacc40e6e8ccc98931840301f1006e95647ceb2dd5c3aa06f7c" +dependencies = [ + "libsecp256k1-core", +] [[package]] name = "linux-raw-sys" -version = "0.4.14" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" + +[[package]] +name = "litemap" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" [[package]] name = "lock_api" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" dependencies = [ "autocfg", "scopeguard", @@ -2128,64 +2797,62 @@ dependencies = [ [[package]] name = "log" -version = "0.4.21" +version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" [[package]] name = "lru" -version = "0.12.3" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3262e75e648fce39813cb56ac41f3c3e3f65217ebf3844d818d1f9398cfb0dc" +checksum = "227748d55f2f0ab4735d87fd623798cb6b664512fe979705f829c9f81c934465" dependencies = [ - "hashbrown", + "hashbrown 0.15.4", ] [[package]] -name = "memchr" -version = "2.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" - -[[package]] -name = "microbench" -version = "0.5.0" +name = "macro-string" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4c44e40aee4e6fd2f4257bb91e5948ce79285aeb949129448889cf2fbf6da0b" +checksum = "1b27834086c65ec3f9387b096d66e99f221cf081c2b738042aa252bcd41204e3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.103", +] [[package]] -name = "mime" -version = "0.3.17" +name = "memchr" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" [[package]] name = "miniz_oxide" -version = "0.7.3" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87dfd01fe195c66b572b37921ad8803d010623c0aca821bea2302239d155cdae" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ - "adler", + "adler2", ] [[package]] name = "mio" -version = "0.8.11" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" dependencies = [ "libc", - "wasi", - "windows-sys 0.48.0", + "wasi 0.11.1+wasi-snapshot-preview1", + "windows-sys 0.59.0", ] [[package]] name = "native-tls" -version = "0.2.11" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" +checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" dependencies = [ - "lazy_static", "libc", "log", "openssl", @@ -2203,7 +2870,7 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" dependencies = [ - "num-bigint", + "num-bigint 0.4.6", "num-complex", "num-integer", "num-iter", @@ -2213,9 +2880,20 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.4.5" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f6f7833f2cbf2360a6cfd58cd41a53aa7a90bd4c202f5b1c7dd2ed73c57b2c3" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ "num-integer", "num-traits", @@ -2262,7 +2940,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" dependencies = [ - "num-bigint", + "num-bigint 0.4.6", "num-integer", "num-traits", ] @@ -2279,33 +2957,33 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" dependencies = [ - "hermit-abi 0.3.9", + "hermit-abi", "libc", ] [[package]] name = "num_enum" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02339744ee7253741199f897151b38e72257d13802d4ee837285cc2990a90845" +checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" dependencies = [ "num_enum_derive", ] [[package]] name = "num_enum_derive" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b" +checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.103", ] [[package]] @@ -2314,59 +2992,74 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" +[[package]] +name = "nybbles" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8983bb634df7248924ee0c4c3a749609b5abcb082c28fffe3254b3eb3602b307" +dependencies = [ + "alloy-rlp", + "const-hex", + "proptest", + "serde", + "smallvec", +] + [[package]] name = "object" -version = "0.32.2" +version = "0.36.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.19.0" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] -name = "oorandom" -version = "11.1.3" +name = "once_cell_polyfill" +version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" +checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" [[package]] -name = "open-fastrlp" -version = "0.1.4" +name = "oorandom" +version = "11.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "786393f80485445794f6043fd3138854dd109cc6c4bd1a6383db304c9ce9b9ce" +checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" + +[[package]] +name = "op-revm" +version = "8.1.0" dependencies = [ - "arrayvec", + "alloy-primitives", + "alloy-sol-types", "auto_impl", - "bytes", - "ethereum-types", - "open-fastrlp-derive", + "once_cell", + "revm", + "rstest", + "serde", + "serde_json", + "sha2 0.10.9", ] [[package]] -name = "open-fastrlp-derive" -version = "0.1.1" +name = "opaque-debug" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "003b2be5c6c53c1cfeb0a238b8a1c3915cd410feb684457a36c10038f764bb1c" -dependencies = [ - "bytes", - "proc-macro2", - "quote", - "syn 1.0.109", -] +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "openssl" -version = "0.10.64" +version = "0.10.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f" +checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8" dependencies = [ - "bitflags 2.5.0", + "bitflags", "cfg-if", "foreign-types", "libc", @@ -2383,20 +3076,20 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.103", ] [[package]] name = "openssl-probe" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" [[package]] name = "openssl-sys" -version = "0.9.102" +version = "0.9.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c597637d56fbc83893a35eb0dd04b2b8e7a50c91e64e9493e398b5df4fb45fa2" +checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571" dependencies = [ "cc", "libc", @@ -2413,46 +3106,179 @@ dependencies = [ "ecdsa", "elliptic-curve", "primeorder", - "sha2", + "sha2 0.10.9", +] + +[[package]] +name = "p3-baby-bear" +version = "0.2.3-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7521838ecab2ddf4f7bc4ceebad06ec02414729598485c1ada516c39900820e8" +dependencies = [ + "num-bigint 0.4.6", + "p3-field", + "p3-mds", + "p3-poseidon2", + "p3-symmetric", + "rand 0.8.5", + "serde", +] + +[[package]] +name = "p3-dft" +version = "0.2.3-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46414daedd796f1eefcdc1811c0484e4bced5729486b6eaba9521c572c76761a" +dependencies = [ + "p3-field", + "p3-matrix", + "p3-maybe-rayon", + "p3-util", + "tracing", +] + +[[package]] +name = "p3-field" +version = "0.2.3-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48948a0516b349e9d1cdb95e7236a6ee010c44e68c5cc78b4b92bf1c4022a0d9" +dependencies = [ + "itertools 0.12.1", + "num-bigint 0.4.6", + "num-traits", + "p3-util", + "rand 0.8.5", + "serde", +] + +[[package]] +name = "p3-matrix" +version = "0.2.3-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e4de3f373589477cb735ea58e125898ed20935e03664b4614c7fac258b3c42f" +dependencies = [ + "itertools 0.12.1", + "p3-field", + "p3-maybe-rayon", + "p3-util", + "rand 0.8.5", + "serde", + "tracing", +] + +[[package]] +name = "p3-maybe-rayon" +version = "0.2.3-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3968ad1160310296eb04f91a5f4edfa38fe1d6b2b8cd6b5c64e6f9b7370979e" + +[[package]] +name = "p3-mds" +version = "0.2.3-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2356b1ed0add6d5dfbf7a338ce534a6fde827374394a52cec16a0840af6e97c9" +dependencies = [ + "itertools 0.12.1", + "p3-dft", + "p3-field", + "p3-matrix", + "p3-symmetric", + "p3-util", + "rand 0.8.5", +] + +[[package]] +name = "p3-poseidon2" +version = "0.2.3-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da1eec7e1b6900581bedd95e76e1ef4975608dd55be9872c9d257a8a9651c3a" +dependencies = [ + "gcd", + "p3-field", + "p3-mds", + "p3-symmetric", + "rand 0.8.5", + "serde", +] + +[[package]] +name = "p3-symmetric" +version = "0.2.3-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edb439bea1d822623b41ff4b51e3309e80d13cadf8b86d16ffd5e6efb9fdc360" +dependencies = [ + "itertools 0.12.1", + "p3-field", + "serde", +] + +[[package]] +name = "p3-util" +version = "0.2.3-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c2c2010678b9332b563eaa38364915b585c1a94b5ca61e2c7541c087ddda5c" +dependencies = [ + "serde", +] + +[[package]] +name = "pairing" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81fec4625e73cf41ef4bb6846cafa6d44736525f442ba45e407c4a000a13996f" +dependencies = [ + "group", ] [[package]] name = "parity-scale-codec" -version = "3.6.12" +version = "3.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee" +checksum = "799781ae679d79a948e13d4824a40970bfa500058d245760dd857301059810fa" dependencies = [ "arrayvec", "bitvec", "byte-slice-cast", + "const_format", "impl-trait-for-tuples", "parity-scale-codec-derive", + "rustversion", "serde", ] [[package]] name = "parity-scale-codec-derive" -version = "3.6.12" +version = "3.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d830939c76d294956402033aee57a6da7b438f2294eb94864c37b0569053a42c" +checksum = "34b4653168b563151153c9e4c08ebed57fb8262bebfa79711552fa983c623e7a" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.103", +] + +[[package]] +name = "parking_lot" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" +dependencies = [ + "lock_api", + "parking_lot_core", ] [[package]] name = "parking_lot_core" -version = "0.9.10" +version = "0.9.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-targets 0.52.5", + "windows-targets", ] [[package]] @@ -2461,15 +3287,6 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" -[[package]] -name = "pem" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8835c273a76a90455d7344889b0964598e3316e2a79ede8e36f16bdcf2228b8" -dependencies = [ - "base64 0.13.1", -] - [[package]] name = "percent-encoding" version = "2.3.1" @@ -2478,92 +3295,83 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" -version = "2.7.10" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "560131c633294438da9f7c4b08189194b20946c8274c6b9e38881a7874dc8ee8" +checksum = "1db05f56d34358a8b1066f67cbb203ee3e7ed2ba674a6263a1d5ec6db2204323" dependencies = [ "memchr", "thiserror", "ucd-trie", ] -[[package]] -name = "pharos" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9567389417feee6ce15dd6527a8a1ecac205ef62c2932bcf3d9f6fc5b78b414" -dependencies = [ - "futures", - "rustc_version 0.4.0", -] - [[package]] name = "phf" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" +checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" dependencies = [ "phf_macros", "phf_shared", + "serde", ] [[package]] name = "phf_generator" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" +checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" dependencies = [ "phf_shared", - "rand", + "rand 0.8.5", ] [[package]] name = "phf_macros" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" +checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" dependencies = [ "phf_generator", "phf_shared", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.103", ] [[package]] name = "phf_shared" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" +checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" dependencies = [ "siphasher", ] [[package]] name = "pin-project" -version = "1.1.5" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.5" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.103", ] [[package]] name = "pin-project-lite" -version = "0.2.14" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "pin-utils" @@ -2583,9 +3391,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.30" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" [[package]] name = "plain_hasher" @@ -2598,9 +3406,9 @@ dependencies = [ [[package]] name = "plotters" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a15b6eccb8484002195a3e44fe65a4ce8e93a625797a063735536fd59cb01cf3" +checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" dependencies = [ "num-traits", "plotters-backend", @@ -2611,24 +3419,33 @@ dependencies = [ [[package]] name = "plotters-backend" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "414cec62c6634ae900ea1c56128dfe87cf63e7caece0852ec76aba307cebadb7" +checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" [[package]] name = "plotters-svg" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81b30686a7d9c3e010b84284bdd26a29f2138574f52f5eb6f794fc0ad924e705" +checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" dependencies = [ "plotters-backend", ] [[package]] name = "portable-atomic" -version = "1.6.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0" +checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" + +[[package]] +name = "potential_utf" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" +dependencies = [ + "zerovec", +] [[package]] name = "powerfmt" @@ -2638,9 +3455,12 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] [[package]] name = "primeorder" @@ -2659,67 +3479,62 @@ checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" dependencies = [ "fixed-hash", "impl-codec", - "impl-rlp", - "impl-serde", - "scale-info", "uint", ] [[package]] name = "proc-macro-crate" -version = "3.1.0" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35" dependencies = [ "toml_edit", ] [[package]] -name = "proc-macro-error" -version = "1.0.4" +name = "proc-macro-error-attr2" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" dependencies = [ - "proc-macro-error-attr", "proc-macro2", "quote", - "syn 1.0.109", - "version_check", ] [[package]] -name = "proc-macro-error-attr" -version = "1.0.4" +name = "proc-macro-error2" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" dependencies = [ + "proc-macro-error-attr2", "proc-macro2", "quote", - "version_check", + "syn 2.0.103", ] [[package]] name = "proc-macro2" -version = "1.0.83" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b33eb56c327dec362a9e55b3ad14f9d2f0904fb5a5b03b513ab5465399e9f43" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" dependencies = [ "unicode-ident", ] [[package]] name = "proptest" -version = "1.4.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31b476131c3c86cb68032fdc5cb6d5a1045e3e42d96b69fa599fd77701e1f5bf" +checksum = "6fcdab19deb5195a31cf7726a210015ff1496ba1464fd42cb4f537b8b01b471f" dependencies = [ "bit-set", "bit-vec", - "bitflags 2.5.0", + "bitflags", "lazy_static", "num-traits", - "rand", - "rand_chacha", + "rand 0.9.1", + "rand_chacha 0.9.0", "rand_xorshift", "regex-syntax", "rusty-fork", @@ -2729,13 +3544,13 @@ dependencies = [ [[package]] name = "proptest-derive" -version = "0.4.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf16337405ca084e9c78985114633b6827711d22b9e6ef6c6c0d665eb3f0b6e" +checksum = "4ee1c9ac207483d5e7db4940700de86a9aae46ef90c48b57f99fe7edb8345e49" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.103", ] [[package]] @@ -2746,13 +3561,19 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quote" -version = "1.0.36" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + [[package]] name = "radium" version = "0.7.0" @@ -2766,8 +3587,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", - "rand_chacha", - "rand_core", + "rand_chacha 0.3.1", + "rand_core 0.6.4", + "serde", +] + +[[package]] +name = "rand" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.3", + "serde", ] [[package]] @@ -2777,7 +3610,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.3", ] [[package]] @@ -2786,16 +3629,26 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom", + "getrandom 0.2.16", +] + +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom 0.3.3", + "serde", ] [[package]] name = "rand_xorshift" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a" dependencies = [ - "rand_core", + "rand_core 0.9.3", ] [[package]] @@ -2820,18 +3673,38 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.1" +version = "0.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6" +dependencies = [ + "bitflags", +] + +[[package]] +name = "ref-cast" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a0ae411dbe946a674d89546582cea4ba2bb8defac896622d6496f14c23ba5cf" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" +checksum = "1165225c21bff1f3bbce98f5a1f889949bc902d3575308cc7b0de30b4f6d27c7" dependencies = [ - "bitflags 2.5.0", + "proc-macro2", + "quote", + "syn 2.0.103", ] [[package]] name = "regex" -version = "1.10.4" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", @@ -2841,9 +3714,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.6" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", @@ -2852,9 +3725,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "relative-path" @@ -2864,198 +3737,268 @@ checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2" [[package]] name = "reqwest" -version = "0.11.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" -dependencies = [ - "base64 0.21.7", - "bytes", - "encoding_rs", - "futures-core", - "futures-util", - "h2 0.3.26", - "http 0.2.12", - "http-body 0.4.6", - "hyper 0.14.28", - "hyper-rustls", - "ipnet", - "js-sys", - "log", - "mime", - "once_cell", - "percent-encoding", - "pin-project-lite", - "rustls", - "rustls-pemfile 1.0.4", - "serde", - "serde_json", - "serde_urlencoded", - "sync_wrapper", - "system-configuration", - "tokio", - "tokio-rustls", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "webpki-roots", - "winreg 0.50.0", -] - -[[package]] -name = "reqwest" -version = "0.12.4" +version = "0.12.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "566cafdd92868e0939d3fb961bd0dc25fcfaaed179291093b3d43e6b3150ea10" +checksum = "eabf4c97d9130e2bf606614eb937e86edac8292eaa6f422f995d7e8de1eb1813" dependencies = [ - "base64 0.22.1", + "base64", "bytes", - "encoding_rs", "futures-core", - "futures-util", - "h2 0.4.5", - "http 1.1.0", - "http-body 1.0.0", + "http", + "http-body", "http-body-util", - "hyper 1.3.1", + "hyper", "hyper-tls", "hyper-util", - "ipnet", "js-sys", "log", - "mime", "native-tls", - "once_cell", "percent-encoding", "pin-project-lite", - "rustls-pemfile 2.1.2", + "rustls-pki-types", "serde", "serde_json", "serde_urlencoded", "sync_wrapper", - "system-configuration", "tokio", "tokio-native-tls", + "tower", + "tower-http", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "winreg 0.52.0", ] [[package]] name = "revm" +version = "27.1.0" +dependencies = [ + "revm-bytecode", + "revm-context", + "revm-context-interface", + "revm-database", + "revm-database-interface", + "revm-handler", + "revm-inspector", + "revm-interpreter", + "revm-precompile", + "revm-primitives", + "revm-state", + "serde", + "serde_json", +] + +[[package]] +name = "revm-bytecode" +version = "6.2.1" +dependencies = [ + "bitvec", + "paste", + "phf", + "revm-primitives", + "serde", +] + +[[package]] +name = "revm-context" +version = "8.0.4" +dependencies = [ + "cfg-if", + "derive-where", + "revm-bytecode", + "revm-context-interface", + "revm-database", + "revm-database-interface", + "revm-primitives", + "revm-state", + "serde", +] + +[[package]] +name = "revm-context-interface" version = "9.0.0" dependencies = [ + "alloy-eip2930", + "alloy-eip7702", + "auto_impl", + "either", + "revm-database-interface", + "revm-primitives", + "revm-state", + "serde", +] + +[[package]] +name = "revm-database" +version = "7.1.0" +dependencies = [ + "alloy-eips", "alloy-provider", - "alloy-sol-types", - "alloy-transport-http", + "alloy-transport", + "anyhow", + "revm-bytecode", + "revm-database-interface", + "revm-primitives", + "revm-state", + "rstest", + "serde", + "serde_json", + "tokio", +] + +[[package]] +name = "revm-database-interface" +version = "7.1.0" +dependencies = [ "anyhow", "auto_impl", - "cfg-if", - "criterion", - "dyn-clone", - "ethers-contract", - "ethers-core", - "ethers-providers", - "indicatif", - "reqwest 0.12.4", + "either", + "revm-primitives", + "revm-state", + "rstest", + "serde", + "tokio", +] + +[[package]] +name = "revm-handler" +version = "8.1.0" +dependencies = [ + "alloy-eip7702", + "alloy-provider", + "alloy-signer", + "alloy-signer-local", + "auto_impl", + "derive-where", + "revm-bytecode", + "revm-context", + "revm-context-interface", + "revm-database", + "revm-database-interface", "revm-interpreter", "revm-precompile", - "rstest", + "revm-primitives", + "revm-state", + "serde", +] + +[[package]] +name = "revm-inspector" +version = "8.1.0" +dependencies = [ + "auto_impl", + "either", + "revm-context", + "revm-database", + "revm-database-interface", + "revm-handler", + "revm-interpreter", + "revm-primitives", + "revm-state", "serde", "serde_json", - "tokio", ] [[package]] name = "revm-interpreter" -version = "5.0.0" +version = "24.0.0" dependencies = [ - "bincode", - "paste", - "phf", + "bincode 2.0.1", + "revm-bytecode", + "revm-context-interface", "revm-primitives", "serde", - "serde_json", - "walkdir", ] [[package]] name = "revm-precompile" -version = "7.0.0" -dependencies = [ +version = "25.0.0" +dependencies = [ + "ark-bls12-381", + "ark-bn254", + "ark-ec", + "ark-ff 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "arrayref", "aurora-engine-modexp", "blst", "c-kzg", - "criterion", - "eyre", + "cfg-if", + "codspeed-criterion-compat", "k256", + "kzg-rs", + "libsecp256k1", "once_cell", "p256", - "rand", + "rand 0.9.1", "revm-primitives", "ripemd", "rstest", - "secp256k1", - "serde", - "serde_derive", - "serde_json", - "sha2", + "rug", + "secp256k1 0.31.0", + "sha2 0.10.9", "substrate-bn", ] [[package]] name = "revm-primitives" -version = "4.0.0" +version = "20.2.1" dependencies = [ "alloy-primitives", - "auto_impl", - "bitflags 2.5.0", - "bitvec", - "c-kzg", - "cfg-if", - "derive_more", - "dyn-clone", - "enumn", - "hashbrown", - "hex", + "num_enum", "once_cell", "serde", ] [[package]] -name = "revm-test" -version = "0.1.0" +name = "revm-state" +version = "7.0.4" dependencies = [ - "alloy-sol-macro", - "alloy-sol-types", - "bytes", - "eyre", - "hex", - "microbench", - "regex", + "bitflags", + "revm-bytecode", + "revm-primitives", + "serde", +] + +[[package]] +name = "revm-statetest-types" +version = "8.0.5" +dependencies = [ + "k256", "revm", + "serde", + "serde_json", + "thiserror", ] [[package]] name = "revme" -version = "0.5.0" +version = "7.1.0" dependencies = [ "alloy-rlp", + "alloy-sol-types", + "clap", + "codspeed-criterion-compat", + "csv", "hash-db", - "hashbrown", - "hex", "indicatif", "k256", - "microbench", "plain_hasher", "revm", + "revm-bytecode", + "revm-context", + "revm-context-interface", + "revm-database", + "revm-database-interface", + "revm-inspector", + "revm-primitives", + "revm-state", + "revm-statetest-types", "serde", "serde_json", - "structopt", "thiserror", "triehash", "walkdir", @@ -3071,36 +4014,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "ring" -version = "0.16.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" -dependencies = [ - "cc", - "libc", - "once_cell", - "spin 0.5.2", - "untrusted 0.7.1", - "web-sys", - "winapi", -] - -[[package]] -name = "ring" -version = "0.17.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" -dependencies = [ - "cc", - "cfg-if", - "getrandom", - "libc", - "spin 0.9.8", - "untrusted 0.9.0", - "windows-sys 0.52.0", -] - [[package]] name = "ripemd" version = "0.1.3" @@ -3114,71 +4027,75 @@ dependencies = [ name = "rlp" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" -dependencies = [ - "bytes", - "rlp-derive", - "rustc-hex", -] - -[[package]] -name = "rlp-derive" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e33d7b2abe0c340d8797fe2907d3f20d3b5ea5908683618bfe80df7f621f672a" +checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", + "bytes", + "rustc-hex", ] [[package]] name = "rstest" -version = "0.19.0" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d5316d2a1479eeef1ea21e7f9ddc67c191d497abc8fc3ba2467857abbb68330" +checksum = "6fc39292f8613e913f7df8fa892b8944ceb47c247b78e1b1ae2f09e019be789d" dependencies = [ - "futures", "futures-timer", + "futures-util", "rstest_macros", - "rustc_version 0.4.0", + "rustc_version 0.4.1", ] [[package]] name = "rstest_macros" -version = "0.19.0" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04a9df72cc1f67020b0d63ad9bfe4a323e459ea7eb68e03bd9824db49f9a4c25" +checksum = "1f168d99749d307be9de54d23fd226628d99768225ef08f6ffb52e0182a27746" dependencies = [ "cfg-if", "glob", + "proc-macro-crate", "proc-macro2", "quote", "regex", "relative-path", - "rustc_version 0.4.0", - "syn 2.0.66", + "rustc_version 0.4.1", + "syn 2.0.103", "unicode-ident", ] +[[package]] +name = "rug" +version = "1.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4207e8d668e5b8eb574bda8322088ccd0d7782d3d03c7e8d562e82ed82bdcbc3" +dependencies = [ + "az", + "gmp-mpfr-sys", + "libc", + "libm", +] + [[package]] name = "ruint" -version = "1.12.1" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f308135fef9fc398342da5472ce7c484529df23743fb7c734e0f3d472971e62" +checksum = "11256b5fe8c68f56ac6f39ef0720e592f33d2367a4782740d9c9142e889c7fb4" dependencies = [ "alloy-rlp", "arbitrary", "ark-ff 0.3.0", "ark-ff 0.4.2", "bytes", - "fastrlp", - "num-bigint", + "fastrlp 0.3.1", + "fastrlp 0.4.0", + "num-bigint 0.4.6", + "num-integer", "num-traits", "parity-scale-codec", "primitive-types", "proptest", - "rand", + "rand 0.8.5", + "rand 0.9.1", "rlp", "ruint-macro", "serde", @@ -3188,15 +4105,24 @@ dependencies = [ [[package]] name = "ruint-macro" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f86854cf50259291520509879a5c294c3c9a4c334e9ff65071c51e42ef1e2343" +checksum = "48fd7bd8a6377e15ad9d42a8ec25371b94ddc67abe7c8b9127bec79bebaaae18" [[package]] name = "rustc-demangle" -version = "0.1.24" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f" + +[[package]] +name = "rustc-hash" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" +dependencies = [ + "rand 0.8.5", +] [[package]] name = "rustc-hex" @@ -3215,78 +4141,40 @@ dependencies = [ [[package]] name = "rustc_version" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ - "semver 1.0.23", + "semver 1.0.26", ] [[package]] name = "rustix" -version = "0.38.34" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" dependencies = [ - "bitflags 2.5.0", + "bitflags", "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", -] - -[[package]] -name = "rustls" -version = "0.21.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" -dependencies = [ - "log", - "ring 0.17.8", - "rustls-webpki", - "sct", -] - -[[package]] -name = "rustls-pemfile" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" -dependencies = [ - "base64 0.21.7", -] - -[[package]] -name = "rustls-pemfile" -version = "2.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d" -dependencies = [ - "base64 0.22.1", - "rustls-pki-types", + "windows-sys 0.59.0", ] [[package]] name = "rustls-pki-types" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" - -[[package]] -name = "rustls-webpki" -version = "0.101.7" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" dependencies = [ - "ring 0.17.8", - "untrusted 0.9.0", + "zeroize", ] [[package]] name = "rustversion" -version = "1.0.17" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" +checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" [[package]] name = "rusty-fork" @@ -3302,9 +4190,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.18" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "same-file" @@ -3316,36 +4204,24 @@ dependencies = [ ] [[package]] -name = "scale-info" -version = "2.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eca070c12893629e2cc820a9761bedf6ce1dcddc9852984d1dc734b8bd9bd024" -dependencies = [ - "cfg-if", - "derive_more", - "parity-scale-codec", - "scale-info-derive", -] - -[[package]] -name = "scale-info-derive" -version = "2.11.3" +name = "schannel" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d35494501194174bda522a32605929eefc9ecf7e0a326c26db1fdd85881eb62" +checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn 1.0.109", + "windows-sys 0.59.0", ] [[package]] -name = "schannel" -version = "0.1.23" +name = "schemars" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f" dependencies = [ - "windows-sys 0.52.0", + "dyn-clone", + "ref-cast", + "serde", + "serde_json", ] [[package]] @@ -3354,16 +4230,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" -[[package]] -name = "sct" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" -dependencies = [ - "ring 0.17.8", - "untrusted 0.9.0", -] - [[package]] name = "sec1" version = "0.7.3" @@ -3374,36 +4240,59 @@ dependencies = [ "der", "generic-array", "pkcs8", + "serdect", "subtle", "zeroize", ] [[package]] name = "secp256k1" -version = "0.29.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e0cc0f1cf93f4969faf3ea1c7d8a9faed25918d96affa959720823dfe86d4f3" +checksum = "b50c5943d326858130af85e049f2661ba3c78b26589b8ab98e65e80ae44a1252" dependencies = [ - "rand", - "secp256k1-sys", + "bitcoin_hashes", + "rand 0.8.5", + "secp256k1-sys 0.10.1", + "serde", +] + +[[package]] +name = "secp256k1" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a3dff2d01c9aa65c3186a45ff846bfea52cbe6de3b6320ed2a358d90dad0d76" +dependencies = [ + "bitcoin_hashes", + "rand 0.9.1", + "secp256k1-sys 0.11.0", +] + +[[package]] +name = "secp256k1-sys" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4387882333d3aa8cb20530a17c69a3752e97837832f34f6dccc760e715001d9" +dependencies = [ + "cc", ] [[package]] name = "secp256k1-sys" -version = "0.10.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1433bd67156263443f14d603720b082dd3121779323fce20cba2aa07b874bc1b" +checksum = "dcb913707158fadaf0d8702c2db0e857de66eb003ccfdda5924b5f5ac98efb38" dependencies = [ "cc", ] [[package]] name = "security-framework" -version = "2.11.0" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 2.5.0", + "bitflags", "core-foundation", "core-foundation-sys", "libc", @@ -3412,9 +4301,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.11.0" +version = "2.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "317936bbbd05227752583946b9e66d7ce3b489f84e11a94a510b4437fef407d7" +checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" dependencies = [ "core-foundation-sys", "libc", @@ -3431,59 +4320,57 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.23" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" +checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" [[package]] name = "semver-parser" -version = "0.10.2" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" +checksum = "9900206b54a3527fdc7b8a938bffd94a568bac4f4aa8113b209df75a09c0dec2" dependencies = [ "pest", ] [[package]] -name = "send_wrapper" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f638d531eccd6e23b980caf34876660d38e265409d8e99b397ab71eb3612fad0" - -[[package]] -name = "send_wrapper" -version = "0.6.0" +name = "serde" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +dependencies = [ + "serde_derive", +] [[package]] -name = "serde" -version = "1.0.203" +name = "serde_arrays" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" +checksum = "94a16b99c5ea4fe3daccd14853ad260ec00ea043b2708d1fd1da3106dcd8d9df" dependencies = [ - "serde_derive", + "serde", ] [[package]] name = "serde_derive" -version = "1.0.203" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.103", ] [[package]] name = "serde_json" -version = "1.0.117" +version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" dependencies = [ - "indexmap", + "indexmap 2.9.0", "itoa", + "memchr", "ryu", "serde", ] @@ -3501,25 +4388,78 @@ dependencies = [ ] [[package]] -name = "sha1" -version = "0.10.6" +name = "serde_with" +version = "3.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf65a400f8f66fb7b0552869ad70157166676db75ed8181f8104ea91cf9d0b42" +dependencies = [ + "base64", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.9.0", + "schemars", + "serde", + "serde_derive", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "3.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81679d9ed988d5e9a5e6531dc3f2c28efbd639cbd1dfb628df08edea6004da77" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.103", +] + +[[package]] +name = "serdect" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a84f14a19e9a014bb9f4512488d9829a68e04ecabffb0f9904cd1ace94598177" +dependencies = [ + "base16ct", + "serde", +] + +[[package]] +name = "sha2" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" dependencies = [ + "block-buffer 0.9.0", "cfg-if", "cpufeatures", - "digest 0.10.7", + "digest 0.9.0", + "opaque-debug", ] [[package]] name = "sha2" -version = "0.10.8" +version = "0.10.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", "cpufeatures", "digest 0.10.7", + "sha2-asm", +] + +[[package]] +name = "sha2-asm" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b845214d6175804686b2bd482bcffe96651bb2d1200742b712003504a2dac1ab" +dependencies = [ + "cc", ] [[package]] @@ -3534,14 +4474,20 @@ dependencies = [ [[package]] name = "sha3-asm" -version = "0.1.1" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9b57fd861253bff08bb1919e995f90ba8f4889de2726091c8876f3a4e823b40" +checksum = "c28efc5e327c837aa837c59eae585fc250715ef939ac32881bcc11677cd02d46" dependencies = [ "cc", "cfg-if", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signature" version = "2.2.0" @@ -3549,57 +4495,85 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ "digest 0.10.7", - "rand_core", -] - -[[package]] -name = "simple_asn1" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adc4e5204eb1910f40f9cfa375f6f05b68c3abac4b6fd879c8ff5e7ae8a0a085" -dependencies = [ - "num-bigint", - "num-traits", - "thiserror", - "time", + "rand_core 0.6.4", ] [[package]] name = "siphasher" -version = "0.3.11" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" +checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" [[package]] name = "slab" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] +checksum = "04dc19736151f35336d325007ac991178d504a119863a2fcb3758cdb5e52c50d" [[package]] name = "smallvec" -version = "1.13.2" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +dependencies = [ + "serde", +] [[package]] name = "socket2" -version = "0.5.7" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" dependencies = [ "libc", "windows-sys 0.52.0", ] [[package]] -name = "spin" -version = "0.5.2" +name = "sp1-lib" +version = "5.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0fd8bc101e5603ccf2dc1836ea06410f25ce2298755b2dac626add9be2424b4" +dependencies = [ + "bincode 1.3.3", + "serde", + "sp1-primitives", +] + +[[package]] +name = "sp1-primitives" +version = "5.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "699935774a5131c1a8b371108d0666c0c80c43611045fb77fae43f2f242676d5" +dependencies = [ + "bincode 1.3.3", + "blake3", + "cfg-if", + "hex", + "lazy_static", + "num-bigint 0.4.6", + "p3-baby-bear", + "p3-field", + "p3-poseidon2", + "p3-symmetric", + "serde", + "sha2 0.10.9", +] + +[[package]] +name = "sp1_bls12_381" +version = "0.8.0-sp1-5.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +checksum = "ac255e1704ebcdeec5e02f6a0ebc4d2e9e6b802161938330b6810c13a610c583" +dependencies = [ + "cfg-if", + "ff", + "group", + "pairing", + "rand_core 0.6.4", + "sp1-lib", + "subtle", +] [[package]] name = "spin" @@ -3617,6 +4591,12 @@ dependencies = [ "der", ] +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "static_assertions" version = "1.1.0" @@ -3625,54 +4605,30 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "strsim" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" - -[[package]] -name = "structopt" -version = "0.3.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c6b5c64445ba8094a6ab0c3cd2ad323e07171012d9c98b0b15651daf1787a10" -dependencies = [ - "clap 2.34.0", - "lazy_static", - "structopt-derive", -] - -[[package]] -name = "structopt-derive" -version = "0.4.18" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0" -dependencies = [ - "heck 0.3.3", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 1.0.109", -] +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "strum" -version = "0.26.2" +version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d8cec3501a5194c432b2b7976db6b7d10ec95c253208b45f83f7136aa985e29" +checksum = "f64def088c51c9510a8579e3c5d67c65349dcf755e5479ad3d010aa6454e2c32" dependencies = [ "strum_macros", ] [[package]] name = "strum_macros" -version = "0.26.2" +version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6cf59daf282c0a494ba14fd21610a0325f9f90ec9d1231dea26bcb1d696c946" +checksum = "c77a8c5abcaf0f9ce05d62342b7d298c346515365c36b673df4ebe3ced01fde8" dependencies = [ - "heck 0.4.1", + "heck", "proc-macro2", "quote", "rustversion", - "syn 2.0.66", + "syn 2.0.103", ] [[package]] @@ -3684,15 +4640,15 @@ dependencies = [ "byteorder", "crunchy", "lazy_static", - "rand", + "rand 0.8.5", "rustc-hex", ] [[package]] name = "subtle" -version = "2.5.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" @@ -3707,9 +4663,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.66" +version = "2.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" +checksum = "e4307e30089d6fd6aff212f2da3a1f9e32f3223b1f010fb09b7c95f90f3ca1e8" dependencies = [ "proc-macro2", "quote", @@ -3718,41 +4674,34 @@ dependencies = [ [[package]] name = "syn-solidity" -version = "0.7.4" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8db114c44cf843a8bacd37a146e37987a0b823a0e8bc4fdc610c9c72ab397a5" +checksum = "14c8c8f496c33dc6343dac05b4be8d9e0bca180a4caa81d7b8416b10cc2273cd" dependencies = [ "paste", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.103", ] [[package]] name = "sync_wrapper" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" - -[[package]] -name = "system-configuration" -version = "0.5.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "system-configuration-sys", + "futures-core", ] [[package]] -name = "system-configuration-sys" -version = "0.5.0" +name = "synstructure" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ - "core-foundation-sys", - "libc", + "proc-macro2", + "quote", + "syn 2.0.103", ] [[package]] @@ -3763,43 +4712,35 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" -version = "3.10.1" +version = "3.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" dependencies = [ - "cfg-if", "fastrand", + "getrandom 0.3.3", + "once_cell", "rustix", - "windows-sys 0.52.0", -] - -[[package]] -name = "textwrap" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" -dependencies = [ - "unicode-width", + "windows-sys 0.59.0", ] [[package]] name = "thiserror" -version = "1.0.61" +version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.61" +version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.103", ] [[package]] @@ -3813,9 +4754,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.36" +version = "0.3.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" dependencies = [ "deranged", "itoa", @@ -3828,15 +4769,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" +checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" [[package]] name = "time-macros" -version = "0.2.18" +version = "0.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" dependencies = [ "num-conv", "time-core", @@ -3852,56 +4793,50 @@ dependencies = [ ] [[package]] -name = "tinytemplate" -version = "1.2.1" +name = "tinystr" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" dependencies = [ - "serde", - "serde_json", + "displaydoc", + "zerovec", ] [[package]] -name = "tinyvec" -version = "1.6.0" +name = "tinytemplate" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + "serde", + "serde_json", +] [[package]] name = "tokio" -version = "1.37.0" +version = "1.45.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" +checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779" dependencies = [ "backtrace", "bytes", "libc", "mio", - "num_cpus", "pin-project-lite", "socket2", "tokio-macros", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "tokio-macros" -version = "2.2.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.103", ] [[package]] @@ -3914,21 +4849,11 @@ dependencies = [ "tokio", ] -[[package]] -name = "tokio-rustls" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" -dependencies = [ - "rustls", - "tokio", -] - [[package]] name = "tokio-stream" -version = "0.1.15" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" +checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" dependencies = [ "futures-core", "pin-project-lite", @@ -3936,26 +4861,11 @@ dependencies = [ "tokio-util", ] -[[package]] -name = "tokio-tungstenite" -version = "0.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" -dependencies = [ - "futures-util", - "log", - "rustls", - "tokio", - "tokio-rustls", - "tungstenite", - "webpki-roots", -] - [[package]] name = "tokio-util" -version = "0.7.11" +version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df" dependencies = [ "bytes", "futures-core", @@ -3966,56 +4876,72 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.6" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" [[package]] name = "toml_edit" -version = "0.21.1" +version = "0.22.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ - "indexmap", + "indexmap 2.9.0", "toml_datetime", "winnow", ] [[package]] name = "tower" -version = "0.4.13" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" dependencies = [ "futures-core", "futures-util", - "pin-project", "pin-project-lite", + "sync_wrapper", "tokio", "tower-layer", "tower-service", - "tracing", +] + +[[package]] +name = "tower-http" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" +dependencies = [ + "bitflags", + "bytes", + "futures-util", + "http", + "http-body", + "iri-string", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", ] [[package]] name = "tower-layer" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" [[package]] name = "tower-service" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.40" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ - "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -4023,22 +4949,23 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.27" +version = "0.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.103", ] [[package]] name = "tracing-core" -version = "0.1.32" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" dependencies = [ "once_cell", + "valuable", ] [[package]] @@ -4047,10 +4974,21 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" dependencies = [ + "futures", + "futures-task", "pin-project", "tracing", ] +[[package]] +name = "tracing-subscriber" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e0d2eaa99c3c2e41547cfa109e910a68ea03823cccad4a0525dcbc9b01e8c71" +dependencies = [ + "tracing-core", +] + [[package]] name = "triehash" version = "0.8.4" @@ -4067,37 +5005,17 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" -[[package]] -name = "tungstenite" -version = "0.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9" -dependencies = [ - "byteorder", - "bytes", - "data-encoding", - "http 0.2.12", - "httparse", - "log", - "rand", - "rustls", - "sha1", - "thiserror", - "url", - "utf-8", -] - [[package]] name = "typenum" -version = "1.17.0" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" [[package]] name = "ucd-trie" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" [[package]] name = "uint" @@ -4105,7 +5023,6 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" dependencies = [ - "arbitrary", "byteorder", "crunchy", "hex", @@ -4118,62 +5035,35 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" -[[package]] -name = "unicode-bidi" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" - [[package]] name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "unicode-normalization" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "unicode-segmentation" -version = "1.11.0" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] name = "unicode-width" -version = "0.1.12" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6" +checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c" [[package]] name = "unicode-xid" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" - -[[package]] -name = "untrusted" -version = "0.7.1" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] -name = "untrusted" -version = "0.9.0" +name = "unty" +version = "0.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" +checksum = "6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae" [[package]] name = "url" -version = "2.5.0" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" dependencies = [ "form_urlencoded", "idna", @@ -4181,16 +5071,33 @@ dependencies = [ ] [[package]] -name = "utf-8" -version = "0.7.6" +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "uuid" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" +checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d" +dependencies = [ + "getrandom 0.3.3", + "js-sys", + "wasm-bindgen", +] [[package]] name = "valuable" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" [[package]] name = "vcpkg" @@ -4199,22 +5106,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] -name = "vec_map" -version = "0.8.2" +name = "version_check" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] -name = "version_check" -version = "0.9.4" +name = "virtue" +version = "0.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "051eb1abcf10076295e815102942cc58f9d5e3b4560e46e53c21e8ff6f3af7b1" [[package]] name = "wait-timeout" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" +checksum = "09ac3b126d3914f9849036f826e054cbabdc8519970b8998ddaf3b5bd3c65f11" dependencies = [ "libc", ] @@ -4240,52 +5147,63 @@ dependencies = [ [[package]] name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasi" +version = "0.14.2+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +dependencies = [ + "wit-bindgen-rt", +] [[package]] name = "wasm-bindgen" -version = "0.2.92" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" dependencies = [ "cfg-if", + "once_cell", + "rustversion", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.92" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" dependencies = [ "bumpalo", "log", - "once_cell", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.103", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.42" +version = "0.4.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" +checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" dependencies = [ "cfg-if", "js-sys", + "once_cell", "wasm-bindgen", "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.92" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -4293,77 +5211,126 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.92" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.103", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.92" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "wasmtimer" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" +checksum = "d8d49b5d6c64e8558d9b1b065014426f35c18de636895d24893dbbd329743446" +dependencies = [ + "futures", + "js-sys", + "parking_lot", + "pin-utils", + "slab", + "wasm-bindgen", +] [[package]] name = "web-sys" -version = "0.3.69" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" dependencies = [ "js-sys", "wasm-bindgen", ] [[package]] -name = "webpki-roots" -version = "0.25.4" +name = "web-time" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] [[package]] -name = "winapi" -version = "0.3.9" +name = "winapi-util" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", + "windows-sys 0.59.0", ] [[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" +name = "windows-core" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] [[package]] -name = "winapi-util" -version = "0.1.8" +name = "windows-implement" +version = "0.60.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" +checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" dependencies = [ - "windows-sys 0.52.0", + "proc-macro2", + "quote", + "syn 2.0.103", ] [[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" +name = "windows-interface" +version = "0.59.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.103", +] [[package]] -name = "windows-sys" -version = "0.48.0" +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + +[[package]] +name = "windows-result" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" dependencies = [ - "windows-targets 0.48.5", + "windows-link", ] [[package]] @@ -4372,212 +5339,185 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.5", + "windows-targets", ] [[package]] -name = "windows-targets" -version = "0.48.5" +name = "windows-sys" +version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", + "windows-targets", ] [[package]] name = "windows-targets" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.5", - "windows_aarch64_msvc 0.52.5", - "windows_i686_gnu 0.52.5", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", "windows_i686_gnullvm", - "windows_i686_msvc 0.52.5", - "windows_x86_64_gnu 0.52.5", - "windows_x86_64_gnullvm 0.52.5", - "windows_x86_64_msvc 0.52.5", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] -name = "windows_x86_64_gnu" -version = "0.52.5" +name = "windows_x86_64_gnullvm" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" +name = "windows_x86_64_msvc" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.5" +name = "winnow" +version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" +checksum = "74c7b26e3480b707944fc872477815d29a8e429d2f93a1ce000f5fa84a15cbcd" +dependencies = [ + "memchr", +] [[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" +name = "wit-bindgen-rt" +version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +dependencies = [ + "bitflags", +] [[package]] -name = "windows_x86_64_msvc" -version = "0.52.5" +name = "writeable" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" +checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" [[package]] -name = "winnow" -version = "0.5.40" +name = "wyz" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" dependencies = [ - "memchr", + "tap", ] [[package]] -name = "winreg" -version = "0.50.0" +name = "yoke" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" dependencies = [ - "cfg-if", - "windows-sys 0.48.0", + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", ] [[package]] -name = "winreg" -version = "0.52.0" +name = "yoke-derive" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" +checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" dependencies = [ - "cfg-if", - "windows-sys 0.48.0", + "proc-macro2", + "quote", + "syn 2.0.103", + "synstructure", ] [[package]] -name = "ws_stream_wasm" -version = "0.7.4" +name = "zerocopy" +version = "0.8.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7999f5f4217fe3818726b66257a4475f71e74ffd190776ad053fa159e50737f5" +checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" dependencies = [ - "async_io_stream", - "futures", - "js-sys", - "log", - "pharos", - "rustc_version 0.4.0", - "send_wrapper 0.6.0", - "thiserror", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", + "zerocopy-derive", ] [[package]] -name = "wyz" -version = "0.5.1" +name = "zerocopy-derive" +version = "0.8.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" dependencies = [ - "tap", + "proc-macro2", + "quote", + "syn 2.0.103", ] [[package]] -name = "zerocopy" -version = "0.7.34" +name = "zerofrom" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" dependencies = [ - "zerocopy-derive", + "zerofrom-derive", ] [[package]] -name = "zerocopy-derive" -version = "0.7.34" +name = "zerofrom-derive" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.103", + "synstructure", ] [[package]] name = "zeroize" -version = "1.7.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" dependencies = [ "zeroize_derive", ] @@ -4590,5 +5530,38 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.103", +] + +[[package]] +name = "zerotrie" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.103", ] diff --git a/Cargo.toml b/Cargo.toml index 426d6e403f..5cad800fa0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,23 +1,171 @@ [workspace] members = [ + # binary "bins/revme", - "bins/revm-test", + + # libraries "crates/revm", "crates/primitives", "crates/interpreter", "crates/precompile", + "crates/database", + "crates/database/interface", + "crates/bytecode", + "crates/state", + "crates/context", + "crates/context/interface", + "crates/handler", + + # variants + "crates/op-revm", + "crates/inspector", + + # utility + "crates/statetest-types", + + # examples + "examples/block_traces", + "examples/cheatcode_inspector", + "examples/contract_deployment", + "examples/database_components", + "examples/uniswap_get_reserves", + "examples/uniswap_v2_usdc_swap", + "examples/erc20_gas", + "examples/my_evm", + "examples/custom_opcodes", + "examples/custom_precompile_journal", ] resolver = "2" default-members = ["crates/revm"] +[workspace.dependencies] +# revm +revm = { path = "crates/revm", version = "27.1.0", default-features = false } +primitives = { path = "crates/primitives", package = "revm-primitives", version = "20.2.1", default-features = false } +bytecode = { path = "crates/bytecode", package = "revm-bytecode", version = "6.2.1", default-features = false } +database = { path = "crates/database", package = "revm-database", version = "7.1.0", default-features = false } +database-interface = { path = "crates/database/interface", package = "revm-database-interface", version = "7.1.0", default-features = false } +state = { path = "crates/state", package = "revm-state", version = "7.0.4", default-features = false } +interpreter = { path = "crates/interpreter", package = "revm-interpreter", version = "24.0.0", default-features = false } +inspector = { path = "crates/inspector", package = "revm-inspector", version = "8.1.0", default-features = false } +precompile = { path = "crates/precompile", package = "revm-precompile", version = "25.0.0", default-features = false } +statetest-types = { path = "crates/statetest-types", package = "revm-statetest-types", version = "8.0.5", default-features = false } +context = { path = "crates/context", package = "revm-context", version = "8.0.4", default-features = false } +context-interface = { path = "crates/context/interface", package = "revm-context-interface", version = "9.0.0", default-features = false } +handler = { path = "crates/handler", package = "revm-handler", version = "8.1.0", default-features = false } +op-revm = { path = "crates/op-revm", package = "op-revm", version = "8.1.0", default-features = false } + +# alloy +alloy-eip2930 = { version = "0.2.1", default-features = false } +alloy-eip7702 = { version = "0.6.1", default-features = false } +alloy-primitives = { version = "1.2.0", default-features = false } + +# alloy in examples, revme or feature flagged. +alloy-rlp = { version = "0.3.12", default-features = false } +alloy-sol-types = { version = "1.2.0", default-features = false } +alloy-consensus = { version = "1.0.12", default-features = false } +alloy-eips = { version = "1.0.12", default-features = false } +alloy-provider = { version = "1.0.12", default-features = false } +alloy-signer = { version = "1.0.12", default-features = false } +alloy-signer-local = { version = "1.0.12", default-features = false } +alloy-transport = { version = "1.0.12", default-features = false } + +# precompiles +ark-bls12-381 = { version = "0.5", default-features = false } +ark-bn254 = { version = "0.5", default-features = false } +ark-ec = { version = "0.5", default-features = false } +ark-ff = { version = "0.5", default-features = false } +ark-serialize = { version = "0.5", default-features = false } +ark-std = { version = "0.5", default-features = false } +aurora-engine-modexp = { version = "1.2", default-features = false } +rug = { version = "1.27.0", default-features = false } +blst = "0.3.15" +bn = { package = "substrate-bn", version = "0.6", default-features = false } +c-kzg = { version = "2.1.1", default-features = false } +k256 = { version = "0.13.4", default-features = false } +libsecp256k1 = { version = "0.7", default-features = false } +kzg-rs = { version = "0.2.7", default-features = false } +secp256k1 = { version = "0.31.0", default-features = false } +sha2 = { version = "0.10.9", default-features = false } +ripemd = { version = "0.1.3", default-features = false } +p256 = { version = "0.13.2", default-features = false } + +# bytecode +bitvec = { version = "1", default-features = false } +paste = "1.0" +phf = { version = "0.11", default-features = false } + +# revme +clap = { version = "4", features = ["derive"] } +criterion = { package = "codspeed-criterion-compat", version = "2.10" } + +# serde +serde = { version = "1.0", default-features = false } +serde_json = { version = "1.0", default-features = false } + +# misc +auto_impl = "1.3.0" +bitflags = { version = "2.9.1", default-features = false } +cfg-if = { version = "1.0", default-features = false } +derive-where = { version = "1.5.0", default-features = false } +once_cell = { version = "1.21", default-features = false } +rand = "0.9" +tokio = "1.45" +either = { version = "1.15.0", default-features = false } + +# dev-dependencies +anyhow = "1.0.98" +bincode = { version = "2.0", features = ["serde"] } +eyre = "0.6.12" +hash-db = "0.15" +indicatif = "0.17" +plain_hasher = "0.2" +rstest = "0.25.0" +serde_derive = "1.0" +thiserror = "2.0" +triehash = "0.8" +walkdir = "2.5" + +[workspace.package] +license = "MIT" +authors = ["Dragan Rakita "] +categories = ["no-std", "compilers", "cryptography::cryptocurrencies"] +keywords = ["revm", "evm", "ethereum", "blockchain", "no_std"] +repository = "https://github.com/bluealloy/revm" +documentation = "https://bluealloy.github.io/revm/" +homepage = "" +edition = "2021" + +[workspace.lints] +rust.missing_debug_implementations = "warn" +rust.missing_docs = "warn" +rust.rust_2018_idioms = { level = "deny", priority = -1 } +rust.unreachable_pub = "warn" +rust.unused_must_use = "deny" +rustdoc.all = "warn" + [workspace.metadata.docs.rs] all-features = true rustdoc-args = ["--cfg", "docsrs"] [profile.release] -lto = true -codegen-units = 1 -debug = true +codegen-units = 16 +debug = "line-tables-only" +lto = "thin" +opt-level = 3 +panic = "abort" +strip = true + +# Use the `--profile profiling` flag to show symbols in release mode. +# e.g. `cargo build --profile profiling` +[profile.profiling] +debug = 2 +inherits = "release" +strip = false + +# Make sure debug symbols are in the bench profile +[profile.bench] +inherits = "profiling" [profile.ethtests] inherits = "test" diff --git a/LICENSE b/LICENSE index ad98ff22cc..be6d350ebe 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2021-2024 draganrakita +Copyright (c) 2021-2025 draganrakita Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/MIGRATION_GUIDE.md b/MIGRATION_GUIDE.md new file mode 100644 index 0000000000..d1bb31cd23 --- /dev/null +++ b/MIGRATION_GUIDE.md @@ -0,0 +1,39 @@ +# v82 tag (revm v27.1.0) from v81 tag (revm v27.0.3) + +* `ContextTr` gained `Host` supertrait. + * Previously Host was implemented for any T that has ContextTr, this restricts specializations. + https://github.com/bluealloy/revm/issues/2732 + * `Host` is moved to `revm-context-interface` + * If you custom struct that implement `ContextTr` you would need to manually implement `Host` trait, in most cases no action needed. +* In `revm-interpreter`, fn `cast_slice_to_u256` was removed and `push_slice` fn is added to `StackTrait`. +* `PrecompileOutput` now contains revert flag. + * It is safe to put to false. +* In `kzg` and `blake2` modules few internal functions were made private or removed. + +# v80 tag (revm v27.0.0) -> v81 tag ( revm v27.0.1) + +* Inspector fn `step_end` is now called even if Inspector `step` sets the action. Previously this was not the case. + * https://github.com/bluealloy/revm/pull/2687 + * this additionally fixes panic bug where `bytecode.opcode()` would panic in `step_end` + +# v70 tag (revm v22.0.2) -> v71 tag ( revm v23.0.0) + +* Removal of `EvmData`. + * It got flattened and ctx/inspector fields moved directly to Evm, additional layering didn't have purpose. +* Merging of `Handler`'s `validate_tx_against_state` and `deduct_caller` into one function `validate_against_state_and_deduct_caller` + * If you dont override those functions there is no action. If you do please look at `pre_execution::validate_against_state_and_deduct_caller` + function or `OpHandler` for examples of migration. +* Breaking changed for EOF to support eof-devnet1. +* `SharedMemory` is not longer Rc> and internally uses Rc>> buffer. + * No action if you dont use it inside Interpreter. +* In `JournalExt` fn `last_journal_mut()` is renamed to `journal_mut()` +* EOF is disabled from Osaka and not accessible. + +# v68 tag (revm v21.0.0) -> v70 tag ( revm v22.0.2) + +No breaking changes + +# v67 tag (revm v21.0.0) -> v68 tag ( revm v22.0.0) + +* No code breaking changes +* alloy-primitives bumped to v1.0.0 and we had a major bump because of it. \ No newline at end of file diff --git a/README.md b/README.md index 0d748be079..57a72e32a1 100644 --- a/README.md +++ b/README.md @@ -1,138 +1,75 @@ -# revm +### Revm [![CI](https://github.com/bluealloy/revm/actions/workflows/ci.yml/badge.svg)][gh-ci] [![License](https://img.shields.io/badge/License-MIT-orange.svg)][mit-license] +[![crates.io](https://img.shields.io/crates/v/revm.svg)](https://crates.io/crates/revm) [![Chat][tg-badge]][tg-url] +Revm is a highly efficient and stable implementation of the Ethereum Virtual Machine (EVM) written in Rust. + +![banner](https://raw.githubusercontent.com/bluealloy/revm/refs/heads/main/assets/logo/revm-banner.png) + [mit-license]: https://opensource.org/license/mit/ [gh-ci]: https://github.com/bluealloy/revm/actions/workflows/ci.yml [tg-url]: https://t.me/+Ig4WDWOzikA3MzA0 [tg-badge]: https://img.shields.io/badge/chat-telegram-blue -**Rust Ethereum Virtual Machine** - -![](./assets/revm-banner.png) - -Revm is an EVM written in Rust that is focused on **speed** and **simplicity**. -It has a fast and flexible implementation with a simple interface and embedded Host. -It passes all `ethereum/tests` test suites. - -Here is a list of guiding principles that Revm follows. - -* **EVM compatibility and stability** - this goes without saying but it is nice to put it here. In the blockchain industry, stability is the most desired attribute of any system. -* **Speed** - is one of the most important things and most decisions are made to complement this. -* **Simplicity** - simplification of internals so that it can be easily understood and extended, and interface that can be easily used or integrated into other projects. -* **interfacing** - `[no_std]` so that it can be used as wasm lib and integrate with JavaScript and cpp binding if needed. - -# Project - -Structure: +Known for its robustness, it stands as one of the most popular libraries and a critical component of the Ethereum ecosystem. Revm plays a crucial role across various projects, being widely utilized by almost all tooling and block builders. It is integrated into Reth, multiple Layer 2 variants and other clients and serving as a standard for zkVMs. -* crates - * revm -> main EVM library. - * revm-primitives -> Primitive data types. - * revm-interpreter -> Execution loop with instructions - * revm-precompile -> EVM precompiles -* bins: - * revme: cli binary, used for running state test jsons +Revm offers two primary applications: firstly, it functions as an executor where users can set up block info and process mainnet transactions; secondly, it acts as a framework that facilitates the extension and support of different EVM variants such as op-revm. -This project tends to use the newest rust version, so if you're encountering a build error try running `rustup update` first. +### How to use: -There were some big efforts on optimization of revm: +Here is a straightforward example of using the Execution API: It allows us to create an Ethereum Virtual Machine (EVM) and execute transactions. Additionally, it can be utilized to generate traces with the inspector or more complex example of foundry cheatcodes. -* Optimizing interpreter loop: https://github.com/bluealloy/revm/issues/7 -* Introducing Bytecode format (and better bytecode analysis): https://github.com/bluealloy/revm/issues/121 -* Unification of instruction signatures: https://github.com/bluealloy/revm/pull/283 +```rust,ignore +let mut evm = Context::mainnet().with_block(block).build_mainnet(); +let out = evm.transact(tx); -# Building from source - -```shell -git clone https://github.com/bluealloy/revm.git -cd revm -cargo build --release +// or you can use powerful inspection tool to trace it +let mut evm = evm.with_inspector(tracer); +let out = evm.inspect_tx(tx); ``` -**_Note:_** `clang` is required for building revm with `c-kzg` or `secp256k1` feature flags as they depend on `C` libraries. If you don't have it installed, you can install it with `apt install clang`. - -# Running eth tests +The Evm Framework API is somewhat complex to use, but this document provides a detailed explanation. It enables users to extend logic, incorporate various context types, and offers built-in support for inspection. For a practical example, you can refer to the [op-revm crate](https://github.com/op-rs/op-revm). -go to `cd bins/revme/` +### Users: -Download eth tests from (this will take some time): `git clone https://github.com/ethereum/tests` +As previously noted, there are several groups of projects that utilize this technology: -run tests with command: `cargo run --release -- statetest tests/GeneralStateTests/ tests/LegacyTests/Constantinople/GeneralStateTests` +* **Major block builders**. +* **Clients**: [Reth](https://github.com/paradigmxyz/reth), [Helios](https://github.com/a16z/helios), [Trin](https://github.com/ethereum/trin),.. +* **Tooling**: [Foundry](https://github.com/foundry-rs/foundry/), [Hardhat](https://github.com/NomicFoundation/hardhat),.. +* **L2s**: [Optimism](https://github.com/bluealloy/revm/tree/main/crates/op-revm), [Coinbase](https://www.base.org/), [Scroll](https://github.com/scroll-tech/revm),.. +* **zkVM**: [Risc0](https://github.com/risc0/risc0-ethereum), [Succinct](https://github.com/succinctlabs/rsp),.. -`GeneralStateTests` contains all tests related to EVM. +The full list of projects that use Revm is available in the [awesome-revm](https://bluealloy.github.io/revm/awesome.html) section of the book. -## Running benchmarks +### How to, dev section -Benches can be found in [`crates/revm/benches`](./crates/revm/benches). +The [book](https://bluealloy.github.io/revm/) and [`Architecture and API`](https://bluealloy.github.io/revm/architecture.html) page is the best starting resource. -Currently, available benches include the following. -- *analysis* -- *snailtracer* -- *transfer* +Some quick links can be found here. Some point to code documentation or the book. code docs are there to explain usage of a particular part of the code where the book is to get more of an overview of the architecture or how components/projects fit together. -To run the `snailtracer` bench, execute the `cargo bench` subcommand below. - -```shell -cargo bench --package revm --profile release -- snailtracer -``` - -Using [flamegraph][flamegraph], you can create a visualization breaking down the runtime of various -sections of the bench execution - a flame graph. Executing the `cargo flamegraph` subcommand requires -installing [flamegraph][flamegraph] by running `cargo install flamegraph`. - -```shell -cargo flamegraph --root --freq 4000 --min-width 0.001 --package revm --bench bench -- snailtracer -``` +* How to build and use revm can be found here. [book](https://bluealloy.github.io/revm/dev.html) +* Architecture overview can be seen here. [book](https://bluealloy.github.io/revm/architecture.html) +* Structure of the project (list of crates and their versions) can be seen here. [book](https://github.com/bluealloy/revm/tree/main/crates) +* How to use Revm Framework can be found in MyEvm example. [book](https://github.com/bluealloy/revm/tree/main/examples/my_evm) +* Release procedure and changelogs explanation. [book](https://bluealloy.github.io/revm/release_procedure.html) +* How to use revme (Revm binary with few commands) can be found here. [code](https://github.com/bluealloy/revm/tree/main/bins/revme) +* How to run Ethereum test can be found here: [book](https://bluealloy.github.io/revm/revme.html#running-eth-tests) +* If there is more need for explanations please open a PR request. -This command will produce a flamegraph image output to `flamegraph.svg`. -Flamegraph also requires sudo mode to run (hence the `--root` cli arg) and will prompt you for your password if not in sudo mode already. +### Community: +For questions please open a github issue or join the public telegram group: [https://t.me/+Ig4WDWOzikA3MzA0](https://t.me/+Ig4WDWOzikA3MzA0) -[flamegraph]: https://docs.rs/crate/flamegraph/0.1.6 +### Licence +Revm is licensed under MIT Licence. -## Running examples - -```shell -cargo run -p revm --features ethersdb --example fork_ref_transact -``` - -Generate block traces and write them to json files in a new `traces/` directory. -Each file corresponds to a transaction in the block and is named as such: `.json`. - -```shell -cargo run -p revm --features std,serde-json,ethersdb --example generate_block_traces -``` - -# Used by: - -* [Foundry](https://github.com/foundry-rs/foundry) is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust. -* [Helios](https://github.com/a16z/helios) is a fully trustless, efficient, and portable Ethereum light client written in Rust. -* [Reth](https://github.com/paradigmxyz/reth) Modular, contributor-friendly and blazing-fast implementation of the Ethereum protocol -* [Arbiter](https://github.com/primitivefinance/arbiter) is a framework for stateful Ethereum smart-contract simulation -* [Zeth](https://github.com/risc0/zeth) is an open-source ZK block prover for Ethereum built on the RISC Zero zkVM. -* [VERBS](https://github.com/simtopia/verbs) an open-source Ethereum agent-based modelling and simulation library with a Python API. -* [Hardhat](https://github.com/NomicFoundation/hardhat) is a development environment to compile, deploy, test, and debug your Ethereum software. -* [Trin](https://github.com/ethereum/trin) is Portal Network client. An execution and consensus layer Ethereum light client written in Rust. Portal Network client's provide complete, provable, and distributed execution archival access. -* ... - -(If you want to add project to the list, ping me or open the PR) - -# Documentation - -The book can be found at github page here: https://bluealloy.github.io/revm/ - -The documentation (alas needs some love) can be found here: https://bluealloy.github.io/revm/docs/ - -To serve the mdbook documentation in a local environment, ensure you have mdbook installed (if not install it with cargo) and then run: - -```shell -mdbook serve documentation -``` +Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in these crates by you, shall be licensed as above, without any additional terms or conditions. -# Contact +If `gmp` feature flag is used, GPL code gets compiled, if enabled please make sure to follow this license. -There is public telegram group: https://t.me/+Ig4WDWOzikA3MzA0 +### Security -Or if you want to contact me directly, here is my email: dragan0rakita@gmail.com and telegram: https://t.me/draganrakita +For any security questions or findings, please reach out to me directly via email at dragan0rakita@gmail.com or contact me on Keybase under the username @draganrakita. diff --git a/assets/logo.pdf b/assets/logo/old/logo.pdf similarity index 100% rename from assets/logo.pdf rename to assets/logo/old/logo.pdf diff --git a/assets/logo.png b/assets/logo/old/logo.png similarity index 100% rename from assets/logo.png rename to assets/logo/old/logo.png diff --git a/assets/revm-banner.png b/assets/logo/old/logo_banner.png similarity index 100% rename from assets/revm-banner.png rename to assets/logo/old/logo_banner.png diff --git a/assets/logo/revm-banner.png b/assets/logo/revm-banner.png new file mode 100644 index 0000000000..d816be03b6 Binary files /dev/null and b/assets/logo/revm-banner.png differ diff --git a/assets/logo/revm.fig b/assets/logo/revm.fig new file mode 100644 index 0000000000..71c118613b Binary files /dev/null and b/assets/logo/revm.fig differ diff --git a/assets/logo/revm.png b/assets/logo/revm.png new file mode 100644 index 0000000000..6369229606 Binary files /dev/null and b/assets/logo/revm.png differ diff --git a/bins/revm-test/CHANGELOG.md b/bins/revm-test/CHANGELOG.md deleted file mode 100644 index 4821d7ec54..0000000000 --- a/bins/revm-test/CHANGELOG.md +++ /dev/null @@ -1,72 +0,0 @@ -# Changelog -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), -and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - -## [Unreleased] - -## [0.1.0](https://github.com/bluealloy/revm/releases/tag/revm-test-v0.1.0) - 2024-02-07 - -### Added -- EvmBuilder and External Contexts ([#888](https://github.com/bluealloy/revm/pull/888)) -- separate initial checks ([#486](https://github.com/bluealloy/revm/pull/486)) -- revm-interpreter created ([#320](https://github.com/bluealloy/revm/pull/320)) -- *(interpreter)* Unify instruction fn signature ([#283](https://github.com/bluealloy/revm/pull/283)) -- Migrate `primitive_types::U256` to `ruint::Uint<256, 4>` ([#239](https://github.com/bluealloy/revm/pull/239)) -- Introduce ByteCode format, Update Readme ([#156](https://github.com/bluealloy/revm/pull/156)) - -### Fixed -- *(clippy)* fix some clippy lints - -### Other -- *(deps)* bump eyre from 0.6.11 to 0.6.12 ([#1051](https://github.com/bluealloy/revm/pull/1051)) -- *(deps)* bump alloy-sol-types from 0.6.0 to 0.6.2 ([#1035](https://github.com/bluealloy/revm/pull/1035)) -- *(deps)* bump alloy-sol-macro from 0.6.0 to 0.6.2 ([#1013](https://github.com/bluealloy/revm/pull/1013)) -- chore(Test) : const to static ([#1016](https://github.com/bluealloy/revm/pull/1016)) -- Burntpix criterion bench ([#1004](https://github.com/bluealloy/revm/pull/1004)) -- Instruction table ([#759](https://github.com/bluealloy/revm/pull/759)) -- rewrite revm-test as a criterion bench ([#579](https://github.com/bluealloy/revm/pull/579)) -- optimize stack usage for recursive `call` and `create` programs ([#522](https://github.com/bluealloy/revm/pull/522)) -- Bump v24, revm v3.3.0 ([#476](https://github.com/bluealloy/revm/pull/476)) -- Release v23, revm v3.2.0 ([#464](https://github.com/bluealloy/revm/pull/464)) -- Release v22, revm v3.1.1 ([#460](https://github.com/bluealloy/revm/pull/460)) -- v21, revm v3.1.0 ([#444](https://github.com/bluealloy/revm/pull/444)) -- remove gas blocks ([#391](https://github.com/bluealloy/revm/pull/391)) -- *(deps)* bump bytes from 1.3.0 to 1.4.0 ([#355](https://github.com/bluealloy/revm/pull/355)) -- Bump v20, changelog ([#350](https://github.com/bluealloy/revm/pull/350)) -- includes to libs ([#338](https://github.com/bluealloy/revm/pull/338)) -- Creating revm-primitives, revm better errors and db components ([#334](https://github.com/bluealloy/revm/pull/334)) -- Cleanup, move hot fields toggether in Interpreter ([#321](https://github.com/bluealloy/revm/pull/321)) -- native bits ([#278](https://github.com/bluealloy/revm/pull/278)) -- *(release)* Bump revm and precompiles versions -- Bump primitive_types. Add statetest spec -- Bump revm v2.1.0 ([#224](https://github.com/bluealloy/revm/pull/224)) -- revm bump v2.0.0, precompile bump v1.1.1 ([#212](https://github.com/bluealloy/revm/pull/212)) -- Cfg choose create analysis, option on bytecode size limit ([#210](https://github.com/bluealloy/revm/pull/210)) -- Cargo sort. Bump lib versions ([#208](https://github.com/bluealloy/revm/pull/208)) -- Return `ExecutionResult`, which includes `gas_refunded` ([#169](https://github.com/bluealloy/revm/pull/169)) -- Bytecode hash, remove override_spec, ([#165](https://github.com/bluealloy/revm/pull/165)) -- revm bump 1.8. update libs. snailtracer rename ([#159](https://github.com/bluealloy/revm/pull/159)) -- v6 changelog, bump versions -- Big Refactor. Machine to Interpreter. refactor instructions. call/create struct ([#52](https://github.com/bluealloy/revm/pull/52)) -- [revm] pop_top and unsafe comments ([#51](https://github.com/bluealloy/revm/pull/51)) -- [precompiles] remove unused borsh -- [recompl] Bump precompile deps, cargo sort on workspace -- [revm] output log. Stetetest test log output. fmt -- Bump versions, Changelogs, fmt, revm readme, clippy. -- [revm] Run test multiple times. fmt, BenchmarkDB -- Multiple changes: web3 db, debugger initial commit, precompile load -- Memory to usize, clippy,fmt -- wip optimize i256 -- TEMP switch stacks H256 with U256 -- [revm] some perfs -- [revm] Perfs stack pop. Benchmark snailtracer. -- [revm] cleanup -- fmt -- EVM Interface changed. Inspector called separately -- Bump revm v0.3.0. README updated -- DB ref mut polished -- And now we debug -- [revm] Interface. Inspector added, Env cleanup. revm-test passes -- Rename bin to bins diff --git a/bins/revm-test/Cargo.toml b/bins/revm-test/Cargo.toml deleted file mode 100644 index ef50c94059..0000000000 --- a/bins/revm-test/Cargo.toml +++ /dev/null @@ -1,28 +0,0 @@ -[package] -name = "revm-test" -version = "0.1.0" -edition = "2021" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -bytes = "1.6" -hex = "0.4" -revm = { path = "../../crates/revm", version = "9.0.0", default-features=false } -microbench = "0.5" -alloy-sol-macro = "0.7.0" -alloy-sol-types = "0.7.0" -regex = "1.10.4" -eyre = "0.6.12" - - -[[bin]] -name = "analysis" - -[[bin]] -name = "snailtracer" - -[[bin]] -name = "transfer" - -[[bin]] -name = "burntpix" diff --git a/bins/revm-test/src/bin/analysis.rs b/bins/revm-test/src/bin/analysis.rs deleted file mode 100644 index 40bbcf39c4..0000000000 --- a/bins/revm-test/src/bin/analysis.rs +++ /dev/null @@ -1,48 +0,0 @@ -use revm::{ - db::BenchmarkDB, - interpreter::analysis::to_analysed, - primitives::{address, bytes, Bytecode, Bytes, TransactTo}, - Evm, -}; -use std::time::Instant; - -fn main() { - let contract_data : Bytes = hex::decode( "6060604052341561000f57600080fd5b604051610dd1380380610dd18339810160405280805190602001909190805182019190602001805190602001909190805182019190505083600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508360008190555082600390805190602001906100a79291906100e3565b5081600460006101000a81548160ff021916908360ff16021790555080600590805190602001906100d99291906100e3565b5050505050610188565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061012457805160ff1916838001178555610152565b82800160010185558215610152579182015b82811115610151578251825591602001919060010190610136565b5b50905061015f9190610163565b5090565b61018591905b80821115610181576000816000905550600101610169565b5090565b90565b610c3a806101976000396000f3006060604052600436106100af576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306fdde03146100b4578063095ea7b31461014257806318160ddd1461019c57806323b872dd146101c557806327e235e31461023e578063313ce5671461028b5780635c658165146102ba57806370a082311461032657806395d89b4114610373578063a9059cbb14610401578063dd62ed3e1461045b575b600080fd5b34156100bf57600080fd5b6100c76104c7565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156101075780820151818401526020810190506100ec565b50505050905090810190601f1680156101345780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561014d57600080fd5b610182600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035906020019091905050610565565b604051808215151515815260200191505060405180910390f35b34156101a757600080fd5b6101af610657565b6040518082815260200191505060405180910390f35b34156101d057600080fd5b610224600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061065d565b604051808215151515815260200191505060405180910390f35b341561024957600080fd5b610275600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919050506108f7565b6040518082815260200191505060405180910390f35b341561029657600080fd5b61029e61090f565b604051808260ff1660ff16815260200191505060405180910390f35b34156102c557600080fd5b610310600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610922565b6040518082815260200191505060405180910390f35b341561033157600080fd5b61035d600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610947565b6040518082815260200191505060405180910390f35b341561037e57600080fd5b610386610990565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156103c65780820151818401526020810190506103ab565b50505050905090810190601f1680156103f35780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561040c57600080fd5b610441600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035906020019091905050610a2e565b604051808215151515815260200191505060405180910390f35b341561046657600080fd5b6104b1600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610b87565b6040518082815260200191505060405180910390f35b60038054600181600116156101000203166002900480601f01602080910402602001604051908101604052809291908181526020018280546001816001161561010002031660029004801561055d5780601f106105325761010080835404028352916020019161055d565b820191906000526020600020905b81548152906001019060200180831161054057829003601f168201915b505050505081565b600081600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040518082815260200191505060405180910390a36001905092915050565b60005481565b600080600260008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905082600160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541015801561072e5750828110155b151561073957600080fd5b82600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254019250508190555082600160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8110156108865782600260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055505b8373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef856040518082815260200191505060405180910390a360019150509392505050565b60016020528060005260406000206000915090505481565b600460009054906101000a900460ff1681565b6002602052816000526040600020602052806000526040600020600091509150505481565b6000600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b60058054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610a265780601f106109fb57610100808354040283529160200191610a26565b820191906000526020600020905b815481529060010190602001808311610a0957829003601f168201915b505050505081565b600081600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410151515610a7e57600080fd5b81600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555081600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a36001905092915050565b6000600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050929150505600a165627a7a72305820df254047bc8f2904ad3e966b6db116d703bebd40efadadb5e738c836ffc8f58a0029").unwrap().into(); - - let bytecode_raw = Bytecode::new_raw(contract_data.clone()); - let bytecode_analysed = to_analysed(Bytecode::new_raw(contract_data)); - - // BenchmarkDB is dummy state that implements Database trait. - let mut evm = Evm::builder() - .modify_tx_env(|tx| { - // execution globals block hash/gas_limit/coinbase/timestamp.. - tx.caller = address!("1000000000000000000000000000000000000000"); - tx.transact_to = TransactTo::Call(address!("0000000000000000000000000000000000000000")); - //evm.env.tx.data = Bytes::from(hex::decode("30627b7c").unwrap()); - tx.data = bytes!("8035F0CE"); - }) - .with_db(BenchmarkDB::new_bytecode(bytecode_raw)) - .build(); - - // Just to warm up the processor. - for _ in 0..10000 { - let _ = evm.transact().unwrap(); - } - - let timer = Instant::now(); - for _ in 0..30000 { - let _ = evm.transact().unwrap(); - } - println!("Raw elapsed time: {:?}", timer.elapsed()); - - let mut evm = evm - .modify() - .reset_handler_with_db(BenchmarkDB::new_bytecode(bytecode_analysed)) - .build(); - - let timer = Instant::now(); - for _ in 0..30000 { - let _ = evm.transact().unwrap(); - } - println!("Analyzed elapsed time: {:?}", timer.elapsed()); -} diff --git a/bins/revm-test/src/bin/burntpix/main.rs b/bins/revm-test/src/bin/burntpix/main.rs deleted file mode 100644 index 8cd9eea66c..0000000000 --- a/bins/revm-test/src/bin/burntpix/main.rs +++ /dev/null @@ -1,162 +0,0 @@ -use alloy_sol_macro::sol; -use alloy_sol_types::SolCall; -use regex::bytes::Regex; -use revm::{ - db::{CacheDB, EmptyDB}, - primitives::{ - address, hex, keccak256, AccountInfo, Address, Bytecode, Bytes, ExecutionResult, Output, - TransactTo, B256, U256, - }, - Evm, -}; -use static_data::{ - BURNTPIX_ADDRESS_ONE, BURNTPIX_ADDRESS_THREE, BURNTPIX_ADDRESS_TWO, BURNTPIX_BYTECODE_FOUR, - BURNTPIX_BYTECODE_ONE, BURNTPIX_BYTECODE_THREE, BURNTPIX_BYTECODE_TWO, BURNTPIX_MAIN_ADDRESS, - STORAGE_ONE, STORAGE_TWO, STORAGE_ZERO, -}; - -use std::fs::File; -use std::{error::Error, time::Instant}; - -use std::{io::Write, str::FromStr}; -pub mod static_data; - -sol! { - #[derive(Debug, PartialEq, Eq)] - interface IBURNTPIX { - function run( uint32 seed, uint256 iterations) returns (string); - } -} - -fn main() { - let (seed, iterations) = try_init_env_vars().expect("Failed to parse env vars"); - - let run_call_data = IBURNTPIX::runCall { seed, iterations }.abi_encode(); - - let db = init_db(); - - let mut evm = Evm::builder() - .modify_tx_env(|tx| { - tx.caller = address!("1000000000000000000000000000000000000000"); - tx.transact_to = TransactTo::Call(BURNTPIX_MAIN_ADDRESS); - tx.data = run_call_data.clone().into(); - }) - .with_db(db) - .build(); - - let started = Instant::now(); - let tx_result = evm.transact().unwrap().result; - let return_data = match tx_result { - ExecutionResult::Success { - output, gas_used, .. - } => { - println!("Gas used: {:?}", gas_used); - println!("Time elapsed: {:?}", started.elapsed()); - match output { - Output::Call(value) => value, - _ => unreachable!("Unexpected output type"), - } - } - _ => unreachable!("Execution failed: {:?}", tx_result), - }; - - // remove returndata offset and length from output - let returndata_offset = 64; - let data = &return_data[returndata_offset..]; - - // remove trailing zeros - let re = Regex::new(r"[0\x00]+$").unwrap(); - let trimmed_data = re.replace_all(data, &[]); - let file_name = format!("{}_{}", seed, iterations); - - svg(file_name, &trimmed_data).expect("Failed to store svg"); -} - -fn svg(filename: String, svg_data: &[u8]) -> Result<(), Box> { - let current_dir = std::env::current_dir()?; - let svg_dir = current_dir.join("burntpix").join("svgs"); - std::fs::create_dir_all(&svg_dir)?; - - let file_path = svg_dir.join(format!("{}.svg", filename)); - let mut file = File::create(file_path)?; - file.write_all(svg_data)?; - - Ok(()) -} - -const DEFAULT_SEED: &str = "0"; -const DEFAULT_ITERATIONS: &str = "0x7A120"; -fn try_init_env_vars() -> Result<(u32, U256), Box> { - let seed_from_env = std::env::var("SEED").unwrap_or(DEFAULT_SEED.to_string()); - let seed: u32 = try_from_hex_to_u32(&seed_from_env)?; - let iterations_from_env = std::env::var("ITERATIONS").unwrap_or(DEFAULT_ITERATIONS.to_string()); - let iterations = U256::from_str(&iterations_from_env)?; - Ok((seed, iterations)) -} - -fn try_from_hex_to_u32(hex: &str) -> eyre::Result { - let trimmed = hex.strip_prefix("0x").unwrap_or(hex); - u32::from_str_radix(trimmed, 16).map_err(|e| eyre::eyre!("Failed to parse hex: {}", e)) -} - -fn insert_account_info(cache_db: &mut CacheDB, addr: Address, code: Bytes) { - let code_hash = hex::encode(keccak256(code.clone())); - let account_info = AccountInfo::new( - U256::from(0), - 0, - B256::from_str(&code_hash).unwrap(), - Bytecode::new_raw(code), - ); - cache_db.insert_account_info(addr, account_info); -} - -fn init_db() -> CacheDB { - let mut cache_db = CacheDB::new(EmptyDB::default()); - - insert_account_info( - &mut cache_db, - BURNTPIX_ADDRESS_ONE, - BURNTPIX_BYTECODE_ONE.clone(), - ); - insert_account_info( - &mut cache_db, - BURNTPIX_MAIN_ADDRESS, - BURNTPIX_BYTECODE_TWO.clone(), - ); - insert_account_info( - &mut cache_db, - BURNTPIX_ADDRESS_TWO, - BURNTPIX_BYTECODE_THREE.clone(), - ); - insert_account_info( - &mut cache_db, - BURNTPIX_ADDRESS_THREE, - BURNTPIX_BYTECODE_FOUR.clone(), - ); - - cache_db - .insert_account_storage( - BURNTPIX_MAIN_ADDRESS, - U256::from(0), - U256::from_be_bytes(*STORAGE_ZERO), - ) - .unwrap(); - - cache_db - .insert_account_storage( - BURNTPIX_MAIN_ADDRESS, - U256::from(1), - U256::from_be_bytes(*STORAGE_ONE), - ) - .unwrap(); - - cache_db - .insert_account_storage( - BURNTPIX_MAIN_ADDRESS, - U256::from(2), - U256::from_be_bytes(*STORAGE_TWO), - ) - .unwrap(); - - cache_db -} diff --git a/bins/revm-test/src/bin/burntpix/static_data.rs b/bins/revm-test/src/bin/burntpix/static_data.rs deleted file mode 100644 index 3f2a995045..0000000000 --- a/bins/revm-test/src/bin/burntpix/static_data.rs +++ /dev/null @@ -1,21 +0,0 @@ -use revm::primitives::{address, bytes, fixed_bytes, Address, Bytes, FixedBytes}; - -pub const BURNTPIX_MAIN_ADDRESS: Address = address!("49206861766520746f6f206d7563682074696d65"); -pub const BURNTPIX_ADDRESS_ONE: Address = address!("0a743ba7304efcc9e384ece9be7631e2470e401e"); -pub const BURNTPIX_ADDRESS_TWO: Address = address!("c917e98213a05d271adc5d93d2fee6c1f1006f75"); -pub const BURNTPIX_ADDRESS_THREE: Address = address!("f529c70db0800449ebd81fbc6e4221523a989f05"); - -pub const STORAGE_ZERO: FixedBytes<32> = - fixed_bytes!("000000000000000000000000f529c70db0800449ebd81fbc6e4221523a989f05"); -pub const STORAGE_ONE: FixedBytes<32> = - fixed_bytes!("0000000000000000000000000a743ba7304efcc9e384ece9be7631e2470e401e"); -pub const STORAGE_TWO: FixedBytes<32> = - fixed_bytes!("000000000000000000000000c917e98213a05d271adc5d93d2fee6c1f1006f75"); - -pub static BURNTPIX_BYTECODE_ONE: Bytes = bytes!("60806040526004361015610011575f80fd5b5f3560e01c63d85fe4b414610024575f80fd5b346100925760603660031901126100925767ffffffffffffffff60043581811161009257366023820112156100925780600401359182116100925736602483830101116100925761008e9161008291604435916024803592016103ee565b604051918291826100b7565b0390f35b5f80fd5b5f5b8381106100a75750505f910152565b8181015183820152602001610098565b604091602082526100d78151809281602086015260208686019101610096565b601f01601f1916010190565b634e487b7160e01b5f52604160045260245ffd5b6040810190811067ffffffffffffffff82111761011357604052565b6100e3565b90601f8019910116810190811067ffffffffffffffff82111761011357604052565b67ffffffffffffffff811161011357601f01601f191660200190565b60405190610163826100f7565b60208083523683820137565b906101798261013a565b6101866040519182610118565b8281528092610197601f199161013a565b0190602036910137565b604051906060820182811067ffffffffffffffff82111761011357604052603c82527f74683d22313522206865696768743d223135222072783d2232222f3e000000006040837f3c726563742069643d22702220783d222d31352220793d222d3135222077696460208201520152565b9061022460209282815194859201610096565b0190565b60206102699193929360405194816102498793518092868087019101610096565b820161025d82518093868085019101610096565b01038085520183610118565b565b60405190610278826100f7565b601082526f181899199a1a9b1b9c1cb0b131b232b360811b6020830152565b634e487b7160e01b5f52603260045260245ffd5b908210156102b7570190565b610297565b9081518110156102b7570160200190565b9693909897949195929560405199888b9951908160208c0191602001916102f392610096565b8901711e3ab9b290343932b31e9111b811103c1e9160711b60208201528151918260328301916020019161032692610096565b016411103c9e9160d91b603282015260370161034191610211565b68222066696c6c3d222360b81b8152956001600160f81b03191660098701526001600160f81b031916600a8601526001600160f81b031916600b8501526001600160f81b031916600c8401526001600160f81b031916600d8301526001600160f81b031916600e8201526211179f60e91b600f82015203600d19810183526012016102699083610118565b604051906103d9826100f7565b60068252651e17b9bb339f60d11b6020830152565b91909161040361011c6036868502020161016f565b9361042b61042261041483866105a2565b61041c6101a1565b90610228565b602087016106fd565b93909461043661026b565b5f94859160105b86881061047957505050505050505061047692916104606104669261041c6103cc565b906106fd565b90829003601f1901825290610228565b90565b5f60105b87821061049457505060106001910197019661043d565b949a90998b6104a48189886102ab565b3560f81c6104b6600183018a896102ab565b3560f81c916104c9906002018a896102ab565b3560f81c906104d78961079c565b926104e18761079c565b600492600f91826104f683871c82168d6102bc565b516001600160f81b031916921661050d908c6102bc565b516001600160f81b0319169280878d8261052b898b1c8216836102bc565b516001600160f81b0319169816610541916102bc565b516001600160f81b031916971c16610559908d6102bc565b516001600160f81b0319169616610570908c6102bc565b516001600160f81b03191696610585986102cd565b61058e916106fd565b99909a60030194601001906001019061047d565b601960016104769260041b01926106cb60016105bd8661079c565b9260041b01600a6106b66105e26105dc6105d68561079c565b9961079c565b9361079c565b92607f604051998a977f3c73766720786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323060208a01527f30302f737667222076657273696f6e3d22312e31222076696577426f783d223060408a01526201018160ed1b60608a015261065781518092602060638d019101610096565b8801600160fd1b6063820152610677825180936020606485019101610096565b0161111f60f11b60648201526106af606682017f3c7265637420783d22302220793d2230222077696474683d22000000000000009052565b0190610211565b6911103432b4b3b43a1e9160b11b81526106af565b7f222072783d2233222066696c6c3d2223323032303230222f3e00000000000000815203600619810184520182610118565b91909160208084018451918260051c905f5b82811061076b5750505050601f1916808451039061072c8261016f565b945f5b83811061073e57505050509190565b6001906001600160f81b0319610756858301856102bc565b51165f1a610764828a6102bc565b530161072f565b83518652948101949281019260010161070f565b6040519061078c826100f7565b60018252600360fc1b6020830152565b8015610832576107aa610156565b90805f915b61080357506107bd8161016f565b915f5b8281106107cd5750505090565b6001906107f06107e28286035f1901856102bc565b516001600160f81b03191690565b5f1a6107fc82876102bc565b53016107c0565b90600a80830692048161082c6001839492019460ff60f81b9060300160f81b165f1a91866102bc565b536107af565b5061047661077f56fea26469706673582212202620cded94f0cf54cc3df219c4b7a2d33ca1cff9b87da504fdd707bc8b7d38e464736f6c63430008170033"); - -pub static BURNTPIX_BYTECODE_TWO: Bytes = bytes!("608060408181526004918236101562000016575f80fd5b5f925f3560e01c91826318a87fb6146200051a575081638c72c54e14620004f0578163a4de9ab4146200007f575063ab5fb7961462000053575f80fd5b346200007b57816003193601126200007b57905490516001600160a01b039091168152602090f35b5080fd5b828434620004d05781600319360112620004d05782359063ffffffff8216809203620004d0576024908351946103f19586810167ffffffffffffffff9782821089831117620004de57908291620005af833903905ff0918215620004d4575f546001600160a01b0393841695908416863b15620004d0578751906302b41d8760e51b8252848201525f818781838b5af18015620004c657620004b0575b508360015416863b15620003665787519063218d3ebf60e01b82528482015282818781838b5af18015620003925790839162000498575b50508360025416863b156200036657875190632b18342560e01b82528482015282818781838b5af18015620003925790839162000480575b505086516151df808201908282108b831117620004485789918391620009a083398581526020998a82015203019083f080156200047657841690813b15620003665787519063d35e29d760e01b8252338583015286820152828160448183865af1801562000392579083916200045e575b505086516351d930f960e11b8152338482015282818781855afa90811562000392578391620003ae575b508051156200039c5786015190803b15620003665782809160448a518094819363ea25558360e01b8352878a8401528b358c8401525af1801562000392579083916200037a575b5090838851809681936303cf32ab60e61b8352165afa9384156200036e578194620002c3575b8651868152855181880181905288908290620002b5818385018b8d016200053f565b601f01601f19168101030190f35b90919293503d8083863e620002d981866200058b565b840193858186031262000366578051908882116200036a57019284601f85011215620003665783519788116200035557505084519262000323601f8801601f19168601856200058b565b868452848784010111620003525750620002b59462000348918480850191016200053f565b8480808062000293565b80fd5b634e487b7160e01b83526041905281fd5b8280fd5b8380fd5b508551903d90823e3d90fd5b620003859062000562565b6200007b5781896200026d565b88513d85823e3d90fd5b634e487b7160e01b8352603284528583fd5b90503d8084833e620003c181836200058b565b81019087818303126200036a578051908a82116200045a57019080601f830112156200036a578151918a831162000448578260051b908a5193620004088b8401866200058b565b84528980850192820101928311620004445789809101915b8383106200043357505050508962000226565b82518152918101918a910162000420565b8580fd5b634e487b7160e01b8552604186528785fd5b8480fd5b620004699062000562565b6200007b578189620001fc565b87513d84823e3d90fd5b6200048b9062000562565b6200007b5781896200018b565b620004a39062000562565b6200007b57818962000153565b620004bd91925062000562565b5f90886200011c565b88513d5f823e3d90fd5b5f80fd5b85513d5f823e3d90fd5b85604185634e487b7160e01b5f52525ffd5b8234620004d0575f366003190112620004d05760025490516001600160a01b039091168152602090f35b34620004d0575f366003190112620004d0576001546001600160a01b03168152602090f35b5f5b838110620005515750505f910152565b818101518382015260200162000541565b67ffffffffffffffff81116200057757604052565b634e487b7160e01b5f52604160045260245ffd5b90601f8019910116810190811067ffffffffffffffff821117620005775760405256fe6080806040523461005a575f8054336001600160a01b0319821681178355916001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a3610392908161005f8239f35b5f80fdfe60808060405260049081361015610014575f80fd5b5f3560e01c90816318a87fb6146102e257508063218d3ebf1461029e5780632b1834251461025a5780635683b0e014610216578063715018a6146101bf5780638c72c54e146101975780638da5cb5b14610170578063ab5fb796146101485763f2fde38b14610081575f80fd5b34610144576020366003190112610144576001600160a01b0381358181169290839003610144576100b0610305565b82156100f157505f54826001600160601b0360a01b8216175f55167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3005b60849060206040519162461bcd60e51b8352820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152fd5b5f80fd5b34610144575f366003190112610144576001546040516001600160a01b039091168152602090f35b34610144575f366003190112610144575f546040516001600160a01b039091168152602090f35b34610144575f366003190112610144576003546040516001600160a01b039091168152602090f35b34610144575f366003190112610144576101d7610305565b5f80546001600160a01b0319811682556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b503461014457602036600319011261014457356001600160a01b0381169081900361014457610243610305565b6001600160601b0360a01b60015416176001555f80f35b503461014457602036600319011261014457356001600160a01b0381169081900361014457610287610305565b6001600160601b0360a01b60035416176003555f80f35b503461014457602036600319011261014457356001600160a01b03811690819003610144576102cb610305565b6001600160601b0360a01b60025416176002555f80f35b34610144575f366003190112610144576002546001600160a01b03168152602090f35b5f546001600160a01b0316330361031857565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fdfea2646970667358221220fe8ff964d09f9b014997308dd60006e6d4f5b368483a50e476a998f6c718631b64736f6c634300081700336080346200100457601f620051df38819003918201601f19168301916001600160401b038311848410176200100857808492604094855283398101031262001004576200005a6020620000528362001038565b920162001038565b90604051916200006a836200101c565b6009835268084eae4dce840a0d2f60bb1b60208401526040516200008e816200101c565b60049384825263084a092b60e31b6020830152331562000ff3575f546001600160a01b0381163381900362000fb6575b5050604051620000ce816200101c565b858152632936598960e21b60208201527feafec4d89fa9619884b60000a4d96624a38f7ac2d8d9a604ecf07c12c77e480c90815f52600160205260405f20815160018060401b03811162000fa3578154600181811c9116801562000f98575b602082101462000f8557601f811162000f3b575b506020601f821160011462000eda5791815f80516020620051bf833981519152949262000190945f91620008a7575b508160011b915f199060031b1c19161790555b604051918291826200104d565b0390a25f805160206200511f8339815191525f52600160205280517f2a367ae1ac46d529739aa27ac74856f860e70af05d3642d18ba60fd5d32a069a906001600160401b03811162000ec7578154600181811c9116801562000ebc575b602082101462000ea957601f811162000e5f575b506020601f821160011462000ded57925f80516020620051bf83398151915292826200025d935f805160206200511f833981519152965f91620008a757508160011b915f199060031b1c1916179055604051918291826200104d565b0390a25f805160206200517f8339815191525f52600160205280517f83b322886c7b7e25779e5d38e06e005c9e7aba1e1267ce9210cf24e31833535a906001600160401b03811162000c50578154600181811c9116801562000de2575b602082101462000c3257601f811162000d98575b506020601f821160011462000d2657925f80516020620051bf83398151915292826200032a935f805160206200517f833981519152965f91620008a757508160011b915f199060031b1c1916179055604051918291826200104d565b0390a2604051600260208201526020815262000346816200101c565b5f805160206200513f8339815191525f52600160205280517ff73b01b344a9bb3b96525b0cb731f6b14cde20ce6cecea8459266944490b411f906001600160401b03811162000c50578154600181811c9116801562000d1b575b602082101462000c3257601f811162000cd5575b506020601f821160011462000c6357925f80516020620051bf833981519152928262000410935f805160206200513f833981519152965f91620008a757508160011b915f199060031b1c1916179055604051918291826200104d565b0390a260405160026020820152602081526200042c816200101c565b5f805160206200515f8339815191525f52600160205280517f01f5eb934e794ddcc86b89a579078013860f8fe92140885511742594f219ad0b906001600160401b03811162000c50578154600181811c9116801562000c45575b602082101462000c3257601f811162000bec575b506020601f821160011462000b7a57925f80516020620051bf8339815191529282620004f6935f805160206200515f833981519152965f91620008a757508160011b915f199060031b1c1916179055604051918291826200104d565b0390a260098054610100600160a81b03191660089290921b610100600160a81b03169190911790556040516200052c816200101c565b60108152600160801b6020808301919091525f805160206200519f8339815191525f526001905280517fde5f0adbf2cf136848982dd95860bdc3e6d8709a8a51ce1295c645c6da617db7906001600160401b03811162000aa4578154600181811c9116801562000b6f575b602082101462000a8657601f811162000b29575b506020601f821160011462000ab757925f80516020620051bf833981519152928262000607935f805160206200519f833981519152965f91620008a757508160011b915f199060031b1c1916179055604051918291826200104d565b0390a2604051606082901b6001600160601b03191660208201526014815262000630816200101c565b6f0452f40ece91b521d65a03607aecad0560821b5f52600160205280517fadf994b8d5b80a46660e628eabff2156c328d301fe5ea8e44cf09dee1b43e512906001600160401b03811162000aa4578154600181811c9116801562000a99575b602082101462000a8657601f811162000a40575b50806020601f8211600114620009d8575f91620009cc575b508160011b915f199060031b1c19161790555b5f80516020620051bf83398151915260405180620007016f0452f40ece91b521d65a03607aecad0560821b94826200104d565b0390a260405169036f42f57aecc15a72ed60b51b60208083019182525f602a84015260609390931b6001600160601b031916602c83015291815262000746816200101c565b5190519060208110620009ba575b5060405162000763816200101c565b601481526324871b3d60e01b60208201525f805160206200515f8339815191528214620009a9575f805160206200511f8339815191528203620007b1576040516385c169bd60e01b81528390fd5b5f805160206200517f8339815191528203620007d857604051630eceab6760e31b81528390fd5b5f805160206200513f8339815191528203620007ff57604051634ef6d7fb60e01b81528390fd5b5f8281526001602052604090208151936001600160401b0385116200099657815490600182811c921680156200098b575b6020831014620009785750601f81116200092e575b50602093601f8111600114620008b35790816200089493925f80516020620051bf83398151915295965f91620008a757508160011b915f199060031b1c1916179055604051918291826200104d565b0390a26040516140889081620010978239f35b90508301515f62000170565b601f198116825f5260205f20905f5b818110620009155750916001915f80516020620051bf8339815191529697826200089497969510620008fc575b5050811b01905562000183565b8501515f1960f88460031b161c191690555f80620008ef565b85880151835560209788019760019093019201620008c2565b815f5260205f20601f860160051c810191602087106200096d575b601f0160051c01905b81811062000961575062000845565b5f815560010162000952565b909150819062000949565b602290634e487b7160e01b5f525260245ffd5b91607f169162000830565b604190634e487b7160e01b5f525260245ffd5b604051631b32400560e11b81528390fd5b5f199060200360031b1b165f62000754565b90508301515f620006bb565b9150825f5260205f205f925b601f198316841062000a27576001935082601f1981161062000a0e575b5050811b019055620006ce565b8501515f1960f88460031b161c191690555f8062000a01565b85810151825560209384019360019092019101620009e4565b825f5260205f20601f830160051c81016020841062000a7e575b601f830160051c8201811062000a72575050620006a3565b5f815560010162000a5a565b508062000a5a565b602286634e487b7160e01b5f525260245ffd5b90607f16906200068f565b604185634e487b7160e01b5f525260245ffd5b825f5260205f20905f5b601f198416811062000b105750926001835f805160206200519f83398151915296935f80516020620051bf833981519152966200060796601f19811610620008fc575050811b01905562000183565b9091602060018192858901518155019301910162000ac1565b825f5260205f20601f830160051c81016020841062000b67575b601f830160051c8201811062000b5b575050620005ab565b5f815560010162000b43565b508062000b43565b90607f169062000597565b825f5260205f20905f5b601f198416811062000bd35750926001835f805160206200515f83398151915296935f80516020620051bf83398151915296620004f696601f19811610620008fc575050811b01905562000183565b9091602060018192858901518155019301910162000b84565b825f5260205f20601f830160051c81016020841062000c2a575b601f830160051c8201811062000c1e5750506200049a565b5f815560010162000c06565b508062000c06565b602287634e487b7160e01b5f525260245ffd5b90607f169062000486565b604186634e487b7160e01b5f525260245ffd5b825f5260205f20905f5b601f198416811062000cbc5750926001835f805160206200513f83398151915296935f80516020620051bf833981519152966200041096601f19811610620008fc575050811b01905562000183565b9091602060018192858901518155019301910162000c6d565b825f5260205f20601f830160051c81016020841062000d13575b601f830160051c8201811062000d07575050620003b4565b5f815560010162000cef565b508062000cef565b90607f1690620003a0565b825f5260205f20905f5b601f198416811062000d7f5750926001835f805160206200517f83398151915296935f80516020620051bf833981519152966200032a96601f19811610620008fc575050811b01905562000183565b9091602060018192858901518155019301910162000d30565b825f5260205f20601f830160051c8101916020841062000dd7575b601f0160051c01905b81811062000dcb5750620002ce565b5f815560010162000dbc565b909150819062000db3565b90607f1690620002ba565b825f5260205f20905f5b601f198416811062000e465750926001835f805160206200511f83398151915296935f80516020620051bf833981519152966200025d96601f19811610620008fc575050811b01905562000183565b9091602060018192858901518155019301910162000df7565b825f5260205f20601f830160051c8101916020841062000e9e575b601f0160051c01905b81811062000e92575062000201565b5f815560010162000e83565b909150819062000e7a565b602288634e487b7160e01b5f525260245ffd5b90607f1690620001ed565b604187634e487b7160e01b5f525260245ffd5b601f19821690835f5260205f20915f5b81811062000f22575092620001909492600192825f80516020620051bf833981519152989610620008fc575050811b01905562000183565b9192602060018192868a01518155019401920162000eea565b825f5260205f20601f830160051c8101916020841062000f7a575b601f0160051c01905b81811062000f6e575062000141565b5f815560010162000f5f565b909150819062000f56565b60228a634e487b7160e01b5f525260245ffd5b90607f16906200012d565b604189634e487b7160e01b5f525260245ffd5b33907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a36001600160a01b03191633175f90815580620000be565b6040516306b620db60e21b81528590fd5b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b604081019081106001600160401b038211176200100857604052565b51906001600160a01b03821682036200100457565b602080825282518183018190529093925f5b8281106200108157505060409293505f838284010152601f8019910116010190565b8181018601518482016040015285016200105f56fe608060405260043610156200002f575b361562000029576200002136620020df565b602081519101f35b620020a1565b5f3560e01c806301ffc9a7146200027f57806302329a29146200027957806316e023b3146200027357806318160ddd146200026d5780631d26fce61462000267578063217b227014620002615780632a3654a4146200025b578063382bf015146200025557806340339a1e146200024f57806348d0528a146200024957806349a6078d1462000243578063511b6952146200023d57806354f6127f14620002375780635c975abb14620002315780636963d438146200022b57806370a082311462000225578063715018a6146200021f578063723a213014620002195780637e87632c14620002135780637f23690c146200020d57806386a10ddd14620002075780638da5cb5b146200020157806392a91a3a14620001fb5780639790242114620001f5578063a3b261f214620001ef578063be9f0e6f14620001e9578063c9d658f014620001e3578063d35e29d714620001dd578063d6c1407c14620001d7578063db8c966314620001d1578063dedff9c614620001cb578063ea25558314620001c55763f2fde38b036200000f5762001715565b620016f2565b62001659565b62001579565b6200152a565b62001405565b620012f5565b620011ec565b62001180565b620010a9565b6200107d565b62001054565b62000eca565b62000e6b565b62000dbf565b62000c20565b62000bbc565b62000b80565b62000b11565b62000aed565b62000ac9565b62000a63565b62000974565b620008ec565b620008a9565b62000776565b62000720565b620006a7565b620005e2565b62000438565b620003f1565b62000354565b346200034057602036600319011262000340576004356001600160e01b031981168082036200034057620002dc91631d138b8360e11b8214918215620002f3575b508115620002e0575b5060405190151581529081906020820190565b0390f35b620002ec91506200212c565b5f620002c9565b90915063a918fa6b60e01b811490811562000312575b50905f620002c0565b6318a6a9a560e21b8114915081156200032e575b505f62000309565b6301ffc9a760e01b1490505f62000326565b5f80fd5b6044359081151582036200034057565b3462000340576020366003190112620003405760043580151580910362000340576200037f620021e6565b60ff8019600954169116176009555f80f35b5f5b838110620003a35750505f910152565b818101518382015260200162000393565b90602091620003cf8151809281855285808601910162000391565b601f01601f1916010190565b906020620003ee928181520190620003b4565b90565b34620003405760403660031901126200034057620002dc620004186024356004356200227a565b604051918291602083526020830190620003b4565b5f9103126200034057565b3462000340575f36600319011262000340576020600254604051908152f35b634e487b7160e01b5f52604160045260245ffd5b6001600160401b0381116200047f57604052565b62000457565b602081019081106001600160401b038211176200047f57604052565b604081019081106001600160401b038211176200047f57604052565b606081019081106001600160401b038211176200047f57604052565b90601f801991011681019081106001600160401b038211176200047f57604052565b6001600160401b0381116200047f5760051b60200190565b9080601f83011215620003405760209082356200053081620004fb565b93620005406040519586620004d9565b81855260208086019260051b8201019283116200034057602001905b8282106200056b575050505090565b813581529083019083016200055c565b6020808201906020835283518092526040830192602060408460051b8301019501935f915b848310620005b15750505050505090565b9091929394958480620005d1600193603f198682030187528a51620003b4565b9801930193019194939290620005a0565b346200034057604036600319011262000340576001600160401b0360043581811162000340576200061890369060040162000513565b9060243590811162000340576200063490369060040162000513565b90620006418151620017a5565b915f5b82518110156200069757806200067662000661600193866200180a565b516200066e83866200180a565b51906200227a565b6200068282876200180a565b526200068f81866200180a565b500162000644565b60405180620002dc86826200057b565b346200034057602036600319011262000340576020620006c960043562001825565b6040516001600160a01b039091168152f35b600435906001600160a01b03821682036200034057565b604435906001600160a01b03821682036200034057565b602435906001600160a01b03821682036200034057565b3462000340576040366003190112620003405760206200075862000743620006db565b602435906200075282620022f7565b62002317565b6040519015158152f35b6024359063ffffffff821682036200034057565b3462000340576060366003190112620003405762000793620006db565b6200079d62000762565b90620007a8620006f2565b90620007b3620021e6565b600160ff60095416151503620003405763ffffffff8084165f908152600b6020526040902054620008a7946001600160a01b039262000894926200082a91906200080490869081165b161562001868565b6001600160a01b0387165f908152600c602052604090205463ffffffff161615620018b5565b6200086785620008488363ffffffff165f52600b60205260405f2090565b80546001600160a01b0319166001600160a01b03909216919091179055565b6001600160a01b0385165f908152600c602052604090205b9063ffffffff1663ffffffff19825416179055565b6200089e62001902565b921690620024a0565b005b3462000340576020366003190112620003405760043563ffffffff811680910362000340575f52600b602052602060018060a01b0360405f205416604051908152f35b346200034057602036600319011262000340576001600160a01b0362000911620006db565b165f52600c602052602063ffffffff60405f205416604051908152f35b60209060206040818301928281528551809452019301915f5b82811062000956575050505090565b83516001600160a01b03168552938101939281019260010162000947565b34620003405760208060031936011262000340576004356200099681620022f7565b5f52600560205260405f20906040519081602084549182815201935f5260205f20915f905b828210620009e357620002dc85620009d681890382620004d9565b604051918291826200092e565b835486529485019460019384019390910190620009bb565b6001600160401b0381116200047f57601f01601f191660200190565b81601f82011215620003405780359062000a3182620009fb565b9262000a416040519485620004d9565b828452602083830101116200034057815f926020809301838601378301015290565b34620003405760a0366003190112620003405762000a80620006db565b62000a8a62000709565b60643580151581036200034057608435926001600160401b038411620003405762000abe620008a794369060040162000a17565b926044359162001916565b34620003405760203660031901126200034057620002dc62000418600435620025a7565b3462000340575f3660031901126200034057602060ff600954166040519015158152f35b346200034057602036600319011262000340576001600160401b036004358181116200034057366023820112156200034057806004013591821162000340573660248360051b830101116200034057620002dc91602462000b73920162001b50565b604051918291826200057b565b346200034057602036600319011262000340576001600160a01b0362000ba5620006db565b165f526004602052602060405f2054604051908152f35b3462000340575f366003190112620003405762000bd8620021e6565b5f546001600160a01b0381168062000bec57005b5f907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a36001600160a01b0319165f55005b3462000340575f3660031901126200034057600a546040516001600160a01b039091168152602090f35b9080601f830112156200034057602090823562000c6781620004fb565b9362000c776040519586620004d9565b81855260208086019260051b8201019283116200034057602001905b82821062000ca2575050505090565b81356001600160a01b03811681036200034057815290830190830162000c93565b9080601f830112156200034057602090823562000ce081620004fb565b9362000cf06040519586620004d9565b81855260208086019260051b8201019283116200034057602001905b82821062000d1b575050505090565b813580151581036200034057815290830190830162000d0c565b81601f82011215620003405780359160209162000d5284620004fb565b9362000d626040519586620004d9565b808552838086019160051b830101928084116200034057848301915b84831062000d8f5750505050505090565b82356001600160401b0381116200034057869162000db38484809489010162000a17565b81520192019162000d7e565b34620003405760a0366003190112620003405760046001600160401b038135818111620003405762000df5903690840162000c4a565b90602435818111620003405762000e10903690850162000c4a565b604435828111620003405762000e2a903690860162000513565b90606435838111620003405762000e45903690870162000cc3565b926084359081116200034057620008a79562000e649136910162000d35565b9362001bfa565b604036600319011262000340576024356001600160401b038111620003405762000e9a90369060040162000a17565b62000ea4620021e6565b3462000eb857620008a790600435620026e3565b60405163f36ba73760e01b8152600490fd5b3462000340576060366003190112620003405762000ee7620006db565b602435906044356001600160401b038111620003405762000f0d90369060040162000a17565b9062000f198362001825565b6001600160a01b0381811691338303620010245750821680156200101257808214620010005762000f6562000f618462000f5b885f52600560205260405f2090565b62002822565b1590565b62000fd457938062000fce92620008a7967f1b1b58aa2ec0cec2228b2d37124556d41f5a1f7b12f089171f896cc2366712156040518062000fa78a82620003db565b0390a462000fbf604051948592336020850162001ce1565b03601f198101845283620004d9565b62003340565b6040516314ec4d6d60e31b81526001600160a01b038416600482015260248101869052604490fd5b0390fd5b6040516344fed6b160e11b8152600490fd5b604051639577b8b360e01b8152600490fd5b604051632d938f5160e11b81526001600160a01b0391909116600482015260248101869052336044820152606490fd5b3462000340575f36600319011262000340575f546040516001600160a01b039091168152602090f35b346200034057602036600319011262000340576004355f526007602052602060405f2054604051908152f35b6040366003190112620003405760046001600160401b0381358181116200034057620010d9903690840162000513565b906024359081116200034057620010f4903690840162000d35565b91620010ff620021e6565b346200117157815183510362001162578151156200115357505f5b8151811015620008a757806200114c62001137600193856200180a565b516200114483876200180a565b5190620026e3565b016200111a565b6040516397da5f9560e01b8152fd5b604051633bcc897960e01b8152fd5b60405163f36ba73760e01b8152fd5b3462000340576020806003193601126200034057620011a8620011a2620006db565b62001d3a565b90604051918183928301818452825180915281604085019301915f5b828110620011d457505050500390f35b835185528695509381019392810192600101620011c4565b3462000340576060366003190112620003405760046001600160401b038135818111620003405762001222903690840162000513565b60243582811162000340576200123c903690850162000513565b91604435908111620003405762001257903690850162000d35565b9262001262620021e6565b8151835180911490811591620012e8575b50620012d957815115620012ca57505f5b8151811015620008a75780620012c3620012a1600193856200180a565b51620012ae83876200180a565b51620012bb84896200180a565b5191620029bd565b0162001284565b6040516380c9830560e01b8152fd5b6040516317d38eff60e11b8152fd5b9050845114155f62001273565b3462000340576060366003190112620003405762001312620006db565b6200131c62000709565b906200138d6200132b620006f2565b9262001336620021e6565b6200135260016200134960095460ff1690565b15151462001860565b60018060a01b0380931692806200138262001375865f52600360205260405f2090565b546001600160a01b031690565b921691161462001860565b803b15620003405760405163ce5494bb60e01b81526001600160a01b039290921660048301525f8260248183855af1918215620013ff57620008a792620013e1575b50620013da62001902565b9062002b3b565b80620013f1620013f8926200046b565b806200042d565b5f620013cf565b62001d9f565b3462000340576040366003190112620003405762001422620006db565b6200142c62000762565b90600954916200144060ff84161562001860565b60018060a01b03926200146a84620007fc620013758563ffffffff165f52600b60205260405f2090565b60405190610b25808301918383106001600160401b038411176200047f578392620014c7926200352e853960089190911c87166001600160a01b0316815263ffffffff851660208201526040808201819052606082015260800190565b03905ff08015620013ff57620008a79362001519911691620014fc83620008488363ffffffff165f52600b60205260405f2090565b6001600160a01b0383165f908152600c602052604090206200087f565b6200152362001902565b91620024a0565b346200034057606036600319011262000340576044356001600160401b038111620003405762001563620008a791369060040162000a17565b6200156d620021e6565b602435600435620029bd565b3462000340576080366003190112620003405762001596620006db565b60243590620015a462000344565b906064356001600160401b0381116200034057620015c790369060040162000a17565b91620015d38462001825565b6001600160a01b03818116903382036200162b578416908115620010125714620010005783828662001606938662002ce4565b6200160d57005b62000fce620008a79362000fbf604051948592336020850162001d0e565b604051632d938f5160e11b81526001600160a01b038416600482015260248101889052336044820152606490fd5b346200034057602036600319011262000340576004356001600160401b03811162000340576200168e90369060040162000513565b6200169a8151620017a5565b905f5b8151811015620016e25780620016c1620016ba600193856200180a565b51620025a7565b620016cd82866200180a565b52620016da81856200180a565b50016200169d565b60405180620002dc85826200057b565b34620003405760403660031901126200034057620008a760243560043562001e28565b3462000340576020366003190112620003405762001732620006db565b6200173c620021e6565b6001600160a01b0390811690811562001793575f549081168083036200175e57005b82907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a36001600160a01b031916175f55005b6040516306b620db60e21b8152600490fd5b90620017b182620004fb565b620017c06040519182620004d9565b8281528092620017d3601f1991620004fb565b01905f5b828110620017e457505050565b806060602080938501015201620017d7565b634e487b7160e01b5f52603260045260245ffd5b80518210156200181f5760209160051b010190565b620017f6565b5f818152600360205260409020546001600160a01b031690811562001848575090565b60249060405190635747cd1b60e11b82526004820152fd5b156200034057565b156200187057565b60405162461bcd60e51b815260206004820152601860248201527f616c7265616479206f776e656420627920736f6d656f6e6500000000000000006044820152606490fd5b15620018bd57565b60405162461bcd60e51b815260206004820152601b60248201527f616c726561647920696e6a656374656420746f20736f6d656f6e6500000000006044820152606490fd5b60405190620019118262000485565b5f8252565b9392919262001926843362002317565b1562001aab576001600160a01b0382811695808216929183881462001a995783620019518862001825565b9182160362001a695750861562001a575762001a49868062001a559962001a4f966200198362000fbf9b8a8862002fbe565b6200198e8362001825565b506200199b838762003142565b6001600160a01b0386165f908152600460205260409020620019bf90849062003473565b506001600160a01b0389165f908152600460205260409020620019e4908490620032d3565b50620019fd8962000848855f52600360205260405f2090565b6040517fb333c813a7426a7a11e2b190cad52c44119421594b47f6f32ace6d8c7207b2bf908062001a318a8e3384620023c6565b0390a460405197889485928886336020870162002464565b620033a8565b620030b0565b565b6040516324ecef4d60e01b8152600490fd5b604051632d938f5160e11b81526001600160a01b0391821660048201526024810188905291166044820152606490fd5b604051635d67d6c160e01b8152600490fd5b604051631294d2a960e01b815260048101859052336024820152604490fd5b91908110156200181f5760051b81013590601e1981360301821215620003405701908135916001600160401b0383116200034057602001823603811362000340579190565b908092918237015f815290565b3d1562001b4b573d9062001b3082620009fb565b9162001b406040519384620004d9565b82523d5f602084013e565b606090565b91909162001b5e83620017a5565b925f5b81811062001b6e57505050565b5f8062001b7d83858762001aca565b6040939162001b9185518093819362001b0f565b0390305af49062001ba162001b1c565b911562001bce57509060019162001bb982886200180a565b5262001bc681876200180a565b500162001b61565b81519192911562001be157825160208401fd5b5163234eb81960e01b8152600481019190915260249150fd5b94939091928551938351851480159062001cd5575b801562001cc9575b801562001cbd575b62001cab575f5b85811062001c38575050505050509050565b8062001ca462001c5c62001c4f6001948c6200180a565b516001600160a01b031690565b62001c6c62001c4f848a6200180a565b62001c7884876200180a565b5162001c8f62001c89868a6200180a565b51151590565b9162001c9c868b6200180a565b519362001916565b0162001c26565b6040516393a8311960e01b8152600490fd5b50825185141562001c1f565b50815185141562001c17565b50805185141562001c0f565b620003ee939260809260018060a01b031682526020820152600160408201528160608201520190620003b4565b620003ee939260809260018060a01b0316825260208201525f60408201528160608201520190620003b4565b60018060a01b03165f526020600460205260405f209060405180928391602082549182815201915f5260205f20935f905b82821062001d8457505050620003ee92500382620004d9565b85548452600195860195879550938101939091019062001d6b565b6040513d5f823e3d90fd5b634e487b7160e01b5f52601160045260245ffd5b5f1981019190821162001dcd57565b62001daa565b811562001dde570690565b634e487b7160e01b5f52601260045260245ffd5b908160011b918083046002149015171562001dcd57565b906063820180921162001dcd57565b9081602091031262000340575190565b5f8181526003602052604090205490919062001e4f906001600160a01b0316151562001860565b6001600160a01b0382811692909190833b15620003405760405163116508a760e21b80825260048201849052915f82602481838a5af1908115620013ff5762001eac9262001375926200208a575b505f52600360205260405f2090565b5f546001600160a01b0316908480831691160362001fd5575b5050600a5462001ee691506001600160a01b03165b6001600160a01b031690565b161562001f5a576040516321ac695f60e11b808252602091908282600481875afa918215620013ff575f9262001fb1575b50600a54839062001f31906001600160a01b031662001eda565b9160046040518094819382525afa928315620013ff575f9362001f7b575b50501162001f5a5750565b600a80546001600160a01b0319166001600160a01b03909216919091179055565b62001fa0929350803d1062001fa9575b62001f978183620004d9565b81019062001e18565b905f8062001f4f565b503d62001f8b565b62001fcd919250833d851162001fa95762001f978183620004d9565b905f62001f17565b62001fe09062001d3a565b80511562001ec55762002036620020306200202962001eda62001eda62001eda62001c4f6200203d9762002022620020184362001dbe565b4082519062001dd3565b906200180a565b9462001df2565b62001e09565b6064900490565b823b1562000340576040519182526004820152905f908290602490829084905af18015620013ff5762002073575b808062001ec5565b80620013f162002083926200046b565b5f6200206b565b80620013f16200209a926200046b565b5f62001e9d565b3415620020ba576040516330fa4a2160e11b8152600490fd5b606460405163e5099ee360e01b815260206004820152600460248201525f6044820152fd5b60043610620020f357620003ee9062002db0565b6044604051809263e5099ee360e01b825260206004830152806024830152805f848401375f828201840152601f01601f19168101030190fd5b6200217862002172604051696773c5a04a6d4300884b60b11b60208201525f602a8201526301ffc9a760e01b602c820152602081526200216c81620004a1565b62003410565b6200322d565b805160148114159081620021db575b50620021b457620021989062002ea1565b60601c908115620021ae57620003ee9162002f39565b50505f90565b6040516342bfe79f60e01b81526020600482015290819062000ffc906024830190620003b4565b905015155f62002187565b5f546001600160a01b03163303620021fa57565b60405163bf1169c560e01b8152336004820152602490fd5b60208183031262000340578051906001600160401b03821162000340570181601f82011215620003405780516200224981620009fb565b92620022596040519485620004d9565b818452602082840101116200034057620003ee916020808501910162000391565b5f818152600360205260409020549091906001600160a01b03161562000340576040516354f6127f60e01b81526004810191909152905f90829060249082906001600160a01b03165afa908115620013ff575f91620022d7575090565b620003ee91503d805f833e620022ee8183620004d9565b81019062002212565b5f818152600360205260409020546001600160a01b031615620018485750565b6001600160a01b03806200232b8462001825565b1691169081149182156200233e57505090565b620003ee92505f52600560205260405f206001915f520160205260405f2054151590565b5f19811462001dcd5760010190565b6001600160a01b0390911681525f6020820152606060408201819052620003ee92910190620003b4565b6001600160a01b03909116815260016020820152606060408201819052620003ee92910190620003b4565b6001600160a01b0390911681529015156020820152606060408201819052620003ee92910190620003b4565b6001600160a01b0391821681525f602082015291166040820152606081019190915260a060808201819052620003ee92910190620003b4565b6001600160a01b039182168152911660208201525f6040820152606081019190915260a060808201819052620003ee92910190620003b4565b6001600160a01b03918216815291811660208301529091166040820152606081019190915260a060808201819052620003ee92910190620003b4565b909291906001600160a01b038116801562001a5757620024c1858362002f6c565b5f858152600360205260409020546001600160a01b03166200258e578462001a5594956200258892620024ff620024fa60025462002362565b600255565b6001600160a01b0385165f90815260046020526040902062002523908390620032d3565b506200253c8562000848845f52600360205260405f2090565b5f7fb333c813a7426a7a11e2b190cad52c44119421594b47f6f32ace6d8c7207b2bf604051806200256f8a33836200239b565b0390a462000fbf604051948592853360208601620023f2565b6200303f565b6040516334c7b51160e01b815260048101869052602490fd5b7f9afb95cacc9f95858ec44aa8c3b685511002e30ae54415823f406128b85b238e811462002684575f52600160206001815260405f206040519283915f91815491620025f38362002837565b80865292600181169081156200266057506001146200261e575b505050620003ee92500382620004d9565b5f90815285812095935091905b81831062002647575050620003ee93508201015f80806200260d565b855487840185015294850194869450918301916200262b565b92505050620003ee94925060ff191682840152151560051b8201015f80806200260d565b50600a546040516354f6127f60e01b81527fef285b02a4f711ad84793f73cc8ed6fea8af7013ece8132dacb7b33f6bce93da6004820152905f90829060249082906001600160a01b03165afa908115620013ff575f91620022d7575090565b907ff675e9361af1c1664c1868cfa3eb97672d6b1a513aa5b81dec34c9ee330e818d821462002810577fdeba1e292f8ba88238e10ab3c7f88bd4be4fac56cad5194b6ecceaf653468af1820362002746576040516385c169bd60e01b8152600490fd5b7f2f0a68ab07768e01943a599e73362a0e17a63a72e94dd2e384d2c1d4db93275682036200278057604051630eceab6760e31b8152600490fd5b7fe0261fa95db2eb3b5439bd033cda66d56b96f92f243a8228fd87550ed7bdfdb38203620027ba57604051634ef6d7fb60e01b8152600490fd5b6200280b81620027fe7fece574603820d07bc9b91f2a932baadf4628aabcb8afba49776529c14a6104b293620027f8865f52600160205260405f2090565b620028e4565b60405191829182620003db565b0390a2565b604051631b32400560e11b8152600490fd5b620003ee916001600160a01b031690620032d3565b90600182811c9216801562002867575b60208310146200285357565b634e487b7160e01b5f52602260045260245ffd5b91607f169162002847565b916200288c9183549060031b91821b915f19901b19161790565b9055565b601f82116200289e57505050565b5f5260205f20906020601f840160051c83019310620028d9575b601f0160051c01905b818110620028cd575050565b5f8155600101620028c1565b9091508190620028b8565b91909182516001600160401b0381116200047f57620029108162002909845462002837565b8462002890565b602080601f831160011462002951575081906200288c9394955f9262002945575b50508160011b915f199060031b1c19161790565b015190505f8062002931565b90601f1983169562002966855f5260205f2090565b925f905b888210620029a4575050836001959697106200298b575b505050811b019055565b01515f1960f88460031b161c191690555f808062002981565b806001859682949686015181550195019301906200296a565b9091604051602090602081019084825285604082015260408152620029e281620004bd565b5190205f5260018060205260405f20918351916001600160401b0383116200047f5762002a1c8362002a15865462002837565b8662002890565b602091601f841160011462002a965750509162002a76827fa6e4251f855f750545fe414f120db91c76b88def14d120969e5bb2d3f05debbb959362002a85955f9162002a8a575b508160011b915f199060031b1c19161790565b905560405191829182620003db565b0390a3565b90508401515f62002a63565b9190601f1984169062002aac865f5260205f2090565b935f915b83831062002b16575050509262002a859492600192827fa6e4251f855f750545fe414f120db91c76b88def14d120969e5bb2d3f05debbb98961062002afd575b5050811b019055620027fe565b8501515f1960f88460031b161c191690555f8062002af0565b88850151865594850194938101939181019162002ab0565b801562001dcd575f190190565b62001a5591906001600160a01b039062001a49908262002b5b8262001825565b161562002cb9575b5f62002ba162002b7560025462001dbe565b62002b88845f52600860205260405f2090565b5481811062002c76575b505f52600760205260405f2090565b555f81815260086020526040812055805f62002bbd8262001825565b9462002bcf620024fa60025462002b2e565b62002bdb838762003142565b6001600160a01b0386165f90815260046020526040902062002bff90849062003473565b5062002c2762002c17845f52600360205260405f2090565b80546001600160a01b0319169055565b7fb333c813a7426a7a11e2b190cad52c44119421594b47f6f32ace6d8c7207b2bf604051918716918062002c5d8a338362002371565b0390a462000fbf6040519485928533602086016200242b565b62002cb162002c8d835f52600760205260405f2090565b548062002ca2845f52600760205260405f2090565b555f52600860205260405f2090565b555f62002b92565b600254805f5260076020528160405f205562002cdd825f52600860205260405f2090565b5562002b63565b919392845f52600560205260405f209260018060a01b039062002d0b828216809662003473565b1562002d5d57509062002d587fc78cd419d6136f9f1c1c6aec1d3fae098cffaf8bc86314a8f2685e32fe574e3c9392604051938493151584526040602085015216956040830190620003b4565b0390a4565b6040516312a8c6a360e21b81526001600160a01b0391909116600482015260248101879052604490fd5b9060349391815f823701916bffffffffffffffffffffffff199060601b16825260148201520190565b63ffffffff60e01b5f35169062002df562002172604051696773c5a04a6d4300884b60b11b60208201525f602a82015284602c820152602081526200216c81620004a1565b80516014811415908162002e96575b50620021b45762002e159062002ea1565b60601c91821562002e7257505f91829160405162002e508162002e416020820194349033908762002d87565b03601f198101835282620004d9565b519134905af162002e6062001b1c565b901562002e6a5790565b602081519101fd5b60405163bb370b2b60e01b81526001600160e01b0319919091166004820152602490fd5b905015155f62002e04565b90602082519201516bffffffffffffffffffffffff1990818116936014811062002eca57505050565b60140360031b82901b16169150565b5f602091604051838101906301ffc9a760e01b8252631aed5a8560e21b60248201526024815262002f0a81620004bd565b5191617530fa5f513d8262002f2c575b508162002f25575090565b9050151590565b6020111591505f62002f1a565b5f90602092604051848101916301ffc9a760e01b835263ffffffff60e01b1660248201526024815262002f0a81620004bd565b600254805f5260076020528260405f205562002f90835f52600860205260405f2090565b556001600160a01b03161562002fa35750565b62002fbb5f918262002ca262002b7560025462001dbe565b55565b6001600160a01b03919082161562002fdb575b161562002fa35750565b600254805f5260076020528360405f205562002fff845f52600860205260405f2090565b5562002fd1565b906040620003ee927f0b084a55ebf70fd3c06fd755269dac2212c4d3f0f4d09079780bfa50c1b2984d81528160208201520190620003b4565b6200304a8162002ed9565b15620030ac57604051631aed5a8560e21b8152915f91839182908490829062003077906004830162003006565b03926001600160a01b03165af18015620013ff57620030935750565b620030a9903d805f833e620022ee8183620004d9565b50565b5050565b9190620030bd8362002ed9565b15620030e95750620030775f928392604051948580948193631aed5a8560e21b83526004830162003006565b905015620030f45750565b803b156200311f57604051634349776d60e01b81526001600160a01b03919091166004820152602490fd5b604051630317313760e01b81526001600160a01b03919091166004820152602490fd5b90805f526005906020926005602052604090815f20938454945f5b8681106200316f575050505050505050565b8154156200181f575f828152889020548551906001600160a01b0390811690620031998362000485565b5f8352885f52858b52620031b082895f2062003473565b1562003206579188917fc78cd419d6136f9f1c1c6aec1d3fae098cffaf8bc86314a8f2685e32fe574e3c898d620031fc6001989783519384935f85528401528c16958d830190620003b4565b0390a4016200315d565b87516312a8c6a360e21b81526001600160a01b0383166004820152602481018a9052604490fd5b5f52600160206001815260405f206040519283915f91815491620032518362002837565b80865292600181169081156200266057506001146200327b57505050620003ee92500382620004d9565b5f90815285812095935091905b818310620032a4575050620003ee93508201015f80806200260d565b8554878401850152948501948694509183019162003288565b80548210156200181f575f5260205f2001905f90565b5f828152600182016020526040902054620021ae57805490680100000000000000008210156200047f57826200332b62003315846001809601855584620032bd565b819391549060031b91821b915f19901b19161790565b90558054925f520160205260405f2055600190565b6200334b8162002ed9565b62003354575050565b620030775f92918392604051948580948193631aed5a8560e21b83527f8a1c15a8799f71b547e08e2bcb2e85257e81b0a07eee2ce6712549eef1f009706004840152604060248401526044830190620003b4565b620033b38162002ed9565b620033bc575050565b620030775f92918392604051948580948193631aed5a8560e21b83527fb23eae7e6d1564b295b4c3e3be402d9a2f0776c57bdf365903496f6fa481ab006004840152604060248401526044830190620003b4565b60208151910151906020811062003425575090565b5f199060200360031b1b1690565b80549081156200345f575f19918201916200344f8383620032bd565b909182549160031b1b1916905555565b634e487b7160e01b5f52603160045260245ffd5b6001810191805f528260205260405f2054928315155f1462003525575f19928484019085821162001dcd57805494850194851162001dcd575f958583620034c994620034d69803620034dc575b50505062003433565b905f5260205260405f2090565b55600190565b6200350d6200350691620034f56200351b9487620032bd565b90549060031b1c92839187620032bd565b9062002872565b85905f5260205260405f2090565b555f8080620034c0565b505050505f9056fe60806040908082523461011357608081610b2580380380916100218285610173565b8339810103126101135761003481610196565b60209160048382015192846060878501519401519160018060a01b03199033825f5416175f5560018060a01b0316809160015416176001558751938480926355afdbcb60e11b82525afa918215610169575f92610132575b508551928584019463466c6dc560e11b86526024850152604484015260648301526064825260a082019060018060401b039383831085841117610117575f938493885251915af4913d1561012b573d918211610117575f908451926100fa82601f19601f8401160185610173565b83523d92013e5b15610113575161097a90816101ab8239f35b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b5050610101565b9091508481813d8311610162575b61014a8183610173565b810103126101135761015b90610196565b905f61008c565b503d610140565b86513d5f823e3d90fd5b601f909101601f19168101906001600160401b0382119082101761011757604052565b51906001600160a01b03821682036101135756fe608060409080825260049081361015610016575f80fd5b5f3560e01c90816301ffc9a71461060457508063221a8729146105e65780634358d2be146105c85780634594229c146104e357806354f6127f146104b05780637b103999146104895780637f23690c146104555780639790242114610395578063c20db68914610377578063ce5494bb14610337578063dedff9c614610226578063e710563c146102085763f3ccaac0146100af575f80fd5b346101cd575f3660031901126101cd57600154825163463962a760e11b815260209290918391839182906001600160a01b03165afa9081156101fe575f91829182916101d1575b508451848101906354f6127f60e01b82527f2abb082c1b23ea79fce2a9e934ecb19ce15738b1483c365d0125f47e8ccc7dfc60248201526024815261013a8161069c565b51915af4916101476107e7565b92156101cd57825183019282818186019503126101cd57828101519067ffffffffffffffff82116101cd57019083603f830112156101cd57828201519161018d836106ee565b9461019a835196876106cc565b8386528284830101116101cd576101c9926101ba91838688019101610656565b51928284938452830190610677565b0390f35b5f80fd5b6101f19150843d86116101f7575b6101e981836106cc565b8101906107c8565b5f6100f6565b503d6101df565b83513d5f823e3d90fd5b82346101cd575f3660031901126101cd576020906012549051908152f35b50346101cd57602090816003193601126101cd5780359067ffffffffffffffff82116101cd5761025891369101610768565b9182519061027d61026883610750565b92610275835194856106cc565b808452610750565b601f1901835f5b828110610327575050505f5b84518110156102cb57806102af6102a96001938861091c565b51610816565b6102b9828661091c565b526102c4818561091c565b5001610290565b509250825191808301818452825180915281858501958260051b8601019301915f955b8287106102fb5785850386f35b909192938280610317600193603f198a82030186528851610677565b96019201960195929190926102ee565b6060828287010152018490610284565b50346101cd5760203660031901126101cd57356001600160a01b03818116918290036101cd575f5490811633036101cd576001600160a01b031916175f55005b82346101cd575f3660031901126101cd576020906013549051908152f35b5090806003193601126101cd5767ffffffffffffffff82358181116101cd576103c19036908501610768565b5060248035908282116101cd57366023830112156101cd57818501356103e681610750565b936103f3865195866106cc565b818552602460208096019260051b850101933685116101cd5760248101925b85841061042f5788883461042257005b5163f36ba73760e01b8152fd5b83358381116101cd57879161044a839288369187010161070a565b815201930192610412565b5090806003193601126101cd5760243567ffffffffffffffff81116101cd57610481903690840161070a565b503461042257005b82346101cd575f3660031901126101cd575f5490516001600160a01b039091168152602090f35b5090346101cd5760203660031901126101cd576104d06101c99235610816565b9051918291602083526020830190610677565b5090346101cd5760203660031901126101cd575f548235926001600160a01b03929091831633036101cd5760205a93600154168251938480926355afdbcb60e11b82525afa9182156105be57915f92918392839261059d575b5051602081019063116508a760e21b8252866024820152602481526105608161069c565b51915af461056c6107e7565b50156101cd575a916010540160105503806011540160115548810260125401601255483a0302601354016013555f80f35b6105b791925060203d6020116101f7576101e981836106cc565b905f61053c565b50513d5f823e3d90fd5b82346101cd575f3660031901126101cd576020906010549051908152f35b82346101cd575f3660031901126101cd576020906011549051908152f35b82346101cd5760203660031901126101cd57359063ffffffff60e01b82168092036101cd576020916301ffc9a760e01b8114908115610645575b5015158152f35b6318a6a9a560e21b1490508361063e565b5f5b8381106106675750505f910152565b8181015183820152602001610658565b9060209161069081518092818552858086019101610656565b601f01601f1916010190565b6060810190811067ffffffffffffffff8211176106b857604052565b634e487b7160e01b5f52604160045260245ffd5b90601f8019910116810190811067ffffffffffffffff8211176106b857604052565b67ffffffffffffffff81116106b857601f01601f191660200190565b81601f820112156101cd57803590610721826106ee565b9261072f60405194856106cc565b828452602083830101116101cd57815f926020809301838601378301015290565b67ffffffffffffffff81116106b85760051b60200190565b9080601f830112156101cd57602090823561078281610750565b9361079060405195866106cc565b81855260208086019260051b8201019283116101cd57602001905b8282106107b9575050505090565b813581529083019083016107ab565b908160209103126101cd57516001600160a01b03811681036101cd5790565b3d15610811573d906107f8826106ee565b9161080660405193846106cc565b82523d5f602084013e565b606090565b6001546040805163463962a760e11b815290926020928390839060049082906001600160a01b03165afa91821561091257915f9291839283926108f3575b508551858101916354f6127f60e01b83526024820152602481526108778161069c565b51915af4916108846107e7565b92156101cd57825183019282818186019503126101cd57828101519067ffffffffffffffff82116101cd570183603f820112156101cd5782810151916108c9836106ee565b946108d6825196876106cc565b8386528184840101116101cd576108f09385019101610656565b90565b61090b919250853d87116101f7576101e981836106cc565b905f610854565b84513d5f823e3d90fd5b80518210156109305760209160051b010190565b634e487b7160e01b5f52603260045260245ffdfea26469706673582212206c5c550fe4870b5c8de9ec4447e02e6de1853a7e6abc9bf7c2adcfb0811426f264736f6c63430008170033a2646970667358221220284f10fd0dc3415ffbddda3e3c1614081dd249040175886fa332e2b6d847ca5d64736f6c63430008170033deba1e292f8ba88238e10ab3c7f88bd4be4fac56cad5194b6ecceaf653468af1e0261fa95db2eb3b5439bd033cda66d56b96f92f243a8228fd87550ed7bdfdb3f675e9361af1c1664c1868cfa3eb97672d6b1a513aa5b81dec34c9ee330e818d2f0a68ab07768e01943a599e73362a0e17a63a72e94dd2e384d2c1d4db932756114bd03b3a46d48759680d81ebb2b414fda7d030a7105a851867accf1c2352e7ece574603820d07bc9b91f2a932baadf4628aabcb8afba49776529c14a6104b2a2646970667358221220193803e886292584245208d51558ce29840826ff8149c83648336d598b01be5c64736f6c63430008170033"); - -pub static BURNTPIX_BYTECODE_THREE: Bytes = bytes!("60806040526004361015610011575f80fd5b5f3560e01c6354f6127f14610024575f80fd5b3461005b57602036600319011261005b5761005761004360043561014b565b604051918291602083526020830190610080565b0390f35b5f80fd5b5f5b8381106100705750505f910152565b8181015183820152602001610061565b906020916100998151809281855285808601910161005f565b601f01601f1916010190565b6040810190811067ffffffffffffffff8211176100c157604052565b634e487b7160e01b5f52604160045260245ffd5b6060810190811067ffffffffffffffff8211176100c157604052565b6020810190811067ffffffffffffffff8211176100c157604052565b90601f8019910116810190811067ffffffffffffffff8211176100c157604052565b67ffffffffffffffff81116100c157601f01601f191660200190565b7f2abb082c1b23ea79fce2a9e934ecb19ce15738b1483c365d0125f47e8ccc7dfc8114610855577fef285b02a4f711ad84793f73cc8ed6fea8af7013ece8132dacb7b33f6bce93da81146106d5577f708e7b881795f2e6b6c2752108c177ec89248458de3bf69d0d43480b3e5034e6811461069f577feafec4d89fa9619884b60000a4d96624a38f7ac2d8d9a604ecf07c12c77e480c811461067e577fdeba1e292f8ba88238e10ab3c7f88bd4be4fac56cad5194b6ecceaf653468af18114610658577f2f0a68ab07768e01943a599e73362a0e17a63a72e94dd2e384d2c1d4db9327568114610637577fe0261fa95db2eb3b5439bd033cda66d56b96f92f243a8228fd87550ed7bdfdb3811461061f577f9afb95cacc9f95858ec44aa8c3b685511002e30ae54415823f406128b85b238e146102985760405161028e816100f1565b5f81525f36813790565b6102a06110e5565b805160208201206102af61085e565b906102b990610a2f565b6102c1610937565b926102cb90610af9565b6040516102d7816100a5565b6013815272227d5d5d2c2261747472696275746573223a5b60681b6020820190815260105461030590610c7c565b60115461031190610e26565b9060125461031e90610f13565b9260135461032b90610f13565b9460405196610339886100a5565b6003885260208801625d7d7d60e81b90526040519a8b9960208b019b8c81516020819301916103679261005f565b8b016020810161060f60f31b90528151918260228301916020019161038b9261005f565b01815191826022830191602001916103a29261005f565b01602281017f646174613a696d6167652f7376672b786d6c3b6261736536342c000000000000905281519182603c830191602001916103e09261005f565b0190519182603c83016103f29261005f565b01603c81017f7b226b6579223a22497465726174696f6e73222c2274797065223a226e756d6290526b32b91116113b30b63ab2911d60a11b605c820152815191826068830191602001916104459261005f565b0160688101611f4b60f21b9052606a81017f7b226b6579223a2247617355736564222c2274797065223a22737472696e672290526916113b30b63ab2911d1160b11b608a820152815191826094830191602001916104a29261005f565b019062089f4b60ea1b91826094820152609781017f7b226b6579223a22466565734275726e74222c2274797065223a22737472696e90526b339116113b30b63ab2911d1160a11b60b78201528151918260c3830191602001916105049261005f565b019060c382015260c681017f7b226b6579223a225469707350616964222c2274797065223a22737472696e6790526a1116113b30b63ab2911d1160a91b60e68201528151918260f18301916020019161055c9261005f565b0161227d60f01b60f18201528151918260f38301916020019161057e9261005f565b010360d38101835260f301610593908361010d565b815181206040515f602082015263379abe3560e11b6022820152600160f51b602682015260288101919091527f646174613a6170706c69636174696f6e2f6a736f6e3b636861727365743d5554604882015263118b4e0b60e21b606882015291518291610606908290606c85019061005f565b810103604c81018252606c0161061c908261010d565b90565b50604051600260208201526020815261061c816100a5565b50604051610644816100a5565b6004815263084a092b60e31b602082015290565b50604051610665816100a5565b6009815268084eae4dce840a0d2f60bb1b602082015290565b5060405161068b816100a5565b60048152632936598960e21b602082015290565b505f546bffffffffffffffffffffffff19806040519260601b1660208301523060601b1660348201526034815261061c816100d5565b506106de6110e5565b8051602090818301206106ef61085e565b906106f990610a2f565b610701610937565b9361070b90610af9565b604051610717816100a5565b600681528481019165227d5d5d7d7d60d01b8352604051968794878087018881995192839101916107479261005f565b860188810161060f60f31b9052815191828a602284019201916107699261005f565b0181519182896022840192019161077f9261005f565b01602281017f646174613a696d6167652f7376672b786d6c3b6261736536342c00000000000090528151918288603c84019201916107bc9261005f565b0190519182603c83016107ce9261005f565b0103601c81018452603c016107e3908461010d565b825181209260405193849384015f90526022840163379abe3560e11b9052600160f51b60268501526028840152604883017f646174613a6170706c69636174696f6e2f6a736f6e3b636861727365743d555490526068830163118b4e0b60e21b9052519081606c84016106069261005f565b5061061c6110e5565b6040519060c0820182811067ffffffffffffffff8211176100c1576040908152609383527f7b224c5350344d65746164617461223a7b226c696e6b73223a5b7b2275726c2260208401527f3a2268747470733a2f2f6275726e747069782e636f6d227d5d2c22696d616765908301527f73223a5b5b7b227769647468223a3736382c22686569676874223a3736382c2260608301527f766572696669636174696f6e223a7b226d6574686f64223a226b656363616b326080830152721a9b14313cba32b9949116113230ba30911d1160691b60a0830152565b60405190610944826100a5565b600a825269113e96113ab936111d1160b11b6020830152565b9081602091031261005b57516001600160a01b038116810361005b5790565b3d156109a6573d9061098d8261012f565b9161099b604051938461010d565b82523d5f602084013e565b606090565b60208183031261005b5780519067ffffffffffffffff821161005b570181601f8201121561005b5780516109de8161012f565b926109ec604051948561010d565b8184526020828401011161005b5761061c916020808501910161005f565b908151811015610a1b570160200190565b634e487b7160e01b5f52603260045260245ffd5b6040805191610a3d836100a5565b601083526020926f181899199a1a9b1b9c1cb0b131b232b360811b6020820152604051610a69816100f1565b5f8152935f935b818510610a7f57505050505090565b9091929394600190610aee60228789601f0360031b1c9260ff60f81b610aba600f82610ab0828960041c168d610a0a565b511696168a610a0a565b51169386519482610ad487945180928c808801910161005f565b83019189830152602182015203600281018452018261010d565b950193929190610a70565b805115610c6957604051610b0c816100d5565b604081527f4142434445464748494a4b4c4d4e4f505152535455565758595a61626364656660208201527f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f604082015281519160029260028101809111610c5557600390819004600281901b94906001600160fe1b03811603610c55579290610bad610b978661012f565b95610ba5604051978861010d565b80875261012f565b6020860190601f190136823793839284518501935b848110610c02575050505050600390510680600114610bf057600214610be6575090565b603d905f19015390565b50603d90815f19820153600119015390565b8360049197929394959701918251600190603f9082828260121c16880101518453828282600c1c16880101518385015382828260061c168801015188850153168501015186820153019593929190610bc2565b634e487b7160e01b5f52601160045260245ffd5b50604051610c76816100f1565b5f815290565b8015610d3d57604051610c8e816100a5565b6020815260203681830137815f925b610d0e5750610cab8261012f565b91610cb9604051938461010d565b808352601f19610cc88261012f565b013660208501375f5b818110610cde5750505090565b6001906001600160f81b0319610cf98285035f190186610a0a565b51165f1a610d078287610a0a565b5301610cd1565b91600a808406930481610d376001839492019560ff60f81b9060300160f81b165f1a9185610a0a565b53610c9d565b50604051610d4a816100a5565b60018152600360fc1b602082015290565b602190610dbf9294936040519582610d7d88945180926020808801910161005f565b8301601760f91b6020820152610d9c825180936020888501910161005f565b01610db0825180936020878501910161005f565b0103600181018552018361010d565b565b602290610dbf9294936040519582610de388945180926020808801910161005f565b83016102e360f41b6020820152610e03825180936020888501910161005f565b01610e17825180936020878501910161005f565b0103600281018552018361010d565b620f4240808210610f0957633b9aca0080831015610e9e5750604051610e4b816100a5565b60018152604d60f81b602082015290612710818406049204915b600a811015610e8957610e83610e7d61061c94610c7c565b91610c7c565b90610dc1565b610e98610e7d61061c94610c7c565b90610d5b565b905064e8d4a5100080831015610eda5750604051610ebb816100a5565b60018152602160f91b6020820152906298968081840604920491610e65565b9050604051610ee8816100a5565b60018152601560fa1b6020820152906402540be40081840604920491610e65565b5061061c90610c7c565b6103e88082106110a257620f424080831015610f695750604051610f36816100a5565b60048152634b57656960e01b602082015290600a81840604920491600a811015610e8957610e83610e7d61061c94610c7c565b9050633b9aca0080831015610fa65750604051610f85816100a5565b60048152634d57656960e01b60208201529061271081840604920491610e65565b905064e8d4a5100080831015610fe55750604051610fc3816100a5565b60048152634757656960e01b6020820152906298968081840604920491610e65565b905066038d7ea4c680008083101561102a5750604051611004816100a5565b60058152641856a98b2b60db1b60208201528183049290916402540be400910604610e65565b9050670de0b6b3a76400008083101561106f575060405161104a816100a5565b60048152630da98b2b60e31b6020820152906509184e72a00081840604920491610e65565b905060405161107d816100a5565b6003815262098b2b60eb1b602082015290662386f26fc1000081840604920491610e65565b506110ac90610c7c565b61061c6023604051836110c982955180926020808601910161005f565b81016257656960e81b602082015203600381018452018261010d565b600154604080516355afdbcb60e11b81526020926001600160a01b03919084908290600490829086165afa908115611258575f918291829161123b575b5084516303cf32ab60e61b8782019081526004825290611141816100a5565b51915af49161114e61097c565b921561005b57836111698482806004975183010191016109ab565b9260015416825194858092630c543fdb60e11b82525afa92831561123157915f939184938493611202575b506111df6003549160045490519283916111c68a840196633617f92d60e21b8852606060248601526084850190610080565b916044840152606483015203601f19810183528261010d565b51915afa6111eb61097c565b901561005b578161061c92825183010191016109ab565b611223919350863d881161122a575b61121b818361010d565b81019061095d565b915f611194565b503d611211565b50513d5f823e3d90fd5b6112529150863d881161122a5761121b818361010d565b5f611122565b83513d5f823e3d90fdfea2646970667358221220d754235277b87b31b8acce280204f2b5f322de96296361221743109844254a7c64736f6c63430008170033"); - -pub static BURNTPIX_BYTECODE_FOUR: Bytes = bytes!("60806040526004361015610011575f80fd5b5f3560e01c80634594229c146106865780638cd8db8a146100b15763f3ccaac01461003a575f80fd5b346100ad575f3660031901126100ad57610052610ac3565b604092919251928391606083528351918260608501525f5b8381106100955750608094505f85848601015260208401526040830152601f80199101168101030190f35b6020868201810151608089840101528795500161006a565b5f80fd5b346100ad5760603660031901126100ad576001546004359060443590602435906001600160a01b0316156100ad578060035581600455026101056100fc6100f78361094c565b6108e0565b9180835261094c565b602082019190601f19013683375167ffffffffffffffff918282116105e757600160401b82116105e75760055482600555808310610646575b5060055f525f5b828110610612575050604051916080830191508111828210176105e757604052600381525f5b606081106105fb5750805190600160401b82116105e757600a5482600a55808310610554575b50602001600a5f525f80516020611a418339815191525f915b83831061053657845f620f424060011d620f4240806101d1620f423f198460011b01611a34565b810302055b600383106103b457600a54846101ee6100f78361094c565b9180835260208301600a5f525f80516020611a418339815191525f915b83831061033957858561021c610906565b5f5b83601482106103245750506102316108bf565b60c89060c881526119008036602084013761024a6108bf565b9060c882523660208301375f60208501935b8082106102f357505060809495506102738261178d565b61027c8161178d565b61028f61028883610a60565b5192610a71565b5161029c61028883610a60565b519280820383850381136102db575b506006556007556008556009558151600b5551600c556040810151600d556060810151600e550151600f55600255005b939290920160011d9260011d808401930391886102ab565b90956103028689600193610cab565b96865161030f8287610a82565b52855161031c8286610a82565b52019061025c565b826103329160019395610cab565b920161021e565b600a602060019261034861089e565b855481528486015483820152600286015460408201526003860154606082015260048601546080820152600586015460a0820152600686015460c0820152600786015460e08201526008860154610100820152600986015461012082015281520192019201919061020b565b9091926103bf6109b7565b5061040f6104056103fb6103f16103e76103e06103da6109b7565b96611a0d565b8752611a0d565b6020870152611a0d565b6040860152611a0d565b6060850152611a0d565b6080840152611a0d565b60a0830152600160401b6001675851f42d4c957f2d92830208916101688360201c07603c90620f4240610450620f423f19621e848085848602050701611a34565b8103870205918112156104e9575084905f5b60028705880390810161010085015290810160e08401520160c0820152601a600160401b60018486020860201c06610120820152600a548610156104d557600192600160401b926104ca8593600a5f52600a8a025f80516020611a41833981519152016109fd565b0208930191906101d6565b634e487b7160e01b5f52603260045260245ffd5b60788112156104fa5750845f610462565b60b481121561050c5750845f91610462565b60f081121561051e57505f9085610462565b61012c131561052e575f85610462565b5f8591610462565b600a60208261054860019451866109fd565b019201920191906101aa565b80600a0290600a8204036105d35782600a02600a810484036105d3575f80516020611a4183398151915291820191015b8181106105915750610191565b805f600a92555f60018201555f60028201555f60038201555f60048201555f60058201555f60068201555f60078201555f60088201555f600982015501610584565b634e487b7160e01b5f52601160045260245ffd5b634e487b7160e01b5f52604160045260245ffd5b6020906106066109b7565b8282850101520161016b565b60019060208351930192817f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db0015501610145565b827f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db091820191015b81811061067b575061013e565b5f815560010161066e565b346100ad5760203660031901126100ad576001546001600160a01b0316156100ad5760035460045490600654916007549060085490600954926106c7610906565b93600a54966106d86100f78961094c565b9780895260208901600a5f525f80516020611a418339815191525f915b8383106108155750505050600254965f955b600435871061073c578751600b556020880151600c556040880151600d556060880151600e556080880151600f556002899055005b90919293949597610750888b600193610cab565b9888518581139081159161080a575b5080156107fc575b80156107ee575b6107e957836107888a8a866020818c039301510302610964565b0261079a86890386888d510302610964565b016107be60408b015160c01b60608c015160801b0160808c015160401b0191610982565b620f4240829392549160031b9282841c0101821b915f19901b19161790555b01959493929190610707565b6107dd565b50602089015186131561076e565b508260208a01511315610767565b90508713158c61075f565b600a602060019261082b9d9798999a9b9d61089e565b855481528486015483820152600286015460408201526003860154606082015260048601546080820152600586015460a0820152600686015460c0820152600786015460e082015260088601546101008201526009860154610120820152815201920192019190999796959493996106f5565b60405190610140820182811067ffffffffffffffff8211176105e757604052565b60405190611920820182811067ffffffffffffffff8211176105e757604052565b6040519190601f01601f1916820167ffffffffffffffff8111838210176105e757604052565b6040519060a0820182811067ffffffffffffffff8211176105e75760405281600b548152600c546020820152600d546040820152600e5460608201526080600f54910152565b67ffffffffffffffff81116105e75760051b60200190565b811561096e570490565b634e487b7160e01b5f52601260045260245ffd5b6005548110156104d55760055f527f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db001905f90565b6109bf61089e565b905f82525f60208301525f60408301525f60608301525f60808301525f60a08301525f60c08301525f60e08301525f6101008301525f610120830152565b90610120600991805184556020810151600185015560408101516002850155606081015160038501556080810151600485015560a0810151600585015560c0810151600685015560e0810151600785015561010081015160088501550151910155565b8051600a10156104d5576101600190565b805160be10156104d5576117e00190565b80518210156104d55760209160051b010190565b67ffffffffffffffff81116105e757601f01601f191660200190565b9081518110156104d5570160200190565b600380549160045491828402908482048414851517156105d357808202918083048214901517156105d357610afa6100f783610a96565b91808352610b0a601f1991610a96565b013660208401375f805b858110610c4e57508015610c4757610b2b90611809565b8015610c3f575b5f5b858110610b4357505050929190565b5f5b878110610b555750600101610b34565b8088830201610b6381610982565b905490861b1c67ffffffffffffffff91868684841680610b8c575b505050505050600101610b45565b610b9581611809565b60ff9083610bab8460c08a901c84028502610964565b90610bb591610964565b9784610bcb8560808b901c841685028602610964565b90610bd591610964565b9760401c16020290610be691610964565b90610bf091610964565b91029260ff60f81b80938160f893841b165f1a610c0d878d610ab2565b53821b165f1a610c20600186018b610ab2565b531b165f1a90600201610c339087610ab2565b535f8080868682610b7e565b506001610b32565b5050929190565b5f5b878110610c605750600101610b14565b67ffffffffffffffff610c76828a850201610982565b905490861b1c16808410610c8e575b50600101610c50565b92506001610c85565b811561096e570590565b811561096e570790565b9091600160401b60018181675851f42d4c957f2d958602089160209083968051801561096e5785841c06610cde91610a82565b519585875195815190620f424097868b0191825193888601809d8b8d808451998a98828881604089019c8d51950205920205010195606085015102059060808401998a510205019860a08301998a51018094528481526040810190815160c085015101831c926060820190815160e087015101811c9260800190815161010088015101901c90525252610120015180610dda575b5050505050505050505050505080516305f5e0ff19808212918215610dcc575b508115610dc1575b508015610db3575b610dab57505090565b5f8092525290565b506305f5e100825113610da2565b90508251125f610d9a565b6305f5e1001291505f610d92565b808c03610e195750505050505050505050505050610df881516118ae565b610e0283516118ae565b835281525b5f808080808080808080808080610d72565b60028103610e6d57505050505050505050505050610e5a82518280865180028380020105918215610e63575b610e5191839102610c97565b92855102610c97565b83528152610e07565b9091508190610e45565b60038103610ec457505050505050505050505050610e958183518551800290800201056118ae565b610ea781800264e8d4a510000361187d565b908351918551848382028386020105875202910203058152610e07565b60048103610f1f57505050505050505050505090610e5a90610eee8451865180029080020161187d565b908115610f17575b50610f0a8185518751808201910302610c97565b928451901b855102610c97565b90505f610ef6565b60058103610f535750505050505050505050505050610f418151835190611914565b610e5a8251845180029080020161187d565b60068103610fbd57505050505050505050505050610f748251845190611914565b90610f878351855180029080020161187d565b610fb2610fa48284610f9a8288016118ae565b82020595036118ae565b800264e8d4a510000361187d565b020583528152610e07565b6007810361102157505050505050505050505050610fde8251845190611914565b610ffd82610ff48551875180029080020161187d565b809302056118ae565b908261101183800264e8d4a510000361187d565b825f030205855202058152610e07565b60088103611087575050505050505050505050506110428251845190611914565b6110656110578451865180029080020161187d565b92622fefd8938402056118ae565b908261107983800264e8d4a510000361187d565b820205855202058152610e07565b6009810361110f57505050505050505050505050610e5a6110ab8351855190611914565b6110bd8451865180029080020161187d565b908115611107575b6110ce906118ae565b9264e8d4a510006110ff83836110e7888002850361187d565b936110ff6110f4846118ae565b91828002900361187d565b940102610c97565b8391506110c5565b600a8103611189575050505050505050505050506111308251845190611914565b906111438351855180029080020161187d565b91821561117f575b611154906118ae565b91611173818361116c86800264e8d4a510000361187d565b9502610c97565b92020583528152610e07565b909150819061114b565b600b8103611200575050505050505050505050506111aa8251845190611914565b906111c66111c08451865180029080020161187d565b926118ae565b8164e8d4a51000916111f26111e76111e1838002860361187d565b966118ae565b93848002900361187d565b020592020583528152610e07565b600c810361127857505050505050505050505050506112228151835190611914565b6112496112378351855180029080020161187d565b6112428184016118ae565b92036118ae565b9061125d64e8d4a51000928002830361187d565b90808002029080800202908282820305855201058152610e07565b9b9e98999a9b600d81145f146113035750505050505050506112d993929185910208958380885f941c16146112f8575b6112d16112b88651885190611914565b916112cb8751895180029080020161187d565b0261187d565b931d016118ae565b6112eb81800264e8d4a510000361187d565b8202910283528152610e07565b622fefd891506112a8565b989e98600e819c979b95989c999699145f146113735750505050505050505050505081515f8112155f1461134e57508251905f8212611344575b5050610e07565b1d82525f8061133d565b83519091905f811261136757508251901b825250610e07565b811d84521b8152610e07565b600f819d98999a9b9c9d145f146113fb5750505050505050508290518002059384156113f1575b8290518002059384156113e7575b6113ce6113bf6113c46113bf8694858c5102610c97565b6118ae565b9683895102610c97565b9486519251020501928551925102050183528152610e07565b91935083916113a8565b919350839161139a565b6010919395979b5080929496989c9950145f1461145e575050505050505050610e5a919250806114338551875180029080020161187d565b01908115611456575b61144b82828851871b02610c97565b938551901b02610c97565b90508061143c565b969896601181036114935750505050505050506114816113bf86516003026119cf565b92816113ce6113bf87516003026119cf565b979896976012810361151b5750505050505050509080809351800205918215611512575b826114d8816114ce88518a5180029080020161187d565b931b828401610ca1565b03928203020501906114f06113bf8451865190611914565b8161150382800264e8d4a510000361187d565b84020592020583528152610e07565b915080916114b7565b969796601381036115b3575050505050505061157d90622fefd8945164e8d4a51000958187920202059081156115ab575b81811d92839161155f89518b5190611914565b901d9261157489518b5180029080020161187d565b95518401610ca1565b131561159d57611591916111e791036118ae565b02059083528152610e07565b611591916111e791016118ae565b84915061154c565b601491939597999a50809294969850145f1461161357505050505050509080610e5a916115e88551875180029080020161187d565b0190811561160b575b61160082828751871b02610c97565b938651901b02610c97565b9050806115f1565b60158103611665575050505050505050610e5a825182623d0900818751800284800201050191821561165b575b61164f91839160021b02610c97565b92855160021b02610c97565b9091508190611640565b601681036116875750505050505050505061168081516118ae565b8152610e07565b601781036116f05750505050505050506116dc6116a484516118ae565b826116b782800264e8d4a510000361187d565b9182156116e6575b6116cb91839102610c97565b926116d685516118ae565b02610c97565b9083528152610e07565b90915081906116bf565b6018819c9495969799989c145f14611729575050505090878181869486020880940208961d92838388831c070386521c07038152610e07565b9350945094955097506019915014611744575b505050610e07565b82918183920290800203058002058015611786575b801561096e5761176f9064e8d4a510000561187d565b8251845182028390058552020581525f808061173c565b5080611759565b80515f5b81811061179d57505050565b60018082015b8381106117b4575050600101611791565b81906117c08487610a82565b516117cb8288610a82565b51126117d8575b016117a3565b6117e28187610a82565b516117ed8588610a82565b516117f88389610a82565b526118038588610a82565b526117d2565b5f905b6216e36081101561186a57600190620f423f190181815b600a8410611832575050505090565b90918060028596611844839786610964565b0193620f424093849102049361185c86890186610964565b900396019493920204611823565b9062062fd9600391019160011b0461180c565b90600180830160011d90835b84831261189557505050565b91935090836118a48183610c97565b01821d9190611889565b905f91625fdfb0809107905f821261190d575b50600260018181845b8386136118d957505050505050565b9091929364e8d4a510008280889a6118f489869b8902610c97565b019a0202059594600185018502029301915f03906118ca565b015f6118c1565b91908215806119c7575b6119c1575f9061192d84611a34565b61193682611a34565b80821384146119a95761199191620f42406119519202610c97565b620f42409081808280020581808080612cc81985020561caee018402056201c41019018302056202f2d3018202056205131719010205620f422601020590565b622fefd860011d03935b02126119a357565b905f0390565b61195190620f42406119bb9302610c97565b9361199b565b505f9150565b50801561191e565b6119db6119ff916118ae565b6119ed81800264e8d4a510000361187d565b908115611a02575b620f424002610c97565b90565b620f424091506119f5565b6001600160401b91675851f42d4c957f2d020890621e8480602083901c07620f423f190190565b5f81136119ff575f039056fec65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a8a2646970667358221220b3f2fe21ac0faf4ab1951c6297ccc37675d0c82e067ed2dd736ca86eeb03ebe164736f6c63430008170033"); diff --git a/bins/revm-test/src/bin/snailtracer.rs b/bins/revm-test/src/bin/snailtracer.rs deleted file mode 100644 index a931dc3a31..0000000000 --- a/bins/revm-test/src/bin/snailtracer.rs +++ /dev/null @@ -1,32 +0,0 @@ -use revm::{ - db::BenchmarkDB, - interpreter::analysis::to_analysed, - primitives::{address, bytes, Bytecode, Bytes, TransactTo}, - Evm, -}; - -pub fn simple_example() { - let bytecode = to_analysed(Bytecode::new_raw(CONTRACT_DATA.clone())); - - // BenchmarkDB is dummy state that implements Database trait. - let mut evm = Evm::builder() - .with_db(BenchmarkDB::new_bytecode(bytecode.clone())) - .modify_tx_env(|tx| { - // execution globals block hash/gas_limit/coinbase/timestamp.. - tx.caller = address!("1000000000000000000000000000000000000000"); - tx.transact_to = TransactTo::Call(address!("0000000000000000000000000000000000000000")); - tx.data = bytes!("30627b7c"); - }) - .build(); - - let _ = evm.transact().unwrap(); -} - -fn main() { - println!("Running snailtracer example!"); - let start = std::time::Instant::now(); - simple_example(); - println!("elapsed: {:?}", start.elapsed()); -} - -static CONTRACT_DATA : Bytes = bytes!("608060405234801561001057600080fd5b506004361061004c5760003560e01c806330627b7c1461005157806375ac892a14610085578063784f13661461011d578063c294360114610146575b600080fd5b610059610163565b604080516001600160f81b03199485168152928416602084015292168183015290519081900360600190f35b6100a86004803603604081101561009b57600080fd5b50803590602001356102d1565b6040805160208082528351818301528351919283929083019185019080838360005b838110156100e25781810151838201526020016100ca565b50505050905090810190601f16801561010f5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6100596004803603606081101561013357600080fd5b508035906020810135906040013561055b565b6100a86004803603602081101561015c57600080fd5b5035610590565b6000806000610176610400610300610834565b60405180606001604052806001546000546207d5dc028161019357fe5b058152600060208083018290526040928301919091528251600b81905583820151600c81905593830151600d819055835160608082018652928152808401959095528484015282519081018352600654815260075491810191909152600854918101919091526102259161021c916102139161020e91612ef7565b612f64565b6207d5dc612feb565b620f424061301e565b8051600e556020810151600f55604001516010556102416142dd565b61025a816102556102006101806008613064565b613212565b90506102708161025561014561021c6008613064565b905061028481610255610258806008613064565b905061029a8161025561020a61020c6008613064565b90506102a781600461301e565b90506102b1613250565b8051602082015160409092015160f891821b9692821b9550901b92509050565b606060005b6000548112156104c95760006102ed828686613064565b90506002816000015160f81b90808054603f811680603e811461032a576002830184556001831661031c578192505b600160028404019350610342565b600084815260209081902060ff198516905560419094555b505050600190038154600116156103685790600052602060002090602091828204019190065b909190919091601f036101000a81548160ff02191690600160f81b840402179055506002816020015160f81b90808054603f811680603e81146103c557600283018455600183166103b7578192505b6001600284040193506103dd565b600084815260209081902060ff198516905560419094555b505050600190038154600116156104035790600052602060002090602091828204019190065b909190919091601f036101000a81548160ff02191690600160f81b840402179055506002816040015160f81b90808054603f811680603e81146104605760028301845560018316610452578192505b600160028404019350610478565b600084815260209081902060ff198516905560419094555b5050506001900381546001161561049e5790600052602060002090602091828204019190065b815460ff601f929092036101000a9182021916600160f81b90930402919091179055506001016102d6565b506002805460408051602060018416156101000260001901909316849004601f8101849004840282018401909252818152929183018282801561054d5780601f106105225761010080835404028352916020019161054d565b820191906000526020600020905b81548152906001019060200180831161053057829003601f168201915b505050505090505b92915050565b60008060008061056c878787613064565b8051602082015160409092015160f891821b9a92821b9950901b9650945050505050565b600154606090600019015b600081126107a35760005b6000548112156107995760006105bd828487613064565b90506002816000015160f81b90808054603f811680603e81146105fa57600283018455600183166105ec578192505b600160028404019350610612565b600084815260209081902060ff198516905560419094555b505050600190038154600116156106385790600052602060002090602091828204019190065b909190919091601f036101000a81548160ff02191690600160f81b840402179055506002816020015160f81b90808054603f811680603e81146106955760028301845560018316610687578192505b6001600284040193506106ad565b600084815260209081902060ff198516905560419094555b505050600190038154600116156106d35790600052602060002090602091828204019190065b909190919091601f036101000a81548160ff02191690600160f81b840402179055506002816040015160f81b90808054603f811680603e81146107305760028301845560018316610722578192505b600160028404019350610748565b600084815260209081902060ff198516905560419094555b5050506001900381546001161561076e5790600052602060002090602091828204019190065b815460ff601f929092036101000a9182021916600160f81b90930402919091179055506001016105a6565b506000190161059b565b506002805460408051602060018416156101000260001901909316849004601f810184900484028201840190925281815292918301828280156108275780601f106107fc57610100808354040283529160200191610827565b820191906000526020600020905b81548152906001019060200180831161080a57829003601f168201915b505050505090505b919050565b8160008190555080600181905550604051806080016040528060405180606001604052806302faf08081526020016303197500815260200163119e7f8081525081526020016108a460405180606001604052806000815260200161a673198152602001620f423f19815250612f64565b815260006020808301829052604092830182905283518051600355808201516004558301516005558381015180516006559081015160075582015160085582820151600955606092830151600a805460ff1916911515919091179055815192830190915260015490548291906207d5dc028161091c57fe5b058152600060208083018290526040928301919091528251600b81905583820151600c81905593830151600d819055835160608082018652928152808401959095528484015282519081018352600654815260075491810191909152600854918101919091526109979161021c916102139161020e91612ef7565b8051600e55602080820151600f55604091820151601055815160a08101835264174876e8008152825160608082018552641748862a40825263026e8f00828501526304dd1e008286015282840191825284518082018652600080825281860181905281870181905284870191825286518084018852620b71b081526203d09081880181905281890152928501928352608085018181526011805460018082018355919093528651600b9093027f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c688101938455955180517f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c69880155808901517f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c6a8801558901517f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c6b870155925180517f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c6c870155808801517f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c6d8701558801517f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c6e860155925180517f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c6f860155958601517f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c7085015594909501517f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c71830155517f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c72909101805492949192909160ff1990911690836002811115610c1057fe5b0217905550505060116040518060a0016040528064174876e8008152602001604051806060016040528064174290493f19815260200163026e8f0081526020016304dd1e008152508152602001604051806060016040528060008152602001600081526020016000815250815260200160405180606001604052806203d09081526020016203d0908152602001620b71b0815250815260200160006002811115610cb657fe5b905281546001818101845560009384526020938490208351600b90930201918255838301518051838301558085015160028085019190915560409182015160038501558185015180516004860155808701516005860155820151600685015560608501518051600786015595860151600885015594015160098301556080830151600a83018054949593949193909260ff1990921691908490811115610d5857fe5b0217905550505060116040518060a0016040528064174876e800815260200160405180606001604052806302faf080815260200163026e8f00815260200164174876e800815250815260200160405180606001604052806000815260200160008152602001600081525081526020016040518060600160405280620b71b08152602001620b71b08152602001620b71b0815250815260200160006002811115610dfd57fe5b905281546001818101845560009384526020938490208351600b90930201918255838301518051838301558085015160028085019190915560409182015160038501558185015180516004860155808701516005860155820151600685015560608501518051600786015595860151600885015594015160098301556080830151600a83018054949593949193909260ff1990921691908490811115610e9f57fe5b0217905550505060116040518060a0016040528064174876e800815260200160405180606001604052806302faf080815260200163026e8f00815260200164173e54e97f1981525081526020016040518060600160405280600081526020016000815260200160008152508152602001604051806060016040528060008152602001600081526020016000815250815260200160006002811115610f3f57fe5b905281546001818101845560009384526020938490208351600b90930201918255838301518051838301558085015160028085019190915560409182015160038501558185015180516004860155808701516005860155820151600685015560608501518051600786015595860151600885015594015160098301556080830151600a83018054949593949193909260ff1990921691908490811115610fe157fe5b0217905550505060116040518060a0016040528064174876e800815260200160405180606001604052806302faf080815260200164174876e80081526020016304dd1e00815250815260200160405180606001604052806000815260200160008152602001600081525081526020016040518060600160405280620b71b08152602001620b71b08152602001620b71b081525081526020016000600281111561108657fe5b905281546001818101845560009384526020938490208351600b90930201918255838301518051838301558085015160028085019190915560409182015160038501558185015180516004860155808701516005860155820151600685015560608501518051600786015595860151600885015594015160098301556080830151600a83018054949593949193909260ff199092169190849081111561112857fe5b0217905550505060116040518060a0016040528064174876e800815260200160405180606001604052806302faf080815260200164174399c9ff1981526020016304dd1e00815250815260200160405180606001604052806000815260200160008152602001600081525081526020016040518060600160405280620b71b08152602001620b71b08152602001620b71b08152508152602001600060028111156111ce57fe5b905281546001818101845560009384526020938490208351600b90930201918255838301518051838301558085015160028085019190915560409182015160038501558185015180516004860155808701516005860155820151600685015560608501518051600786015595860151600885015594015160098301556080830151600a83018054949593949193909260ff199092169190849081111561127057fe5b0217905550505060116040518060a0016040528062fbc5208152602001604051806060016040528063019bfcc0815260200162fbc52081526020016302cd29c0815250815260200160405180606001604052806000815260200160008152602001600081525081526020016040518060600160405280620f3e588152602001620f3e588152602001620f3e5881525081526020016001600281111561131157fe5b905281546001818101845560009384526020938490208351600b90930201918255838301518051838301558085015160028085019190915560409182015160038501558185015180516004860155808701516005860155820151600685015560608501518051600786015595860151600885015594015160098301556080830151600a83018054949593949193909260ff19909216919084908111156113b357fe5b0217905550505060116040518060a001604052806323c34600815260200160405180606001604052806302faf080815260200163289c455081526020016304dd1e008152508152602001604051806060016040528062b71b00815260200162b71b00815260200162b71b00815250815260200160405180606001604052806000815260200160008152602001600081525081526020016000600281111561145657fe5b905281546001818101845560009384526020938490208351600b90930201918255838301518051838301558085015160028085019190915560409182015160038501558185015180516004860155808701516005860155820151600685015560608501518051600786015595860151600885015594015160098301556080830151600a83018054949593949193909260ff19909216919084908111156114f857fe5b0217905550505060126040518060e00160405280604051806060016040528063035e1f208152602001630188c2e081526020016304a62f8081525081526020016040518060600160405280630459e4408152602001630188c2e081526020016305a1f4a081525081526020016040518060600160405280630459e44081526020016302f34f6081526020016304a62f808152508152602001604051806060016040528060008152602001600081526020016000815250815260200160405180606001604052806000815260200160008152602001600081525081526020016040518060600160405280620f3e588152602001620f3e588152602001620f3e5881525081526020016001600281111561160c57fe5b905281546001818101845560009384526020938490208351805160139094029091019283558085015183830155604090810151600280850191909155858501518051600386015580870151600486015582015160058501558185015180516006860155808701516007860155820151600885015560608501518051600986015580870151600a860155820151600b85015560808501518051600c86015580870151600d860155820151600e85015560a08501518051600f860155958601516010850155940151601183015560c0830151601283018054949593949193909260ff19909216919084908111156116fd57fe5b0217905550505060126040518060e00160405280604051806060016040528063035e1f20815260200163016a8c8081526020016304a62f8081525081526020016040518060600160405280630459e4408152602001600081526020016304a62f8081525081526020016040518060600160405280630459e440815260200163016a8c8081526020016305a1f4a08152508152602001604051806060016040528060008152602001600081526020016000815250815260200160405180606001604052806000815260200160008152602001600081525081526020016040518060600160405280620f3e588152602001620f3e588152602001620f3e5881525081526020016001600281111561180e57fe5b905281546001818101845560009384526020938490208351805160139094029091019283558085015183830155604090810151600280850191909155858501518051600386015580870151600486015582015160058501558185015180516006860155808701516007860155820151600885015560608501518051600986015580870151600a860155820151600b85015560808501518051600c86015580870151600d860155820151600e85015560a08501518051600f860155958601516010850155940151601183015560c0830151601283018054949593949193909260ff19909216919084908111156118ff57fe5b0217905550505060126040518060e001604052806040518060600160405280630555a9608152602001630188c2e081526020016304a62f8081525081526020016040518060600160405280630459e44081526020016302f34f6081526020016304a62f8081525081526020016040518060600160405280630459e4408152602001630188c2e081526020016305a1f4a08152508152602001604051806060016040528060008152602001600081526020016000815250815260200160405180606001604052806000815260200160008152602001600081525081526020016040518060600160405280620f3e588152602001620f3e588152602001620f3e58815250815260200160016002811115611a1357fe5b905281546001818101845560009384526020938490208351805160139094029091019283558085015183830155604090810151600280850191909155858501518051600386015580870151600486015582015160058501558185015180516006860155808701516007860155820151600885015560608501518051600986015580870151600a860155820151600b85015560808501518051600c86015580870151600d860155820151600e85015560a08501518051600f860155958601516010850155940151601183015560c0830151601283018054949593949193909260ff1990921691908490811115611b0457fe5b0217905550505060126040518060e001604052806040518060600160405280630555a960815260200163016a8c8081526020016304a62f8081525081526020016040518060600160405280630459e440815260200163016a8c8081526020016305a1f4a081525081526020016040518060600160405280630459e4408152602001600081526020016304a62f808152508152602001604051806060016040528060008152602001600081526020016000815250815260200160405180606001604052806000815260200160008152602001600081525081526020016040518060600160405280620f3e588152602001620f3e588152602001620f3e58815250815260200160016002811115611c1557fe5b905281546001818101845560009384526020938490208351805160139094029091019283558085015183830155604090810151600280850191909155858501518051600386015580870151600486015582015160058501558185015180516006860155808701516007860155820151600885015560608501518051600986015580870151600a860155820151600b85015560808501518051600c86015580870151600d860155820151600e85015560a08501518051600f860155958601516010850155940151601183015560c0830151601283018054949593949193909260ff1990921691908490811115611d0657fe5b0217905550505060126040518060e00160405280604051806060016040528063035e1f208152602001630188c2e081526020016304a62f8081525081526020016040518060600160405280630459e44081526020016302f34f6081526020016304a62f8081525081526020016040518060600160405280630459e4408152602001630188c2e081526020016303aa6a608152508152602001604051806060016040528060008152602001600081526020016000815250815260200160405180606001604052806000815260200160008152602001600081525081526020016040518060600160405280620f3e588152602001620f3e588152602001620f3e58815250815260200160016002811115611e1a57fe5b905281546001818101845560009384526020938490208351805160139094029091019283558085015183830155604090810151600280850191909155858501518051600386015580870151600486015582015160058501558185015180516006860155808701516007860155820151600885015560608501518051600986015580870151600a860155820151600b85015560808501518051600c86015580870151600d860155820151600e85015560a08501518051600f860155958601516010850155940151601183015560c0830151601283018054949593949193909260ff1990921691908490811115611f0b57fe5b0217905550505060126040518060e00160405280604051806060016040528063035e1f20815260200163016a8c8081526020016304a62f8081525081526020016040518060600160405280630459e440815260200163016a8c8081526020016303aa6a6081525081526020016040518060600160405280630459e4408152602001600081526020016304a62f808152508152602001604051806060016040528060008152602001600081526020016000815250815260200160405180606001604052806000815260200160008152602001600081525081526020016040518060600160405280620f3e588152602001620f3e588152602001620f3e5881525081526020016001600281111561201c57fe5b905281546001818101845560009384526020938490208351805160139094029091019283558085015183830155604090810151600280850191909155858501518051600386015580870151600486015582015160058501558185015180516006860155808701516007860155820151600885015560608501518051600986015580870151600a860155820151600b85015560808501518051600c86015580870151600d860155820151600e85015560a08501518051600f860155958601516010850155940151601183015560c0830151601283018054949593949193909260ff199092169190849081111561210d57fe5b0217905550505060126040518060e001604052806040518060600160405280630555a9608152602001630188c2e081526020016304a62f8081525081526020016040518060600160405280630459e4408152602001630188c2e081526020016303aa6a6081525081526020016040518060600160405280630459e44081526020016302f34f6081526020016304a62f808152508152602001604051806060016040528060008152602001600081526020016000815250815260200160405180606001604052806000815260200160008152602001600081525081526020016040518060600160405280620f3e588152602001620f3e588152602001620f3e5881525081526020016001600281111561222157fe5b905281546001818101845560009384526020938490208351805160139094029091019283558085015183830155604090810151600280850191909155858501518051600386015580870151600486015582015160058501558185015180516006860155808701516007860155820151600885015560608501518051600986015580870151600a860155820151600b85015560808501518051600c86015580870151600d860155820151600e85015560a08501518051600f860155958601516010850155940151601183015560c0830151601283018054949593949193909260ff199092169190849081111561231257fe5b0217905550505060126040518060e001604052806040518060600160405280630555a960815260200163016a8c8081526020016304a62f8081525081526020016040518060600160405280630459e4408152602001600081526020016304a62f8081525081526020016040518060600160405280630459e440815260200163016a8c8081526020016303aa6a608152508152602001604051806060016040528060008152602001600081526020016000815250815260200160405180606001604052806000815260200160008152602001600081525081526020016040518060600160405280620f3e588152602001620f3e588152602001620f3e5881525081526020016001600281111561242357fe5b905281546001818101845560009384526020938490208351805160139094029091019283558085015183830155604090810151600280850191909155858501518051600386015580870151600486015582015160058501558185015180516006860155808701516007860155820151600885015560608501518051600986015580870151600a860155820151600b85015560808501518051600c86015580870151600d860155820151600e85015560a08501518051600f860155958601516010850155940151601183015560c0830151601283018054949593949193909260ff199092169190849081111561251457fe5b0217905550505060126040518060e00160405280604051806060016040528063035e1f208152602001630188c2e081526020016304a62f8081525081526020016040518060600160405280630459e4408152602001630188c2e081526020016303aa6a6081525081526020016040518060600160405280630555a9608152602001630188c2e081526020016304a62f808152508152602001604051806060016040528060008152602001600081526020016000815250815260200160405180606001604052806000815260200160008152602001600081525081526020016040518060600160405280620f3e588152602001620f3e588152602001620f3e5881525081526020016001600281111561262857fe5b905281546001818101845560009384526020938490208351805160139094029091019283558085015183830155604090810151600280850191909155858501518051600386015580870151600486015582015160058501558185015180516006860155808701516007860155820151600885015560608501518051600986015580870151600a860155820151600b85015560808501518051600c86015580870151600d860155820151600e85015560a08501518051600f860155958601516010850155940151601183015560c0830151601283018054949593949193909260ff199092169190849081111561271957fe5b0217905550505060126040518060e00160405280604051806060016040528063035e1f208152602001630188c2e081526020016304a62f8081525081526020016040518060600160405280630555a9608152602001630188c2e081526020016304a62f8081525081526020016040518060600160405280630459e4408152602001630188c2e081526020016305a1f4a08152508152602001604051806060016040528060008152602001600081526020016000815250815260200160405180606001604052806000815260200160008152602001600081525081526020016040518060600160405280620f3e588152602001620f3e588152602001620f3e5881525081526020016001600281111561282d57fe5b905281546001818101845560009384526020938490208351805160139094029091019283558085015183830155604090810151600280850191909155858501518051600386015580870151600486015582015160058501558185015180516006860155808701516007860155820151600885015560608501518051600986015580870151600a860155820151600b85015560808501518051600c86015580870151600d860155820151600e85015560a08501518051600f860155958601516010850155940151601183015560c0830151601283018054949593949193909260ff199092169190849081111561291e57fe5b0217905550505060126040518060e00160405280604051806060016040528063035e1f20815260200163016a8c8081526020016304a62f8081525081526020016040518060600160405280630555a960815260200163016a8c8081526020016304a62f8081525081526020016040518060600160405280630459e440815260200163016a8c8081526020016303aa6a608152508152602001604051806060016040528060008152602001600081526020016000815250815260200160405180606001604052806000815260200160008152602001600081525081526020016040518060600160405280620f3e588152602001620f3e588152602001620f3e58815250815260200160016002811115612a3257fe5b905281546001818101845560009384526020938490208351805160139094029091019283558085015183830155604090810151600280850191909155858501518051600386015580870151600486015582015160058501558185015180516006860155808701516007860155820151600885015560608501518051600986015580870151600a860155820151600b85015560808501518051600c86015580870151600d860155820151600e85015560a08501518051600f860155958601516010850155940151601183015560c0830151601283018054949593949193909260ff1990921691908490811115612b2357fe5b0217905550505060126040518060e00160405280604051806060016040528063035e1f20815260200163016a8c8081526020016304a62f8081525081526020016040518060600160405280630459e440815260200163016a8c8081526020016305a1f4a081525081526020016040518060600160405280630555a960815260200163016a8c8081526020016304a62f808152508152602001604051806060016040528060008152602001600081526020016000815250815260200160405180606001604052806000815260200160008152602001600081525081526020016040518060600160405280620f3e588152602001620f3e588152602001620f3e58815250815260200160016002811115612c3757fe5b905281546001818101845560009384526020938490208351805160139094029091019283558085015183830155604090810151600280850191909155858501518051600386015580870151600486015582015160058501558185015180516006860155808701516007860155820151600885015560608501518051600986015580870151600a860155820151600b85015560808501518051600c86015580870151600d860155820151600e85015560a08501518051600f860155958601516010850155940151601183015560c0830151601283018054949593949193909260ff1990921691908490811115612d2857fe5b0217905550505060005b601254811015612ef257600060128281548110612d4b57fe5b600091825260209182902060408051610140810182526013909302909101805460e08401908152600182015461010085015260028083015461012086015290845282516060818101855260038401548252600484015482880152600584015482860152858701919091528351808201855260068401548152600784015481880152600884015481860152858501528351808201855260098401548152600a84015481880152600b840154818601528186015283518082018552600c8401548152600d84015481880152600e84015481860152608086015283519081018452600f830154815260108301549581019590955260118201549285019290925260a0830193909352601283015491929160c084019160ff90911690811115612e6c57fe5b6002811115612e7757fe5b815250509050612eac61020e612e95836020015184600001516132cd565b612ea7846040015185600001516132cd565b612ef7565b60128381548110612eb957fe5b60009182526020918290208351600960139093029091019182015590820151600a820155604090910151600b9091015550600101612d32565b505050565b612eff6142dd565b604051806060016040528083602001518560400151028460400151866020015102038152602001836040015185600001510284600001518660400151020381526020018360000151856020015102846020015186600001510203815250905092915050565b612f6c6142dd565b604082015160208301518351600092612f9292918002918002919091019080020161330c565b90506040518060600160405280828560000151620f42400281612fb157fe5b058152602001828560200151620f42400281612fc957fe5b058152602001828560400151620f42400281612fe157fe5b0590529392505050565b612ff36142dd565b5060408051606081018252835183028152602080850151840290820152928101519091029082015290565b6130266142dd565b60405180606001604052808385600001518161303e57fe5b0581526020018385602001518161305157fe5b05815260200183856040015181612fe157fe5b61306c6142dd565b6000546013805463ffffffff1916918502860163ffffffff169190911790556130936142dd565b905060005b828112156131f157600061317261314c61021c613115600b60405180606001604052908160008201548152602001600182015481526020016002820154815250506207a1206000546207a1206130ec613343565b63ffffffff16816130f957fe5b0663ffffffff168d620f424002018161310e57fe5b0503612feb565b60408051606081018252600e548152600f5460208201526010549181019190915260015461025591906207a12090816130ec613343565b604080516060810182526006548152600754602082015260085491810191909152613212565b6040805160e081019091526003546080820190815260045460a083015260055460c083015291925060009181906131ae9061025586608c612feb565b81526020016131bc84612f64565b815260006020820181905260409091015290506131e5846102556131df8461336c565b8861301e565b93505050600101613098565b5061320861021c61320183613753565b60ff612feb565b90505b9392505050565b61321a6142dd565b50604080516060810182528251845101815260208084015181860151019082015291810151928101519092019181019190915290565b60008080556001819055613266906002906142fe565b60006003819055600481905560058190556006819055600781905560088190556009819055600a805460ff19169055600b819055600c819055600d819055600e819055600f81905560108190556132bf90601190614345565b6132cb60126000614366565b565b6132d56142dd565b5060408051606081018252825184510381526020808401518186015103908201528282015184830151039181019190915292915050565b80600260018201055b8181121561333d5780915060028182858161332c57fe5b05018161333557fe5b059050613315565b50919050565b6013805463ffffffff19811663ffffffff9182166341c64e6d0261303901821617918290551690565b6133746142dd565b600a826040015113156133a657604051806060016040528060008152602001600081526020016000815250905061082f565b60008060006133b48561379f565b91945092509050826133e857604051806060016040528060008152602001600081526020016000815250935050505061082f565b6133f0614387565b6133f86143c7565b6134006142dd565b6134086142dd565b600086600181111561341657fe5b1415613505576011858154811061342957fe5b60009182526020918290206040805160a081018252600b90930290910180548352815160608082018452600183015482526002808401548388015260038401548386015285870192909252835180820185526004840154815260058401548188015260068401548186015285850152835180820185526007840154815260088401549681019690965260098301549386019390935291830193909352600a830154919291608084019160ff909116908111156134e157fe5b60028111156134ec57fe5b8152505093508360600151915083604001519050613653565b6012858154811061351257fe5b600091825260209182902060408051610140810182526013909302909101805460e08401908152600182015461010085015260028083015461012086015290845282516060818101855260038401548252600484015482880152600584015482860152858701919091528351808201855260068401548152600784015481880152600884015481860152858501528351808201855260098401548152600a84015481880152600b840154818601528186015283518082018552600c8401548152600d84015481880152600e84015481860152608086015283519081018452600f830154815260108301549581019590955260118201549285019290925260a0830193909352601283015491929160c084019160ff9091169081111561363357fe5b600281111561363e57fe5b8152505092508260a001519150826080015190505b6040820151600190811215613669575060408201515b808360200151131561367c575060208201515b808360400151131561368f575060408201515b60408a01805160010190819052600512156136f75780620f42406136b1613343565b63ffffffff16816136be57fe5b0663ffffffff1612156136e8576136e16136db84620f4240612feb565b8261301e565b92506136f7565b50965061082f95505050505050565b6136ff6142dd565b600088600181111561370d57fe5b14156137255761371e8b878b613a57565b9050613733565b6137308b868b613aec565b90505b6137448361025561021c8785613baa565b9b9a5050505050505050505050565b61375b6142dd565b60405180606001604052806137738460000151613be8565b81526020016137858460200151613be8565b81526020016137978460400151613be8565b905292915050565b60008080808080805b6011548110156138c2576000613890601183815481106137c457fe5b60009182526020918290206040805160a081018252600b90930290910180548352815160608082018452600183015482526002808401548388015260038401548386015285870192909252835180820185526004840154815260058401548188015260068401548186015285850152835180820185526007840154815260088401549681019690965260098301549386019390935291830193909352600a830154919291608084019160ff9091169081111561387c57fe5b600281111561388757fe5b9052508a613c13565b90506000811380156138a957508415806138a957508481125b156138b957809450600093508192505b506001016137a8565b5060005b601254811015613a49576000613a17601283815481106138e257fe5b600091825260209182902060408051610140810182526013909302909101805460e08401908152600182015461010085015260028083015461012086015290845282516060818101855260038401548252600484015482880152600584015482860152858701919091528351808201855260068401548152600784015481880152600884015481860152858501528351808201855260098401548152600a84015481880152600b840154818601528186015283518082018552600c8401548152600d84015481880152600e84015481860152608086015283519081018452600f830154815260108301549581019590955260118201549285019290925260a0830193909352601283015491929160c084019160ff90911690811115613a0357fe5b6002811115613a0e57fe5b9052508a613cbb565b9050600081138015613a305750841580613a3057508481125b15613a4057809450600193508192505b506001016138c6565b509196909550909350915050565b613a5f6142dd565b6000613a7a856000015161025561021c886020015187612feb565b90506000613a8f61020e8387602001516132cd565b9050600085608001516002811115613aa357fe5b1415613ae1576000613ab9828860200151613e0c565b12613acd57613aca81600019612feb565b90505b613ad8868383613e31565b9250505061320b565b613ad8868383613fc1565b613af46142dd565b6000613b0f856000015161025561021c886020015187612feb565b6060860151909150620a2c2a9015613b2757506216e3605b6000620f4240613b3f87606001518960200151613e0c565b81613b4657fe5b05905060008112613b55576000035b64e8d4a5100081800281038380020281900590036000811215613b8c57613b8188858960600151613fc1565b94505050505061320b565b613b9e88858960600151868686614039565b98975050505050505050565b613bb26142dd565b50604080516060810182528251845102815260208084015181860151029082015291810151928101519092029181019190915290565b600080821215613bfa5750600061082f565b620f4240821315613c0f5750620f424061082f565b5090565b600080613c28846020015184600001516132cd565b90506000620f4240613c3e838660200151613e0c565b81613c4557fe5b865191900591506000908002613c5b8480613e0c565b838402030190506000811215613c775760009350505050610555565b613c808161330c565b90506103e88183031315613c9957900391506105559050565b6103e88183011315613caf570191506105559050565b50600095945050505050565b600080613cd0846020015185600001516132cd565b90506000613ce6856040015186600001516132cd565b90506000613cf8856020015183612ef7565b90506000620f4240613d0a8584613e0c565b81613d1157fe5b0590506103e71981138015613d2757506103e881125b15613d39576000945050505050610555565b85518751600091613d49916132cd565b9050600082613d588386613e0c565b81613d5f57fe5b0590506000811280613d735750620f424081135b15613d875760009650505050505050610555565b6000613d938388612ef7565b9050600084613da68b6020015184613e0c565b81613dad57fe5b0590506000811280613dc35750620f4240818401135b15613dd957600098505050505050505050610555565b600085613de68985613e0c565b81613ded57fe5b0590506103e88112156137445760009950505050505050505050610555565b6040808201519083015160208084015190850151845186510291020191020192915050565b613e396142dd565b6000620f424080613e48613343565b63ffffffff1681613e5557fe5b0663ffffffff16625fdfb00281613e6857fe5b0590506000620f4240613e79613343565b63ffffffff1681613e8657fe5b0663ffffffff1690506000613e9a8261330c565b6103e8029050613ea86142dd565b620186a0613eb98760000151614216565b1315613ee657604051806060016040528060008152602001620f4240815260200160008152509050613f09565b6040518060600160405280620f4240815260200160008152602001600081525090505b613f1661020e8288612ef7565b90506000613f2761020e8884612ef7565b9050613f7f61020e613f64613f5285620f424088613f448c61422e565b0281613f4c57fe5b05612feb565b61025585620f424089613f448d61424e565b6102558a613f7689620f42400361330c565b6103e802612feb565b9150613fb460405180608001604052808a81526020018481526020018b6040015181526020018b60600151151581525061336c565b9998505050505050505050565b613fc96142dd565b6000613ffb61020e8660200151613ff686620f4240613fec898c60200151613e0c565b60020281613f4c57fe5b6132cd565b90506140306040518060800160405280868152602001838152602001876040015181526020018760600151151581525061336c565b95945050505050565b6140416142dd565b60608701516000199015614053575060015b600061408961020e61021c61406c8c602001518a612feb565b613ff68b6140798a61330c565b620f42408c8e0205018802612feb565b60608a0151909150620f42408601906140ba57620f42406140aa838a613e0c565b816140b157fe5b05620f42400390505b60408a0151619c406c0c9f2c9cd04674edea40000000620ea6008480028502850285020205019060021261415e5761412a61411f60405180608001604052808d81526020018681526020018e6040015181526020018e6060015115151581525061336c565b82620f424003612feb565b92506141448361025561413e8e8e8e613fc1565b84612feb565b925061415383620f424061301e565b94505050505061420c565b600281056203d09001620f4240614173613343565b63ffffffff168161418057fe5b0663ffffffff1612156141b2576141536141a461419e8d8d8d613fc1565b83612feb565b600283056203d0900161301e565b6142056141f76141ec60405180608001604052808e81526020018781526020018f6040015181526020018f6060015115151581525061336c565b83620f424003612feb565b60028305620b71b00361301e565b9450505050505b9695505050505050565b60008082131561422757508061082f565b5060000390565b60008061423a8361424e565b905061320b81820264e8d4a510000361330c565b60005b600082121561426757625fdfb082019150614251565b5b625fdfb0821261427f57625fdfb082039150614268565b6001828160025b818313156142d457818385028161429957fe5b0585019450620f4240808788860202816142af57fe5b05816142b757fe5b600095909503940592506001810181029190910290600201614286565b50505050919050565b60405180606001604052806000815260200160008152602001600081525090565b50805460018160011615610100020316600290046000825580601f106143245750614342565b601f0160209004906000526020600020908101906143429190614401565b50565b50805460008255600b02906000526020600020908101906143429190614416565b50805460008255601302906000526020600020908101906143429190614475565b6040518060a00160405280600081526020016143a16142dd565b81526020016143ae6142dd565b81526020016143bb6142dd565b81526020016000905290565b6040518060e001604052806143da6142dd565b81526020016143e76142dd565b81526020016143f46142dd565b81526020016143a16142dd565b5b80821115613c0f5760008155600101614402565b5b80821115613c0f57600080825560018201819055600282018190556003820181905560048201819055600582018190556006820181905560078201819055600882018190556009820155600a8101805460ff19169055600b01614417565b5b80821115613c0f576000808255600182018190556002820181905560038201819055600482018190556005820181905560068201819055600782018190556008820181905560098201819055600a8201819055600b8201819055600c8201819055600d8201819055600e8201819055600f820181905560108201819055601182015560128101805460ff1916905560130161447656fea2646970667358221220037024f5647853879c58fbcc61ac3616455f6f731cc6e84f91eb5a3b4e06c00464736f6c63430007060033"); diff --git a/bins/revm-test/src/bin/transfer.rs b/bins/revm-test/src/bin/transfer.rs deleted file mode 100644 index 8abd0910ef..0000000000 --- a/bins/revm-test/src/bin/transfer.rs +++ /dev/null @@ -1,33 +0,0 @@ -use revm::{ - db::BenchmarkDB, - primitives::{Bytecode, TransactTo, U256}, - Evm, -}; - -use std::time::Duration; - -fn main() { - // BenchmarkDB is dummy state that implements Database trait. - let mut evm = Evm::builder() - .with_db(BenchmarkDB::new_bytecode(Bytecode::new())) - .modify_tx_env(|tx| { - // execution globals block hash/gas_limit/coinbase/timestamp.. - tx.caller = "0x0000000000000000000000000000000000000001" - .parse() - .unwrap(); - tx.value = U256::from(10); - tx.transact_to = TransactTo::Call( - "0x0000000000000000000000000000000000000000" - .parse() - .unwrap(), - ); - }) - .build(); - - // Microbenchmark - let bench_options = microbench::Options::default().time(Duration::from_secs(3)); - - microbench::bench(&bench_options, "Simple value transfer", || { - let _ = evm.transact().unwrap(); - }); -} diff --git a/bins/revme/CHANGELOG.md b/bins/revme/CHANGELOG.md index 41e895456c..3932b96718 100644 --- a/bins/revme/CHANGELOG.md +++ b/bins/revme/CHANGELOG.md @@ -6,6 +6,392 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [7.1.0](https://github.com/bluealloy/revm/compare/revme-v7.0.4...revme-v7.1.0) - 2025-07-23 + +### Added + +- count inspector and bench test ([#2730](https://github.com/bluealloy/revm/pull/2730)) + +### Fixed + +- fully deprecate serde-json ([#2767](https://github.com/bluealloy/revm/pull/2767)) + +### Other + +- back to hashbrown map in revme ([#2770](https://github.com/bluealloy/revm/pull/2770)) +- back to better map ([#2768](https://github.com/bluealloy/revm/pull/2768)) +- bump develop statetests to devnet-3 ([#2754](https://github.com/bluealloy/revm/pull/2754)) +- add clz_50 codspeed ([#2743](https://github.com/bluealloy/revm/pull/2743)) + +## [7.0.4](https://github.com/bluealloy/revm/compare/revme-v7.0.3...revme-v7.0.4) - 2025-07-14 + +### Other + +- incorrect StorageKey and StorageValue parameter order in burntpix benchmark ([#2704](https://github.com/bluealloy/revm/pull/2704)) + +## [7.0.3](https://github.com/bluealloy/revm/compare/revme-v7.0.2...revme-v7.0.3) - 2025-07-03 + +### Other + +- update Cargo.lock dependencies + +## [7.0.2](https://github.com/bluealloy/revm/compare/revme-v7.0.1...revme-v7.0.2) - 2025-06-30 + +### Other + +- cargo clippy --fix --all ([#2671](https://github.com/bluealloy/revm/pull/2671)) +- statetest runner cleanup ([#2665](https://github.com/bluealloy/revm/pull/2665)) +- use TxEnv::builder ([#2652](https://github.com/bluealloy/revm/pull/2652)) + +## [7.0.1](https://github.com/bluealloy/revm/compare/revme-v7.0.0...revme-v7.0.1) - 2025-06-20 + +### Other + +- updated the following local packages: revm-context-interface, revm-context, revm, revm-inspector, revm-statetest-types + +## [7.0.0](https://github.com/bluealloy/revm/compare/revme-v6.0.0...revme-v7.0.0) - 2025-06-19 + +### Added + +- remove EOF ([#2644](https://github.com/bluealloy/revm/pull/2644)) +- *(precompile)* rug/gmp-based modexp ([#2596](https://github.com/bluealloy/revm/pull/2596)) +- change blob_max_count to max_blobs_per_tx ([#2608](https://github.com/bluealloy/revm/pull/2608)) + +### Other + +- re-use frame allocation ([#2636](https://github.com/bluealloy/revm/pull/2636)) +- rename `transact` methods ([#2616](https://github.com/bluealloy/revm/pull/2616)) + +## [6.0.0](https://github.com/bluealloy/revm/compare/revme-v5.1.1...revme-v6.0.0) - 2025-06-06 + +### Added + +- Config blob basefee fraction ([#2551](https://github.com/bluealloy/revm/pull/2551)) +- expand timestamp/block_number to u256 ([#2546](https://github.com/bluealloy/revm/pull/2546)) +- transact multi tx ([#2517](https://github.com/bluealloy/revm/pull/2517)) + +### Other + +- tag v75 revm v24.0.1 ([#2563](https://github.com/bluealloy/revm/pull/2563)) ([#2589](https://github.com/bluealloy/revm/pull/2589)) +- use iter_batched for revme benches ([#2584](https://github.com/bluealloy/revm/pull/2584)) +- unify calling of journal account loading ([#2561](https://github.com/bluealloy/revm/pull/2561)) +- ContextTr rm *_ref, and add *_mut fn ([#2560](https://github.com/bluealloy/revm/pull/2560)) +- *(cfg)* add tx_chain_id_check fields. Optimize effective gas cost calc ([#2557](https://github.com/bluealloy/revm/pull/2557)) +- add gas-cost-estimator selected bytecodes ([#2555](https://github.com/bluealloy/revm/pull/2555)) + +## [5.1.1](https://github.com/bluealloy/revm/compare/revme-v5.1.0...revme-v5.1.1) - 2025-05-31 + +### Other + +- unify calling of journal account loading + +## [5.1.0](https://github.com/bluealloy/revm/compare/revme-v5.0.0...revme-v5.1.0) - 2025-05-22 + +### Added + +- make blob max number optional ([#2532](https://github.com/bluealloy/revm/pull/2532)) + +### Other + +- Change legacy statetests repo ([#2519](https://github.com/bluealloy/revm/pull/2519)) +- Storage Types Alias ([#2461](https://github.com/bluealloy/revm/pull/2461)) + +## [5.0.0](https://github.com/bluealloy/revm/compare/revme-v4.1.0...revme-v5.0.0) - 2025-05-07 + +Dependency bump + +## [4.1.0](https://github.com/bluealloy/revm/compare/revme-v4.0.2...revme-v4.1.0) - 2025-05-07 + +### Added + +- *(Osaka)* disable EOF ([#2480](https://github.com/bluealloy/revm/pull/2480)) +- skip cloning of call input from shared memory ([#2462](https://github.com/bluealloy/revm/pull/2462)) +- *(tx)* Add Either RecoveredAuthorization ([#2448](https://github.com/bluealloy/revm/pull/2448)) +- *(EOF)* Changes needed for devnet-1 ([#2377](https://github.com/bluealloy/revm/pull/2377)) +- Move SharedMemory buffer to context ([#2382](https://github.com/bluealloy/revm/pull/2382)) + +### Fixed + +- *(revme)* evm command caller/target for bench ([#2476](https://github.com/bluealloy/revm/pull/2476)) + +### Other + +- *(revme)* simplify repeated code ([#2432](https://github.com/bluealloy/revm/pull/2432)) +- backport from release branch ([#2415](https://github.com/bluealloy/revm/pull/2415)) ([#2416](https://github.com/bluealloy/revm/pull/2416)) +- *(lints)* revm-context lints ([#2404](https://github.com/bluealloy/revm/pull/2404)) + +## [4.0.2](https://github.com/bluealloy/revm/compare/revme-v4.0.0..revme-v4.0.1) - 2025-04-15 + +### Other + + +## [4.0.1](https://github.com/bluealloy/revm/compare/revme-v4.0.0...revme-v4.0.1) - 2025-04-09 + +### Other + +- *(revme)* remove revm-handler dependency ([#2366](https://github.com/bluealloy/revm/pull/2366)) + +## [4.0.0](https://github.com/bluealloy/revm/compare/revme-v3.0.0...revme-v4.0.0) - 2025-03-28 + +### Added + +- Add JournalInner ([#2311](https://github.com/bluealloy/revm/pull/2311)) +- Add criterion to revme bench command ([#2295](https://github.com/bluealloy/revm/pull/2295)) + +### Other + +- add criterion benchmark for evm build ([#2319](https://github.com/bluealloy/revm/pull/2319)) +- add check for path and existence existence ([#2320](https://github.com/bluealloy/revm/pull/2320)) +- bump bench time, and reduce burntpix iterations ([#2315](https://github.com/bluealloy/revm/pull/2315)) +- update EOF validation logic and improve error handling ([#2304](https://github.com/bluealloy/revm/pull/2304)) + +## [3.0.0](https://github.com/bluealloy/revm/compare/revme-v3.0.0-alpha.7...revme-v3.0.0) - 2025-03-24 + +### Other + +- updated the following local packages: revm-database + +## [3.0.0-alpha.7](https://github.com/bluealloy/revm/compare/revme-v3.0.0-alpha.6...revme-v3.0.0-alpha.7) - 2025-03-21 + +### Added + +- InspectEvm fn renames, inspector docs, book cleanup ([#2275](https://github.com/bluealloy/revm/pull/2275)) + +### Fixed + +- correct eof kind in verification tests ([#2250](https://github.com/bluealloy/revm/pull/2250)) + +### Other + +- *(revme)* remove deprecated #[clap] attribute + +## [3.0.0-alpha.6](https://github.com/bluealloy/revm/compare/revme-v3.0.0-alpha.5...revme-v3.0.0-alpha.6) - 2025-03-16 + +### Other + +- updated the following local packages: revm-primitives, revm-bytecode, revm-context-interface, revm-context, revm-handler, revm-inspector + +## [3.0.0-alpha.5](https://github.com/bluealloy/revm/compare/revme-v3.0.0-alpha.4...revme-v3.0.0-alpha.5) - 2025-03-12 + +### Added + +- rename inspect_previous to inspect_replay ([#2194](https://github.com/bluealloy/revm/pull/2194)) + +## [3.0.0-alpha.4](https://github.com/bluealloy/revm/compare/revme-v3.0.0-alpha.3...revme-v3.0.0-alpha.4) - 2025-03-11 + +### Other + +- Add comments to handler methods ([#2188](https://github.com/bluealloy/revm/pull/2188)) + +## [3.0.0-alpha.3](https://github.com/bluealloy/revm/compare/revme-v3.0.0-alpha.2...revme-v3.0.0-alpha.3) - 2025-03-10 + +### Other + +- updated the following local packages: revm + +## [3.0.0-alpha.2](https://github.com/bluealloy/revm/compare/revme-v3.0.0-alpha.1...revme-v3.0.0-alpha.2) - 2025-03-10 + +### Added + +- remove specification crate ([#2165](https://github.com/bluealloy/revm/pull/2165)) + +### Other + +- JournalTr, JournalOutput, op only using revm crate ([#2155](https://github.com/bluealloy/revm/pull/2155)) +- rename transact_previous to replay, move EvmTr traits ([#2153](https://github.com/bluealloy/revm/pull/2153)) +- Add docs to revm-bytecode crate ([#2108](https://github.com/bluealloy/revm/pull/2108)) +- *(deps)* bump breaking deps ([#2093](https://github.com/bluealloy/revm/pull/2093)) +- move all dependencies to workspace ([#2092](https://github.com/bluealloy/revm/pull/2092)) + +## [3.0.0-alpha.1](https://github.com/bluealloy/revm/compare/revme-v2.5.0...revme-v3.0.0-alpha.1) - 2025-02-16 + +### Added + +- Split Inspector trait from EthHandler into standalone crate (#2075) +- integrate alloy-eips (#2078) +- *(op)* Isthmus precompiles (#2054) +- Evm structure (Cached Instructions and Precompiles) (#2049) +- Context execution (#2013) +- EthHandler trait (#2001) +- *(EIP-7840)* Add blob schedule to execution client cfg (#1980) +- bump eof validation tests (#1963) +- simplify Transaction trait (#1959) +- Split inspector.rs (#1958) +- align Block trait (#1957) +- integrate codspeed (#1935) +- Restucturing Part7 Handler and Context rework (#1865) +- restructuring Part6 transaction crate (#1814) +- extract statetest models/structs to standalone crate (#1808) +- Merge validation/analyzis with Bytecode (#1793) +- restructure part3 fix examples (#1792) +- Restructuring Part3 inspector crate (#1788) +- restructure Part2 database crate (#1784) +- use TestAuthorization and skip decoding of eip7702 tx (#1785) +- project restructuring Part1 (#1776) +- introducing EvmWiring, a chain-specific configuration (#1672) + +### Fixed + +- *(revme)* Statetest stop exec when print output is true (#1995) +- *(revme)* statetest remove redundant json output (#1994) +- *(eof)* dont run precompile on ext delegate call (#1964) +- *(revme)* Burntpix bench (#1937) +- *(revme)* include correct bytecode for snailtracer (#1917) +- statetest json set spec_id (#1766) + +### Other + +- set alpha.1 version +- Bump licence year to 2025 (#2058) +- improve EIP-3155 tracer (#2033) +- align crates versions (#1983) +- remove analysis bench inner loops (#1936) +- fix comments and docs into more sensible (#1920) +- tie journal database with database getter (#1923) +- use stderr for revme tracer. not panic on bytecode (#1916) +- put snailtracer and analysis contracts in files (#1911) +- Move CfgEnv from context-interface to context crate (#1910) +- Rename PRAGUE_EOF to OSAKA (#1903) +- bump EOF evmone tests to v0.13.0 (#1816) +- *(primitives)* replace HashMap re-exports with alloy_primitives::map (#1805) +- *(revme)* replace `structopt` with `clap` (#1754) + +## [2.5.0](https://github.com/bluealloy/revm/compare/revme-v2.4.0...revme-v2.5.0) - 2025-02-11 + +### Other + +- updated the following local packages: revm + +## [2.4.0](https://github.com/bluealloy/revm/compare/revme-v2.3.0...revme-v2.4.0) - 2025-01-28 + +### Other + +- devnet5 tests v1.3.0 ([#2021](https://github.com/bluealloy/revm/pull/2021)) + +## [2.3.0](https://github.com/bluealloy/revm/compare/revme-v2.2.0...revme-v2.3.0) - 2025-01-13 + +### Added + +- *(EIP-7623)* adjuct floor gas check order ([#1990](https://github.com/bluealloy/revm/pull/1990)) + +### Other + +- v53 revm v19.2.0 ([#1972](https://github.com/bluealloy/revm/pull/1972)) + +## [2.2.0](https://github.com/bluealloy/revm/compare/revme-v2.1.0...revme-v2.2.0) - 2024-12-26 + +### Added + +- blst reprice, remove g1/g2 mul, eest test bump ([#1951](https://github.com/bluealloy/revm/pull/1951)) +- eip7691 fraction update ([#1900](https://github.com/bluealloy/revm/pull/1900)) + +### Other + +- Uncouple blob count between CL and EL ([#1899](https://github.com/bluealloy/revm/pull/1899)) + +## [2.1.0](https://github.com/bluealloy/revm/compare/revme-v2.0.0...revme-v2.1.0) - 2024-11-06 + +### Other + +- Osaka Activation (release_49 branch) ([#1835](https://github.com/bluealloy/revm/pull/1835)) +- v49 release ([#1833](https://github.com/bluealloy/revm/pull/1833)) + +## [2.0.0](https://github.com/bluealloy/revm/compare/revme-v1.0.0...revme-v2.0.0) - 2024-10-23 + +### Other + +- update Cargo.lock dependencies + +## [1.0.0](https://github.com/bluealloy/revm/compare/revme-v0.11.0...revme-v1.0.0) - 2024-09-26 + +### Other + +- update Cargo.lock dependencies + +## [0.11.0](https://github.com/bluealloy/revm/compare/revme-v0.10.3...revme-v0.11.0) - 2024-10-17 + +### Added + +- Rename PRAGUE_EOF to OSAKA ([#1822](https://github.com/bluealloy/revm/pull/1822)) +- *(EIP-7702)* devnet-4 changes ([#1821](https://github.com/bluealloy/revm/pull/1821)) + +### Other + +- remove test u8 check ([#1825](https://github.com/bluealloy/revm/pull/1825)) + +## [0.10.3](https://github.com/bluealloy/revm/compare/revme-v0.10.2...revme-v0.10.3) - 2024-09-26 + +### Other + +- update Cargo.lock dependencies + +## [0.10.2](https://github.com/bluealloy/revm/compare/revme-v0.10.1...revme-v0.10.2) - 2024-09-18 + +### Added + +- *(statetest)* enable EOF in Prague tests ([#1753](https://github.com/bluealloy/revm/pull/1753)) + + +## [0.10.1](https://github.com/bluealloy/revm/compare/revme-v0.10.0...revme-v0.10.1) - 2024-08-30 + +### Other +- updated the following local packages: revm + +## [0.10.0](https://github.com/bluealloy/revm/compare/revme-v0.9.0...revme-v0.10.0) - 2024-08-29 + +### Added +- *(eip7702)* Impl newest version of EIP ([#1695](https://github.com/bluealloy/revm/pull/1695)) +- c-kzg bump, cleanup on kzgsetting ([#1719](https://github.com/bluealloy/revm/pull/1719)) + +## [0.9.0](https://github.com/bluealloy/revm/compare/revme-v0.8.0...revme-v0.9.0) - 2024-08-08 + +### Added +- *(EOF)* Run EOF tests from eth/tests ([#1690](https://github.com/bluealloy/revm/pull/1690)) +- *(EOF)* add evmone test suite ([#1689](https://github.com/bluealloy/revm/pull/1689)) +- *(EOF)* Add EOF validation in revme bytecode cmd ([#1660](https://github.com/bluealloy/revm/pull/1660)) +- *(EOF)* EOF Validation add code type and sub container tracker ([#1648](https://github.com/bluealloy/revm/pull/1648)) + +### Fixed +- *(statetest)* make bytecode analyzed ([#1666](https://github.com/bluealloy/revm/pull/1666)) +- *(EOF)* returning to non-returning jumpf, enable valition error ([#1664](https://github.com/bluealloy/revm/pull/1664)) +- *(statetest)* Add back Merge spec ([#1658](https://github.com/bluealloy/revm/pull/1658)) + +### Other +- Add EOF Layout Fuzz Loop to `revme bytecode` ([#1677](https://github.com/bluealloy/revm/pull/1677)) +- *(clippy)* 1.80 rust clippy list paragraph ident ([#1661](https://github.com/bluealloy/revm/pull/1661)) +- use `is_zero` for `U256` and `B256` ([#1638](https://github.com/bluealloy/revm/pull/1638)) +- bump versions bcs of primitives ([#1631](https://github.com/bluealloy/revm/pull/1631)) + +## [0.8.0](https://github.com/bluealloy/revm/compare/revme-v0.7.0...revme-v0.8.0) - 2024-07-16 + +### Added +- *(eof)* cli eof-validation ([#1622](https://github.com/bluealloy/revm/pull/1622)) +- *(EOF)* Bytecode::new_raw supports EOF, new_raw_checked added ([#1607](https://github.com/bluealloy/revm/pull/1607)) + +### Fixed +- *(eip7702)* Add tests and fix some bugs ([#1605](https://github.com/bluealloy/revm/pull/1605)) + +### Other +- *(GeneralState)* skip fewer specs ([#1603](https://github.com/bluealloy/revm/pull/1603)) + +## [0.7.0](https://github.com/bluealloy/revm/compare/revme-v0.6.0...revme-v0.7.0) - 2024-07-08 + +### Other +- replace AccessList with alloy version ([#1552](https://github.com/bluealloy/revm/pull/1552)) + +## [0.6.0](https://github.com/bluealloy/revm/compare/revme-v0.5.0...revme-v0.6.0) - 2024-06-20 + +### Added +- *(EOF)* Put EOF bytecode behind an Arc ([#1517](https://github.com/bluealloy/revm/pull/1517)) +- *(revme)* add prague spec ([#1506](https://github.com/bluealloy/revm/pull/1506)) + +### Fixed +- *(eof)* fixture 2 tests ([#1550](https://github.com/bluealloy/revm/pull/1550)) + +### Other +- replace TransactTo with TxKind ([#1542](https://github.com/bluealloy/revm/pull/1542)) +- skip tests with storage check and return status ([#1452](https://github.com/bluealloy/revm/pull/1452)) + ## [0.5.0](https://github.com/bluealloy/revm/compare/revme-v0.4.0...revme-v0.5.0) - 2024-05-12 ### Added diff --git a/bins/revme/Cargo.toml b/bins/revme/Cargo.toml index 71d9d6543d..20c416ed6e 100644 --- a/bins/revme/Cargo.toml +++ b/bins/revme/Cargo.toml @@ -1,35 +1,48 @@ [package] -authors = ["Dragan Rakita "] -edition = "2021" name = "revme" -keywords = ["ethereum", "evm"] -license = "MIT" -repository = "https://github.com/bluealloy/revm" description = "Rust Ethereum Virtual Machine Executable" -version = "0.5.0" +version = "7.1.0" +authors.workspace = true +edition.workspace = true +keywords.workspace = true +license.workspace = true +repository.workspace = true [dependencies] -hash-db = "0.15" -hex = "0.4" -hashbrown = "0.14" -indicatif = "0.17" -microbench = "0.5" -plain_hasher = "0.2" -revm = { path = "../../crates/revm", version = "9.0.0", default-features = false, features = [ - "ethersdb", - "std", - "serde-json", - "c-kzg", - "blst" -] } -alloy-rlp = { version = "0.3", default-features = false, features = [ - "arrayvec", - "derive", -] } -serde = { version = "1.0", features = ["derive", "rc"] } -serde_json = { version = "1.0", features = ["preserve_order"] } -structopt = "0.3" -thiserror = "1.0" -triehash = "0.8" -walkdir = "2.5" -k256 = { version = "0.13.3", features = ["ecdsa"] } +# revm +revm = { workspace = true, features = ["std", "c-kzg", "blst", "hashbrown"] } +primitives.workspace = true +database.workspace = true +database-interface.workspace = true +state.workspace = true +bytecode = { workspace = true, features = ["std", "parse"] } +context.workspace = true +context-interface.workspace = true +inspector = { workspace = true, features = ["std", "tracer"] } +statetest-types.workspace = true +criterion.workspace = true + +# alloy +alloy-rlp = { workspace = true, features = ["arrayvec", "derive"] } +alloy-sol-types.workspace = true + +# misc +hash-db.workspace = true +indicatif.workspace = true +plain_hasher.workspace = true +serde = { workspace = true, features = ["derive", "rc"] } +serde_json = { workspace = true, features = ["preserve_order"] } +clap.workspace = true +thiserror.workspace = true +triehash.workspace = true +walkdir.workspace = true +k256 = { workspace = true, features = ["ecdsa"] } +csv = "1.1.6" + +[features] +# Optionally enable gmp because it doesn't work on i686 github actions runners +gmp = ["revm/gmp"] + +[[bench]] +name = "evm" +harness = false diff --git a/bins/revme/LICENSE b/bins/revme/LICENSE index ad98ff22cc..be6d350ebe 100644 --- a/bins/revme/LICENSE +++ b/bins/revme/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2021-2024 draganrakita +Copyright (c) 2021-2025 draganrakita Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/bins/revme/benches/evm.rs b/bins/revme/benches/evm.rs new file mode 100644 index 0000000000..14f0884d30 --- /dev/null +++ b/bins/revme/benches/evm.rs @@ -0,0 +1,14 @@ +use criterion::{criterion_group, criterion_main, Criterion}; +use revme::cmd::bench; + +fn evm(c: &mut Criterion) { + bench::analysis::run(c); + bench::burntpix::run(c); + bench::snailtracer::run(c); + bench::transfer::run(c); + bench::transfer_multi::run(c); + bench::evm_build::run(c); + bench::gas_cost_estimator::run(c); +} +criterion_group!(benches, evm); +criterion_main!(benches); diff --git a/bins/revme/src/cmd.rs b/bins/revme/src/cmd.rs index ec4d419a35..600ca8ce4c 100644 --- a/bins/revme/src/cmd.rs +++ b/bins/revme/src/cmd.rs @@ -1,26 +1,22 @@ +pub mod bench; pub mod bytecode; pub mod evmrunner; -pub mod format_kzg_setup; pub mod statetest; -use structopt::{clap::AppSettings, StructOpt}; +use clap::Parser; -#[derive(StructOpt, Debug)] -#[structopt(setting = AppSettings::InferSubcommands)] +#[derive(Parser, Debug)] +#[command(infer_subcommands = true)] #[allow(clippy::large_enum_variant)] pub enum MainCmd { - #[structopt(about = "Launch Ethereum state tests")] + /// Execute Ethereum state tests. Statetest(statetest::Cmd), - #[structopt( - about = "Format kzg settings from a trusted setup file (.txt) into binary format (.bin)" - )] - FormatKzgSetup(format_kzg_setup::Cmd), - #[structopt( - about = "Evm runner command allows running arbitrary evm bytecode.\nBytecode can be provided from cli or from file with --path option." - )] + /// Run arbitrary EVM bytecode. Evm(evmrunner::Cmd), - #[structopt(alias = "bc", about = "Prints the opcodes of an hex Bytecodes.")] + /// Print the structure of an EVM bytecode. Bytecode(bytecode::Cmd), + /// Run bench from specified list. + Bench(bench::Cmd), } #[derive(Debug, thiserror::Error)] @@ -28,21 +24,23 @@ pub enum Error { #[error(transparent)] Statetest(#[from] statetest::Error), #[error(transparent)] - KzgErrors(#[from] format_kzg_setup::KzgErrors), - #[error(transparent)] EvmRunnerErrors(#[from] evmrunner::Errors), + #[error("Custom error: {0}")] + Custom(&'static str), } impl MainCmd { pub fn run(&self) -> Result<(), Error> { match self { - Self::Statetest(cmd) => cmd.run().map_err(Into::into), - Self::FormatKzgSetup(cmd) => cmd.run().map_err(Into::into), - Self::Evm(cmd) => cmd.run().map_err(Into::into), + Self::Statetest(cmd) => cmd.run()?, + Self::Evm(cmd) => cmd.run()?, Self::Bytecode(cmd) => { cmd.run(); - Ok(()) + } + Self::Bench(cmd) => { + cmd.run(); } } + Ok(()) } } diff --git a/bins/revme/src/cmd/bench.rs b/bins/revme/src/cmd/bench.rs new file mode 100644 index 0000000000..f05b6b9a5e --- /dev/null +++ b/bins/revme/src/cmd/bench.rs @@ -0,0 +1,97 @@ +pub mod analysis; +pub mod burntpix; +pub mod evm_build; +pub mod gas_cost_estimator; +pub mod snailtracer; +pub mod transfer; +pub mod transfer_multi; + +use clap::{Parser, ValueEnum}; + +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, ValueEnum)] +pub enum BenchName { + Analysis, + Burntpix, + Snailtracer, + Transfer, + EvmBuild, + TransferMulti, + GasCostEstimator, +} + +impl BenchName { + pub const ALL: &[BenchName] = &[ + BenchName::Analysis, + BenchName::Burntpix, + BenchName::Snailtracer, + BenchName::Transfer, + BenchName::TransferMulti, + BenchName::EvmBuild, + BenchName::GasCostEstimator, + ]; + + pub fn as_str(self) -> &'static str { + match self { + BenchName::Analysis => "analysis", + BenchName::Burntpix => "burntpix", + BenchName::Snailtracer => "snailtracer", + BenchName::Transfer => "transfer", + BenchName::EvmBuild => "evm-build", + BenchName::TransferMulti => "transfer-multi", + BenchName::GasCostEstimator => "gas-cost-estimator", + } + } +} + +/// `bytecode` subcommand +#[derive(Parser, Debug)] +pub struct Cmd { + #[arg(value_enum)] + pub name: BenchName, + /// Warmup represents warm up time for benchmarks ran + #[arg(short = 'w', long)] + pub warmup: Option, + /// Samples represents default measurement time for benchmarks ran + #[arg(short = 'm', long)] + pub time: Option, + /// Samples represents size of the sample for benchmarks ran + #[arg(short = 's', long)] + pub samples: Option, +} + +impl Cmd { + /// Runs bench command. + pub fn run(&self) { + let mut criterion = criterion::Criterion::default() + .warm_up_time(std::time::Duration::from_secs_f64( + self.warmup.unwrap_or(0.5), + )) + // Measurement_time of 0.1 will get 500+ iterations for analysis and transfer and will be extended if needed in order to test the given sample size (minimum sample size is 10 per criterion documentation) as is the case with burntpix and snailtracer benchmark tests + .measurement_time(std::time::Duration::from_secs_f64(self.time.unwrap_or(1.5))) + .sample_size(self.samples.unwrap_or(10)); + + match self.name { + BenchName::Analysis => { + analysis::run(&mut criterion); + } + BenchName::Burntpix => { + burntpix::run(&mut criterion); + } + BenchName::Snailtracer => { + snailtracer::run(&mut criterion); + } + BenchName::Transfer => { + transfer::run(&mut criterion); + } + BenchName::EvmBuild => { + evm_build::run(&mut criterion); + } + BenchName::TransferMulti => { + transfer_multi::run(&mut criterion); + } + BenchName::GasCostEstimator => { + gas_cost_estimator::run(&mut criterion); + } + } + } +} diff --git a/bins/revme/src/cmd/bench/analysis.hex b/bins/revme/src/cmd/bench/analysis.hex new file mode 100644 index 0000000000..4d2cbe91b0 --- /dev/null +++ b/bins/revme/src/cmd/bench/analysis.hex @@ -0,0 +1 @@ +6060604052341561000f57600080fd5b604051610dd1380380610dd18339810160405280805190602001909190805182019190602001805190602001909190805182019190505083600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508360008190555082600390805190602001906100a79291906100e3565b5081600460006101000a81548160ff021916908360ff16021790555080600590805190602001906100d99291906100e3565b5050505050610188565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061012457805160ff1916838001178555610152565b82800160010185558215610152579182015b82811115610151578251825591602001919060010190610136565b5b50905061015f9190610163565b5090565b61018591905b80821115610181576000816000905550600101610169565b5090565b90565b610c3a806101976000396000f3006060604052600436106100af576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306fdde03146100b4578063095ea7b31461014257806318160ddd1461019c57806323b872dd146101c557806327e235e31461023e578063313ce5671461028b5780635c658165146102ba57806370a082311461032657806395d89b4114610373578063a9059cbb14610401578063dd62ed3e1461045b575b600080fd5b34156100bf57600080fd5b6100c76104c7565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156101075780820151818401526020810190506100ec565b50505050905090810190601f1680156101345780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561014d57600080fd5b610182600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035906020019091905050610565565b604051808215151515815260200191505060405180910390f35b34156101a757600080fd5b6101af610657565b6040518082815260200191505060405180910390f35b34156101d057600080fd5b610224600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061065d565b604051808215151515815260200191505060405180910390f35b341561024957600080fd5b610275600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919050506108f7565b6040518082815260200191505060405180910390f35b341561029657600080fd5b61029e61090f565b604051808260ff1660ff16815260200191505060405180910390f35b34156102c557600080fd5b610310600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610922565b6040518082815260200191505060405180910390f35b341561033157600080fd5b61035d600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610947565b6040518082815260200191505060405180910390f35b341561037e57600080fd5b610386610990565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156103c65780820151818401526020810190506103ab565b50505050905090810190601f1680156103f35780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561040c57600080fd5b610441600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035906020019091905050610a2e565b604051808215151515815260200191505060405180910390f35b341561046657600080fd5b6104b1600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610b87565b6040518082815260200191505060405180910390f35b60038054600181600116156101000203166002900480601f01602080910402602001604051908101604052809291908181526020018280546001816001161561010002031660029004801561055d5780601f106105325761010080835404028352916020019161055d565b820191906000526020600020905b81548152906001019060200180831161054057829003601f168201915b505050505081565b600081600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040518082815260200191505060405180910390a36001905092915050565b60005481565b600080600260008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905082600160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541015801561072e5750828110155b151561073957600080fd5b82600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254019250508190555082600160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8110156108865782600260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055505b8373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef856040518082815260200191505060405180910390a360019150509392505050565b60016020528060005260406000206000915090505481565b600460009054906101000a900460ff1681565b6002602052816000526040600020602052806000526040600020600091509150505481565b6000600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b60058054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610a265780601f106109fb57610100808354040283529160200191610a26565b820191906000526020600020905b815481529060010190602001808311610a0957829003601f168201915b505050505081565b600081600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410151515610a7e57600080fd5b81600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555081600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a36001905092915050565b6000600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050929150505600a165627a7a72305820df254047bc8f2904ad3e966b6db116d703bebd40efadadb5e738c836ffc8f58a0029 \ No newline at end of file diff --git a/bins/revme/src/cmd/bench/analysis.rs b/bins/revme/src/cmd/bench/analysis.rs new file mode 100644 index 0000000000..e8fdb3704f --- /dev/null +++ b/bins/revme/src/cmd/bench/analysis.rs @@ -0,0 +1,37 @@ +use context::TxEnv; +use criterion::Criterion; +use database::{BenchmarkDB, BENCH_CALLER, BENCH_TARGET}; +use revm::{ + bytecode::Bytecode, + primitives::{bytes, hex, Bytes, TxKind}, + Context, ExecuteEvm, MainBuilder, MainContext, +}; + +const BYTES: &str = include_str!("analysis.hex"); + +pub fn run(criterion: &mut Criterion) { + let bytecode = Bytecode::new_raw(Bytes::from(hex::decode(BYTES).unwrap())); + // BenchmarkDB is dummy state that implements Database trait. + let context = Context::mainnet() + .with_db(BenchmarkDB::new_bytecode(bytecode)) + .modify_cfg_chained(|c| c.disable_nonce_check = true); + let tx = TxEnv::builder() + .caller(BENCH_CALLER) + .kind(TxKind::Call(BENCH_TARGET)) + .data(bytes!("8035F0CE")) + .build() + .unwrap(); + let mut evm = context.build_mainnet(); + criterion.bench_function("analysis", |b| { + b.iter_batched( + || { + // create a transaction input + tx.clone() + }, + |input| { + let _ = evm.transact_one(input); + }, + criterion::BatchSize::SmallInput, + ); + }); +} diff --git a/bins/revme/src/cmd/bench/burntpix.rs b/bins/revme/src/cmd/bench/burntpix.rs new file mode 100644 index 0000000000..1e65627fe4 --- /dev/null +++ b/bins/revme/src/cmd/bench/burntpix.rs @@ -0,0 +1,172 @@ +pub mod static_data; + +use context::TxEnv; +use criterion::Criterion; +use primitives::{StorageKey, StorageValue}; +use static_data::{ + BURNTPIX_ADDRESS_ONE, BURNTPIX_ADDRESS_THREE, BURNTPIX_ADDRESS_TWO, BURNTPIX_BYTECODE_FOUR, + BURNTPIX_BYTECODE_ONE, BURNTPIX_BYTECODE_THREE, BURNTPIX_BYTECODE_TWO, BURNTPIX_MAIN_ADDRESS, + STORAGE_ONE, STORAGE_TWO, STORAGE_ZERO, +}; + +use alloy_sol_types::{sol, SolCall}; +use database::{CacheDB, BENCH_CALLER}; +use revm::{ + database_interface::EmptyDB, + primitives::{hex, keccak256, Address, Bytes, TxKind, B256, U256}, + state::{AccountInfo, Bytecode}, + Context, ExecuteEvm, MainBuilder, MainContext, +}; + +use std::{error::Error, fs::File, io::Write}; + +use std::str::FromStr; + +sol! { + #[derive(Debug, PartialEq, Eq)] + interface IBURNTPIX { + function run( uint32 seed, uint256 iterations) returns (string); + } +} + +pub fn run(criterion: &mut Criterion) { + let (seed, iterations) = try_init_env_vars().expect("Failed to parse env vars"); + + let run_call_data = IBURNTPIX::runCall { seed, iterations }.abi_encode(); + + let db = init_db(); + + let mut evm = Context::mainnet() + .with_db(db) + .modify_cfg_chained(|c| c.disable_nonce_check = true) + .build_mainnet(); + + let tx = TxEnv::builder() + .caller(BENCH_CALLER) + .kind(TxKind::Call(BURNTPIX_MAIN_ADDRESS)) + .data(run_call_data.clone().into()) + .gas_limit(u64::MAX) + .build() + .unwrap(); + + criterion.bench_function("burntpix", |b| { + b.iter_batched( + || { + // create a transaction input + tx.clone() + }, + |input| { + evm.transact_one(input).unwrap(); + }, + criterion::BatchSize::SmallInput, + ); + }); + + //Collects the data and uses it to generate the svg after running the benchmark + /* + let tx_result = evm.replay().unwrap(); + let return_data = match tx_result.result { + context::result::ExecutionResult::Success { + output, gas_used, .. + } => { + println!("Gas used: {:?}", gas_used); + match output { + context::result::Output::Call(value) => value, + _ => unreachable!("Unexpected output type"), + } + } + _ => unreachable!("Execution failed: {:?}", tx_result), + }; + + // Remove returndata offset and length from output + let returndata_offset = 64; + let data = &return_data[returndata_offset..]; + + // Remove trailing zeros + let trimmed_data = data + .split_at(data.len() - data.iter().rev().filter(|&x| *x == 0).count()) + .0; + let file_name = format!("{}_{}", seed, iterations); + + svg(file_name, trimmed_data).expect("Failed to store svg"); + */ +} + +/// Actually generates the svg +pub fn svg(filename: String, svg_data: &[u8]) -> Result<(), Box> { + let current_dir = std::env::current_dir()?; + let svg_dir = current_dir.join("burntpix").join("svgs"); + std::fs::create_dir_all(&svg_dir)?; + + let file_path = svg_dir.join(format!("{filename}.svg")); + let mut file = File::create(file_path)?; + file.write_all(svg_data)?; + + Ok(()) +} + +const DEFAULT_SEED: &str = "0"; +const DEFAULT_ITERATIONS: &str = "0x4E20"; // 20_000 iterations +fn try_init_env_vars() -> Result<(u32, U256), Box> { + let seed_from_env = std::env::var("SEED").unwrap_or(DEFAULT_SEED.to_string()); + let seed: u32 = try_from_hex_to_u32(&seed_from_env)?; + let iterations_from_env = std::env::var("ITERATIONS").unwrap_or(DEFAULT_ITERATIONS.to_string()); + let iterations = U256::from_str(&iterations_from_env)?; + Ok((seed, iterations)) +} + +fn try_from_hex_to_u32(hex: &str) -> Result> { + let trimmed = hex.strip_prefix("0x").unwrap_or(hex); + u32::from_str_radix(trimmed, 16).map_err(|e| format!("Failed to parse hex: {e}").into()) +} + +fn insert_account_info(cache_db: &mut CacheDB, addr: Address, code: &str) { + let code = Bytes::from(hex::decode(code).unwrap()); + let code_hash = hex::encode(keccak256(&code)); + let account_info = AccountInfo::new( + U256::from(0), + 0, + B256::from_str(&code_hash).unwrap(), + Bytecode::new_raw(code), + ); + cache_db.insert_account_info(addr, account_info); +} + +fn init_db() -> CacheDB { + let mut cache_db = CacheDB::new(EmptyDB::default()); + + insert_account_info(&mut cache_db, BURNTPIX_ADDRESS_ONE, BURNTPIX_BYTECODE_ONE); + insert_account_info(&mut cache_db, BURNTPIX_MAIN_ADDRESS, BURNTPIX_BYTECODE_TWO); + insert_account_info(&mut cache_db, BURNTPIX_ADDRESS_TWO, BURNTPIX_BYTECODE_THREE); + insert_account_info( + &mut cache_db, + BURNTPIX_ADDRESS_THREE, + BURNTPIX_BYTECODE_FOUR, + ); + + cache_db + .insert_account_storage( + BURNTPIX_MAIN_ADDRESS, + StorageKey::from(0), + StorageValue::from_be_bytes(*STORAGE_ZERO), + ) + .unwrap(); + + cache_db + .insert_account_storage( + BURNTPIX_MAIN_ADDRESS, + StorageKey::from(1), + StorageValue::from_be_bytes(*STORAGE_ONE), + ) + .unwrap(); + + cache_db + .insert_account_storage( + BURNTPIX_MAIN_ADDRESS, + StorageKey::from(2), + StorageValue::from_be_bytes(*STORAGE_TWO), + ) + .unwrap(); + + cache_db +} diff --git a/bins/revme/src/cmd/bench/burntpix/bytecode_four.hex b/bins/revme/src/cmd/bench/burntpix/bytecode_four.hex new file mode 100644 index 0000000000..6ee2ee3e6a --- /dev/null +++ b/bins/revme/src/cmd/bench/burntpix/bytecode_four.hex @@ -0,0 +1 @@ +60806040526004361015610011575f80fd5b5f3560e01c80634594229c146106865780638cd8db8a146100b15763f3ccaac01461003a575f80fd5b346100ad575f3660031901126100ad57610052610ac3565b604092919251928391606083528351918260608501525f5b8381106100955750608094505f85848601015260208401526040830152601f80199101168101030190f35b6020868201810151608089840101528795500161006a565b5f80fd5b346100ad5760603660031901126100ad576001546004359060443590602435906001600160a01b0316156100ad578060035581600455026101056100fc6100f78361094c565b6108e0565b9180835261094c565b602082019190601f19013683375167ffffffffffffffff918282116105e757600160401b82116105e75760055482600555808310610646575b5060055f525f5b828110610612575050604051916080830191508111828210176105e757604052600381525f5b606081106105fb5750805190600160401b82116105e757600a5482600a55808310610554575b50602001600a5f525f80516020611a418339815191525f915b83831061053657845f620f424060011d620f4240806101d1620f423f198460011b01611a34565b810302055b600383106103b457600a54846101ee6100f78361094c565b9180835260208301600a5f525f80516020611a418339815191525f915b83831061033957858561021c610906565b5f5b83601482106103245750506102316108bf565b60c89060c881526119008036602084013761024a6108bf565b9060c882523660208301375f60208501935b8082106102f357505060809495506102738261178d565b61027c8161178d565b61028f61028883610a60565b5192610a71565b5161029c61028883610a60565b519280820383850381136102db575b506006556007556008556009558151600b5551600c556040810151600d556060810151600e550151600f55600255005b939290920160011d9260011d808401930391886102ab565b90956103028689600193610cab565b96865161030f8287610a82565b52855161031c8286610a82565b52019061025c565b826103329160019395610cab565b920161021e565b600a602060019261034861089e565b855481528486015483820152600286015460408201526003860154606082015260048601546080820152600586015460a0820152600686015460c0820152600786015460e08201526008860154610100820152600986015461012082015281520192019201919061020b565b9091926103bf6109b7565b5061040f6104056103fb6103f16103e76103e06103da6109b7565b96611a0d565b8752611a0d565b6020870152611a0d565b6040860152611a0d565b6060850152611a0d565b6080840152611a0d565b60a0830152600160401b6001675851f42d4c957f2d92830208916101688360201c07603c90620f4240610450620f423f19621e848085848602050701611a34565b8103870205918112156104e9575084905f5b60028705880390810161010085015290810160e08401520160c0820152601a600160401b60018486020860201c06610120820152600a548610156104d557600192600160401b926104ca8593600a5f52600a8a025f80516020611a41833981519152016109fd565b0208930191906101d6565b634e487b7160e01b5f52603260045260245ffd5b60788112156104fa5750845f610462565b60b481121561050c5750845f91610462565b60f081121561051e57505f9085610462565b61012c131561052e575f85610462565b5f8591610462565b600a60208261054860019451866109fd565b019201920191906101aa565b80600a0290600a8204036105d35782600a02600a810484036105d3575f80516020611a4183398151915291820191015b8181106105915750610191565b805f600a92555f60018201555f60028201555f60038201555f60048201555f60058201555f60068201555f60078201555f60088201555f600982015501610584565b634e487b7160e01b5f52601160045260245ffd5b634e487b7160e01b5f52604160045260245ffd5b6020906106066109b7565b8282850101520161016b565b60019060208351930192817f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db0015501610145565b827f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db091820191015b81811061067b575061013e565b5f815560010161066e565b346100ad5760203660031901126100ad576001546001600160a01b0316156100ad5760035460045490600654916007549060085490600954926106c7610906565b93600a54966106d86100f78961094c565b9780895260208901600a5f525f80516020611a418339815191525f915b8383106108155750505050600254965f955b600435871061073c578751600b556020880151600c556040880151600d556060880151600e556080880151600f556002899055005b90919293949597610750888b600193610cab565b9888518581139081159161080a575b5080156107fc575b80156107ee575b6107e957836107888a8a866020818c039301510302610964565b0261079a86890386888d510302610964565b016107be60408b015160c01b60608c015160801b0160808c015160401b0191610982565b620f4240829392549160031b9282841c0101821b915f19901b19161790555b01959493929190610707565b6107dd565b50602089015186131561076e565b508260208a01511315610767565b90508713158c61075f565b600a602060019261082b9d9798999a9b9d61089e565b855481528486015483820152600286015460408201526003860154606082015260048601546080820152600586015460a0820152600686015460c0820152600786015460e082015260088601546101008201526009860154610120820152815201920192019190999796959493996106f5565b60405190610140820182811067ffffffffffffffff8211176105e757604052565b60405190611920820182811067ffffffffffffffff8211176105e757604052565b6040519190601f01601f1916820167ffffffffffffffff8111838210176105e757604052565b6040519060a0820182811067ffffffffffffffff8211176105e75760405281600b548152600c546020820152600d546040820152600e5460608201526080600f54910152565b67ffffffffffffffff81116105e75760051b60200190565b811561096e570490565b634e487b7160e01b5f52601260045260245ffd5b6005548110156104d55760055f527f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db001905f90565b6109bf61089e565b905f82525f60208301525f60408301525f60608301525f60808301525f60a08301525f60c08301525f60e08301525f6101008301525f610120830152565b90610120600991805184556020810151600185015560408101516002850155606081015160038501556080810151600485015560a0810151600585015560c0810151600685015560e0810151600785015561010081015160088501550151910155565b8051600a10156104d5576101600190565b805160be10156104d5576117e00190565b80518210156104d55760209160051b010190565b67ffffffffffffffff81116105e757601f01601f191660200190565b9081518110156104d5570160200190565b600380549160045491828402908482048414851517156105d357808202918083048214901517156105d357610afa6100f783610a96565b91808352610b0a601f1991610a96565b013660208401375f805b858110610c4e57508015610c4757610b2b90611809565b8015610c3f575b5f5b858110610b4357505050929190565b5f5b878110610b555750600101610b34565b8088830201610b6381610982565b905490861b1c67ffffffffffffffff91868684841680610b8c575b505050505050600101610b45565b610b9581611809565b60ff9083610bab8460c08a901c84028502610964565b90610bb591610964565b9784610bcb8560808b901c841685028602610964565b90610bd591610964565b9760401c16020290610be691610964565b90610bf091610964565b91029260ff60f81b80938160f893841b165f1a610c0d878d610ab2565b53821b165f1a610c20600186018b610ab2565b531b165f1a90600201610c339087610ab2565b535f8080868682610b7e565b506001610b32565b5050929190565b5f5b878110610c605750600101610b14565b67ffffffffffffffff610c76828a850201610982565b905490861b1c16808410610c8e575b50600101610c50565b92506001610c85565b811561096e570590565b811561096e570790565b9091600160401b60018181675851f42d4c957f2d958602089160209083968051801561096e5785841c06610cde91610a82565b519585875195815190620f424097868b0191825193888601809d8b8d808451998a98828881604089019c8d51950205920205010195606085015102059060808401998a510205019860a08301998a51018094528481526040810190815160c085015101831c926060820190815160e087015101811c9260800190815161010088015101901c90525252610120015180610dda575b5050505050505050505050505080516305f5e0ff19808212918215610dcc575b508115610dc1575b508015610db3575b610dab57505090565b5f8092525290565b506305f5e100825113610da2565b90508251125f610d9a565b6305f5e1001291505f610d92565b808c03610e195750505050505050505050505050610df881516118ae565b610e0283516118ae565b835281525b5f808080808080808080808080610d72565b60028103610e6d57505050505050505050505050610e5a82518280865180028380020105918215610e63575b610e5191839102610c97565b92855102610c97565b83528152610e07565b9091508190610e45565b60038103610ec457505050505050505050505050610e958183518551800290800201056118ae565b610ea781800264e8d4a510000361187d565b908351918551848382028386020105875202910203058152610e07565b60048103610f1f57505050505050505050505090610e5a90610eee8451865180029080020161187d565b908115610f17575b50610f0a8185518751808201910302610c97565b928451901b855102610c97565b90505f610ef6565b60058103610f535750505050505050505050505050610f418151835190611914565b610e5a8251845180029080020161187d565b60068103610fbd57505050505050505050505050610f748251845190611914565b90610f878351855180029080020161187d565b610fb2610fa48284610f9a8288016118ae565b82020595036118ae565b800264e8d4a510000361187d565b020583528152610e07565b6007810361102157505050505050505050505050610fde8251845190611914565b610ffd82610ff48551875180029080020161187d565b809302056118ae565b908261101183800264e8d4a510000361187d565b825f030205855202058152610e07565b60088103611087575050505050505050505050506110428251845190611914565b6110656110578451865180029080020161187d565b92622fefd8938402056118ae565b908261107983800264e8d4a510000361187d565b820205855202058152610e07565b6009810361110f57505050505050505050505050610e5a6110ab8351855190611914565b6110bd8451865180029080020161187d565b908115611107575b6110ce906118ae565b9264e8d4a510006110ff83836110e7888002850361187d565b936110ff6110f4846118ae565b91828002900361187d565b940102610c97565b8391506110c5565b600a8103611189575050505050505050505050506111308251845190611914565b906111438351855180029080020161187d565b91821561117f575b611154906118ae565b91611173818361116c86800264e8d4a510000361187d565b9502610c97565b92020583528152610e07565b909150819061114b565b600b8103611200575050505050505050505050506111aa8251845190611914565b906111c66111c08451865180029080020161187d565b926118ae565b8164e8d4a51000916111f26111e76111e1838002860361187d565b966118ae565b93848002900361187d565b020592020583528152610e07565b600c810361127857505050505050505050505050506112228151835190611914565b6112496112378351855180029080020161187d565b6112428184016118ae565b92036118ae565b9061125d64e8d4a51000928002830361187d565b90808002029080800202908282820305855201058152610e07565b9b9e98999a9b600d81145f146113035750505050505050506112d993929185910208958380885f941c16146112f8575b6112d16112b88651885190611914565b916112cb8751895180029080020161187d565b0261187d565b931d016118ae565b6112eb81800264e8d4a510000361187d565b8202910283528152610e07565b622fefd891506112a8565b989e98600e819c979b95989c999699145f146113735750505050505050505050505081515f8112155f1461134e57508251905f8212611344575b5050610e07565b1d82525f8061133d565b83519091905f811261136757508251901b825250610e07565b811d84521b8152610e07565b600f819d98999a9b9c9d145f146113fb5750505050505050508290518002059384156113f1575b8290518002059384156113e7575b6113ce6113bf6113c46113bf8694858c5102610c97565b6118ae565b9683895102610c97565b9486519251020501928551925102050183528152610e07565b91935083916113a8565b919350839161139a565b6010919395979b5080929496989c9950145f1461145e575050505050505050610e5a919250806114338551875180029080020161187d565b01908115611456575b61144b82828851871b02610c97565b938551901b02610c97565b90508061143c565b969896601181036114935750505050505050506114816113bf86516003026119cf565b92816113ce6113bf87516003026119cf565b979896976012810361151b5750505050505050509080809351800205918215611512575b826114d8816114ce88518a5180029080020161187d565b931b828401610ca1565b03928203020501906114f06113bf8451865190611914565b8161150382800264e8d4a510000361187d565b84020592020583528152610e07565b915080916114b7565b969796601381036115b3575050505050505061157d90622fefd8945164e8d4a51000958187920202059081156115ab575b81811d92839161155f89518b5190611914565b901d9261157489518b5180029080020161187d565b95518401610ca1565b131561159d57611591916111e791036118ae565b02059083528152610e07565b611591916111e791016118ae565b84915061154c565b601491939597999a50809294969850145f1461161357505050505050509080610e5a916115e88551875180029080020161187d565b0190811561160b575b61160082828751871b02610c97565b938651901b02610c97565b9050806115f1565b60158103611665575050505050505050610e5a825182623d0900818751800284800201050191821561165b575b61164f91839160021b02610c97565b92855160021b02610c97565b9091508190611640565b601681036116875750505050505050505061168081516118ae565b8152610e07565b601781036116f05750505050505050506116dc6116a484516118ae565b826116b782800264e8d4a510000361187d565b9182156116e6575b6116cb91839102610c97565b926116d685516118ae565b02610c97565b9083528152610e07565b90915081906116bf565b6018819c9495969799989c145f14611729575050505090878181869486020880940208961d92838388831c070386521c07038152610e07565b9350945094955097506019915014611744575b505050610e07565b82918183920290800203058002058015611786575b801561096e5761176f9064e8d4a510000561187d565b8251845182028390058552020581525f808061173c565b5080611759565b80515f5b81811061179d57505050565b60018082015b8381106117b4575050600101611791565b81906117c08487610a82565b516117cb8288610a82565b51126117d8575b016117a3565b6117e28187610a82565b516117ed8588610a82565b516117f88389610a82565b526118038588610a82565b526117d2565b5f905b6216e36081101561186a57600190620f423f190181815b600a8410611832575050505090565b90918060028596611844839786610964565b0193620f424093849102049361185c86890186610964565b900396019493920204611823565b9062062fd9600391019160011b0461180c565b90600180830160011d90835b84831261189557505050565b91935090836118a48183610c97565b01821d9190611889565b905f91625fdfb0809107905f821261190d575b50600260018181845b8386136118d957505050505050565b9091929364e8d4a510008280889a6118f489869b8902610c97565b019a0202059594600185018502029301915f03906118ca565b015f6118c1565b91908215806119c7575b6119c1575f9061192d84611a34565b61193682611a34565b80821384146119a95761199191620f42406119519202610c97565b620f42409081808280020581808080612cc81985020561caee018402056201c41019018302056202f2d3018202056205131719010205620f422601020590565b622fefd860011d03935b02126119a357565b905f0390565b61195190620f42406119bb9302610c97565b9361199b565b505f9150565b50801561191e565b6119db6119ff916118ae565b6119ed81800264e8d4a510000361187d565b908115611a02575b620f424002610c97565b90565b620f424091506119f5565b6001600160401b91675851f42d4c957f2d020890621e8480602083901c07620f423f190190565b5f81136119ff575f039056fec65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a8a2646970667358221220b3f2fe21ac0faf4ab1951c6297ccc37675d0c82e067ed2dd736ca86eeb03ebe164736f6c63430008170033 \ No newline at end of file diff --git a/bins/revme/src/cmd/bench/burntpix/bytecode_one.hex b/bins/revme/src/cmd/bench/burntpix/bytecode_one.hex new file mode 100644 index 0000000000..3091ce7069 --- /dev/null +++ b/bins/revme/src/cmd/bench/burntpix/bytecode_one.hex @@ -0,0 +1 @@ +60806040526004361015610011575f80fd5b5f3560e01c63d85fe4b414610024575f80fd5b346100925760603660031901126100925767ffffffffffffffff60043581811161009257366023820112156100925780600401359182116100925736602483830101116100925761008e9161008291604435916024803592016103ee565b604051918291826100b7565b0390f35b5f80fd5b5f5b8381106100a75750505f910152565b8181015183820152602001610098565b604091602082526100d78151809281602086015260208686019101610096565b601f01601f1916010190565b634e487b7160e01b5f52604160045260245ffd5b6040810190811067ffffffffffffffff82111761011357604052565b6100e3565b90601f8019910116810190811067ffffffffffffffff82111761011357604052565b67ffffffffffffffff811161011357601f01601f191660200190565b60405190610163826100f7565b60208083523683820137565b906101798261013a565b6101866040519182610118565b8281528092610197601f199161013a565b0190602036910137565b604051906060820182811067ffffffffffffffff82111761011357604052603c82527f74683d22313522206865696768743d223135222072783d2232222f3e000000006040837f3c726563742069643d22702220783d222d31352220793d222d3135222077696460208201520152565b9061022460209282815194859201610096565b0190565b60206102699193929360405194816102498793518092868087019101610096565b820161025d82518093868085019101610096565b01038085520183610118565b565b60405190610278826100f7565b601082526f181899199a1a9b1b9c1cb0b131b232b360811b6020830152565b634e487b7160e01b5f52603260045260245ffd5b908210156102b7570190565b610297565b9081518110156102b7570160200190565b9693909897949195929560405199888b9951908160208c0191602001916102f392610096565b8901711e3ab9b290343932b31e9111b811103c1e9160711b60208201528151918260328301916020019161032692610096565b016411103c9e9160d91b603282015260370161034191610211565b68222066696c6c3d222360b81b8152956001600160f81b03191660098701526001600160f81b031916600a8601526001600160f81b031916600b8501526001600160f81b031916600c8401526001600160f81b031916600d8301526001600160f81b031916600e8201526211179f60e91b600f82015203600d19810183526012016102699083610118565b604051906103d9826100f7565b60068252651e17b9bb339f60d11b6020830152565b91909161040361011c6036868502020161016f565b9361042b61042261041483866105a2565b61041c6101a1565b90610228565b602087016106fd565b93909461043661026b565b5f94859160105b86881061047957505050505050505061047692916104606104669261041c6103cc565b906106fd565b90829003601f1901825290610228565b90565b5f60105b87821061049457505060106001910197019661043d565b949a90998b6104a48189886102ab565b3560f81c6104b6600183018a896102ab565b3560f81c916104c9906002018a896102ab565b3560f81c906104d78961079c565b926104e18761079c565b600492600f91826104f683871c82168d6102bc565b516001600160f81b031916921661050d908c6102bc565b516001600160f81b0319169280878d8261052b898b1c8216836102bc565b516001600160f81b0319169816610541916102bc565b516001600160f81b031916971c16610559908d6102bc565b516001600160f81b0319169616610570908c6102bc565b516001600160f81b03191696610585986102cd565b61058e916106fd565b99909a60030194601001906001019061047d565b601960016104769260041b01926106cb60016105bd8661079c565b9260041b01600a6106b66105e26105dc6105d68561079c565b9961079c565b9361079c565b92607f604051998a977f3c73766720786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323060208a01527f30302f737667222076657273696f6e3d22312e31222076696577426f783d223060408a01526201018160ed1b60608a015261065781518092602060638d019101610096565b8801600160fd1b6063820152610677825180936020606485019101610096565b0161111f60f11b60648201526106af606682017f3c7265637420783d22302220793d2230222077696474683d22000000000000009052565b0190610211565b6911103432b4b3b43a1e9160b11b81526106af565b7f222072783d2233222066696c6c3d2223323032303230222f3e00000000000000815203600619810184520182610118565b91909160208084018451918260051c905f5b82811061076b5750505050601f1916808451039061072c8261016f565b945f5b83811061073e57505050509190565b6001906001600160f81b0319610756858301856102bc565b51165f1a610764828a6102bc565b530161072f565b83518652948101949281019260010161070f565b6040519061078c826100f7565b60018252600360fc1b6020830152565b8015610832576107aa610156565b90805f915b61080357506107bd8161016f565b915f5b8281106107cd5750505090565b6001906107f06107e28286035f1901856102bc565b516001600160f81b03191690565b5f1a6107fc82876102bc565b53016107c0565b90600a80830692048161082c6001839492019460ff60f81b9060300160f81b165f1a91866102bc565b536107af565b5061047661077f56fea26469706673582212202620cded94f0cf54cc3df219c4b7a2d33ca1cff9b87da504fdd707bc8b7d38e464736f6c63430008170033 \ No newline at end of file diff --git a/bins/revme/src/cmd/bench/burntpix/bytecode_three.hex b/bins/revme/src/cmd/bench/burntpix/bytecode_three.hex new file mode 100644 index 0000000000..5e2eb3ed1e --- /dev/null +++ b/bins/revme/src/cmd/bench/burntpix/bytecode_three.hex @@ -0,0 +1 @@ +60806040526004361015610011575f80fd5b5f3560e01c6354f6127f14610024575f80fd5b3461005b57602036600319011261005b5761005761004360043561014b565b604051918291602083526020830190610080565b0390f35b5f80fd5b5f5b8381106100705750505f910152565b8181015183820152602001610061565b906020916100998151809281855285808601910161005f565b601f01601f1916010190565b6040810190811067ffffffffffffffff8211176100c157604052565b634e487b7160e01b5f52604160045260245ffd5b6060810190811067ffffffffffffffff8211176100c157604052565b6020810190811067ffffffffffffffff8211176100c157604052565b90601f8019910116810190811067ffffffffffffffff8211176100c157604052565b67ffffffffffffffff81116100c157601f01601f191660200190565b7f2abb082c1b23ea79fce2a9e934ecb19ce15738b1483c365d0125f47e8ccc7dfc8114610855577fef285b02a4f711ad84793f73cc8ed6fea8af7013ece8132dacb7b33f6bce93da81146106d5577f708e7b881795f2e6b6c2752108c177ec89248458de3bf69d0d43480b3e5034e6811461069f577feafec4d89fa9619884b60000a4d96624a38f7ac2d8d9a604ecf07c12c77e480c811461067e577fdeba1e292f8ba88238e10ab3c7f88bd4be4fac56cad5194b6ecceaf653468af18114610658577f2f0a68ab07768e01943a599e73362a0e17a63a72e94dd2e384d2c1d4db9327568114610637577fe0261fa95db2eb3b5439bd033cda66d56b96f92f243a8228fd87550ed7bdfdb3811461061f577f9afb95cacc9f95858ec44aa8c3b685511002e30ae54415823f406128b85b238e146102985760405161028e816100f1565b5f81525f36813790565b6102a06110e5565b805160208201206102af61085e565b906102b990610a2f565b6102c1610937565b926102cb90610af9565b6040516102d7816100a5565b6013815272227d5d5d2c2261747472696275746573223a5b60681b6020820190815260105461030590610c7c565b60115461031190610e26565b9060125461031e90610f13565b9260135461032b90610f13565b9460405196610339886100a5565b6003885260208801625d7d7d60e81b90526040519a8b9960208b019b8c81516020819301916103679261005f565b8b016020810161060f60f31b90528151918260228301916020019161038b9261005f565b01815191826022830191602001916103a29261005f565b01602281017f646174613a696d6167652f7376672b786d6c3b6261736536342c000000000000905281519182603c830191602001916103e09261005f565b0190519182603c83016103f29261005f565b01603c81017f7b226b6579223a22497465726174696f6e73222c2274797065223a226e756d6290526b32b91116113b30b63ab2911d60a11b605c820152815191826068830191602001916104459261005f565b0160688101611f4b60f21b9052606a81017f7b226b6579223a2247617355736564222c2274797065223a22737472696e672290526916113b30b63ab2911d1160b11b608a820152815191826094830191602001916104a29261005f565b019062089f4b60ea1b91826094820152609781017f7b226b6579223a22466565734275726e74222c2274797065223a22737472696e90526b339116113b30b63ab2911d1160a11b60b78201528151918260c3830191602001916105049261005f565b019060c382015260c681017f7b226b6579223a225469707350616964222c2274797065223a22737472696e6790526a1116113b30b63ab2911d1160a91b60e68201528151918260f18301916020019161055c9261005f565b0161227d60f01b60f18201528151918260f38301916020019161057e9261005f565b010360d38101835260f301610593908361010d565b815181206040515f602082015263379abe3560e11b6022820152600160f51b602682015260288101919091527f646174613a6170706c69636174696f6e2f6a736f6e3b636861727365743d5554604882015263118b4e0b60e21b606882015291518291610606908290606c85019061005f565b810103604c81018252606c0161061c908261010d565b90565b50604051600260208201526020815261061c816100a5565b50604051610644816100a5565b6004815263084a092b60e31b602082015290565b50604051610665816100a5565b6009815268084eae4dce840a0d2f60bb1b602082015290565b5060405161068b816100a5565b60048152632936598960e21b602082015290565b505f546bffffffffffffffffffffffff19806040519260601b1660208301523060601b1660348201526034815261061c816100d5565b506106de6110e5565b8051602090818301206106ef61085e565b906106f990610a2f565b610701610937565b9361070b90610af9565b604051610717816100a5565b600681528481019165227d5d5d7d7d60d01b8352604051968794878087018881995192839101916107479261005f565b860188810161060f60f31b9052815191828a602284019201916107699261005f565b0181519182896022840192019161077f9261005f565b01602281017f646174613a696d6167652f7376672b786d6c3b6261736536342c00000000000090528151918288603c84019201916107bc9261005f565b0190519182603c83016107ce9261005f565b0103601c81018452603c016107e3908461010d565b825181209260405193849384015f90526022840163379abe3560e11b9052600160f51b60268501526028840152604883017f646174613a6170706c69636174696f6e2f6a736f6e3b636861727365743d555490526068830163118b4e0b60e21b9052519081606c84016106069261005f565b5061061c6110e5565b6040519060c0820182811067ffffffffffffffff8211176100c1576040908152609383527f7b224c5350344d65746164617461223a7b226c696e6b73223a5b7b2275726c2260208401527f3a2268747470733a2f2f6275726e747069782e636f6d227d5d2c22696d616765908301527f73223a5b5b7b227769647468223a3736382c22686569676874223a3736382c2260608301527f766572696669636174696f6e223a7b226d6574686f64223a226b656363616b326080830152721a9b14313cba32b9949116113230ba30911d1160691b60a0830152565b60405190610944826100a5565b600a825269113e96113ab936111d1160b11b6020830152565b9081602091031261005b57516001600160a01b038116810361005b5790565b3d156109a6573d9061098d8261012f565b9161099b604051938461010d565b82523d5f602084013e565b606090565b60208183031261005b5780519067ffffffffffffffff821161005b570181601f8201121561005b5780516109de8161012f565b926109ec604051948561010d565b8184526020828401011161005b5761061c916020808501910161005f565b908151811015610a1b570160200190565b634e487b7160e01b5f52603260045260245ffd5b6040805191610a3d836100a5565b601083526020926f181899199a1a9b1b9c1cb0b131b232b360811b6020820152604051610a69816100f1565b5f8152935f935b818510610a7f57505050505090565b9091929394600190610aee60228789601f0360031b1c9260ff60f81b610aba600f82610ab0828960041c168d610a0a565b511696168a610a0a565b51169386519482610ad487945180928c808801910161005f565b83019189830152602182015203600281018452018261010d565b950193929190610a70565b805115610c6957604051610b0c816100d5565b604081527f4142434445464748494a4b4c4d4e4f505152535455565758595a61626364656660208201527f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f604082015281519160029260028101809111610c5557600390819004600281901b94906001600160fe1b03811603610c55579290610bad610b978661012f565b95610ba5604051978861010d565b80875261012f565b6020860190601f190136823793839284518501935b848110610c02575050505050600390510680600114610bf057600214610be6575090565b603d905f19015390565b50603d90815f19820153600119015390565b8360049197929394959701918251600190603f9082828260121c16880101518453828282600c1c16880101518385015382828260061c168801015188850153168501015186820153019593929190610bc2565b634e487b7160e01b5f52601160045260245ffd5b50604051610c76816100f1565b5f815290565b8015610d3d57604051610c8e816100a5565b6020815260203681830137815f925b610d0e5750610cab8261012f565b91610cb9604051938461010d565b808352601f19610cc88261012f565b013660208501375f5b818110610cde5750505090565b6001906001600160f81b0319610cf98285035f190186610a0a565b51165f1a610d078287610a0a565b5301610cd1565b91600a808406930481610d376001839492019560ff60f81b9060300160f81b165f1a9185610a0a565b53610c9d565b50604051610d4a816100a5565b60018152600360fc1b602082015290565b602190610dbf9294936040519582610d7d88945180926020808801910161005f565b8301601760f91b6020820152610d9c825180936020888501910161005f565b01610db0825180936020878501910161005f565b0103600181018552018361010d565b565b602290610dbf9294936040519582610de388945180926020808801910161005f565b83016102e360f41b6020820152610e03825180936020888501910161005f565b01610e17825180936020878501910161005f565b0103600281018552018361010d565b620f4240808210610f0957633b9aca0080831015610e9e5750604051610e4b816100a5565b60018152604d60f81b602082015290612710818406049204915b600a811015610e8957610e83610e7d61061c94610c7c565b91610c7c565b90610dc1565b610e98610e7d61061c94610c7c565b90610d5b565b905064e8d4a5100080831015610eda5750604051610ebb816100a5565b60018152602160f91b6020820152906298968081840604920491610e65565b9050604051610ee8816100a5565b60018152601560fa1b6020820152906402540be40081840604920491610e65565b5061061c90610c7c565b6103e88082106110a257620f424080831015610f695750604051610f36816100a5565b60048152634b57656960e01b602082015290600a81840604920491600a811015610e8957610e83610e7d61061c94610c7c565b9050633b9aca0080831015610fa65750604051610f85816100a5565b60048152634d57656960e01b60208201529061271081840604920491610e65565b905064e8d4a5100080831015610fe55750604051610fc3816100a5565b60048152634757656960e01b6020820152906298968081840604920491610e65565b905066038d7ea4c680008083101561102a5750604051611004816100a5565b60058152641856a98b2b60db1b60208201528183049290916402540be400910604610e65565b9050670de0b6b3a76400008083101561106f575060405161104a816100a5565b60048152630da98b2b60e31b6020820152906509184e72a00081840604920491610e65565b905060405161107d816100a5565b6003815262098b2b60eb1b602082015290662386f26fc1000081840604920491610e65565b506110ac90610c7c565b61061c6023604051836110c982955180926020808601910161005f565b81016257656960e81b602082015203600381018452018261010d565b600154604080516355afdbcb60e11b81526020926001600160a01b03919084908290600490829086165afa908115611258575f918291829161123b575b5084516303cf32ab60e61b8782019081526004825290611141816100a5565b51915af49161114e61097c565b921561005b57836111698482806004975183010191016109ab565b9260015416825194858092630c543fdb60e11b82525afa92831561123157915f939184938493611202575b506111df6003549160045490519283916111c68a840196633617f92d60e21b8852606060248601526084850190610080565b916044840152606483015203601f19810183528261010d565b51915afa6111eb61097c565b901561005b578161061c92825183010191016109ab565b611223919350863d881161122a575b61121b818361010d565b81019061095d565b915f611194565b503d611211565b50513d5f823e3d90fd5b6112529150863d881161122a5761121b818361010d565b5f611122565b83513d5f823e3d90fdfea2646970667358221220d754235277b87b31b8acce280204f2b5f322de96296361221743109844254a7c64736f6c63430008170033 \ No newline at end of file diff --git a/bins/revme/src/cmd/bench/burntpix/bytecode_two.hex b/bins/revme/src/cmd/bench/burntpix/bytecode_two.hex new file mode 100644 index 0000000000..cc407b95ad --- /dev/null +++ b/bins/revme/src/cmd/bench/burntpix/bytecode_two.hex @@ -0,0 +1 @@ +608060408181526004918236101562000016575f80fd5b5f925f3560e01c91826318a87fb6146200051a575081638c72c54e14620004f0578163a4de9ab4146200007f575063ab5fb7961462000053575f80fd5b346200007b57816003193601126200007b57905490516001600160a01b039091168152602090f35b5080fd5b828434620004d05781600319360112620004d05782359063ffffffff8216809203620004d0576024908351946103f19586810167ffffffffffffffff9782821089831117620004de57908291620005af833903905ff0918215620004d4575f546001600160a01b0393841695908416863b15620004d0578751906302b41d8760e51b8252848201525f818781838b5af18015620004c657620004b0575b508360015416863b15620003665787519063218d3ebf60e01b82528482015282818781838b5af18015620003925790839162000498575b50508360025416863b156200036657875190632b18342560e01b82528482015282818781838b5af18015620003925790839162000480575b505086516151df808201908282108b831117620004485789918391620009a083398581526020998a82015203019083f080156200047657841690813b15620003665787519063d35e29d760e01b8252338583015286820152828160448183865af1801562000392579083916200045e575b505086516351d930f960e11b8152338482015282818781855afa90811562000392578391620003ae575b508051156200039c5786015190803b15620003665782809160448a518094819363ea25558360e01b8352878a8401528b358c8401525af1801562000392579083916200037a575b5090838851809681936303cf32ab60e61b8352165afa9384156200036e578194620002c3575b8651868152855181880181905288908290620002b5818385018b8d016200053f565b601f01601f19168101030190f35b90919293503d8083863e620002d981866200058b565b840193858186031262000366578051908882116200036a57019284601f85011215620003665783519788116200035557505084519262000323601f8801601f19168601856200058b565b868452848784010111620003525750620002b59462000348918480850191016200053f565b8480808062000293565b80fd5b634e487b7160e01b83526041905281fd5b8280fd5b8380fd5b508551903d90823e3d90fd5b620003859062000562565b6200007b5781896200026d565b88513d85823e3d90fd5b634e487b7160e01b8352603284528583fd5b90503d8084833e620003c181836200058b565b81019087818303126200036a578051908a82116200045a57019080601f830112156200036a578151918a831162000448578260051b908a5193620004088b8401866200058b565b84528980850192820101928311620004445789809101915b8383106200043357505050508962000226565b82518152918101918a910162000420565b8580fd5b634e487b7160e01b8552604186528785fd5b8480fd5b620004699062000562565b6200007b578189620001fc565b87513d84823e3d90fd5b6200048b9062000562565b6200007b5781896200018b565b620004a39062000562565b6200007b57818962000153565b620004bd91925062000562565b5f90886200011c565b88513d5f823e3d90fd5b5f80fd5b85513d5f823e3d90fd5b85604185634e487b7160e01b5f52525ffd5b8234620004d0575f366003190112620004d05760025490516001600160a01b039091168152602090f35b34620004d0575f366003190112620004d0576001546001600160a01b03168152602090f35b5f5b838110620005515750505f910152565b818101518382015260200162000541565b67ffffffffffffffff81116200057757604052565b634e487b7160e01b5f52604160045260245ffd5b90601f8019910116810190811067ffffffffffffffff821117620005775760405256fe6080806040523461005a575f8054336001600160a01b0319821681178355916001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a3610392908161005f8239f35b5f80fdfe60808060405260049081361015610014575f80fd5b5f3560e01c90816318a87fb6146102e257508063218d3ebf1461029e5780632b1834251461025a5780635683b0e014610216578063715018a6146101bf5780638c72c54e146101975780638da5cb5b14610170578063ab5fb796146101485763f2fde38b14610081575f80fd5b34610144576020366003190112610144576001600160a01b0381358181169290839003610144576100b0610305565b82156100f157505f54826001600160601b0360a01b8216175f55167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3005b60849060206040519162461bcd60e51b8352820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152fd5b5f80fd5b34610144575f366003190112610144576001546040516001600160a01b039091168152602090f35b34610144575f366003190112610144575f546040516001600160a01b039091168152602090f35b34610144575f366003190112610144576003546040516001600160a01b039091168152602090f35b34610144575f366003190112610144576101d7610305565b5f80546001600160a01b0319811682556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b503461014457602036600319011261014457356001600160a01b0381169081900361014457610243610305565b6001600160601b0360a01b60015416176001555f80f35b503461014457602036600319011261014457356001600160a01b0381169081900361014457610287610305565b6001600160601b0360a01b60035416176003555f80f35b503461014457602036600319011261014457356001600160a01b03811690819003610144576102cb610305565b6001600160601b0360a01b60025416176002555f80f35b34610144575f366003190112610144576002546001600160a01b03168152602090f35b5f546001600160a01b0316330361031857565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fdfea2646970667358221220fe8ff964d09f9b014997308dd60006e6d4f5b368483a50e476a998f6c718631b64736f6c634300081700336080346200100457601f620051df38819003918201601f19168301916001600160401b038311848410176200100857808492604094855283398101031262001004576200005a6020620000528362001038565b920162001038565b90604051916200006a836200101c565b6009835268084eae4dce840a0d2f60bb1b60208401526040516200008e816200101c565b60049384825263084a092b60e31b6020830152331562000ff3575f546001600160a01b0381163381900362000fb6575b5050604051620000ce816200101c565b858152632936598960e21b60208201527feafec4d89fa9619884b60000a4d96624a38f7ac2d8d9a604ecf07c12c77e480c90815f52600160205260405f20815160018060401b03811162000fa3578154600181811c9116801562000f98575b602082101462000f8557601f811162000f3b575b506020601f821160011462000eda5791815f80516020620051bf833981519152949262000190945f91620008a7575b508160011b915f199060031b1c19161790555b604051918291826200104d565b0390a25f805160206200511f8339815191525f52600160205280517f2a367ae1ac46d529739aa27ac74856f860e70af05d3642d18ba60fd5d32a069a906001600160401b03811162000ec7578154600181811c9116801562000ebc575b602082101462000ea957601f811162000e5f575b506020601f821160011462000ded57925f80516020620051bf83398151915292826200025d935f805160206200511f833981519152965f91620008a757508160011b915f199060031b1c1916179055604051918291826200104d565b0390a25f805160206200517f8339815191525f52600160205280517f83b322886c7b7e25779e5d38e06e005c9e7aba1e1267ce9210cf24e31833535a906001600160401b03811162000c50578154600181811c9116801562000de2575b602082101462000c3257601f811162000d98575b506020601f821160011462000d2657925f80516020620051bf83398151915292826200032a935f805160206200517f833981519152965f91620008a757508160011b915f199060031b1c1916179055604051918291826200104d565b0390a2604051600260208201526020815262000346816200101c565b5f805160206200513f8339815191525f52600160205280517ff73b01b344a9bb3b96525b0cb731f6b14cde20ce6cecea8459266944490b411f906001600160401b03811162000c50578154600181811c9116801562000d1b575b602082101462000c3257601f811162000cd5575b506020601f821160011462000c6357925f80516020620051bf833981519152928262000410935f805160206200513f833981519152965f91620008a757508160011b915f199060031b1c1916179055604051918291826200104d565b0390a260405160026020820152602081526200042c816200101c565b5f805160206200515f8339815191525f52600160205280517f01f5eb934e794ddcc86b89a579078013860f8fe92140885511742594f219ad0b906001600160401b03811162000c50578154600181811c9116801562000c45575b602082101462000c3257601f811162000bec575b506020601f821160011462000b7a57925f80516020620051bf8339815191529282620004f6935f805160206200515f833981519152965f91620008a757508160011b915f199060031b1c1916179055604051918291826200104d565b0390a260098054610100600160a81b03191660089290921b610100600160a81b03169190911790556040516200052c816200101c565b60108152600160801b6020808301919091525f805160206200519f8339815191525f526001905280517fde5f0adbf2cf136848982dd95860bdc3e6d8709a8a51ce1295c645c6da617db7906001600160401b03811162000aa4578154600181811c9116801562000b6f575b602082101462000a8657601f811162000b29575b506020601f821160011462000ab757925f80516020620051bf833981519152928262000607935f805160206200519f833981519152965f91620008a757508160011b915f199060031b1c1916179055604051918291826200104d565b0390a2604051606082901b6001600160601b03191660208201526014815262000630816200101c565b6f0452f40ece91b521d65a03607aecad0560821b5f52600160205280517fadf994b8d5b80a46660e628eabff2156c328d301fe5ea8e44cf09dee1b43e512906001600160401b03811162000aa4578154600181811c9116801562000a99575b602082101462000a8657601f811162000a40575b50806020601f8211600114620009d8575f91620009cc575b508160011b915f199060031b1c19161790555b5f80516020620051bf83398151915260405180620007016f0452f40ece91b521d65a03607aecad0560821b94826200104d565b0390a260405169036f42f57aecc15a72ed60b51b60208083019182525f602a84015260609390931b6001600160601b031916602c83015291815262000746816200101c565b5190519060208110620009ba575b5060405162000763816200101c565b601481526324871b3d60e01b60208201525f805160206200515f8339815191528214620009a9575f805160206200511f8339815191528203620007b1576040516385c169bd60e01b81528390fd5b5f805160206200517f8339815191528203620007d857604051630eceab6760e31b81528390fd5b5f805160206200513f8339815191528203620007ff57604051634ef6d7fb60e01b81528390fd5b5f8281526001602052604090208151936001600160401b0385116200099657815490600182811c921680156200098b575b6020831014620009785750601f81116200092e575b50602093601f8111600114620008b35790816200089493925f80516020620051bf83398151915295965f91620008a757508160011b915f199060031b1c1916179055604051918291826200104d565b0390a26040516140889081620010978239f35b90508301515f62000170565b601f198116825f5260205f20905f5b818110620009155750916001915f80516020620051bf8339815191529697826200089497969510620008fc575b5050811b01905562000183565b8501515f1960f88460031b161c191690555f80620008ef565b85880151835560209788019760019093019201620008c2565b815f5260205f20601f860160051c810191602087106200096d575b601f0160051c01905b81811062000961575062000845565b5f815560010162000952565b909150819062000949565b602290634e487b7160e01b5f525260245ffd5b91607f169162000830565b604190634e487b7160e01b5f525260245ffd5b604051631b32400560e11b81528390fd5b5f199060200360031b1b165f62000754565b90508301515f620006bb565b9150825f5260205f205f925b601f198316841062000a27576001935082601f1981161062000a0e575b5050811b019055620006ce565b8501515f1960f88460031b161c191690555f8062000a01565b85810151825560209384019360019092019101620009e4565b825f5260205f20601f830160051c81016020841062000a7e575b601f830160051c8201811062000a72575050620006a3565b5f815560010162000a5a565b508062000a5a565b602286634e487b7160e01b5f525260245ffd5b90607f16906200068f565b604185634e487b7160e01b5f525260245ffd5b825f5260205f20905f5b601f198416811062000b105750926001835f805160206200519f83398151915296935f80516020620051bf833981519152966200060796601f19811610620008fc575050811b01905562000183565b9091602060018192858901518155019301910162000ac1565b825f5260205f20601f830160051c81016020841062000b67575b601f830160051c8201811062000b5b575050620005ab565b5f815560010162000b43565b508062000b43565b90607f169062000597565b825f5260205f20905f5b601f198416811062000bd35750926001835f805160206200515f83398151915296935f80516020620051bf83398151915296620004f696601f19811610620008fc575050811b01905562000183565b9091602060018192858901518155019301910162000b84565b825f5260205f20601f830160051c81016020841062000c2a575b601f830160051c8201811062000c1e5750506200049a565b5f815560010162000c06565b508062000c06565b602287634e487b7160e01b5f525260245ffd5b90607f169062000486565b604186634e487b7160e01b5f525260245ffd5b825f5260205f20905f5b601f198416811062000cbc5750926001835f805160206200513f83398151915296935f80516020620051bf833981519152966200041096601f19811610620008fc575050811b01905562000183565b9091602060018192858901518155019301910162000c6d565b825f5260205f20601f830160051c81016020841062000d13575b601f830160051c8201811062000d07575050620003b4565b5f815560010162000cef565b508062000cef565b90607f1690620003a0565b825f5260205f20905f5b601f198416811062000d7f5750926001835f805160206200517f83398151915296935f80516020620051bf833981519152966200032a96601f19811610620008fc575050811b01905562000183565b9091602060018192858901518155019301910162000d30565b825f5260205f20601f830160051c8101916020841062000dd7575b601f0160051c01905b81811062000dcb5750620002ce565b5f815560010162000dbc565b909150819062000db3565b90607f1690620002ba565b825f5260205f20905f5b601f198416811062000e465750926001835f805160206200511f83398151915296935f80516020620051bf833981519152966200025d96601f19811610620008fc575050811b01905562000183565b9091602060018192858901518155019301910162000df7565b825f5260205f20601f830160051c8101916020841062000e9e575b601f0160051c01905b81811062000e92575062000201565b5f815560010162000e83565b909150819062000e7a565b602288634e487b7160e01b5f525260245ffd5b90607f1690620001ed565b604187634e487b7160e01b5f525260245ffd5b601f19821690835f5260205f20915f5b81811062000f22575092620001909492600192825f80516020620051bf833981519152989610620008fc575050811b01905562000183565b9192602060018192868a01518155019401920162000eea565b825f5260205f20601f830160051c8101916020841062000f7a575b601f0160051c01905b81811062000f6e575062000141565b5f815560010162000f5f565b909150819062000f56565b60228a634e487b7160e01b5f525260245ffd5b90607f16906200012d565b604189634e487b7160e01b5f525260245ffd5b33907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a36001600160a01b03191633175f90815580620000be565b6040516306b620db60e21b81528590fd5b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b604081019081106001600160401b038211176200100857604052565b51906001600160a01b03821682036200100457565b602080825282518183018190529093925f5b8281106200108157505060409293505f838284010152601f8019910116010190565b8181018601518482016040015285016200105f56fe608060405260043610156200002f575b361562000029576200002136620020df565b602081519101f35b620020a1565b5f3560e01c806301ffc9a7146200027f57806302329a29146200027957806316e023b3146200027357806318160ddd146200026d5780631d26fce61462000267578063217b227014620002615780632a3654a4146200025b578063382bf015146200025557806340339a1e146200024f57806348d0528a146200024957806349a6078d1462000243578063511b6952146200023d57806354f6127f14620002375780635c975abb14620002315780636963d438146200022b57806370a082311462000225578063715018a6146200021f578063723a213014620002195780637e87632c14620002135780637f23690c146200020d57806386a10ddd14620002075780638da5cb5b146200020157806392a91a3a14620001fb5780639790242114620001f5578063a3b261f214620001ef578063be9f0e6f14620001e9578063c9d658f014620001e3578063d35e29d714620001dd578063d6c1407c14620001d7578063db8c966314620001d1578063dedff9c614620001cb578063ea25558314620001c55763f2fde38b036200000f5762001715565b620016f2565b62001659565b62001579565b6200152a565b62001405565b620012f5565b620011ec565b62001180565b620010a9565b6200107d565b62001054565b62000eca565b62000e6b565b62000dbf565b62000c20565b62000bbc565b62000b80565b62000b11565b62000aed565b62000ac9565b62000a63565b62000974565b620008ec565b620008a9565b62000776565b62000720565b620006a7565b620005e2565b62000438565b620003f1565b62000354565b346200034057602036600319011262000340576004356001600160e01b031981168082036200034057620002dc91631d138b8360e11b8214918215620002f3575b508115620002e0575b5060405190151581529081906020820190565b0390f35b620002ec91506200212c565b5f620002c9565b90915063a918fa6b60e01b811490811562000312575b50905f620002c0565b6318a6a9a560e21b8114915081156200032e575b505f62000309565b6301ffc9a760e01b1490505f62000326565b5f80fd5b6044359081151582036200034057565b3462000340576020366003190112620003405760043580151580910362000340576200037f620021e6565b60ff8019600954169116176009555f80f35b5f5b838110620003a35750505f910152565b818101518382015260200162000393565b90602091620003cf8151809281855285808601910162000391565b601f01601f1916010190565b906020620003ee928181520190620003b4565b90565b34620003405760403660031901126200034057620002dc620004186024356004356200227a565b604051918291602083526020830190620003b4565b5f9103126200034057565b3462000340575f36600319011262000340576020600254604051908152f35b634e487b7160e01b5f52604160045260245ffd5b6001600160401b0381116200047f57604052565b62000457565b602081019081106001600160401b038211176200047f57604052565b604081019081106001600160401b038211176200047f57604052565b606081019081106001600160401b038211176200047f57604052565b90601f801991011681019081106001600160401b038211176200047f57604052565b6001600160401b0381116200047f5760051b60200190565b9080601f83011215620003405760209082356200053081620004fb565b93620005406040519586620004d9565b81855260208086019260051b8201019283116200034057602001905b8282106200056b575050505090565b813581529083019083016200055c565b6020808201906020835283518092526040830192602060408460051b8301019501935f915b848310620005b15750505050505090565b9091929394958480620005d1600193603f198682030187528a51620003b4565b9801930193019194939290620005a0565b346200034057604036600319011262000340576001600160401b0360043581811162000340576200061890369060040162000513565b9060243590811162000340576200063490369060040162000513565b90620006418151620017a5565b915f5b82518110156200069757806200067662000661600193866200180a565b516200066e83866200180a565b51906200227a565b6200068282876200180a565b526200068f81866200180a565b500162000644565b60405180620002dc86826200057b565b346200034057602036600319011262000340576020620006c960043562001825565b6040516001600160a01b039091168152f35b600435906001600160a01b03821682036200034057565b604435906001600160a01b03821682036200034057565b602435906001600160a01b03821682036200034057565b3462000340576040366003190112620003405760206200075862000743620006db565b602435906200075282620022f7565b62002317565b6040519015158152f35b6024359063ffffffff821682036200034057565b3462000340576060366003190112620003405762000793620006db565b6200079d62000762565b90620007a8620006f2565b90620007b3620021e6565b600160ff60095416151503620003405763ffffffff8084165f908152600b6020526040902054620008a7946001600160a01b039262000894926200082a91906200080490869081165b161562001868565b6001600160a01b0387165f908152600c602052604090205463ffffffff161615620018b5565b6200086785620008488363ffffffff165f52600b60205260405f2090565b80546001600160a01b0319166001600160a01b03909216919091179055565b6001600160a01b0385165f908152600c602052604090205b9063ffffffff1663ffffffff19825416179055565b6200089e62001902565b921690620024a0565b005b3462000340576020366003190112620003405760043563ffffffff811680910362000340575f52600b602052602060018060a01b0360405f205416604051908152f35b346200034057602036600319011262000340576001600160a01b0362000911620006db565b165f52600c602052602063ffffffff60405f205416604051908152f35b60209060206040818301928281528551809452019301915f5b82811062000956575050505090565b83516001600160a01b03168552938101939281019260010162000947565b34620003405760208060031936011262000340576004356200099681620022f7565b5f52600560205260405f20906040519081602084549182815201935f5260205f20915f905b828210620009e357620002dc85620009d681890382620004d9565b604051918291826200092e565b835486529485019460019384019390910190620009bb565b6001600160401b0381116200047f57601f01601f191660200190565b81601f82011215620003405780359062000a3182620009fb565b9262000a416040519485620004d9565b828452602083830101116200034057815f926020809301838601378301015290565b34620003405760a0366003190112620003405762000a80620006db565b62000a8a62000709565b60643580151581036200034057608435926001600160401b038411620003405762000abe620008a794369060040162000a17565b926044359162001916565b34620003405760203660031901126200034057620002dc62000418600435620025a7565b3462000340575f3660031901126200034057602060ff600954166040519015158152f35b346200034057602036600319011262000340576001600160401b036004358181116200034057366023820112156200034057806004013591821162000340573660248360051b830101116200034057620002dc91602462000b73920162001b50565b604051918291826200057b565b346200034057602036600319011262000340576001600160a01b0362000ba5620006db565b165f526004602052602060405f2054604051908152f35b3462000340575f366003190112620003405762000bd8620021e6565b5f546001600160a01b0381168062000bec57005b5f907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a36001600160a01b0319165f55005b3462000340575f3660031901126200034057600a546040516001600160a01b039091168152602090f35b9080601f830112156200034057602090823562000c6781620004fb565b9362000c776040519586620004d9565b81855260208086019260051b8201019283116200034057602001905b82821062000ca2575050505090565b81356001600160a01b03811681036200034057815290830190830162000c93565b9080601f830112156200034057602090823562000ce081620004fb565b9362000cf06040519586620004d9565b81855260208086019260051b8201019283116200034057602001905b82821062000d1b575050505090565b813580151581036200034057815290830190830162000d0c565b81601f82011215620003405780359160209162000d5284620004fb565b9362000d626040519586620004d9565b808552838086019160051b830101928084116200034057848301915b84831062000d8f5750505050505090565b82356001600160401b0381116200034057869162000db38484809489010162000a17565b81520192019162000d7e565b34620003405760a0366003190112620003405760046001600160401b038135818111620003405762000df5903690840162000c4a565b90602435818111620003405762000e10903690850162000c4a565b604435828111620003405762000e2a903690860162000513565b90606435838111620003405762000e45903690870162000cc3565b926084359081116200034057620008a79562000e649136910162000d35565b9362001bfa565b604036600319011262000340576024356001600160401b038111620003405762000e9a90369060040162000a17565b62000ea4620021e6565b3462000eb857620008a790600435620026e3565b60405163f36ba73760e01b8152600490fd5b3462000340576060366003190112620003405762000ee7620006db565b602435906044356001600160401b038111620003405762000f0d90369060040162000a17565b9062000f198362001825565b6001600160a01b0381811691338303620010245750821680156200101257808214620010005762000f6562000f618462000f5b885f52600560205260405f2090565b62002822565b1590565b62000fd457938062000fce92620008a7967f1b1b58aa2ec0cec2228b2d37124556d41f5a1f7b12f089171f896cc2366712156040518062000fa78a82620003db565b0390a462000fbf604051948592336020850162001ce1565b03601f198101845283620004d9565b62003340565b6040516314ec4d6d60e31b81526001600160a01b038416600482015260248101869052604490fd5b0390fd5b6040516344fed6b160e11b8152600490fd5b604051639577b8b360e01b8152600490fd5b604051632d938f5160e11b81526001600160a01b0391909116600482015260248101869052336044820152606490fd5b3462000340575f36600319011262000340575f546040516001600160a01b039091168152602090f35b346200034057602036600319011262000340576004355f526007602052602060405f2054604051908152f35b6040366003190112620003405760046001600160401b0381358181116200034057620010d9903690840162000513565b906024359081116200034057620010f4903690840162000d35565b91620010ff620021e6565b346200117157815183510362001162578151156200115357505f5b8151811015620008a757806200114c62001137600193856200180a565b516200114483876200180a565b5190620026e3565b016200111a565b6040516397da5f9560e01b8152fd5b604051633bcc897960e01b8152fd5b60405163f36ba73760e01b8152fd5b3462000340576020806003193601126200034057620011a8620011a2620006db565b62001d3a565b90604051918183928301818452825180915281604085019301915f5b828110620011d457505050500390f35b835185528695509381019392810192600101620011c4565b3462000340576060366003190112620003405760046001600160401b038135818111620003405762001222903690840162000513565b60243582811162000340576200123c903690850162000513565b91604435908111620003405762001257903690850162000d35565b9262001262620021e6565b8151835180911490811591620012e8575b50620012d957815115620012ca57505f5b8151811015620008a75780620012c3620012a1600193856200180a565b51620012ae83876200180a565b51620012bb84896200180a565b5191620029bd565b0162001284565b6040516380c9830560e01b8152fd5b6040516317d38eff60e11b8152fd5b9050845114155f62001273565b3462000340576060366003190112620003405762001312620006db565b6200131c62000709565b906200138d6200132b620006f2565b9262001336620021e6565b6200135260016200134960095460ff1690565b15151462001860565b60018060a01b0380931692806200138262001375865f52600360205260405f2090565b546001600160a01b031690565b921691161462001860565b803b15620003405760405163ce5494bb60e01b81526001600160a01b039290921660048301525f8260248183855af1918215620013ff57620008a792620013e1575b50620013da62001902565b9062002b3b565b80620013f1620013f8926200046b565b806200042d565b5f620013cf565b62001d9f565b3462000340576040366003190112620003405762001422620006db565b6200142c62000762565b90600954916200144060ff84161562001860565b60018060a01b03926200146a84620007fc620013758563ffffffff165f52600b60205260405f2090565b60405190610b25808301918383106001600160401b038411176200047f578392620014c7926200352e853960089190911c87166001600160a01b0316815263ffffffff851660208201526040808201819052606082015260800190565b03905ff08015620013ff57620008a79362001519911691620014fc83620008488363ffffffff165f52600b60205260405f2090565b6001600160a01b0383165f908152600c602052604090206200087f565b6200152362001902565b91620024a0565b346200034057606036600319011262000340576044356001600160401b038111620003405762001563620008a791369060040162000a17565b6200156d620021e6565b602435600435620029bd565b3462000340576080366003190112620003405762001596620006db565b60243590620015a462000344565b906064356001600160401b0381116200034057620015c790369060040162000a17565b91620015d38462001825565b6001600160a01b03818116903382036200162b578416908115620010125714620010005783828662001606938662002ce4565b6200160d57005b62000fce620008a79362000fbf604051948592336020850162001d0e565b604051632d938f5160e11b81526001600160a01b038416600482015260248101889052336044820152606490fd5b346200034057602036600319011262000340576004356001600160401b03811162000340576200168e90369060040162000513565b6200169a8151620017a5565b905f5b8151811015620016e25780620016c1620016ba600193856200180a565b51620025a7565b620016cd82866200180a565b52620016da81856200180a565b50016200169d565b60405180620002dc85826200057b565b34620003405760403660031901126200034057620008a760243560043562001e28565b3462000340576020366003190112620003405762001732620006db565b6200173c620021e6565b6001600160a01b0390811690811562001793575f549081168083036200175e57005b82907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a36001600160a01b031916175f55005b6040516306b620db60e21b8152600490fd5b90620017b182620004fb565b620017c06040519182620004d9565b8281528092620017d3601f1991620004fb565b01905f5b828110620017e457505050565b806060602080938501015201620017d7565b634e487b7160e01b5f52603260045260245ffd5b80518210156200181f5760209160051b010190565b620017f6565b5f818152600360205260409020546001600160a01b031690811562001848575090565b60249060405190635747cd1b60e11b82526004820152fd5b156200034057565b156200187057565b60405162461bcd60e51b815260206004820152601860248201527f616c7265616479206f776e656420627920736f6d656f6e6500000000000000006044820152606490fd5b15620018bd57565b60405162461bcd60e51b815260206004820152601b60248201527f616c726561647920696e6a656374656420746f20736f6d656f6e6500000000006044820152606490fd5b60405190620019118262000485565b5f8252565b9392919262001926843362002317565b1562001aab576001600160a01b0382811695808216929183881462001a995783620019518862001825565b9182160362001a695750861562001a575762001a49868062001a559962001a4f966200198362000fbf9b8a8862002fbe565b6200198e8362001825565b506200199b838762003142565b6001600160a01b0386165f908152600460205260409020620019bf90849062003473565b506001600160a01b0389165f908152600460205260409020620019e4908490620032d3565b50620019fd8962000848855f52600360205260405f2090565b6040517fb333c813a7426a7a11e2b190cad52c44119421594b47f6f32ace6d8c7207b2bf908062001a318a8e3384620023c6565b0390a460405197889485928886336020870162002464565b620033a8565b620030b0565b565b6040516324ecef4d60e01b8152600490fd5b604051632d938f5160e11b81526001600160a01b0391821660048201526024810188905291166044820152606490fd5b604051635d67d6c160e01b8152600490fd5b604051631294d2a960e01b815260048101859052336024820152604490fd5b91908110156200181f5760051b81013590601e1981360301821215620003405701908135916001600160401b0383116200034057602001823603811362000340579190565b908092918237015f815290565b3d1562001b4b573d9062001b3082620009fb565b9162001b406040519384620004d9565b82523d5f602084013e565b606090565b91909162001b5e83620017a5565b925f5b81811062001b6e57505050565b5f8062001b7d83858762001aca565b6040939162001b9185518093819362001b0f565b0390305af49062001ba162001b1c565b911562001bce57509060019162001bb982886200180a565b5262001bc681876200180a565b500162001b61565b81519192911562001be157825160208401fd5b5163234eb81960e01b8152600481019190915260249150fd5b94939091928551938351851480159062001cd5575b801562001cc9575b801562001cbd575b62001cab575f5b85811062001c38575050505050509050565b8062001ca462001c5c62001c4f6001948c6200180a565b516001600160a01b031690565b62001c6c62001c4f848a6200180a565b62001c7884876200180a565b5162001c8f62001c89868a6200180a565b51151590565b9162001c9c868b6200180a565b519362001916565b0162001c26565b6040516393a8311960e01b8152600490fd5b50825185141562001c1f565b50815185141562001c17565b50805185141562001c0f565b620003ee939260809260018060a01b031682526020820152600160408201528160608201520190620003b4565b620003ee939260809260018060a01b0316825260208201525f60408201528160608201520190620003b4565b60018060a01b03165f526020600460205260405f209060405180928391602082549182815201915f5260205f20935f905b82821062001d8457505050620003ee92500382620004d9565b85548452600195860195879550938101939091019062001d6b565b6040513d5f823e3d90fd5b634e487b7160e01b5f52601160045260245ffd5b5f1981019190821162001dcd57565b62001daa565b811562001dde570690565b634e487b7160e01b5f52601260045260245ffd5b908160011b918083046002149015171562001dcd57565b906063820180921162001dcd57565b9081602091031262000340575190565b5f8181526003602052604090205490919062001e4f906001600160a01b0316151562001860565b6001600160a01b0382811692909190833b15620003405760405163116508a760e21b80825260048201849052915f82602481838a5af1908115620013ff5762001eac9262001375926200208a575b505f52600360205260405f2090565b5f546001600160a01b0316908480831691160362001fd5575b5050600a5462001ee691506001600160a01b03165b6001600160a01b031690565b161562001f5a576040516321ac695f60e11b808252602091908282600481875afa918215620013ff575f9262001fb1575b50600a54839062001f31906001600160a01b031662001eda565b9160046040518094819382525afa928315620013ff575f9362001f7b575b50501162001f5a5750565b600a80546001600160a01b0319166001600160a01b03909216919091179055565b62001fa0929350803d1062001fa9575b62001f978183620004d9565b81019062001e18565b905f8062001f4f565b503d62001f8b565b62001fcd919250833d851162001fa95762001f978183620004d9565b905f62001f17565b62001fe09062001d3a565b80511562001ec55762002036620020306200202962001eda62001eda62001eda62001c4f6200203d9762002022620020184362001dbe565b4082519062001dd3565b906200180a565b9462001df2565b62001e09565b6064900490565b823b1562000340576040519182526004820152905f908290602490829084905af18015620013ff5762002073575b808062001ec5565b80620013f162002083926200046b565b5f6200206b565b80620013f16200209a926200046b565b5f62001e9d565b3415620020ba576040516330fa4a2160e11b8152600490fd5b606460405163e5099ee360e01b815260206004820152600460248201525f6044820152fd5b60043610620020f357620003ee9062002db0565b6044604051809263e5099ee360e01b825260206004830152806024830152805f848401375f828201840152601f01601f19168101030190fd5b6200217862002172604051696773c5a04a6d4300884b60b11b60208201525f602a8201526301ffc9a760e01b602c820152602081526200216c81620004a1565b62003410565b6200322d565b805160148114159081620021db575b50620021b457620021989062002ea1565b60601c908115620021ae57620003ee9162002f39565b50505f90565b6040516342bfe79f60e01b81526020600482015290819062000ffc906024830190620003b4565b905015155f62002187565b5f546001600160a01b03163303620021fa57565b60405163bf1169c560e01b8152336004820152602490fd5b60208183031262000340578051906001600160401b03821162000340570181601f82011215620003405780516200224981620009fb565b92620022596040519485620004d9565b818452602082840101116200034057620003ee916020808501910162000391565b5f818152600360205260409020549091906001600160a01b03161562000340576040516354f6127f60e01b81526004810191909152905f90829060249082906001600160a01b03165afa908115620013ff575f91620022d7575090565b620003ee91503d805f833e620022ee8183620004d9565b81019062002212565b5f818152600360205260409020546001600160a01b031615620018485750565b6001600160a01b03806200232b8462001825565b1691169081149182156200233e57505090565b620003ee92505f52600560205260405f206001915f520160205260405f2054151590565b5f19811462001dcd5760010190565b6001600160a01b0390911681525f6020820152606060408201819052620003ee92910190620003b4565b6001600160a01b03909116815260016020820152606060408201819052620003ee92910190620003b4565b6001600160a01b0390911681529015156020820152606060408201819052620003ee92910190620003b4565b6001600160a01b0391821681525f602082015291166040820152606081019190915260a060808201819052620003ee92910190620003b4565b6001600160a01b039182168152911660208201525f6040820152606081019190915260a060808201819052620003ee92910190620003b4565b6001600160a01b03918216815291811660208301529091166040820152606081019190915260a060808201819052620003ee92910190620003b4565b909291906001600160a01b038116801562001a5757620024c1858362002f6c565b5f858152600360205260409020546001600160a01b03166200258e578462001a5594956200258892620024ff620024fa60025462002362565b600255565b6001600160a01b0385165f90815260046020526040902062002523908390620032d3565b506200253c8562000848845f52600360205260405f2090565b5f7fb333c813a7426a7a11e2b190cad52c44119421594b47f6f32ace6d8c7207b2bf604051806200256f8a33836200239b565b0390a462000fbf604051948592853360208601620023f2565b6200303f565b6040516334c7b51160e01b815260048101869052602490fd5b7f9afb95cacc9f95858ec44aa8c3b685511002e30ae54415823f406128b85b238e811462002684575f52600160206001815260405f206040519283915f91815491620025f38362002837565b80865292600181169081156200266057506001146200261e575b505050620003ee92500382620004d9565b5f90815285812095935091905b81831062002647575050620003ee93508201015f80806200260d565b855487840185015294850194869450918301916200262b565b92505050620003ee94925060ff191682840152151560051b8201015f80806200260d565b50600a546040516354f6127f60e01b81527fef285b02a4f711ad84793f73cc8ed6fea8af7013ece8132dacb7b33f6bce93da6004820152905f90829060249082906001600160a01b03165afa908115620013ff575f91620022d7575090565b907ff675e9361af1c1664c1868cfa3eb97672d6b1a513aa5b81dec34c9ee330e818d821462002810577fdeba1e292f8ba88238e10ab3c7f88bd4be4fac56cad5194b6ecceaf653468af1820362002746576040516385c169bd60e01b8152600490fd5b7f2f0a68ab07768e01943a599e73362a0e17a63a72e94dd2e384d2c1d4db93275682036200278057604051630eceab6760e31b8152600490fd5b7fe0261fa95db2eb3b5439bd033cda66d56b96f92f243a8228fd87550ed7bdfdb38203620027ba57604051634ef6d7fb60e01b8152600490fd5b6200280b81620027fe7fece574603820d07bc9b91f2a932baadf4628aabcb8afba49776529c14a6104b293620027f8865f52600160205260405f2090565b620028e4565b60405191829182620003db565b0390a2565b604051631b32400560e11b8152600490fd5b620003ee916001600160a01b031690620032d3565b90600182811c9216801562002867575b60208310146200285357565b634e487b7160e01b5f52602260045260245ffd5b91607f169162002847565b916200288c9183549060031b91821b915f19901b19161790565b9055565b601f82116200289e57505050565b5f5260205f20906020601f840160051c83019310620028d9575b601f0160051c01905b818110620028cd575050565b5f8155600101620028c1565b9091508190620028b8565b91909182516001600160401b0381116200047f57620029108162002909845462002837565b8462002890565b602080601f831160011462002951575081906200288c9394955f9262002945575b50508160011b915f199060031b1c19161790565b015190505f8062002931565b90601f1983169562002966855f5260205f2090565b925f905b888210620029a4575050836001959697106200298b575b505050811b019055565b01515f1960f88460031b161c191690555f808062002981565b806001859682949686015181550195019301906200296a565b9091604051602090602081019084825285604082015260408152620029e281620004bd565b5190205f5260018060205260405f20918351916001600160401b0383116200047f5762002a1c8362002a15865462002837565b8662002890565b602091601f841160011462002a965750509162002a76827fa6e4251f855f750545fe414f120db91c76b88def14d120969e5bb2d3f05debbb959362002a85955f9162002a8a575b508160011b915f199060031b1c19161790565b905560405191829182620003db565b0390a3565b90508401515f62002a63565b9190601f1984169062002aac865f5260205f2090565b935f915b83831062002b16575050509262002a859492600192827fa6e4251f855f750545fe414f120db91c76b88def14d120969e5bb2d3f05debbb98961062002afd575b5050811b019055620027fe565b8501515f1960f88460031b161c191690555f8062002af0565b88850151865594850194938101939181019162002ab0565b801562001dcd575f190190565b62001a5591906001600160a01b039062001a49908262002b5b8262001825565b161562002cb9575b5f62002ba162002b7560025462001dbe565b62002b88845f52600860205260405f2090565b5481811062002c76575b505f52600760205260405f2090565b555f81815260086020526040812055805f62002bbd8262001825565b9462002bcf620024fa60025462002b2e565b62002bdb838762003142565b6001600160a01b0386165f90815260046020526040902062002bff90849062003473565b5062002c2762002c17845f52600360205260405f2090565b80546001600160a01b0319169055565b7fb333c813a7426a7a11e2b190cad52c44119421594b47f6f32ace6d8c7207b2bf604051918716918062002c5d8a338362002371565b0390a462000fbf6040519485928533602086016200242b565b62002cb162002c8d835f52600760205260405f2090565b548062002ca2845f52600760205260405f2090565b555f52600860205260405f2090565b555f62002b92565b600254805f5260076020528160405f205562002cdd825f52600860205260405f2090565b5562002b63565b919392845f52600560205260405f209260018060a01b039062002d0b828216809662003473565b1562002d5d57509062002d587fc78cd419d6136f9f1c1c6aec1d3fae098cffaf8bc86314a8f2685e32fe574e3c9392604051938493151584526040602085015216956040830190620003b4565b0390a4565b6040516312a8c6a360e21b81526001600160a01b0391909116600482015260248101879052604490fd5b9060349391815f823701916bffffffffffffffffffffffff199060601b16825260148201520190565b63ffffffff60e01b5f35169062002df562002172604051696773c5a04a6d4300884b60b11b60208201525f602a82015284602c820152602081526200216c81620004a1565b80516014811415908162002e96575b50620021b45762002e159062002ea1565b60601c91821562002e7257505f91829160405162002e508162002e416020820194349033908762002d87565b03601f198101835282620004d9565b519134905af162002e6062001b1c565b901562002e6a5790565b602081519101fd5b60405163bb370b2b60e01b81526001600160e01b0319919091166004820152602490fd5b905015155f62002e04565b90602082519201516bffffffffffffffffffffffff1990818116936014811062002eca57505050565b60140360031b82901b16169150565b5f602091604051838101906301ffc9a760e01b8252631aed5a8560e21b60248201526024815262002f0a81620004bd565b5191617530fa5f513d8262002f2c575b508162002f25575090565b9050151590565b6020111591505f62002f1a565b5f90602092604051848101916301ffc9a760e01b835263ffffffff60e01b1660248201526024815262002f0a81620004bd565b600254805f5260076020528260405f205562002f90835f52600860205260405f2090565b556001600160a01b03161562002fa35750565b62002fbb5f918262002ca262002b7560025462001dbe565b55565b6001600160a01b03919082161562002fdb575b161562002fa35750565b600254805f5260076020528360405f205562002fff845f52600860205260405f2090565b5562002fd1565b906040620003ee927f0b084a55ebf70fd3c06fd755269dac2212c4d3f0f4d09079780bfa50c1b2984d81528160208201520190620003b4565b6200304a8162002ed9565b15620030ac57604051631aed5a8560e21b8152915f91839182908490829062003077906004830162003006565b03926001600160a01b03165af18015620013ff57620030935750565b620030a9903d805f833e620022ee8183620004d9565b50565b5050565b9190620030bd8362002ed9565b15620030e95750620030775f928392604051948580948193631aed5a8560e21b83526004830162003006565b905015620030f45750565b803b156200311f57604051634349776d60e01b81526001600160a01b03919091166004820152602490fd5b604051630317313760e01b81526001600160a01b03919091166004820152602490fd5b90805f526005906020926005602052604090815f20938454945f5b8681106200316f575050505050505050565b8154156200181f575f828152889020548551906001600160a01b0390811690620031998362000485565b5f8352885f52858b52620031b082895f2062003473565b1562003206579188917fc78cd419d6136f9f1c1c6aec1d3fae098cffaf8bc86314a8f2685e32fe574e3c898d620031fc6001989783519384935f85528401528c16958d830190620003b4565b0390a4016200315d565b87516312a8c6a360e21b81526001600160a01b0383166004820152602481018a9052604490fd5b5f52600160206001815260405f206040519283915f91815491620032518362002837565b80865292600181169081156200266057506001146200327b57505050620003ee92500382620004d9565b5f90815285812095935091905b818310620032a4575050620003ee93508201015f80806200260d565b8554878401850152948501948694509183019162003288565b80548210156200181f575f5260205f2001905f90565b5f828152600182016020526040902054620021ae57805490680100000000000000008210156200047f57826200332b62003315846001809601855584620032bd565b819391549060031b91821b915f19901b19161790565b90558054925f520160205260405f2055600190565b6200334b8162002ed9565b62003354575050565b620030775f92918392604051948580948193631aed5a8560e21b83527f8a1c15a8799f71b547e08e2bcb2e85257e81b0a07eee2ce6712549eef1f009706004840152604060248401526044830190620003b4565b620033b38162002ed9565b620033bc575050565b620030775f92918392604051948580948193631aed5a8560e21b83527fb23eae7e6d1564b295b4c3e3be402d9a2f0776c57bdf365903496f6fa481ab006004840152604060248401526044830190620003b4565b60208151910151906020811062003425575090565b5f199060200360031b1b1690565b80549081156200345f575f19918201916200344f8383620032bd565b909182549160031b1b1916905555565b634e487b7160e01b5f52603160045260245ffd5b6001810191805f528260205260405f2054928315155f1462003525575f19928484019085821162001dcd57805494850194851162001dcd575f958583620034c994620034d69803620034dc575b50505062003433565b905f5260205260405f2090565b55600190565b6200350d6200350691620034f56200351b9487620032bd565b90549060031b1c92839187620032bd565b9062002872565b85905f5260205260405f2090565b555f8080620034c0565b505050505f9056fe60806040908082523461011357608081610b2580380380916100218285610173565b8339810103126101135761003481610196565b60209160048382015192846060878501519401519160018060a01b03199033825f5416175f5560018060a01b0316809160015416176001558751938480926355afdbcb60e11b82525afa918215610169575f92610132575b508551928584019463466c6dc560e11b86526024850152604484015260648301526064825260a082019060018060401b039383831085841117610117575f938493885251915af4913d1561012b573d918211610117575f908451926100fa82601f19601f8401160185610173565b83523d92013e5b15610113575161097a90816101ab8239f35b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b5050610101565b9091508481813d8311610162575b61014a8183610173565b810103126101135761015b90610196565b905f61008c565b503d610140565b86513d5f823e3d90fd5b601f909101601f19168101906001600160401b0382119082101761011757604052565b51906001600160a01b03821682036101135756fe608060409080825260049081361015610016575f80fd5b5f3560e01c90816301ffc9a71461060457508063221a8729146105e65780634358d2be146105c85780634594229c146104e357806354f6127f146104b05780637b103999146104895780637f23690c146104555780639790242114610395578063c20db68914610377578063ce5494bb14610337578063dedff9c614610226578063e710563c146102085763f3ccaac0146100af575f80fd5b346101cd575f3660031901126101cd57600154825163463962a760e11b815260209290918391839182906001600160a01b03165afa9081156101fe575f91829182916101d1575b508451848101906354f6127f60e01b82527f2abb082c1b23ea79fce2a9e934ecb19ce15738b1483c365d0125f47e8ccc7dfc60248201526024815261013a8161069c565b51915af4916101476107e7565b92156101cd57825183019282818186019503126101cd57828101519067ffffffffffffffff82116101cd57019083603f830112156101cd57828201519161018d836106ee565b9461019a835196876106cc565b8386528284830101116101cd576101c9926101ba91838688019101610656565b51928284938452830190610677565b0390f35b5f80fd5b6101f19150843d86116101f7575b6101e981836106cc565b8101906107c8565b5f6100f6565b503d6101df565b83513d5f823e3d90fd5b82346101cd575f3660031901126101cd576020906012549051908152f35b50346101cd57602090816003193601126101cd5780359067ffffffffffffffff82116101cd5761025891369101610768565b9182519061027d61026883610750565b92610275835194856106cc565b808452610750565b601f1901835f5b828110610327575050505f5b84518110156102cb57806102af6102a96001938861091c565b51610816565b6102b9828661091c565b526102c4818561091c565b5001610290565b509250825191808301818452825180915281858501958260051b8601019301915f955b8287106102fb5785850386f35b909192938280610317600193603f198a82030186528851610677565b96019201960195929190926102ee565b6060828287010152018490610284565b50346101cd5760203660031901126101cd57356001600160a01b03818116918290036101cd575f5490811633036101cd576001600160a01b031916175f55005b82346101cd575f3660031901126101cd576020906013549051908152f35b5090806003193601126101cd5767ffffffffffffffff82358181116101cd576103c19036908501610768565b5060248035908282116101cd57366023830112156101cd57818501356103e681610750565b936103f3865195866106cc565b818552602460208096019260051b850101933685116101cd5760248101925b85841061042f5788883461042257005b5163f36ba73760e01b8152fd5b83358381116101cd57879161044a839288369187010161070a565b815201930192610412565b5090806003193601126101cd5760243567ffffffffffffffff81116101cd57610481903690840161070a565b503461042257005b82346101cd575f3660031901126101cd575f5490516001600160a01b039091168152602090f35b5090346101cd5760203660031901126101cd576104d06101c99235610816565b9051918291602083526020830190610677565b5090346101cd5760203660031901126101cd575f548235926001600160a01b03929091831633036101cd5760205a93600154168251938480926355afdbcb60e11b82525afa9182156105be57915f92918392839261059d575b5051602081019063116508a760e21b8252866024820152602481526105608161069c565b51915af461056c6107e7565b50156101cd575a916010540160105503806011540160115548810260125401601255483a0302601354016013555f80f35b6105b791925060203d6020116101f7576101e981836106cc565b905f61053c565b50513d5f823e3d90fd5b82346101cd575f3660031901126101cd576020906010549051908152f35b82346101cd575f3660031901126101cd576020906011549051908152f35b82346101cd5760203660031901126101cd57359063ffffffff60e01b82168092036101cd576020916301ffc9a760e01b8114908115610645575b5015158152f35b6318a6a9a560e21b1490508361063e565b5f5b8381106106675750505f910152565b8181015183820152602001610658565b9060209161069081518092818552858086019101610656565b601f01601f1916010190565b6060810190811067ffffffffffffffff8211176106b857604052565b634e487b7160e01b5f52604160045260245ffd5b90601f8019910116810190811067ffffffffffffffff8211176106b857604052565b67ffffffffffffffff81116106b857601f01601f191660200190565b81601f820112156101cd57803590610721826106ee565b9261072f60405194856106cc565b828452602083830101116101cd57815f926020809301838601378301015290565b67ffffffffffffffff81116106b85760051b60200190565b9080601f830112156101cd57602090823561078281610750565b9361079060405195866106cc565b81855260208086019260051b8201019283116101cd57602001905b8282106107b9575050505090565b813581529083019083016107ab565b908160209103126101cd57516001600160a01b03811681036101cd5790565b3d15610811573d906107f8826106ee565b9161080660405193846106cc565b82523d5f602084013e565b606090565b6001546040805163463962a760e11b815290926020928390839060049082906001600160a01b03165afa91821561091257915f9291839283926108f3575b508551858101916354f6127f60e01b83526024820152602481526108778161069c565b51915af4916108846107e7565b92156101cd57825183019282818186019503126101cd57828101519067ffffffffffffffff82116101cd570183603f820112156101cd5782810151916108c9836106ee565b946108d6825196876106cc565b8386528184840101116101cd576108f09385019101610656565b90565b61090b919250853d87116101f7576101e981836106cc565b905f610854565b84513d5f823e3d90fd5b80518210156109305760209160051b010190565b634e487b7160e01b5f52603260045260245ffdfea26469706673582212206c5c550fe4870b5c8de9ec4447e02e6de1853a7e6abc9bf7c2adcfb0811426f264736f6c63430008170033a2646970667358221220284f10fd0dc3415ffbddda3e3c1614081dd249040175886fa332e2b6d847ca5d64736f6c63430008170033deba1e292f8ba88238e10ab3c7f88bd4be4fac56cad5194b6ecceaf653468af1e0261fa95db2eb3b5439bd033cda66d56b96f92f243a8228fd87550ed7bdfdb3f675e9361af1c1664c1868cfa3eb97672d6b1a513aa5b81dec34c9ee330e818d2f0a68ab07768e01943a599e73362a0e17a63a72e94dd2e384d2c1d4db932756114bd03b3a46d48759680d81ebb2b414fda7d030a7105a851867accf1c2352e7ece574603820d07bc9b91f2a932baadf4628aabcb8afba49776529c14a6104b2a2646970667358221220193803e886292584245208d51558ce29840826ff8149c83648336d598b01be5c64736f6c63430008170033 \ No newline at end of file diff --git a/bins/revme/src/cmd/bench/burntpix/static_data.rs b/bins/revme/src/cmd/bench/burntpix/static_data.rs new file mode 100644 index 0000000000..e7fe174832 --- /dev/null +++ b/bins/revme/src/cmd/bench/burntpix/static_data.rs @@ -0,0 +1,18 @@ +use revm::primitives::{address, fixed_bytes, Address, FixedBytes}; + +pub const BURNTPIX_MAIN_ADDRESS: Address = address!("49206861766520746f6f206d7563682074696d65"); +pub const BURNTPIX_ADDRESS_ONE: Address = address!("0a743ba7304efcc9e384ece9be7631e2470e401e"); +pub const BURNTPIX_ADDRESS_TWO: Address = address!("c917e98213a05d271adc5d93d2fee6c1f1006f75"); +pub const BURNTPIX_ADDRESS_THREE: Address = address!("f529c70db0800449ebd81fbc6e4221523a989f05"); + +pub const STORAGE_ZERO: FixedBytes<32> = + fixed_bytes!("000000000000000000000000f529c70db0800449ebd81fbc6e4221523a989f05"); +pub const STORAGE_ONE: FixedBytes<32> = + fixed_bytes!("0000000000000000000000000a743ba7304efcc9e384ece9be7631e2470e401e"); +pub const STORAGE_TWO: FixedBytes<32> = + fixed_bytes!("000000000000000000000000c917e98213a05d271adc5d93d2fee6c1f1006f75"); + +pub const BURNTPIX_BYTECODE_ONE: &str = include_str!("bytecode_one.hex"); +pub const BURNTPIX_BYTECODE_TWO: &str = include_str!("bytecode_two.hex"); +pub const BURNTPIX_BYTECODE_THREE: &str = include_str!("bytecode_three.hex"); +pub const BURNTPIX_BYTECODE_FOUR: &str = include_str!("bytecode_four.hex"); diff --git a/bins/revme/src/cmd/bench/evm_build.rs b/bins/revme/src/cmd/bench/evm_build.rs new file mode 100644 index 0000000000..a7e2ea7b51 --- /dev/null +++ b/bins/revme/src/cmd/bench/evm_build.rs @@ -0,0 +1,10 @@ +use criterion::Criterion; +use revm::{Context, MainBuilder, MainContext}; + +pub fn run(criterion: &mut Criterion) { + criterion.bench_function("evm-build", |b| { + b.iter(|| { + let _ = Context::mainnet().build_mainnet(); + }); + }); +} diff --git a/bins/revme/src/cmd/bench/gas_cost_estimator.rs b/bins/revme/src/cmd/bench/gas_cost_estimator.rs new file mode 100644 index 0000000000..d596ac1dab --- /dev/null +++ b/bins/revme/src/cmd/bench/gas_cost_estimator.rs @@ -0,0 +1,51 @@ +use context::TxEnv; +use criterion::Criterion; +use database::{BenchmarkDB, BENCH_CALLER, BENCH_TARGET}; +use revm::{ + bytecode::Bytecode, + primitives::{hex, Bytes, TxKind}, + Context, ExecuteEvm, MainBuilder, MainContext, +}; +use std::io::Cursor; + +pub fn run(criterion: &mut Criterion) { + //let bytecode = Bytecode::new_raw(Bytes::from(hex::decode(BYTES).unwrap())); + + let mut rdr = csv::Reader::from_reader(Cursor::new(SAMPLE_CSV)); + for result in rdr.records() { + let result = result.expect("Failed to read record"); + let name = &result[0]; + let bytecode_hex = &result[3]; + let Ok(hex) = hex::decode(bytecode_hex) else { + continue; + }; + let bytecode = Bytecode::new_raw(Bytes::from(hex)); + + let mut evm = Context::mainnet() + .with_db(BenchmarkDB::new_bytecode(bytecode.clone())) + .modify_cfg_chained(|c| c.disable_nonce_check = true) + .build_mainnet(); + + let tx = TxEnv::builder() + .caller(BENCH_CALLER) + .kind(TxKind::Call(BENCH_TARGET)) + .gas_limit(1_000_000_000) + .build() + .unwrap(); + + criterion.bench_function(name, |b| { + b.iter_batched( + || { + // create a transaction input + tx.clone() + }, + |input| { + let _ = evm.transact_one(input).unwrap(); + }, + criterion::BatchSize::SmallInput, + ); + }); + } +} + +const SAMPLE_CSV: &str = include_str!("gas_cost_estimator_sample.csv"); diff --git a/bins/revme/src/cmd/bench/gas_cost_estimator_sample.csv b/bins/revme/src/cmd/bench/gas_cost_estimator_sample.csv new file mode 100644 index 0000000000..29eb985378 --- /dev/null +++ b/bins/revme/src/cmd/bench/gas_cost_estimator_sample.csv @@ -0,0 +1,139 @@ +program_id,opcode,op_count,bytecode +ADD_50,ADD,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360030150015001500150015001500150015001500150015001500150015001500150015001500150015001500150015001500150015001500150015001500150015001500150015001500150015001500150015001500150015001500150015001500150015050505050505050505050 +MUL_50,MUL,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360030250025002500250025002500250025002500250025002500250025002500250025002500250025002500250025002500250025002500250025002500250025002500250025002500250025002500250025002500250025002500250025002500250025050505050505050505050 +SUB_50,SUB,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360030350035003500350035003500350035003500350035003500350035003500350035003500350035003500350035003500350035003500350035003500350035003500350035003500350035003500350035003500350035003500350035003500350035050505050505050505050 +DIV_50,DIV,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360030450045004500450045004500450045004500450045004500450045004500450045004500450045004500450045004500450045004500450045004500450045004500450045004500450045004500450045004500450045004500450045004500450045050505050505050505050 +SDIV_50,SDIV,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360030550055005500550055005500550055005500550055005500550055005500550055005500550055005500550055005500550055005500550055005500550055005500550055005500550055005500550055005500550055005500550055005500550055050505050505050505050 +MOD_50,MOD,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360030650065006500650065006500650065006500650065006500650065006500650065006500650065006500650065006500650065006500650065006500650065006500650065006500650065006500650065006500650065006500650065006500650065050505050505050505050 +SMOD_50,SMOD,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360030750075007500750075007500750075007500750075007500750075007500750075007500750075007500750075007500750075007500750075007500750075007500750075007500750075007500750075007500750075007500750075007500750075050505050505050505050 +ADDMOD_50,ADDMOD,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360030850085008500850085008500850085008500850085008500850085008500850085008500850085008500850085008500850085008500850085008500850085008500850085008500850085008500850085008500850085008500850085008500850085050505050505050505050 +MULMOD_50,MULMOD,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360030950095009500950095009500950095009500950095009500950095009500950095009500950095009500950095009500950095009500950095009500950095009500950095009500950095009500950095009500950095009500950095009500950095050505050505050505050 +EXP_50,EXP,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360030a500a500a500a500a500a500a500a500a500a500a500a500a500a500a500a500a500a500a500a500a500a500a500a500a500a500a500a500a500a500a500a500a500a500a500a500a500a500a500a500a500a500a500a500a500a500a500a500a500a5050505050505050505050 +SIGNEXTEND_50,SIGNEXTEND,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360030b500b500b500b500b500b500b500b500b500b500b500b500b500b500b500b500b500b500b500b500b500b500b500b500b500b500b500b500b500b500b500b500b500b500b500b500b500b500b500b500b500b500b500b500b500b500b500b500b500b5050505050505050505050 +LT_50,LT,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360031050105010501050105010501050105010501050105010501050105010501050105010501050105010501050105010501050105010501050105010501050105010501050105010501050105010501050105010501050105010501050105010501050105050505050505050505050 +GT_50,GT,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360031150115011501150115011501150115011501150115011501150115011501150115011501150115011501150115011501150115011501150115011501150115011501150115011501150115011501150115011501150115011501150115011501150115050505050505050505050 +SLT_50,SLT,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360031250125012501250125012501250125012501250125012501250125012501250125012501250125012501250125012501250125012501250125012501250125012501250125012501250125012501250125012501250125012501250125012501250125050505050505050505050 +SGT_50,SGT,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360031350135013501350135013501350135013501350135013501350135013501350135013501350135013501350135013501350135013501350135013501350135013501350135013501350135013501350135013501350135013501350135013501350135050505050505050505050 +EQ_50,EQ,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360031450145014501450145014501450145014501450145014501450145014501450145014501450145014501450145014501450145014501450145014501450145014501450145014501450145014501450145014501450145014501450145014501450145050505050505050505050 +ISZERO_50,ISZERO,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360031550155015501550155015501550155015501550155015501550155015501550155015501550155015501550155015501550155015501550155015501550155015501550155015501550155015501550155015501550155015501550155015501550155050505050505050505050 +AND_50,AND,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360031650165016501650165016501650165016501650165016501650165016501650165016501650165016501650165016501650165016501650165016501650165016501650165016501650165016501650165016501650165016501650165016501650165050505050505050505050 +OR_50,OR,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360031750175017501750175017501750175017501750175017501750175017501750175017501750175017501750175017501750175017501750175017501750175017501750175017501750175017501750175017501750175017501750175017501750175050505050505050505050 +XOR_50,XOR,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360031850185018501850185018501850185018501850185018501850185018501850185018501850185018501850185018501850185018501850185018501850185018501850185018501850185018501850185018501850185018501850185018501850185050505050505050505050 +NOT_50,NOT,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360031950195019501950195019501950195019501950195019501950195019501950195019501950195019501950195019501950195019501950195019501950195019501950195019501950195019501950195019501950195019501950195019501950195050505050505050505050 +BYTE_50,BYTE,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360031a501a501a501a501a501a501a501a501a501a501a501a501a501a501a501a501a501a501a501a501a501a501a501a501a501a501a501a501a501a501a501a501a501a501a501a501a501a501a501a501a501a501a501a501a501a501a501a501a501a5050505050505050505050 +SHL_50,SHL,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360031b501b501b501b501b501b501b501b501b501b501b501b501b501b501b501b501b501b501b501b501b501b501b501b501b501b501b501b501b501b501b501b501b501b501b501b501b501b501b501b501b501b501b501b501b501b501b501b501b501b5050505050505050505050 +SHR_50,SHR,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360031c501c501c501c501c501c501c501c501c501c501c501c501c501c501c501c501c501c501c501c501c501c501c501c501c501c501c501c501c501c501c501c501c501c501c501c501c501c501c501c501c501c501c501c501c501c501c501c501c501c5050505050505050505050 +SAR_50,SAR,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360031d501d501d501d501d501d501d501d501d501d501d501d501d501d501d501d501d501d501d501d501d501d501d501d501d501d501d501d501d501d501d501d501d501d501d501d501d501d501d501d501d501d501d501d501d501d501d501d501d501d5050505050505050505050 +KECCAK256_50,KECCAK256,50,7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5f525f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f602060006020600060206000602060006020600060206000602060006020600060206000602060006020600060206000602060006020600060206000602060006020600060206000602060006020600060206000602060006020600060206000602060006020600060206000602060006020600060206000602060006020600060206000602060006020600060206000602060006020600060206000602060006020600060206000602060006020600060206000602060006020600060206000602060006020600020502050205020502050205020502050205020502050205020502050205020502050205020502050205020502050205020502050205020502050205020502050205020502050205020502050205020502050205020502050205020502050205020502050 +ADDRESS_50,ADDRESS,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060003050305030503050305030503050305030503050305030503050305030503050305030503050305030503050305030503050305030503050305030503050305030503050305030503050305030503050305030503050305030503050305030503050305050505050505050505050 +ORIGIN_50,ORIGIN,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060003250325032503250325032503250325032503250325032503250325032503250325032503250325032503250325032503250325032503250325032503250325032503250325032503250325032503250325032503250325032503250325032503250325050505050505050505050 +CALLER_50,CALLER,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060003350335033503350335033503350335033503350335033503350335033503350335033503350335033503350335033503350335033503350335033503350335033503350335033503350335033503350335033503350335033503350335033503350335050505050505050505050 +CALLVALUE_50,CALLVALUE,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060003450345034503450345034503450345034503450345034503450345034503450345034503450345034503450345034503450345034503450345034503450345034503450345034503450345034503450345034503450345034503450345034503450345050505050505050505050 +CALLDATALOAD_50,CALLDATALOAD,50,6000617fff536000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360033550355035503550355035503550355035503550355035503550355035503550355035503550355035503550355035503550355035503550355035503550355035503550355035503550355035503550355035503550355035503550355035503550355050505050505050505050 +CALLDATASIZE_50,CALLDATASIZE,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060003650365036503650365036503650365036503650365036503650365036503650365036503650365036503650365036503650365036503650365036503650365036503650365036503650365036503650365036503650365036503650365036503650365050505050505050505050 +CALLDATACOPY_50,CALLDATACOPY,50,6000617fff536003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360033737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737 +CODESIZE_50,CODESIZE,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060003850385038503850385038503850385038503850385038503850385038503850385038503850385038503850385038503850385038503850385038503850385038503850385038503850385038503850385038503850385038503850385038503850385050505050505050505050 +CODECOPY_50,CODECOPY,50,6000617fff536003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360033939393939393939393939393939393939393939393939393939393939393939393939393939393939393939393939393939unreachable +GASPRICE_50,GASPRICE,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060003a503a503a503a503a503a503a503a503a503a503a503a503a503a503a503a503a503a503a503a503a503a503a503a503a503a503a503a503a503a503a503a503a503a503a503a503a503a503a503a503a503a503a503a503a503a503a503a503a503a5050505050505050505050 +EXTCODESIZE_50,EXTCODESIZE,50,60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff6c63ffffffff60005260046000f3600052600d60006000f0808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080803b503b503b503b503b503b503b503b503b503b503b503b503b503b503b503b503b503b503b503b503b503b503b503b503b503b503b503b503b503b503b503b503b503b503b503b503b503b503b503b503b503b503b503b503b503b503b503b503b503b50505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050 +EXTCODECOPY_50,EXTCODECOPY,50,60ff60ff60ff60ff60ff7f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6000527fff60005260206000f30000000000000000000000000000000000000000000000602052602960006000f060206000600083602060006000836020600060008360206000600083602060006000836020600060008360206000600083602060006000836020600060008360206000600083602060006000836020600060008360206000600083602060006000836020600060008360206000600083602060006000836020600060008360206000600083602060006000836020600060008360206000600083602060006000836020600060008360206000600083602060006000836020600060008360206000600083602060006000836020600060008360206000600083602060006000836020600060008360206000600083602060006000836020600060008360206000600083602060006000836020600060008360206000600083602060006000836020600060008360206000600083602060006000836020600060008360206000600083602060006000836020600060008360206000600083602060006000833c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c5050505050 +RETURNDATASIZE_50,RETURNDATASIZE,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060003d503d503d503d503d503d503d503d503d503d503d503d503d503d503d503d503d503d503d503d503d503d503d503d503d503d503d503d503d503d503d503d503d503d503d503d503d503d503d503d503d503d503d503d503d503d503d503d503d503d5050505050505050505050 +RETURNDATACOPY_50,RETURNDATACOPY,50,6000617fff536000600061800060006000600461ffffF1506003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360033e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e +EXTCODEHASH_50,EXTCODEHASH,50,60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff60ff6c63ffffffff60005260046000f3600052600d60006000f0808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080803f503f503f503f503f503f503f503f503f503f503f503f503f503f503f503f503f503f503f503f503f503f503f503f503f503f503f503f503f503f503f503f503f503f503f503f503f503f503f503f503f503f503f503f503f503f503f503f503f503f50505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050 +COINBASE_50,COINBASE,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060004150415041504150415041504150415041504150415041504150415041504150415041504150415041504150415041504150415041504150415041504150415041504150415041504150415041504150415041504150415041504150415041504150415050505050505050505050 +TIMESTAMP_50,TIMESTAMP,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060004250425042504250425042504250425042504250425042504250425042504250425042504250425042504250425042504250425042504250425042504250425042504250425042504250425042504250425042504250425042504250425042504250425050505050505050505050 +NUMBER_50,NUMBER,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060004350435043504350435043504350435043504350435043504350435043504350435043504350435043504350435043504350435043504350435043504350435043504350435043504350435043504350435043504350435043504350435043504350435050505050505050505050 +DIFFICULTY_50,DIFFICULTY,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060004450445044504450445044504450445044504450445044504450445044504450445044504450445044504450445044504450445044504450445044504450445044504450445044504450445044504450445044504450445044504450445044504450445050505050505050505050 +GASLIMIT_50,GASLIMIT,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060004550455045504550455045504550455045504550455045504550455045504550455045504550455045504550455045504550455045504550455045504550455045504550455045504550455045504550455045504550455045504550455045504550455050505050505050505050 +CHAINID_50,CHAINID,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060004650465046504650465046504650465046504650465046504650465046504650465046504650465046504650465046504650465046504650465046504650465046504650465046504650465046504650465046504650465046504650465046504650465050505050505050505050 +SELFBALANCE_50,SELFBALANCE,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060004750475047504750475047504750475047504750475047504750475047504750475047504750475047504750475047504750475047504750475047504750475047504750475047504750475047504750475047504750475047504750475047504750475050505050505050505050 +POP_50,POP,50,6003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360035050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050 +MLOAD_50,MLOAD,50,6000617fff536000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360035150515051505150515051505150515051505150515051505150515051505150515051505150515051505150515051505150515051505150515051505150515051505150515051505150515051505150515051505150515051505150515051505150515050505050505050505050 +MSTORE_50,MSTORE,50,60ff5f5260ff5f5260ff5f5260ff5f5260ff5f5260ff5f5260ff5f5260ff5f5260ff5f5260ff5f5260ff5f5260ff5f5260ff5f5260ff5f5260ff5f5260ff5f5260ff5f5260ff5f5260ff5f5260ff5f5260ff5f5260ff5f5260ff5f5260ff5f5260ff5f5260ff5f5260ff5f5260ff5f5260ff5f5260ff5f5260ff5f5260ff5f5260ff5f5260ff5f5260ff5f5260ff5f5260ff5f5260ff5f5260ff5f5260ff5f5260ff5f5260ff5f5260ff5f5260ff5f5260ff5f5260ff5f5260ff5f5260ff5f5260ff5f5260ff5f5260ff5f52 +MSTORE_COLD_50,MSTORE_COLD,50,60ff5f525f60200160ff815260200160ff815260200160ff815260200160ff815260200160ff815260200160ff815260200160ff815260200160ff815260200160ff815260200160ff815260200160ff815260200160ff815260200160ff815260200160ff815260200160ff815260200160ff815260200160ff815260200160ff815260200160ff815260200160ff815260200160ff815260200160ff815260200160ff815260200160ff815260200160ff815260200160ff815260200160ff815260200160ff815260200160ff815260200160ff815260200160ff815260200160ff815260200160ff815260200160ff815260200160ff815260200160ff815260200160ff815260200160ff815260200160ff815260200160ff815260200160ff815260200160ff815260200160ff815260200160ff815260200160ff815260200160ff815260200160ff815260200160ff815260200160ff815260200160ff8152 +MSTORE8_50,MSTORE8,50,6000617fff536003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360035353535353535353535353535353535353535353535353535353535353535353535353535353535353535353535353535353 +JUMP_50,JUMP,50,62000005565b6200000b565b62000011565b62000017565b6200001d565b62000023565b62000029565b6200002f565b62000035565b6200003b565b62000041565b62000047565b6200004d565b62000053565b62000059565b6200005f565b62000065565b6200006b565b62000071565b62000077565b6200007d565b62000083565b62000089565b6200008f565b62000095565b6200009b565b620000a1565b620000a7565b620000ad565b620000b3565b620000b9565b620000bf565b620000c5565b620000cb565b620000d1565b620000d7565b620000dd565b620000e3565b620000e9565b620000ef565b620000f5565b620000fb565b62000101565b62000107565b6200010d565b62000113565b62000119565b6200011f565b62000125565b6200012b565b620001305b620001355b6200013a5b6200013f5b620001445b620001495b6200014e5b620001535b620001585b6200015d5b +JUMPI_50,JUMPI,50,6003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036200016d575b62000173575b62000179575b6200017f575b62000185575b6200018b575b62000191575b62000197575b6200019d575b620001a3575b620001a9575b620001af575b620001b5575b620001bb575b620001c1575b620001c7575b620001cd575b620001d3575b620001d9575b620001df575b620001e5575b620001eb575b620001f1575b620001f7575b620001fd575b62000203575b62000209575b6200020f575b62000215575b6200021b575b62000221575b62000227575b6200022d575b62000233575b62000239575b6200023f575b62000245575b6200024b575b62000251575b62000257575b6200025d575b62000263575b62000269575b6200026f575b62000275575b6200027b575b62000281575b62000287575b6200028d575b62000293575b620002985b6200029d5b620002a25b620002a75b620002ac5b620002b15b620002b65b620002bb5b620002c05b620002c55b +PC_50,PC,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060005850585058505850585058505850585058505850585058505850585058505850585058505850585058505850585058505850585058505850585058505850585058505850585058505850585058505850585058505850585058505850585058505850585050505050505050505050 +MSIZE_50,MSIZE,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060005950595059505950595059505950595059505950595059505950595059505950595059505950595059505950595059505950595059505950595059505950595059505950595059505950595059505950595059505950595059505950595059505950595050505050505050505050 +GAS_50,GAS,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060005a505a505a505a505a505a505a505a505a505a505a505a505a505a505a505a505a505a505a505a505a505a505a505a505a505a505a505a505a505a505a505a505a505a505a505a505a505a505a505a505a505a505a505a505a505a505a505a505a505a5050505050505050505050 +JUMPDEST_50,JUMPDEST,50,5f5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b +MCOPY_50,MCOPY,50,60ff5f5260fe60205260205f60205e60205f60205e60205f60205e60205f60205e60205f60205e60205f60205e60205f60205e60205f60205e60205f60205e60205f60205e60205f60205e60205f60205e60205f60205e60205f60205e60205f60205e60205f60205e60205f60205e60205f60205e60205f60205e60205f60205e60205f60205e60205f60205e60205f60205e60205f60205e60205f60205e60205f60205e60205f60205e60205f60205e60205f60205e60205f60205e60205f60205e60205f60205e60205f60205e60205f60205e60205f60205e60205f60205e60205f60205e60205f60205e60205f60205e60205f60205e60205f60205e60205f60205e60205f60205e60205f60205e60205f60205e60205f60205e60205f60205e60205f60205e60205f60205e60205f60205e +MCOPY_COLD_50,MCOPY_COLD,50,60ff5f525f60200160205f825e60200160205f825e60200160205f825e60200160205f825e60200160205f825e60200160205f825e60200160205f825e60200160205f825e60200160205f825e60200160205f825e60200160205f825e60200160205f825e60200160205f825e60200160205f825e60200160205f825e60200160205f825e60200160205f825e60200160205f825e60200160205f825e60200160205f825e60200160205f825e60200160205f825e60200160205f825e60200160205f825e60200160205f825e60200160205f825e60200160205f825e60200160205f825e60200160205f825e60200160205f825e60200160205f825e60200160205f825e60200160205f825e60200160205f825e60200160205f825e60200160205f825e60200160205f825e60200160205f825e60200160205f825e60200160205f825e60200160205f825e60200160205f825e60200160205f825e60200160205f825e60200160205f825e60200160205f825e60200160205f825e60200160205f825e60200160205f825e60200160205f825e +PUSH0_50,PUSH0,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060005f505f505f505f505f505f505f505f505f505f505f505f505f505f505f505f505f505f505f505f505f505f505f505f505f505f505f505f505f505f505f505f505f505f505f505f505f505f505f505f505f505f505f505f505f505f505f505f505f505f5050505050505050505050 +LOG0_50,LOG0,50,7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6000526020600060206000602060006020600060206000602060006020600060206000602060006020600060206000602060006020600060206000602060006020600060206000602060006020600060206000602060006020600060206000602060006020600060206000602060006020600060206000602060006020600060206000602060006020600060206000602060006020600060206000602060006020600060206000602060006020600060206000602060006020600060206000602060006020600060206000a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 +LOG1_50,LOG1,50,7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60005260ff6020600060ff6020600060ff6020600060ff6020600060ff6020600060ff6020600060ff6020600060ff6020600060ff6020600060ff6020600060ff6020600060ff6020600060ff6020600060ff6020600060ff6020600060ff6020600060ff6020600060ff6020600060ff6020600060ff6020600060ff6020600060ff6020600060ff6020600060ff6020600060ff6020600060ff6020600060ff6020600060ff6020600060ff6020600060ff6020600060ff6020600060ff6020600060ff6020600060ff6020600060ff6020600060ff6020600060ff6020600060ff6020600060ff6020600060ff6020600060ff6020600060ff6020600060ff6020600060ff6020600060ff6020600060ff6020600060ff6020600060ff6020600060ff6020600060ff60206000a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1 +LOG2_50,LOG2,50,7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60005260ff60ff6020600060ff60ff6020600060ff60ff6020600060ff60ff6020600060ff60ff6020600060ff60ff6020600060ff60ff6020600060ff60ff6020600060ff60ff6020600060ff60ff6020600060ff60ff6020600060ff60ff6020600060ff60ff6020600060ff60ff6020600060ff60ff6020600060ff60ff6020600060ff60ff6020600060ff60ff6020600060ff60ff6020600060ff60ff6020600060ff60ff6020600060ff60ff6020600060ff60ff6020600060ff60ff6020600060ff60ff6020600060ff60ff6020600060ff60ff6020600060ff60ff6020600060ff60ff6020600060ff60ff6020600060ff60ff6020600060ff60ff6020600060ff60ff6020600060ff60ff6020600060ff60ff6020600060ff60ff6020600060ff60ff6020600060ff60ff6020600060ff60ff6020600060ff60ff6020600060ff60ff6020600060ff60ff6020600060ff60ff6020600060ff60ff6020600060ff60ff6020600060ff60ff6020600060ff60ff6020600060ff60ff6020600060ff60ff6020600060ff60ff60206000a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2 +LOG3_50,LOG3,50,7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60005260ff60ff60ff6020600060ff60ff60ff6020600060ff60ff60ff6020600060ff60ff60ff6020600060ff60ff60ff6020600060ff60ff60ff6020600060ff60ff60ff6020600060ff60ff60ff6020600060ff60ff60ff6020600060ff60ff60ff6020600060ff60ff60ff6020600060ff60ff60ff6020600060ff60ff60ff6020600060ff60ff60ff6020600060ff60ff60ff6020600060ff60ff60ff6020600060ff60ff60ff6020600060ff60ff60ff6020600060ff60ff60ff6020600060ff60ff60ff6020600060ff60ff60ff6020600060ff60ff60ff6020600060ff60ff60ff6020600060ff60ff60ff6020600060ff60ff60ff6020600060ff60ff60ff6020600060ff60ff60ff6020600060ff60ff60ff6020600060ff60ff60ff6020600060ff60ff60ff6020600060ff60ff60ff6020600060ff60ff60ff6020600060ff60ff60ff6020600060ff60ff60ff6020600060ff60ff60ff6020600060ff60ff60ff6020600060ff60ff60ff6020600060ff60ff60ff6020600060ff60ff60ff6020600060ff60ff60ff6020600060ff60ff60ff6020600060ff60ff60ff6020600060ff60ff60ff6020600060ff60ff60ff6020600060ff60ff60ff6020600060ff60ff60ff6020600060ff60ff60ff6020600060ff60ff60ff6020600060ff60ff60ff6020600060ff60ff60ff60206000a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3 +LOG4_50,LOG4,50,7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60005260ff60ff60ff60ff6020600060ff60ff60ff60ff6020600060ff60ff60ff60ff6020600060ff60ff60ff60ff6020600060ff60ff60ff60ff6020600060ff60ff60ff60ff6020600060ff60ff60ff60ff6020600060ff60ff60ff60ff6020600060ff60ff60ff60ff6020600060ff60ff60ff60ff6020600060ff60ff60ff60ff6020600060ff60ff60ff60ff6020600060ff60ff60ff60ff6020600060ff60ff60ff60ff6020600060ff60ff60ff60ff6020600060ff60ff60ff60ff6020600060ff60ff60ff60ff6020600060ff60ff60ff60ff6020600060ff60ff60ff60ff6020600060ff60ff60ff60ff6020600060ff60ff60ff60ff6020600060ff60ff60ff60ff6020600060ff60ff60ff60ff6020600060ff60ff60ff60ff6020600060ff60ff60ff60ff6020600060ff60ff60ff60ff6020600060ff60ff60ff60ff6020600060ff60ff60ff60ff6020600060ff60ff60ff60ff6020600060ff60ff60ff60ff6020600060ff60ff60ff60ff6020600060ff60ff60ff60ff6020600060ff60ff60ff60ff6020600060ff60ff60ff60ff6020600060ff60ff60ff60ff6020600060ff60ff60ff60ff6020600060ff60ff60ff60ff6020600060ff60ff60ff60ff6020600060ff60ff60ff60ff6020600060ff60ff60ff60ff6020600060ff60ff60ff60ff6020600060ff60ff60ff60ff6020600060ff60ff60ff60ff6020600060ff60ff60ff60ff6020600060ff60ff60ff60ff6020600060ff60ff60ff60ff6020600060ff60ff60ff60ff6020600060ff60ff60ff60ff6020600060ff60ff60ff60ff6020600060ff60ff60ff60ff60206000a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4a4 +CREATE_50,CREATE,50,6d6460016001016000526005601bf3600052600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600e60126000600e60126000600e60126000600e60126000600e60126000600e60126000600e60126000600e60126000600e60126000600e60126000600e60126000600e60126000600e60126000600e60126000600e60126000600e60126000600e60126000600e60126000600e60126000600e60126000600e60126000600e60126000600e60126000600e60126000600e60126000600e60126000600e60126000600e60126000600e60126000600e60126000600e60126000600e60126000600e60126000600e60126000600e60126000600e60126000600e60126000600e60126000600e60126000600e60126000600e60126000600e60126000600e60126000600e60126000600e60126000600e60126000600e60126000600e60126000600e60126000600e60126000f050f050f050f050f050f050f050f050f050f050f050f050f050f050f050f050f050f050f050f050f050f050f050f050f050f050f050f050f050f050f050f050f050f050f050f050f050f050f050f050f050f050f050f050f050f050f050f050f050f05050505050505050505050 +CALL_50,CALL,50,60ff60ff60ff60ff60ff716860015860060157fe5b60005260096017f36000526012600e6000f05f5f60205f5f8561ffff86868686868686f15086868686868686f15086868686868686f15086868686868686f15086868686868686f15086868686868686f15086868686868686f15086868686868686f15086868686868686f15086868686868686f15086868686868686f15086868686868686f15086868686868686f15086868686868686f15086868686868686f15086868686868686f15086868686868686f15086868686868686f15086868686868686f15086868686868686f15086868686868686f15086868686868686f15086868686868686f15086868686868686f15086868686868686f15086868686868686f15086868686868686f15086868686868686f15086868686868686f15086868686868686f15086868686868686f15086868686868686f15086868686868686f15086868686868686f15086868686868686f15086868686868686f15086868686868686f15086868686868686f15086868686868686f15086868686868686f15086868686868686f15086868686868686f15086868686868686f15086868686868686f15086868686868686f15086868686868686f15086868686868686f15086868686868686f15086868686868686f15086868686868686f1505050505050 +RETURN_50,RETURN,50,726960ff60005260026018f3600052600a6016f36000526013600d6000f060ff52716860ff6000526002601860005260096017f36000526012600e6000f060ff5160006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff450 +DELEGATECALL_50,DELEGATECALL,50,60ff60ff60ff60ff60ff716860015860060157fe5b60005260096017f36000526012600e6000f05f5f60205f5f8561ffff858585858585f450858585858585f450858585858585f450858585858585f450858585858585f450858585858585f450858585858585f450858585858585f450858585858585f450858585858585f450858585858585f450858585858585f450858585858585f450858585858585f450858585858585f450858585858585f450858585858585f450858585858585f450858585858585f450858585858585f450858585858585f450858585858585f450858585858585f450858585858585f450858585858585f450858585858585f450858585858585f450858585858585f450858585858585f450858585858585f450858585858585f450858585858585f450858585858585f450858585858585f450858585858585f450858585858585f450858585858585f450858585858585f450858585858585f450858585858585f450858585858585f450858585858585f450858585858585f450858585858585f450858585858585f450858585858585f450858585858585f450858585858585f450858585858585f450858585858585f4505050505050 +STATICCALL_50,STATICCALL,50,60ff60ff60ff60ff60ff716860015860060157fe5b60005260096017f36000526012600e6000f05f5f60205f5f8561ffff858585858585fa50858585858585fa50858585858585fa50858585858585fa50858585858585fa50858585858585fa50858585858585fa50858585858585fa50858585858585fa50858585858585fa50858585858585fa50858585858585fa50858585858585fa50858585858585fa50858585858585fa50858585858585fa50858585858585fa50858585858585fa50858585858585fa50858585858585fa50858585858585fa50858585858585fa50858585858585fa50858585858585fa50858585858585fa50858585858585fa50858585858585fa50858585858585fa50858585858585fa50858585858585fa50858585858585fa50858585858585fa50858585858585fa50858585858585fa50858585858585fa50858585858585fa50858585858585fa50858585858585fa50858585858585fa50858585858585fa50858585858585fa50858585858585fa50858585858585fa50858585858585fa50858585858585fa50858585858585fa50858585858585fa50858585858585fa50858585858585fa50858585858585fa505050505050 +REVERT_50,REVERT,50,726960ff60005260026018fd600052600a6016f36000526013600d6000f060ff52716860ff6000526002601860005260096017f36000526012600e6000f060ff5160006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff45060006000600060008461fffff450 +PUSH1_50,PUSH1,50,60006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060035060035060035060035060035060035060035060035060035060035060035060035060035060035060035060035060035060035060035060035060035060035060035060035060035060035060035060035060035060035060035060035060035060035060035060035060035060035060035060035060035060035060035060035060035060035060035060035060035060035050505050505050505050 +PUSH2_50,PUSH2,50,600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000610303506103035061030350610303506103035061030350610303506103035061030350610303506103035061030350610303506103035061030350610303506103035061030350610303506103035061030350610303506103035061030350610303506103035061030350610303506103035061030350610303506103035061030350610303506103035061030350610303506103035061030350610303506103035061030350610303506103035061030350610303506103035061030350610303506103035050505050505050505050 +PUSH3_50,PUSH3,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006203030350620303035062030303506203030350620303035062030303506203030350620303035062030303506203030350620303035062030303506203030350620303035062030303506203030350620303035062030303506203030350620303035062030303506203030350620303035062030303506203030350620303035062030303506203030350620303035062030303506203030350620303035062030303506203030350620303035062030303506203030350620303035062030303506203030350620303035062030303506203030350620303035062030303506203030350620303035062030303506203030350620303035050505050505050505050 +PUSH4_50,PUSH4,50,60006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600063030303035063030303035063030303035063030303035063030303035063030303035063030303035063030303035063030303035063030303035063030303035063030303035063030303035063030303035063030303035063030303035063030303035063030303035063030303035063030303035063030303035063030303035063030303035063030303035063030303035063030303035063030303035063030303035063030303035063030303035063030303035063030303035063030303035063030303035063030303035063030303035063030303035063030303035063030303035063030303035063030303035063030303035063030303035063030303035063030303035063030303035063030303035063030303035063030303035063030303035050505050505050505050 +PUSH5_50,PUSH5,50,600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000640303030303506403030303035064030303030350640303030303506403030303035064030303030350640303030303506403030303035064030303030350640303030303506403030303035064030303030350640303030303506403030303035064030303030350640303030303506403030303035064030303030350640303030303506403030303035064030303030350640303030303506403030303035064030303030350640303030303506403030303035064030303030350640303030303506403030303035064030303030350640303030303506403030303035064030303030350640303030303506403030303035064030303030350640303030303506403030303035064030303030350640303030303506403030303035064030303030350640303030303506403030303035064030303030350640303030303506403030303035064030303030350640303030303506403030303035050505050505050505050 +PUSH6_50,PUSH6,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006503030303030350650303030303035065030303030303506503030303030350650303030303035065030303030303506503030303030350650303030303035065030303030303506503030303030350650303030303035065030303030303506503030303030350650303030303035065030303030303506503030303030350650303030303035065030303030303506503030303030350650303030303035065030303030303506503030303030350650303030303035065030303030303506503030303030350650303030303035065030303030303506503030303030350650303030303035065030303030303506503030303030350650303030303035065030303030303506503030303030350650303030303035065030303030303506503030303030350650303030303035065030303030303506503030303030350650303030303035065030303030303506503030303030350650303030303035065030303030303506503030303030350650303030303035065030303030303506503030303030350650303030303035050505050505050505050 +PUSH7_50,PUSH7,50,60006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600066030303030303035066030303030303035066030303030303035066030303030303035066030303030303035066030303030303035066030303030303035066030303030303035066030303030303035066030303030303035066030303030303035066030303030303035066030303030303035066030303030303035066030303030303035066030303030303035066030303030303035066030303030303035066030303030303035066030303030303035066030303030303035066030303030303035066030303030303035066030303030303035066030303030303035066030303030303035066030303030303035066030303030303035066030303030303035066030303030303035066030303030303035066030303030303035066030303030303035066030303030303035066030303030303035066030303030303035066030303030303035066030303030303035066030303030303035066030303030303035066030303030303035066030303030303035066030303030303035066030303030303035066030303030303035066030303030303035066030303030303035066030303030303035066030303030303035066030303030303035050505050505050505050 +PUSH8_50,PUSH8,50,600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000670303030303030303506703030303030303035067030303030303030350670303030303030303506703030303030303035067030303030303030350670303030303030303506703030303030303035067030303030303030350670303030303030303506703030303030303035067030303030303030350670303030303030303506703030303030303035067030303030303030350670303030303030303506703030303030303035067030303030303030350670303030303030303506703030303030303035067030303030303030350670303030303030303506703030303030303035067030303030303030350670303030303030303506703030303030303035067030303030303030350670303030303030303506703030303030303035067030303030303030350670303030303030303506703030303030303035067030303030303030350670303030303030303506703030303030303035067030303030303030350670303030303030303506703030303030303035067030303030303030350670303030303030303506703030303030303035067030303030303030350670303030303030303506703030303030303035067030303030303030350670303030303030303506703030303030303035067030303030303030350670303030303030303506703030303030303035050505050505050505050 +PUSH9_50,PUSH9,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006803030303030303030350680303030303030303035068030303030303030303506803030303030303030350680303030303030303035068030303030303030303506803030303030303030350680303030303030303035068030303030303030303506803030303030303030350680303030303030303035068030303030303030303506803030303030303030350680303030303030303035068030303030303030303506803030303030303030350680303030303030303035068030303030303030303506803030303030303030350680303030303030303035068030303030303030303506803030303030303030350680303030303030303035068030303030303030303506803030303030303030350680303030303030303035068030303030303030303506803030303030303030350680303030303030303035068030303030303030303506803030303030303030350680303030303030303035068030303030303030303506803030303030303030350680303030303030303035068030303030303030303506803030303030303030350680303030303030303035068030303030303030303506803030303030303030350680303030303030303035068030303030303030303506803030303030303030350680303030303030303035068030303030303030303506803030303030303030350680303030303030303035068030303030303030303506803030303030303030350680303030303030303035050505050505050505050 +PUSH10_50,PUSH10,50,60006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600069030303030303030303035069030303030303030303035069030303030303030303035069030303030303030303035069030303030303030303035069030303030303030303035069030303030303030303035069030303030303030303035069030303030303030303035069030303030303030303035069030303030303030303035069030303030303030303035069030303030303030303035069030303030303030303035069030303030303030303035069030303030303030303035069030303030303030303035069030303030303030303035069030303030303030303035069030303030303030303035069030303030303030303035069030303030303030303035069030303030303030303035069030303030303030303035069030303030303030303035069030303030303030303035069030303030303030303035069030303030303030303035069030303030303030303035069030303030303030303035069030303030303030303035069030303030303030303035069030303030303030303035069030303030303030303035069030303030303030303035069030303030303030303035069030303030303030303035069030303030303030303035069030303030303030303035069030303030303030303035069030303030303030303035069030303030303030303035069030303030303030303035069030303030303030303035069030303030303030303035069030303030303030303035069030303030303030303035069030303030303030303035069030303030303030303035069030303030303030303035050505050505050505050 +PUSH11_50,PUSH11,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006a0303030303030303030303506a0303030303030303030303506a0303030303030303030303506a0303030303030303030303506a0303030303030303030303506a0303030303030303030303506a0303030303030303030303506a0303030303030303030303506a0303030303030303030303506a0303030303030303030303506a0303030303030303030303506a0303030303030303030303506a0303030303030303030303506a0303030303030303030303506a0303030303030303030303506a0303030303030303030303506a0303030303030303030303506a0303030303030303030303506a0303030303030303030303506a0303030303030303030303506a0303030303030303030303506a0303030303030303030303506a0303030303030303030303506a0303030303030303030303506a0303030303030303030303506a0303030303030303030303506a0303030303030303030303506a0303030303030303030303506a0303030303030303030303506a0303030303030303030303506a0303030303030303030303506a0303030303030303030303506a0303030303030303030303506a0303030303030303030303506a0303030303030303030303506a0303030303030303030303506a0303030303030303030303506a0303030303030303030303506a0303030303030303030303506a0303030303030303030303506a0303030303030303030303506a0303030303030303030303506a0303030303030303030303506a0303030303030303030303506a0303030303030303030303506a0303030303030303030303506a0303030303030303030303506a0303030303030303030303506a0303030303030303030303506a03030303030303030303035050505050505050505050 +PUSH12_50,PUSH12,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006b030303030303030303030303506b030303030303030303030303506b030303030303030303030303506b030303030303030303030303506b030303030303030303030303506b030303030303030303030303506b030303030303030303030303506b030303030303030303030303506b030303030303030303030303506b030303030303030303030303506b030303030303030303030303506b030303030303030303030303506b030303030303030303030303506b030303030303030303030303506b030303030303030303030303506b030303030303030303030303506b030303030303030303030303506b030303030303030303030303506b030303030303030303030303506b030303030303030303030303506b030303030303030303030303506b030303030303030303030303506b030303030303030303030303506b030303030303030303030303506b030303030303030303030303506b030303030303030303030303506b030303030303030303030303506b030303030303030303030303506b030303030303030303030303506b030303030303030303030303506b030303030303030303030303506b030303030303030303030303506b030303030303030303030303506b030303030303030303030303506b030303030303030303030303506b030303030303030303030303506b030303030303030303030303506b030303030303030303030303506b030303030303030303030303506b030303030303030303030303506b030303030303030303030303506b030303030303030303030303506b030303030303030303030303506b030303030303030303030303506b030303030303030303030303506b030303030303030303030303506b030303030303030303030303506b030303030303030303030303506b030303030303030303030303506b0303030303030303030303035050505050505050505050 +PUSH13_50,PUSH13,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006c03030303030303030303030303506c03030303030303030303030303506c03030303030303030303030303506c03030303030303030303030303506c03030303030303030303030303506c03030303030303030303030303506c03030303030303030303030303506c03030303030303030303030303506c03030303030303030303030303506c03030303030303030303030303506c03030303030303030303030303506c03030303030303030303030303506c03030303030303030303030303506c03030303030303030303030303506c03030303030303030303030303506c03030303030303030303030303506c03030303030303030303030303506c03030303030303030303030303506c03030303030303030303030303506c03030303030303030303030303506c03030303030303030303030303506c03030303030303030303030303506c03030303030303030303030303506c03030303030303030303030303506c03030303030303030303030303506c03030303030303030303030303506c03030303030303030303030303506c03030303030303030303030303506c03030303030303030303030303506c03030303030303030303030303506c03030303030303030303030303506c03030303030303030303030303506c03030303030303030303030303506c03030303030303030303030303506c03030303030303030303030303506c03030303030303030303030303506c03030303030303030303030303506c03030303030303030303030303506c03030303030303030303030303506c03030303030303030303030303506c03030303030303030303030303506c03030303030303030303030303506c03030303030303030303030303506c03030303030303030303030303506c03030303030303030303030303506c03030303030303030303030303506c03030303030303030303030303506c03030303030303030303030303506c03030303030303030303030303506c030303030303030303030303035050505050505050505050 +PUSH14_50,PUSH14,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006d0303030303030303030303030303506d0303030303030303030303030303506d0303030303030303030303030303506d0303030303030303030303030303506d0303030303030303030303030303506d0303030303030303030303030303506d0303030303030303030303030303506d0303030303030303030303030303506d0303030303030303030303030303506d0303030303030303030303030303506d0303030303030303030303030303506d0303030303030303030303030303506d0303030303030303030303030303506d0303030303030303030303030303506d0303030303030303030303030303506d0303030303030303030303030303506d0303030303030303030303030303506d0303030303030303030303030303506d0303030303030303030303030303506d0303030303030303030303030303506d0303030303030303030303030303506d0303030303030303030303030303506d0303030303030303030303030303506d0303030303030303030303030303506d0303030303030303030303030303506d0303030303030303030303030303506d0303030303030303030303030303506d0303030303030303030303030303506d0303030303030303030303030303506d0303030303030303030303030303506d0303030303030303030303030303506d0303030303030303030303030303506d0303030303030303030303030303506d0303030303030303030303030303506d0303030303030303030303030303506d0303030303030303030303030303506d0303030303030303030303030303506d0303030303030303030303030303506d0303030303030303030303030303506d0303030303030303030303030303506d0303030303030303030303030303506d0303030303030303030303030303506d0303030303030303030303030303506d0303030303030303030303030303506d0303030303030303030303030303506d0303030303030303030303030303506d0303030303030303030303030303506d0303030303030303030303030303506d0303030303030303030303030303506d03030303030303030303030303035050505050505050505050 +PUSH15_50,PUSH15,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006e030303030303030303030303030303506e030303030303030303030303030303506e030303030303030303030303030303506e030303030303030303030303030303506e030303030303030303030303030303506e030303030303030303030303030303506e030303030303030303030303030303506e030303030303030303030303030303506e030303030303030303030303030303506e030303030303030303030303030303506e030303030303030303030303030303506e030303030303030303030303030303506e030303030303030303030303030303506e030303030303030303030303030303506e030303030303030303030303030303506e030303030303030303030303030303506e030303030303030303030303030303506e030303030303030303030303030303506e030303030303030303030303030303506e030303030303030303030303030303506e030303030303030303030303030303506e030303030303030303030303030303506e030303030303030303030303030303506e030303030303030303030303030303506e030303030303030303030303030303506e030303030303030303030303030303506e030303030303030303030303030303506e030303030303030303030303030303506e030303030303030303030303030303506e030303030303030303030303030303506e030303030303030303030303030303506e030303030303030303030303030303506e030303030303030303030303030303506e030303030303030303030303030303506e030303030303030303030303030303506e030303030303030303030303030303506e030303030303030303030303030303506e030303030303030303030303030303506e030303030303030303030303030303506e030303030303030303030303030303506e030303030303030303030303030303506e030303030303030303030303030303506e030303030303030303030303030303506e030303030303030303030303030303506e030303030303030303030303030303506e030303030303030303030303030303506e030303030303030303030303030303506e030303030303030303030303030303506e030303030303030303030303030303506e0303030303030303030303030303035050505050505050505050 +PUSH16_50,PUSH16,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006f03030303030303030303030303030303506f03030303030303030303030303030303506f03030303030303030303030303030303506f03030303030303030303030303030303506f03030303030303030303030303030303506f03030303030303030303030303030303506f03030303030303030303030303030303506f03030303030303030303030303030303506f03030303030303030303030303030303506f03030303030303030303030303030303506f03030303030303030303030303030303506f03030303030303030303030303030303506f03030303030303030303030303030303506f03030303030303030303030303030303506f03030303030303030303030303030303506f03030303030303030303030303030303506f03030303030303030303030303030303506f03030303030303030303030303030303506f03030303030303030303030303030303506f03030303030303030303030303030303506f03030303030303030303030303030303506f03030303030303030303030303030303506f03030303030303030303030303030303506f03030303030303030303030303030303506f03030303030303030303030303030303506f03030303030303030303030303030303506f03030303030303030303030303030303506f03030303030303030303030303030303506f03030303030303030303030303030303506f03030303030303030303030303030303506f03030303030303030303030303030303506f03030303030303030303030303030303506f03030303030303030303030303030303506f03030303030303030303030303030303506f03030303030303030303030303030303506f03030303030303030303030303030303506f03030303030303030303030303030303506f03030303030303030303030303030303506f03030303030303030303030303030303506f03030303030303030303030303030303506f03030303030303030303030303030303506f03030303030303030303030303030303506f03030303030303030303030303030303506f03030303030303030303030303030303506f03030303030303030303030303030303506f03030303030303030303030303030303506f03030303030303030303030303030303506f03030303030303030303030303030303506f03030303030303030303030303030303506f030303030303030303030303030303035050505050505050505050 +PUSH17_50,PUSH17,50,600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000700303030303030303030303030303030303507003030303030303030303030303030303035070030303030303030303030303030303030350700303030303030303030303030303030303507003030303030303030303030303030303035070030303030303030303030303030303030350700303030303030303030303030303030303507003030303030303030303030303030303035070030303030303030303030303030303030350700303030303030303030303030303030303507003030303030303030303030303030303035070030303030303030303030303030303030350700303030303030303030303030303030303507003030303030303030303030303030303035070030303030303030303030303030303030350700303030303030303030303030303030303507003030303030303030303030303030303035070030303030303030303030303030303030350700303030303030303030303030303030303507003030303030303030303030303030303035070030303030303030303030303030303030350700303030303030303030303030303030303507003030303030303030303030303030303035070030303030303030303030303030303030350700303030303030303030303030303030303507003030303030303030303030303030303035070030303030303030303030303030303030350700303030303030303030303030303030303507003030303030303030303030303030303035070030303030303030303030303030303030350700303030303030303030303030303030303507003030303030303030303030303030303035070030303030303030303030303030303030350700303030303030303030303030303030303507003030303030303030303030303030303035070030303030303030303030303030303030350700303030303030303030303030303030303507003030303030303030303030303030303035070030303030303030303030303030303030350700303030303030303030303030303030303507003030303030303030303030303030303035070030303030303030303030303030303030350700303030303030303030303030303030303507003030303030303030303030303030303035070030303030303030303030303030303030350700303030303030303030303030303030303507003030303030303030303030303030303035070030303030303030303030303030303030350700303030303030303030303030303030303507003030303030303030303030303030303035050505050505050505050 +PUSH18_50,PUSH18,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060007103030303030303030303030303030303030350710303030303030303030303030303030303035071030303030303030303030303030303030303507103030303030303030303030303030303030350710303030303030303030303030303030303035071030303030303030303030303030303030303507103030303030303030303030303030303030350710303030303030303030303030303030303035071030303030303030303030303030303030303507103030303030303030303030303030303030350710303030303030303030303030303030303035071030303030303030303030303030303030303507103030303030303030303030303030303030350710303030303030303030303030303030303035071030303030303030303030303030303030303507103030303030303030303030303030303030350710303030303030303030303030303030303035071030303030303030303030303030303030303507103030303030303030303030303030303030350710303030303030303030303030303030303035071030303030303030303030303030303030303507103030303030303030303030303030303030350710303030303030303030303030303030303035071030303030303030303030303030303030303507103030303030303030303030303030303030350710303030303030303030303030303030303035071030303030303030303030303030303030303507103030303030303030303030303030303030350710303030303030303030303030303030303035071030303030303030303030303030303030303507103030303030303030303030303030303030350710303030303030303030303030303030303035071030303030303030303030303030303030303507103030303030303030303030303030303030350710303030303030303030303030303030303035071030303030303030303030303030303030303507103030303030303030303030303030303030350710303030303030303030303030303030303035071030303030303030303030303030303030303507103030303030303030303030303030303030350710303030303030303030303030303030303035071030303030303030303030303030303030303507103030303030303030303030303030303030350710303030303030303030303030303030303035071030303030303030303030303030303030303507103030303030303030303030303030303030350710303030303030303030303030303030303035071030303030303030303030303030303030303507103030303030303030303030303030303030350710303030303030303030303030303030303035050505050505050505050 +PUSH19_50,PUSH19,50,60006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600072030303030303030303030303030303030303035072030303030303030303030303030303030303035072030303030303030303030303030303030303035072030303030303030303030303030303030303035072030303030303030303030303030303030303035072030303030303030303030303030303030303035072030303030303030303030303030303030303035072030303030303030303030303030303030303035072030303030303030303030303030303030303035072030303030303030303030303030303030303035072030303030303030303030303030303030303035072030303030303030303030303030303030303035072030303030303030303030303030303030303035072030303030303030303030303030303030303035072030303030303030303030303030303030303035072030303030303030303030303030303030303035072030303030303030303030303030303030303035072030303030303030303030303030303030303035072030303030303030303030303030303030303035072030303030303030303030303030303030303035072030303030303030303030303030303030303035072030303030303030303030303030303030303035072030303030303030303030303030303030303035072030303030303030303030303030303030303035072030303030303030303030303030303030303035072030303030303030303030303030303030303035072030303030303030303030303030303030303035072030303030303030303030303030303030303035072030303030303030303030303030303030303035072030303030303030303030303030303030303035072030303030303030303030303030303030303035072030303030303030303030303030303030303035072030303030303030303030303030303030303035072030303030303030303030303030303030303035072030303030303030303030303030303030303035072030303030303030303030303030303030303035072030303030303030303030303030303030303035072030303030303030303030303030303030303035072030303030303030303030303030303030303035072030303030303030303030303030303030303035072030303030303030303030303030303030303035072030303030303030303030303030303030303035072030303030303030303030303030303030303035072030303030303030303030303030303030303035072030303030303030303030303030303030303035072030303030303030303030303030303030303035072030303030303030303030303030303030303035072030303030303030303030303030303030303035072030303030303030303030303030303030303035072030303030303030303030303030303030303035050505050505050505050 +PUSH20_50,PUSH20,50,600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000730303030303030303030303030303030303030303507303030303030303030303030303030303030303035073030303030303030303030303030303030303030350730303030303030303030303030303030303030303507303030303030303030303030303030303030303035073030303030303030303030303030303030303030350730303030303030303030303030303030303030303507303030303030303030303030303030303030303035073030303030303030303030303030303030303030350730303030303030303030303030303030303030303507303030303030303030303030303030303030303035073030303030303030303030303030303030303030350730303030303030303030303030303030303030303507303030303030303030303030303030303030303035073030303030303030303030303030303030303030350730303030303030303030303030303030303030303507303030303030303030303030303030303030303035073030303030303030303030303030303030303030350730303030303030303030303030303030303030303507303030303030303030303030303030303030303035073030303030303030303030303030303030303030350730303030303030303030303030303030303030303507303030303030303030303030303030303030303035073030303030303030303030303030303030303030350730303030303030303030303030303030303030303507303030303030303030303030303030303030303035073030303030303030303030303030303030303030350730303030303030303030303030303030303030303507303030303030303030303030303030303030303035073030303030303030303030303030303030303030350730303030303030303030303030303030303030303507303030303030303030303030303030303030303035073030303030303030303030303030303030303030350730303030303030303030303030303030303030303507303030303030303030303030303030303030303035073030303030303030303030303030303030303030350730303030303030303030303030303030303030303507303030303030303030303030303030303030303035073030303030303030303030303030303030303030350730303030303030303030303030303030303030303507303030303030303030303030303030303030303035073030303030303030303030303030303030303030350730303030303030303030303030303030303030303507303030303030303030303030303030303030303035073030303030303030303030303030303030303030350730303030303030303030303030303030303030303507303030303030303030303030303030303030303035073030303030303030303030303030303030303030350730303030303030303030303030303030303030303507303030303030303030303030303030303030303035050505050505050505050 +PUSH21_50,PUSH21,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060007403030303030303030303030303030303030303030350740303030303030303030303030303030303030303035074030303030303030303030303030303030303030303507403030303030303030303030303030303030303030350740303030303030303030303030303030303030303035074030303030303030303030303030303030303030303507403030303030303030303030303030303030303030350740303030303030303030303030303030303030303035074030303030303030303030303030303030303030303507403030303030303030303030303030303030303030350740303030303030303030303030303030303030303035074030303030303030303030303030303030303030303507403030303030303030303030303030303030303030350740303030303030303030303030303030303030303035074030303030303030303030303030303030303030303507403030303030303030303030303030303030303030350740303030303030303030303030303030303030303035074030303030303030303030303030303030303030303507403030303030303030303030303030303030303030350740303030303030303030303030303030303030303035074030303030303030303030303030303030303030303507403030303030303030303030303030303030303030350740303030303030303030303030303030303030303035074030303030303030303030303030303030303030303507403030303030303030303030303030303030303030350740303030303030303030303030303030303030303035074030303030303030303030303030303030303030303507403030303030303030303030303030303030303030350740303030303030303030303030303030303030303035074030303030303030303030303030303030303030303507403030303030303030303030303030303030303030350740303030303030303030303030303030303030303035074030303030303030303030303030303030303030303507403030303030303030303030303030303030303030350740303030303030303030303030303030303030303035074030303030303030303030303030303030303030303507403030303030303030303030303030303030303030350740303030303030303030303030303030303030303035074030303030303030303030303030303030303030303507403030303030303030303030303030303030303030350740303030303030303030303030303030303030303035074030303030303030303030303030303030303030303507403030303030303030303030303030303030303030350740303030303030303030303030303030303030303035074030303030303030303030303030303030303030303507403030303030303030303030303030303030303030350740303030303030303030303030303030303030303035074030303030303030303030303030303030303030303507403030303030303030303030303030303030303030350740303030303030303030303030303030303030303035050505050505050505050 +PUSH22_50,PUSH22,50,60006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600075030303030303030303030303030303030303030303035075030303030303030303030303030303030303030303035075030303030303030303030303030303030303030303035075030303030303030303030303030303030303030303035075030303030303030303030303030303030303030303035075030303030303030303030303030303030303030303035075030303030303030303030303030303030303030303035075030303030303030303030303030303030303030303035075030303030303030303030303030303030303030303035075030303030303030303030303030303030303030303035075030303030303030303030303030303030303030303035075030303030303030303030303030303030303030303035075030303030303030303030303030303030303030303035075030303030303030303030303030303030303030303035075030303030303030303030303030303030303030303035075030303030303030303030303030303030303030303035075030303030303030303030303030303030303030303035075030303030303030303030303030303030303030303035075030303030303030303030303030303030303030303035075030303030303030303030303030303030303030303035075030303030303030303030303030303030303030303035075030303030303030303030303030303030303030303035075030303030303030303030303030303030303030303035075030303030303030303030303030303030303030303035075030303030303030303030303030303030303030303035075030303030303030303030303030303030303030303035075030303030303030303030303030303030303030303035075030303030303030303030303030303030303030303035075030303030303030303030303030303030303030303035075030303030303030303030303030303030303030303035075030303030303030303030303030303030303030303035075030303030303030303030303030303030303030303035075030303030303030303030303030303030303030303035075030303030303030303030303030303030303030303035075030303030303030303030303030303030303030303035075030303030303030303030303030303030303030303035075030303030303030303030303030303030303030303035075030303030303030303030303030303030303030303035075030303030303030303030303030303030303030303035075030303030303030303030303030303030303030303035075030303030303030303030303030303030303030303035075030303030303030303030303030303030303030303035075030303030303030303030303030303030303030303035075030303030303030303030303030303030303030303035075030303030303030303030303030303030303030303035075030303030303030303030303030303030303030303035075030303030303030303030303030303030303030303035075030303030303030303030303030303030303030303035075030303030303030303030303030303030303030303035075030303030303030303030303030303030303030303035050505050505050505050 +PUSH23_50,PUSH23,50,600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000760303030303030303030303030303030303030303030303507603030303030303030303030303030303030303030303035076030303030303030303030303030303030303030303030350760303030303030303030303030303030303030303030303507603030303030303030303030303030303030303030303035076030303030303030303030303030303030303030303030350760303030303030303030303030303030303030303030303507603030303030303030303030303030303030303030303035076030303030303030303030303030303030303030303030350760303030303030303030303030303030303030303030303507603030303030303030303030303030303030303030303035076030303030303030303030303030303030303030303030350760303030303030303030303030303030303030303030303507603030303030303030303030303030303030303030303035076030303030303030303030303030303030303030303030350760303030303030303030303030303030303030303030303507603030303030303030303030303030303030303030303035076030303030303030303030303030303030303030303030350760303030303030303030303030303030303030303030303507603030303030303030303030303030303030303030303035076030303030303030303030303030303030303030303030350760303030303030303030303030303030303030303030303507603030303030303030303030303030303030303030303035076030303030303030303030303030303030303030303030350760303030303030303030303030303030303030303030303507603030303030303030303030303030303030303030303035076030303030303030303030303030303030303030303030350760303030303030303030303030303030303030303030303507603030303030303030303030303030303030303030303035076030303030303030303030303030303030303030303030350760303030303030303030303030303030303030303030303507603030303030303030303030303030303030303030303035076030303030303030303030303030303030303030303030350760303030303030303030303030303030303030303030303507603030303030303030303030303030303030303030303035076030303030303030303030303030303030303030303030350760303030303030303030303030303030303030303030303507603030303030303030303030303030303030303030303035076030303030303030303030303030303030303030303030350760303030303030303030303030303030303030303030303507603030303030303030303030303030303030303030303035076030303030303030303030303030303030303030303030350760303030303030303030303030303030303030303030303507603030303030303030303030303030303030303030303035076030303030303030303030303030303030303030303030350760303030303030303030303030303030303030303030303507603030303030303030303030303030303030303030303035076030303030303030303030303030303030303030303030350760303030303030303030303030303030303030303030303507603030303030303030303030303030303030303030303035050505050505050505050 +PUSH24_50,PUSH24,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060007703030303030303030303030303030303030303030303030350770303030303030303030303030303030303030303030303035077030303030303030303030303030303030303030303030303507703030303030303030303030303030303030303030303030350770303030303030303030303030303030303030303030303035077030303030303030303030303030303030303030303030303507703030303030303030303030303030303030303030303030350770303030303030303030303030303030303030303030303035077030303030303030303030303030303030303030303030303507703030303030303030303030303030303030303030303030350770303030303030303030303030303030303030303030303035077030303030303030303030303030303030303030303030303507703030303030303030303030303030303030303030303030350770303030303030303030303030303030303030303030303035077030303030303030303030303030303030303030303030303507703030303030303030303030303030303030303030303030350770303030303030303030303030303030303030303030303035077030303030303030303030303030303030303030303030303507703030303030303030303030303030303030303030303030350770303030303030303030303030303030303030303030303035077030303030303030303030303030303030303030303030303507703030303030303030303030303030303030303030303030350770303030303030303030303030303030303030303030303035077030303030303030303030303030303030303030303030303507703030303030303030303030303030303030303030303030350770303030303030303030303030303030303030303030303035077030303030303030303030303030303030303030303030303507703030303030303030303030303030303030303030303030350770303030303030303030303030303030303030303030303035077030303030303030303030303030303030303030303030303507703030303030303030303030303030303030303030303030350770303030303030303030303030303030303030303030303035077030303030303030303030303030303030303030303030303507703030303030303030303030303030303030303030303030350770303030303030303030303030303030303030303030303035077030303030303030303030303030303030303030303030303507703030303030303030303030303030303030303030303030350770303030303030303030303030303030303030303030303035077030303030303030303030303030303030303030303030303507703030303030303030303030303030303030303030303030350770303030303030303030303030303030303030303030303035077030303030303030303030303030303030303030303030303507703030303030303030303030303030303030303030303030350770303030303030303030303030303030303030303030303035077030303030303030303030303030303030303030303030303507703030303030303030303030303030303030303030303030350770303030303030303030303030303030303030303030303035077030303030303030303030303030303030303030303030303507703030303030303030303030303030303030303030303030350770303030303030303030303030303030303030303030303035050505050505050505050 +PUSH25_50,PUSH25,50,60006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600078030303030303030303030303030303030303030303030303035078030303030303030303030303030303030303030303030303035078030303030303030303030303030303030303030303030303035078030303030303030303030303030303030303030303030303035078030303030303030303030303030303030303030303030303035078030303030303030303030303030303030303030303030303035078030303030303030303030303030303030303030303030303035078030303030303030303030303030303030303030303030303035078030303030303030303030303030303030303030303030303035078030303030303030303030303030303030303030303030303035078030303030303030303030303030303030303030303030303035078030303030303030303030303030303030303030303030303035078030303030303030303030303030303030303030303030303035078030303030303030303030303030303030303030303030303035078030303030303030303030303030303030303030303030303035078030303030303030303030303030303030303030303030303035078030303030303030303030303030303030303030303030303035078030303030303030303030303030303030303030303030303035078030303030303030303030303030303030303030303030303035078030303030303030303030303030303030303030303030303035078030303030303030303030303030303030303030303030303035078030303030303030303030303030303030303030303030303035078030303030303030303030303030303030303030303030303035078030303030303030303030303030303030303030303030303035078030303030303030303030303030303030303030303030303035078030303030303030303030303030303030303030303030303035078030303030303030303030303030303030303030303030303035078030303030303030303030303030303030303030303030303035078030303030303030303030303030303030303030303030303035078030303030303030303030303030303030303030303030303035078030303030303030303030303030303030303030303030303035078030303030303030303030303030303030303030303030303035078030303030303030303030303030303030303030303030303035078030303030303030303030303030303030303030303030303035078030303030303030303030303030303030303030303030303035078030303030303030303030303030303030303030303030303035078030303030303030303030303030303030303030303030303035078030303030303030303030303030303030303030303030303035078030303030303030303030303030303030303030303030303035078030303030303030303030303030303030303030303030303035078030303030303030303030303030303030303030303030303035078030303030303030303030303030303030303030303030303035078030303030303030303030303030303030303030303030303035078030303030303030303030303030303030303030303030303035078030303030303030303030303030303030303030303030303035078030303030303030303030303030303030303030303030303035078030303030303030303030303030303030303030303030303035078030303030303030303030303030303030303030303030303035078030303030303030303030303030303030303030303030303035078030303030303030303030303030303030303030303030303035050505050505050505050 +PUSH26_50,PUSH26,50,600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000790303030303030303030303030303030303030303030303030303507903030303030303030303030303030303030303030303030303035079030303030303030303030303030303030303030303030303030350790303030303030303030303030303030303030303030303030303507903030303030303030303030303030303030303030303030303035079030303030303030303030303030303030303030303030303030350790303030303030303030303030303030303030303030303030303507903030303030303030303030303030303030303030303030303035079030303030303030303030303030303030303030303030303030350790303030303030303030303030303030303030303030303030303507903030303030303030303030303030303030303030303030303035079030303030303030303030303030303030303030303030303030350790303030303030303030303030303030303030303030303030303507903030303030303030303030303030303030303030303030303035079030303030303030303030303030303030303030303030303030350790303030303030303030303030303030303030303030303030303507903030303030303030303030303030303030303030303030303035079030303030303030303030303030303030303030303030303030350790303030303030303030303030303030303030303030303030303507903030303030303030303030303030303030303030303030303035079030303030303030303030303030303030303030303030303030350790303030303030303030303030303030303030303030303030303507903030303030303030303030303030303030303030303030303035079030303030303030303030303030303030303030303030303030350790303030303030303030303030303030303030303030303030303507903030303030303030303030303030303030303030303030303035079030303030303030303030303030303030303030303030303030350790303030303030303030303030303030303030303030303030303507903030303030303030303030303030303030303030303030303035079030303030303030303030303030303030303030303030303030350790303030303030303030303030303030303030303030303030303507903030303030303030303030303030303030303030303030303035079030303030303030303030303030303030303030303030303030350790303030303030303030303030303030303030303030303030303507903030303030303030303030303030303030303030303030303035079030303030303030303030303030303030303030303030303030350790303030303030303030303030303030303030303030303030303507903030303030303030303030303030303030303030303030303035079030303030303030303030303030303030303030303030303030350790303030303030303030303030303030303030303030303030303507903030303030303030303030303030303030303030303030303035079030303030303030303030303030303030303030303030303030350790303030303030303030303030303030303030303030303030303507903030303030303030303030303030303030303030303030303035079030303030303030303030303030303030303030303030303030350790303030303030303030303030303030303030303030303030303507903030303030303030303030303030303030303030303030303035079030303030303030303030303030303030303030303030303030350790303030303030303030303030303030303030303030303030303507903030303030303030303030303030303030303030303030303035050505050505050505050 +PUSH27_50,PUSH27,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060007a030303030303030303030303030303030303030303030303030303507a030303030303030303030303030303030303030303030303030303507a030303030303030303030303030303030303030303030303030303507a030303030303030303030303030303030303030303030303030303507a030303030303030303030303030303030303030303030303030303507a030303030303030303030303030303030303030303030303030303507a030303030303030303030303030303030303030303030303030303507a030303030303030303030303030303030303030303030303030303507a030303030303030303030303030303030303030303030303030303507a030303030303030303030303030303030303030303030303030303507a030303030303030303030303030303030303030303030303030303507a030303030303030303030303030303030303030303030303030303507a030303030303030303030303030303030303030303030303030303507a030303030303030303030303030303030303030303030303030303507a030303030303030303030303030303030303030303030303030303507a030303030303030303030303030303030303030303030303030303507a030303030303030303030303030303030303030303030303030303507a030303030303030303030303030303030303030303030303030303507a030303030303030303030303030303030303030303030303030303507a030303030303030303030303030303030303030303030303030303507a030303030303030303030303030303030303030303030303030303507a030303030303030303030303030303030303030303030303030303507a030303030303030303030303030303030303030303030303030303507a030303030303030303030303030303030303030303030303030303507a030303030303030303030303030303030303030303030303030303507a030303030303030303030303030303030303030303030303030303507a030303030303030303030303030303030303030303030303030303507a030303030303030303030303030303030303030303030303030303507a030303030303030303030303030303030303030303030303030303507a030303030303030303030303030303030303030303030303030303507a030303030303030303030303030303030303030303030303030303507a030303030303030303030303030303030303030303030303030303507a030303030303030303030303030303030303030303030303030303507a030303030303030303030303030303030303030303030303030303507a030303030303030303030303030303030303030303030303030303507a030303030303030303030303030303030303030303030303030303507a030303030303030303030303030303030303030303030303030303507a030303030303030303030303030303030303030303030303030303507a030303030303030303030303030303030303030303030303030303507a030303030303030303030303030303030303030303030303030303507a030303030303030303030303030303030303030303030303030303507a030303030303030303030303030303030303030303030303030303507a030303030303030303030303030303030303030303030303030303507a030303030303030303030303030303030303030303030303030303507a030303030303030303030303030303030303030303030303030303507a030303030303030303030303030303030303030303030303030303507a030303030303030303030303030303030303030303030303030303507a030303030303030303030303030303030303030303030303030303507a030303030303030303030303030303030303030303030303030303507a0303030303030303030303030303030303030303030303030303035050505050505050505050 +PUSH28_50,PUSH28,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060007b03030303030303030303030303030303030303030303030303030303507b03030303030303030303030303030303030303030303030303030303507b03030303030303030303030303030303030303030303030303030303507b03030303030303030303030303030303030303030303030303030303507b03030303030303030303030303030303030303030303030303030303507b03030303030303030303030303030303030303030303030303030303507b03030303030303030303030303030303030303030303030303030303507b03030303030303030303030303030303030303030303030303030303507b03030303030303030303030303030303030303030303030303030303507b03030303030303030303030303030303030303030303030303030303507b03030303030303030303030303030303030303030303030303030303507b03030303030303030303030303030303030303030303030303030303507b03030303030303030303030303030303030303030303030303030303507b03030303030303030303030303030303030303030303030303030303507b03030303030303030303030303030303030303030303030303030303507b03030303030303030303030303030303030303030303030303030303507b03030303030303030303030303030303030303030303030303030303507b03030303030303030303030303030303030303030303030303030303507b03030303030303030303030303030303030303030303030303030303507b03030303030303030303030303030303030303030303030303030303507b03030303030303030303030303030303030303030303030303030303507b03030303030303030303030303030303030303030303030303030303507b03030303030303030303030303030303030303030303030303030303507b03030303030303030303030303030303030303030303030303030303507b03030303030303030303030303030303030303030303030303030303507b03030303030303030303030303030303030303030303030303030303507b03030303030303030303030303030303030303030303030303030303507b03030303030303030303030303030303030303030303030303030303507b03030303030303030303030303030303030303030303030303030303507b03030303030303030303030303030303030303030303030303030303507b03030303030303030303030303030303030303030303030303030303507b03030303030303030303030303030303030303030303030303030303507b03030303030303030303030303030303030303030303030303030303507b03030303030303030303030303030303030303030303030303030303507b03030303030303030303030303030303030303030303030303030303507b03030303030303030303030303030303030303030303030303030303507b03030303030303030303030303030303030303030303030303030303507b03030303030303030303030303030303030303030303030303030303507b03030303030303030303030303030303030303030303030303030303507b03030303030303030303030303030303030303030303030303030303507b03030303030303030303030303030303030303030303030303030303507b03030303030303030303030303030303030303030303030303030303507b03030303030303030303030303030303030303030303030303030303507b03030303030303030303030303030303030303030303030303030303507b03030303030303030303030303030303030303030303030303030303507b03030303030303030303030303030303030303030303030303030303507b03030303030303030303030303030303030303030303030303030303507b03030303030303030303030303030303030303030303030303030303507b03030303030303030303030303030303030303030303030303030303507b030303030303030303030303030303030303030303030303030303035050505050505050505050 +PUSH29_50,PUSH29,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060007c0303030303030303030303030303030303030303030303030303030303507c0303030303030303030303030303030303030303030303030303030303507c0303030303030303030303030303030303030303030303030303030303507c0303030303030303030303030303030303030303030303030303030303507c0303030303030303030303030303030303030303030303030303030303507c0303030303030303030303030303030303030303030303030303030303507c0303030303030303030303030303030303030303030303030303030303507c0303030303030303030303030303030303030303030303030303030303507c0303030303030303030303030303030303030303030303030303030303507c0303030303030303030303030303030303030303030303030303030303507c0303030303030303030303030303030303030303030303030303030303507c0303030303030303030303030303030303030303030303030303030303507c0303030303030303030303030303030303030303030303030303030303507c0303030303030303030303030303030303030303030303030303030303507c0303030303030303030303030303030303030303030303030303030303507c0303030303030303030303030303030303030303030303030303030303507c0303030303030303030303030303030303030303030303030303030303507c0303030303030303030303030303030303030303030303030303030303507c0303030303030303030303030303030303030303030303030303030303507c0303030303030303030303030303030303030303030303030303030303507c0303030303030303030303030303030303030303030303030303030303507c0303030303030303030303030303030303030303030303030303030303507c0303030303030303030303030303030303030303030303030303030303507c0303030303030303030303030303030303030303030303030303030303507c0303030303030303030303030303030303030303030303030303030303507c0303030303030303030303030303030303030303030303030303030303507c0303030303030303030303030303030303030303030303030303030303507c0303030303030303030303030303030303030303030303030303030303507c0303030303030303030303030303030303030303030303030303030303507c0303030303030303030303030303030303030303030303030303030303507c0303030303030303030303030303030303030303030303030303030303507c0303030303030303030303030303030303030303030303030303030303507c0303030303030303030303030303030303030303030303030303030303507c0303030303030303030303030303030303030303030303030303030303507c0303030303030303030303030303030303030303030303030303030303507c0303030303030303030303030303030303030303030303030303030303507c0303030303030303030303030303030303030303030303030303030303507c0303030303030303030303030303030303030303030303030303030303507c0303030303030303030303030303030303030303030303030303030303507c0303030303030303030303030303030303030303030303030303030303507c0303030303030303030303030303030303030303030303030303030303507c0303030303030303030303030303030303030303030303030303030303507c0303030303030303030303030303030303030303030303030303030303507c0303030303030303030303030303030303030303030303030303030303507c0303030303030303030303030303030303030303030303030303030303507c0303030303030303030303030303030303030303030303030303030303507c0303030303030303030303030303030303030303030303030303030303507c0303030303030303030303030303030303030303030303030303030303507c0303030303030303030303030303030303030303030303030303030303507c03030303030303030303030303030303030303030303030303030303035050505050505050505050 +PUSH30_50,PUSH30,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060007d030303030303030303030303030303030303030303030303030303030303507d030303030303030303030303030303030303030303030303030303030303507d030303030303030303030303030303030303030303030303030303030303507d030303030303030303030303030303030303030303030303030303030303507d030303030303030303030303030303030303030303030303030303030303507d030303030303030303030303030303030303030303030303030303030303507d030303030303030303030303030303030303030303030303030303030303507d030303030303030303030303030303030303030303030303030303030303507d030303030303030303030303030303030303030303030303030303030303507d030303030303030303030303030303030303030303030303030303030303507d030303030303030303030303030303030303030303030303030303030303507d030303030303030303030303030303030303030303030303030303030303507d030303030303030303030303030303030303030303030303030303030303507d030303030303030303030303030303030303030303030303030303030303507d030303030303030303030303030303030303030303030303030303030303507d030303030303030303030303030303030303030303030303030303030303507d030303030303030303030303030303030303030303030303030303030303507d030303030303030303030303030303030303030303030303030303030303507d030303030303030303030303030303030303030303030303030303030303507d030303030303030303030303030303030303030303030303030303030303507d030303030303030303030303030303030303030303030303030303030303507d030303030303030303030303030303030303030303030303030303030303507d030303030303030303030303030303030303030303030303030303030303507d030303030303030303030303030303030303030303030303030303030303507d030303030303030303030303030303030303030303030303030303030303507d030303030303030303030303030303030303030303030303030303030303507d030303030303030303030303030303030303030303030303030303030303507d030303030303030303030303030303030303030303030303030303030303507d030303030303030303030303030303030303030303030303030303030303507d030303030303030303030303030303030303030303030303030303030303507d030303030303030303030303030303030303030303030303030303030303507d030303030303030303030303030303030303030303030303030303030303507d030303030303030303030303030303030303030303030303030303030303507d030303030303030303030303030303030303030303030303030303030303507d030303030303030303030303030303030303030303030303030303030303507d030303030303030303030303030303030303030303030303030303030303507d030303030303030303030303030303030303030303030303030303030303507d030303030303030303030303030303030303030303030303030303030303507d030303030303030303030303030303030303030303030303030303030303507d030303030303030303030303030303030303030303030303030303030303507d030303030303030303030303030303030303030303030303030303030303507d030303030303030303030303030303030303030303030303030303030303507d030303030303030303030303030303030303030303030303030303030303507d030303030303030303030303030303030303030303030303030303030303507d030303030303030303030303030303030303030303030303030303030303507d030303030303030303030303030303030303030303030303030303030303507d030303030303030303030303030303030303030303030303030303030303507d030303030303030303030303030303030303030303030303030303030303507d030303030303030303030303030303030303030303030303030303030303507d0303030303030303030303030303030303030303030303030303030303035050505050505050505050 +PUSH31_50,PUSH31,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060007e03030303030303030303030303030303030303030303030303030303030303507e03030303030303030303030303030303030303030303030303030303030303507e03030303030303030303030303030303030303030303030303030303030303507e03030303030303030303030303030303030303030303030303030303030303507e03030303030303030303030303030303030303030303030303030303030303507e03030303030303030303030303030303030303030303030303030303030303507e03030303030303030303030303030303030303030303030303030303030303507e03030303030303030303030303030303030303030303030303030303030303507e03030303030303030303030303030303030303030303030303030303030303507e03030303030303030303030303030303030303030303030303030303030303507e03030303030303030303030303030303030303030303030303030303030303507e03030303030303030303030303030303030303030303030303030303030303507e03030303030303030303030303030303030303030303030303030303030303507e03030303030303030303030303030303030303030303030303030303030303507e03030303030303030303030303030303030303030303030303030303030303507e03030303030303030303030303030303030303030303030303030303030303507e03030303030303030303030303030303030303030303030303030303030303507e03030303030303030303030303030303030303030303030303030303030303507e03030303030303030303030303030303030303030303030303030303030303507e03030303030303030303030303030303030303030303030303030303030303507e03030303030303030303030303030303030303030303030303030303030303507e03030303030303030303030303030303030303030303030303030303030303507e03030303030303030303030303030303030303030303030303030303030303507e03030303030303030303030303030303030303030303030303030303030303507e03030303030303030303030303030303030303030303030303030303030303507e03030303030303030303030303030303030303030303030303030303030303507e03030303030303030303030303030303030303030303030303030303030303507e03030303030303030303030303030303030303030303030303030303030303507e03030303030303030303030303030303030303030303030303030303030303507e03030303030303030303030303030303030303030303030303030303030303507e03030303030303030303030303030303030303030303030303030303030303507e03030303030303030303030303030303030303030303030303030303030303507e03030303030303030303030303030303030303030303030303030303030303507e03030303030303030303030303030303030303030303030303030303030303507e03030303030303030303030303030303030303030303030303030303030303507e03030303030303030303030303030303030303030303030303030303030303507e03030303030303030303030303030303030303030303030303030303030303507e03030303030303030303030303030303030303030303030303030303030303507e03030303030303030303030303030303030303030303030303030303030303507e03030303030303030303030303030303030303030303030303030303030303507e03030303030303030303030303030303030303030303030303030303030303507e03030303030303030303030303030303030303030303030303030303030303507e03030303030303030303030303030303030303030303030303030303030303507e03030303030303030303030303030303030303030303030303030303030303507e03030303030303030303030303030303030303030303030303030303030303507e03030303030303030303030303030303030303030303030303030303030303507e03030303030303030303030303030303030303030303030303030303030303507e03030303030303030303030303030303030303030303030303030303030303507e03030303030303030303030303030303030303030303030303030303030303507e030303030303030303030303030303030303030303030303030303030303035050505050505050505050 +PUSH32_50,PUSH32,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060007f0303030303030303030303030303030303030303030303030303030303030303507f0303030303030303030303030303030303030303030303030303030303030303507f0303030303030303030303030303030303030303030303030303030303030303507f0303030303030303030303030303030303030303030303030303030303030303507f0303030303030303030303030303030303030303030303030303030303030303507f0303030303030303030303030303030303030303030303030303030303030303507f0303030303030303030303030303030303030303030303030303030303030303507f0303030303030303030303030303030303030303030303030303030303030303507f0303030303030303030303030303030303030303030303030303030303030303507f0303030303030303030303030303030303030303030303030303030303030303507f0303030303030303030303030303030303030303030303030303030303030303507f0303030303030303030303030303030303030303030303030303030303030303507f0303030303030303030303030303030303030303030303030303030303030303507f0303030303030303030303030303030303030303030303030303030303030303507f0303030303030303030303030303030303030303030303030303030303030303507f0303030303030303030303030303030303030303030303030303030303030303507f0303030303030303030303030303030303030303030303030303030303030303507f0303030303030303030303030303030303030303030303030303030303030303507f0303030303030303030303030303030303030303030303030303030303030303507f0303030303030303030303030303030303030303030303030303030303030303507f0303030303030303030303030303030303030303030303030303030303030303507f0303030303030303030303030303030303030303030303030303030303030303507f0303030303030303030303030303030303030303030303030303030303030303507f0303030303030303030303030303030303030303030303030303030303030303507f0303030303030303030303030303030303030303030303030303030303030303507f0303030303030303030303030303030303030303030303030303030303030303507f0303030303030303030303030303030303030303030303030303030303030303507f0303030303030303030303030303030303030303030303030303030303030303507f0303030303030303030303030303030303030303030303030303030303030303507f0303030303030303030303030303030303030303030303030303030303030303507f0303030303030303030303030303030303030303030303030303030303030303507f0303030303030303030303030303030303030303030303030303030303030303507f0303030303030303030303030303030303030303030303030303030303030303507f0303030303030303030303030303030303030303030303030303030303030303507f0303030303030303030303030303030303030303030303030303030303030303507f0303030303030303030303030303030303030303030303030303030303030303507f0303030303030303030303030303030303030303030303030303030303030303507f0303030303030303030303030303030303030303030303030303030303030303507f0303030303030303030303030303030303030303030303030303030303030303507f0303030303030303030303030303030303030303030303030303030303030303507f0303030303030303030303030303030303030303030303030303030303030303507f0303030303030303030303030303030303030303030303030303030303030303507f0303030303030303030303030303030303030303030303030303030303030303507f0303030303030303030303030303030303030303030303030303030303030303507f0303030303030303030303030303030303030303030303030303030303030303507f0303030303030303030303030303030303030303030303030303030303030303507f0303030303030303030303030303030303030303030303030303030303030303507f0303030303030303030303030303030303030303030303030303030303030303507f0303030303030303030303030303030303030303030303030303030303030303507f03030303030303030303030303030303030303030303030303030303030303035050505050505050505050 +DUP1_50,DUP1,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360038050805080508050805080508050805080508050805080508050805080508050805080508050805080508050805080508050805080508050805080508050805080508050805080508050805080508050805080508050805080508050805080508050805050505050505050505050 +DUP2_50,DUP2,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360038150815081508150815081508150815081508150815081508150815081508150815081508150815081508150815081508150815081508150815081508150815081508150815081508150815081508150815081508150815081508150815081508150815050505050505050505050 +DUP3_50,DUP3,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360038250825082508250825082508250825082508250825082508250825082508250825082508250825082508250825082508250825082508250825082508250825082508250825082508250825082508250825082508250825082508250825082508250825050505050505050505050 +DUP4_50,DUP4,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360038350835083508350835083508350835083508350835083508350835083508350835083508350835083508350835083508350835083508350835083508350835083508350835083508350835083508350835083508350835083508350835083508350835050505050505050505050 +DUP5_50,DUP5,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360038450845084508450845084508450845084508450845084508450845084508450845084508450845084508450845084508450845084508450845084508450845084508450845084508450845084508450845084508450845084508450845084508450845050505050505050505050 +DUP6_50,DUP6,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360038550855085508550855085508550855085508550855085508550855085508550855085508550855085508550855085508550855085508550855085508550855085508550855085508550855085508550855085508550855085508550855085508550855050505050505050505050 +DUP7_50,DUP7,50,600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360038650865086508650865086508650865086508650865086508650865086508650865086508650865086508650865086508650865086508650865086508650865086508650865086508650865086508650865086508650865086508650865086508650865050505050505050505050 +DUP8_50,DUP8,50,60006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360038750875087508750875087508750875087508750875087508750875087508750875087508750875087508750875087508750875087508750875087508750875087508750875087508750875087508750875087508750875087508750875087508750875050505050505050505050 +DUP9_50,DUP9,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360038850885088508850885088508850885088508850885088508850885088508850885088508850885088508850885088508850885088508850885088508850885088508850885088508850885088508850885088508850885088508850885088508850885050505050505050505050 +DUP10_50,DUP10,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360038950895089508950895089508950895089508950895089508950895089508950895089508950895089508950895089508950895089508950895089508950895089508950895089508950895089508950895089508950895089508950895089508950895050505050505050505050 +DUP11_50,DUP11,50,60006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360038a508a508a508a508a508a508a508a508a508a508a508a508a508a508a508a508a508a508a508a508a508a508a508a508a508a508a508a508a508a508a508a508a508a508a508a508a508a508a508a508a508a508a508a508a508a508a508a508a508a5050505050505050505050 +DUP12_50,DUP12,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360038b508b508b508b508b508b508b508b508b508b508b508b508b508b508b508b508b508b508b508b508b508b508b508b508b508b508b508b508b508b508b508b508b508b508b508b508b508b508b508b508b508b508b508b508b508b508b508b508b508b5050505050505050505050 +DUP13_50,DUP13,50,600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360038c508c508c508c508c508c508c508c508c508c508c508c508c508c508c508c508c508c508c508c508c508c508c508c508c508c508c508c508c508c508c508c508c508c508c508c508c508c508c508c508c508c508c508c508c508c508c508c508c508c5050505050505050505050 +DUP14_50,DUP14,50,600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360038d508d508d508d508d508d508d508d508d508d508d508d508d508d508d508d508d508d508d508d508d508d508d508d508d508d508d508d508d508d508d508d508d508d508d508d508d508d508d508d508d508d508d508d508d508d508d508d508d508d5050505050505050505050 +DUP15_50,DUP15,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360038e508e508e508e508e508e508e508e508e508e508e508e508e508e508e508e508e508e508e508e508e508e508e508e508e508e508e508e508e508e508e508e508e508e508e508e508e508e508e508e508e508e508e508e508e508e508e508e508e508e5050505050505050505050 +DUP16_50,DUP16,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360038f508f508f508f508f508f508f508f508f508f508f508f508f508f508f508f508f508f508f508f508f508f508f508f508f508f508f508f508f508f508f508f508f508f508f508f508f508f508f508f508f508f508f508f508f508f508f508f508f508f5050505050505050505050 +SWAP1_50,SWAP1,50,6003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360039090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090 +SWAP2_50,SWAP2,50,6003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360039191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191 +SWAP3_50,SWAP3,50,6003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360039292929292929292929292929292929292929292929292929292929292929292929292929292929292929292929292929292 +SWAP4_50,SWAP4,50,6003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360039393939393939393939393939393939393939393939393939393939393939393939393939393939393939393939393939393 +SWAP5_50,SWAP5,50,6003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360039494949494949494949494949494949494949494949494949494949494949494949494949494949494949494949494949494 +SWAP6_50,SWAP6,50,600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360039595959595959595959595959595959595959595959595959595959595959595959595959595959595959595959595959595 +SWAP7_50,SWAP7,50,60036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360039696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696 +SWAP8_50,SWAP8,50,6003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360039797979797979797979797979797979797979797979797979797979797979797979797979797979797979797979797979797 +SWAP9_50,SWAP9,50,6003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360039898989898989898989898989898989898989898989898989898989898989898989898989898989898989898989898989898 +SWAP10_50,SWAP10,50,60036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360039999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999 +SWAP11_50,SWAP11,50,6003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360039a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a +SWAP12_50,SWAP12,50,600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360039b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b9b +SWAP13_50,SWAP13,50,600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360039c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c9c +SWAP14_50,SWAP14,50,6003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360039d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d +SWAP15_50,SWAP15,50,6003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360039e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e +SWAP16_50,SWAP16,50,60036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360039f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f +CLZ_50,CLZ,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360031e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e5050505050505050505050 \ No newline at end of file diff --git a/bins/revme/src/cmd/bench/snailtracer.hex b/bins/revme/src/cmd/bench/snailtracer.hex new file mode 100644 index 0000000000..9546187294 --- /dev/null +++ b/bins/revme/src/cmd/bench/snailtracer.hex @@ -0,0 +1 @@ +608060405234801561001057600080fd5b506004361061004c5760003560e01c806330627b7c1461005157806375ac892a14610085578063784f13661461011d578063c294360114610146575b600080fd5b610059610163565b604080516001600160f81b03199485168152928416602084015292168183015290519081900360600190f35b6100a86004803603604081101561009b57600080fd5b50803590602001356102d1565b6040805160208082528351818301528351919283929083019185019080838360005b838110156100e25781810151838201526020016100ca565b50505050905090810190601f16801561010f5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6100596004803603606081101561013357600080fd5b508035906020810135906040013561055b565b6100a86004803603602081101561015c57600080fd5b5035610590565b6000806000610176610400610300610834565b60405180606001604052806001546000546207d5dc028161019357fe5b058152600060208083018290526040928301919091528251600b81905583820151600c81905593830151600d819055835160608082018652928152808401959095528484015282519081018352600654815260075491810191909152600854918101919091526102259161021c916102139161020e91612ef7565b612f64565b6207d5dc612feb565b620f424061301e565b8051600e556020810151600f55604001516010556102416142dd565b61025a816102556102006101806008613064565b613212565b90506102708161025561014561021c6008613064565b905061028481610255610258806008613064565b905061029a8161025561020a61020c6008613064565b90506102a781600461301e565b90506102b1613250565b8051602082015160409092015160f891821b9692821b9550901b92509050565b606060005b6000548112156104c95760006102ed828686613064565b90506002816000015160f81b90808054603f811680603e811461032a576002830184556001831661031c578192505b600160028404019350610342565b600084815260209081902060ff198516905560419094555b505050600190038154600116156103685790600052602060002090602091828204019190065b909190919091601f036101000a81548160ff02191690600160f81b840402179055506002816020015160f81b90808054603f811680603e81146103c557600283018455600183166103b7578192505b6001600284040193506103dd565b600084815260209081902060ff198516905560419094555b505050600190038154600116156104035790600052602060002090602091828204019190065b909190919091601f036101000a81548160ff02191690600160f81b840402179055506002816040015160f81b90808054603f811680603e81146104605760028301845560018316610452578192505b600160028404019350610478565b600084815260209081902060ff198516905560419094555b5050506001900381546001161561049e5790600052602060002090602091828204019190065b815460ff601f929092036101000a9182021916600160f81b90930402919091179055506001016102d6565b506002805460408051602060018416156101000260001901909316849004601f8101849004840282018401909252818152929183018282801561054d5780601f106105225761010080835404028352916020019161054d565b820191906000526020600020905b81548152906001019060200180831161053057829003601f168201915b505050505090505b92915050565b60008060008061056c878787613064565b8051602082015160409092015160f891821b9a92821b9950901b9650945050505050565b600154606090600019015b600081126107a35760005b6000548112156107995760006105bd828487613064565b90506002816000015160f81b90808054603f811680603e81146105fa57600283018455600183166105ec578192505b600160028404019350610612565b600084815260209081902060ff198516905560419094555b505050600190038154600116156106385790600052602060002090602091828204019190065b909190919091601f036101000a81548160ff02191690600160f81b840402179055506002816020015160f81b90808054603f811680603e81146106955760028301845560018316610687578192505b6001600284040193506106ad565b600084815260209081902060ff198516905560419094555b505050600190038154600116156106d35790600052602060002090602091828204019190065b909190919091601f036101000a81548160ff02191690600160f81b840402179055506002816040015160f81b90808054603f811680603e81146107305760028301845560018316610722578192505b600160028404019350610748565b600084815260209081902060ff198516905560419094555b5050506001900381546001161561076e5790600052602060002090602091828204019190065b815460ff601f929092036101000a9182021916600160f81b90930402919091179055506001016105a6565b506000190161059b565b506002805460408051602060018416156101000260001901909316849004601f810184900484028201840190925281815292918301828280156108275780601f106107fc57610100808354040283529160200191610827565b820191906000526020600020905b81548152906001019060200180831161080a57829003601f168201915b505050505090505b919050565b8160008190555080600181905550604051806080016040528060405180606001604052806302faf08081526020016303197500815260200163119e7f8081525081526020016108a460405180606001604052806000815260200161a673198152602001620f423f19815250612f64565b815260006020808301829052604092830182905283518051600355808201516004558301516005558381015180516006559081015160075582015160085582820151600955606092830151600a805460ff1916911515919091179055815192830190915260015490548291906207d5dc028161091c57fe5b058152600060208083018290526040928301919091528251600b81905583820151600c81905593830151600d819055835160608082018652928152808401959095528484015282519081018352600654815260075491810191909152600854918101919091526109979161021c916102139161020e91612ef7565b8051600e55602080820151600f55604091820151601055815160a08101835264174876e8008152825160608082018552641748862a40825263026e8f00828501526304dd1e008286015282840191825284518082018652600080825281860181905281870181905284870191825286518084018852620b71b081526203d09081880181905281890152928501928352608085018181526011805460018082018355919093528651600b9093027f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c688101938455955180517f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c69880155808901517f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c6a8801558901517f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c6b870155925180517f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c6c870155808801517f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c6d8701558801517f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c6e860155925180517f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c6f860155958601517f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c7085015594909501517f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c71830155517f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c72909101805492949192909160ff1990911690836002811115610c1057fe5b0217905550505060116040518060a0016040528064174876e8008152602001604051806060016040528064174290493f19815260200163026e8f0081526020016304dd1e008152508152602001604051806060016040528060008152602001600081526020016000815250815260200160405180606001604052806203d09081526020016203d0908152602001620b71b0815250815260200160006002811115610cb657fe5b905281546001818101845560009384526020938490208351600b90930201918255838301518051838301558085015160028085019190915560409182015160038501558185015180516004860155808701516005860155820151600685015560608501518051600786015595860151600885015594015160098301556080830151600a83018054949593949193909260ff1990921691908490811115610d5857fe5b0217905550505060116040518060a0016040528064174876e800815260200160405180606001604052806302faf080815260200163026e8f00815260200164174876e800815250815260200160405180606001604052806000815260200160008152602001600081525081526020016040518060600160405280620b71b08152602001620b71b08152602001620b71b0815250815260200160006002811115610dfd57fe5b905281546001818101845560009384526020938490208351600b90930201918255838301518051838301558085015160028085019190915560409182015160038501558185015180516004860155808701516005860155820151600685015560608501518051600786015595860151600885015594015160098301556080830151600a83018054949593949193909260ff1990921691908490811115610e9f57fe5b0217905550505060116040518060a0016040528064174876e800815260200160405180606001604052806302faf080815260200163026e8f00815260200164173e54e97f1981525081526020016040518060600160405280600081526020016000815260200160008152508152602001604051806060016040528060008152602001600081526020016000815250815260200160006002811115610f3f57fe5b905281546001818101845560009384526020938490208351600b90930201918255838301518051838301558085015160028085019190915560409182015160038501558185015180516004860155808701516005860155820151600685015560608501518051600786015595860151600885015594015160098301556080830151600a83018054949593949193909260ff1990921691908490811115610fe157fe5b0217905550505060116040518060a0016040528064174876e800815260200160405180606001604052806302faf080815260200164174876e80081526020016304dd1e00815250815260200160405180606001604052806000815260200160008152602001600081525081526020016040518060600160405280620b71b08152602001620b71b08152602001620b71b081525081526020016000600281111561108657fe5b905281546001818101845560009384526020938490208351600b90930201918255838301518051838301558085015160028085019190915560409182015160038501558185015180516004860155808701516005860155820151600685015560608501518051600786015595860151600885015594015160098301556080830151600a83018054949593949193909260ff199092169190849081111561112857fe5b0217905550505060116040518060a0016040528064174876e800815260200160405180606001604052806302faf080815260200164174399c9ff1981526020016304dd1e00815250815260200160405180606001604052806000815260200160008152602001600081525081526020016040518060600160405280620b71b08152602001620b71b08152602001620b71b08152508152602001600060028111156111ce57fe5b905281546001818101845560009384526020938490208351600b90930201918255838301518051838301558085015160028085019190915560409182015160038501558185015180516004860155808701516005860155820151600685015560608501518051600786015595860151600885015594015160098301556080830151600a83018054949593949193909260ff199092169190849081111561127057fe5b0217905550505060116040518060a0016040528062fbc5208152602001604051806060016040528063019bfcc0815260200162fbc52081526020016302cd29c0815250815260200160405180606001604052806000815260200160008152602001600081525081526020016040518060600160405280620f3e588152602001620f3e588152602001620f3e5881525081526020016001600281111561131157fe5b905281546001818101845560009384526020938490208351600b90930201918255838301518051838301558085015160028085019190915560409182015160038501558185015180516004860155808701516005860155820151600685015560608501518051600786015595860151600885015594015160098301556080830151600a83018054949593949193909260ff19909216919084908111156113b357fe5b0217905550505060116040518060a001604052806323c34600815260200160405180606001604052806302faf080815260200163289c455081526020016304dd1e008152508152602001604051806060016040528062b71b00815260200162b71b00815260200162b71b00815250815260200160405180606001604052806000815260200160008152602001600081525081526020016000600281111561145657fe5b905281546001818101845560009384526020938490208351600b90930201918255838301518051838301558085015160028085019190915560409182015160038501558185015180516004860155808701516005860155820151600685015560608501518051600786015595860151600885015594015160098301556080830151600a83018054949593949193909260ff19909216919084908111156114f857fe5b0217905550505060126040518060e00160405280604051806060016040528063035e1f208152602001630188c2e081526020016304a62f8081525081526020016040518060600160405280630459e4408152602001630188c2e081526020016305a1f4a081525081526020016040518060600160405280630459e44081526020016302f34f6081526020016304a62f808152508152602001604051806060016040528060008152602001600081526020016000815250815260200160405180606001604052806000815260200160008152602001600081525081526020016040518060600160405280620f3e588152602001620f3e588152602001620f3e5881525081526020016001600281111561160c57fe5b905281546001818101845560009384526020938490208351805160139094029091019283558085015183830155604090810151600280850191909155858501518051600386015580870151600486015582015160058501558185015180516006860155808701516007860155820151600885015560608501518051600986015580870151600a860155820151600b85015560808501518051600c86015580870151600d860155820151600e85015560a08501518051600f860155958601516010850155940151601183015560c0830151601283018054949593949193909260ff19909216919084908111156116fd57fe5b0217905550505060126040518060e00160405280604051806060016040528063035e1f20815260200163016a8c8081526020016304a62f8081525081526020016040518060600160405280630459e4408152602001600081526020016304a62f8081525081526020016040518060600160405280630459e440815260200163016a8c8081526020016305a1f4a08152508152602001604051806060016040528060008152602001600081526020016000815250815260200160405180606001604052806000815260200160008152602001600081525081526020016040518060600160405280620f3e588152602001620f3e588152602001620f3e5881525081526020016001600281111561180e57fe5b905281546001818101845560009384526020938490208351805160139094029091019283558085015183830155604090810151600280850191909155858501518051600386015580870151600486015582015160058501558185015180516006860155808701516007860155820151600885015560608501518051600986015580870151600a860155820151600b85015560808501518051600c86015580870151600d860155820151600e85015560a08501518051600f860155958601516010850155940151601183015560c0830151601283018054949593949193909260ff19909216919084908111156118ff57fe5b0217905550505060126040518060e001604052806040518060600160405280630555a9608152602001630188c2e081526020016304a62f8081525081526020016040518060600160405280630459e44081526020016302f34f6081526020016304a62f8081525081526020016040518060600160405280630459e4408152602001630188c2e081526020016305a1f4a08152508152602001604051806060016040528060008152602001600081526020016000815250815260200160405180606001604052806000815260200160008152602001600081525081526020016040518060600160405280620f3e588152602001620f3e588152602001620f3e58815250815260200160016002811115611a1357fe5b905281546001818101845560009384526020938490208351805160139094029091019283558085015183830155604090810151600280850191909155858501518051600386015580870151600486015582015160058501558185015180516006860155808701516007860155820151600885015560608501518051600986015580870151600a860155820151600b85015560808501518051600c86015580870151600d860155820151600e85015560a08501518051600f860155958601516010850155940151601183015560c0830151601283018054949593949193909260ff1990921691908490811115611b0457fe5b0217905550505060126040518060e001604052806040518060600160405280630555a960815260200163016a8c8081526020016304a62f8081525081526020016040518060600160405280630459e440815260200163016a8c8081526020016305a1f4a081525081526020016040518060600160405280630459e4408152602001600081526020016304a62f808152508152602001604051806060016040528060008152602001600081526020016000815250815260200160405180606001604052806000815260200160008152602001600081525081526020016040518060600160405280620f3e588152602001620f3e588152602001620f3e58815250815260200160016002811115611c1557fe5b905281546001818101845560009384526020938490208351805160139094029091019283558085015183830155604090810151600280850191909155858501518051600386015580870151600486015582015160058501558185015180516006860155808701516007860155820151600885015560608501518051600986015580870151600a860155820151600b85015560808501518051600c86015580870151600d860155820151600e85015560a08501518051600f860155958601516010850155940151601183015560c0830151601283018054949593949193909260ff1990921691908490811115611d0657fe5b0217905550505060126040518060e00160405280604051806060016040528063035e1f208152602001630188c2e081526020016304a62f8081525081526020016040518060600160405280630459e44081526020016302f34f6081526020016304a62f8081525081526020016040518060600160405280630459e4408152602001630188c2e081526020016303aa6a608152508152602001604051806060016040528060008152602001600081526020016000815250815260200160405180606001604052806000815260200160008152602001600081525081526020016040518060600160405280620f3e588152602001620f3e588152602001620f3e58815250815260200160016002811115611e1a57fe5b905281546001818101845560009384526020938490208351805160139094029091019283558085015183830155604090810151600280850191909155858501518051600386015580870151600486015582015160058501558185015180516006860155808701516007860155820151600885015560608501518051600986015580870151600a860155820151600b85015560808501518051600c86015580870151600d860155820151600e85015560a08501518051600f860155958601516010850155940151601183015560c0830151601283018054949593949193909260ff1990921691908490811115611f0b57fe5b0217905550505060126040518060e00160405280604051806060016040528063035e1f20815260200163016a8c8081526020016304a62f8081525081526020016040518060600160405280630459e440815260200163016a8c8081526020016303aa6a6081525081526020016040518060600160405280630459e4408152602001600081526020016304a62f808152508152602001604051806060016040528060008152602001600081526020016000815250815260200160405180606001604052806000815260200160008152602001600081525081526020016040518060600160405280620f3e588152602001620f3e588152602001620f3e5881525081526020016001600281111561201c57fe5b905281546001818101845560009384526020938490208351805160139094029091019283558085015183830155604090810151600280850191909155858501518051600386015580870151600486015582015160058501558185015180516006860155808701516007860155820151600885015560608501518051600986015580870151600a860155820151600b85015560808501518051600c86015580870151600d860155820151600e85015560a08501518051600f860155958601516010850155940151601183015560c0830151601283018054949593949193909260ff199092169190849081111561210d57fe5b0217905550505060126040518060e001604052806040518060600160405280630555a9608152602001630188c2e081526020016304a62f8081525081526020016040518060600160405280630459e4408152602001630188c2e081526020016303aa6a6081525081526020016040518060600160405280630459e44081526020016302f34f6081526020016304a62f808152508152602001604051806060016040528060008152602001600081526020016000815250815260200160405180606001604052806000815260200160008152602001600081525081526020016040518060600160405280620f3e588152602001620f3e588152602001620f3e5881525081526020016001600281111561222157fe5b905281546001818101845560009384526020938490208351805160139094029091019283558085015183830155604090810151600280850191909155858501518051600386015580870151600486015582015160058501558185015180516006860155808701516007860155820151600885015560608501518051600986015580870151600a860155820151600b85015560808501518051600c86015580870151600d860155820151600e85015560a08501518051600f860155958601516010850155940151601183015560c0830151601283018054949593949193909260ff199092169190849081111561231257fe5b0217905550505060126040518060e001604052806040518060600160405280630555a960815260200163016a8c8081526020016304a62f8081525081526020016040518060600160405280630459e4408152602001600081526020016304a62f8081525081526020016040518060600160405280630459e440815260200163016a8c8081526020016303aa6a608152508152602001604051806060016040528060008152602001600081526020016000815250815260200160405180606001604052806000815260200160008152602001600081525081526020016040518060600160405280620f3e588152602001620f3e588152602001620f3e5881525081526020016001600281111561242357fe5b905281546001818101845560009384526020938490208351805160139094029091019283558085015183830155604090810151600280850191909155858501518051600386015580870151600486015582015160058501558185015180516006860155808701516007860155820151600885015560608501518051600986015580870151600a860155820151600b85015560808501518051600c86015580870151600d860155820151600e85015560a08501518051600f860155958601516010850155940151601183015560c0830151601283018054949593949193909260ff199092169190849081111561251457fe5b0217905550505060126040518060e00160405280604051806060016040528063035e1f208152602001630188c2e081526020016304a62f8081525081526020016040518060600160405280630459e4408152602001630188c2e081526020016303aa6a6081525081526020016040518060600160405280630555a9608152602001630188c2e081526020016304a62f808152508152602001604051806060016040528060008152602001600081526020016000815250815260200160405180606001604052806000815260200160008152602001600081525081526020016040518060600160405280620f3e588152602001620f3e588152602001620f3e5881525081526020016001600281111561262857fe5b905281546001818101845560009384526020938490208351805160139094029091019283558085015183830155604090810151600280850191909155858501518051600386015580870151600486015582015160058501558185015180516006860155808701516007860155820151600885015560608501518051600986015580870151600a860155820151600b85015560808501518051600c86015580870151600d860155820151600e85015560a08501518051600f860155958601516010850155940151601183015560c0830151601283018054949593949193909260ff199092169190849081111561271957fe5b0217905550505060126040518060e00160405280604051806060016040528063035e1f208152602001630188c2e081526020016304a62f8081525081526020016040518060600160405280630555a9608152602001630188c2e081526020016304a62f8081525081526020016040518060600160405280630459e4408152602001630188c2e081526020016305a1f4a08152508152602001604051806060016040528060008152602001600081526020016000815250815260200160405180606001604052806000815260200160008152602001600081525081526020016040518060600160405280620f3e588152602001620f3e588152602001620f3e5881525081526020016001600281111561282d57fe5b905281546001818101845560009384526020938490208351805160139094029091019283558085015183830155604090810151600280850191909155858501518051600386015580870151600486015582015160058501558185015180516006860155808701516007860155820151600885015560608501518051600986015580870151600a860155820151600b85015560808501518051600c86015580870151600d860155820151600e85015560a08501518051600f860155958601516010850155940151601183015560c0830151601283018054949593949193909260ff199092169190849081111561291e57fe5b0217905550505060126040518060e00160405280604051806060016040528063035e1f20815260200163016a8c8081526020016304a62f8081525081526020016040518060600160405280630555a960815260200163016a8c8081526020016304a62f8081525081526020016040518060600160405280630459e440815260200163016a8c8081526020016303aa6a608152508152602001604051806060016040528060008152602001600081526020016000815250815260200160405180606001604052806000815260200160008152602001600081525081526020016040518060600160405280620f3e588152602001620f3e588152602001620f3e58815250815260200160016002811115612a3257fe5b905281546001818101845560009384526020938490208351805160139094029091019283558085015183830155604090810151600280850191909155858501518051600386015580870151600486015582015160058501558185015180516006860155808701516007860155820151600885015560608501518051600986015580870151600a860155820151600b85015560808501518051600c86015580870151600d860155820151600e85015560a08501518051600f860155958601516010850155940151601183015560c0830151601283018054949593949193909260ff1990921691908490811115612b2357fe5b0217905550505060126040518060e00160405280604051806060016040528063035e1f20815260200163016a8c8081526020016304a62f8081525081526020016040518060600160405280630459e440815260200163016a8c8081526020016305a1f4a081525081526020016040518060600160405280630555a960815260200163016a8c8081526020016304a62f808152508152602001604051806060016040528060008152602001600081526020016000815250815260200160405180606001604052806000815260200160008152602001600081525081526020016040518060600160405280620f3e588152602001620f3e588152602001620f3e58815250815260200160016002811115612c3757fe5b905281546001818101845560009384526020938490208351805160139094029091019283558085015183830155604090810151600280850191909155858501518051600386015580870151600486015582015160058501558185015180516006860155808701516007860155820151600885015560608501518051600986015580870151600a860155820151600b85015560808501518051600c86015580870151600d860155820151600e85015560a08501518051600f860155958601516010850155940151601183015560c0830151601283018054949593949193909260ff1990921691908490811115612d2857fe5b0217905550505060005b601254811015612ef257600060128281548110612d4b57fe5b600091825260209182902060408051610140810182526013909302909101805460e08401908152600182015461010085015260028083015461012086015290845282516060818101855260038401548252600484015482880152600584015482860152858701919091528351808201855260068401548152600784015481880152600884015481860152858501528351808201855260098401548152600a84015481880152600b840154818601528186015283518082018552600c8401548152600d84015481880152600e84015481860152608086015283519081018452600f830154815260108301549581019590955260118201549285019290925260a0830193909352601283015491929160c084019160ff90911690811115612e6c57fe5b6002811115612e7757fe5b815250509050612eac61020e612e95836020015184600001516132cd565b612ea7846040015185600001516132cd565b612ef7565b60128381548110612eb957fe5b60009182526020918290208351600960139093029091019182015590820151600a820155604090910151600b9091015550600101612d32565b505050565b612eff6142dd565b604051806060016040528083602001518560400151028460400151866020015102038152602001836040015185600001510284600001518660400151020381526020018360000151856020015102846020015186600001510203815250905092915050565b612f6c6142dd565b604082015160208301518351600092612f9292918002918002919091019080020161330c565b90506040518060600160405280828560000151620f42400281612fb157fe5b058152602001828560200151620f42400281612fc957fe5b058152602001828560400151620f42400281612fe157fe5b0590529392505050565b612ff36142dd565b5060408051606081018252835183028152602080850151840290820152928101519091029082015290565b6130266142dd565b60405180606001604052808385600001518161303e57fe5b0581526020018385602001518161305157fe5b05815260200183856040015181612fe157fe5b61306c6142dd565b6000546013805463ffffffff1916918502860163ffffffff169190911790556130936142dd565b905060005b828112156131f157600061317261314c61021c613115600b60405180606001604052908160008201548152602001600182015481526020016002820154815250506207a1206000546207a1206130ec613343565b63ffffffff16816130f957fe5b0663ffffffff168d620f424002018161310e57fe5b0503612feb565b60408051606081018252600e548152600f5460208201526010549181019190915260015461025591906207a12090816130ec613343565b604080516060810182526006548152600754602082015260085491810191909152613212565b6040805160e081019091526003546080820190815260045460a083015260055460c083015291925060009181906131ae9061025586608c612feb565b81526020016131bc84612f64565b815260006020820181905260409091015290506131e5846102556131df8461336c565b8861301e565b93505050600101613098565b5061320861021c61320183613753565b60ff612feb565b90505b9392505050565b61321a6142dd565b50604080516060810182528251845101815260208084015181860151019082015291810151928101519092019181019190915290565b60008080556001819055613266906002906142fe565b60006003819055600481905560058190556006819055600781905560088190556009819055600a805460ff19169055600b819055600c819055600d819055600e819055600f81905560108190556132bf90601190614345565b6132cb60126000614366565b565b6132d56142dd565b5060408051606081018252825184510381526020808401518186015103908201528282015184830151039181019190915292915050565b80600260018201055b8181121561333d5780915060028182858161332c57fe5b05018161333557fe5b059050613315565b50919050565b6013805463ffffffff19811663ffffffff9182166341c64e6d0261303901821617918290551690565b6133746142dd565b600a826040015113156133a657604051806060016040528060008152602001600081526020016000815250905061082f565b60008060006133b48561379f565b91945092509050826133e857604051806060016040528060008152602001600081526020016000815250935050505061082f565b6133f0614387565b6133f86143c7565b6134006142dd565b6134086142dd565b600086600181111561341657fe5b1415613505576011858154811061342957fe5b60009182526020918290206040805160a081018252600b90930290910180548352815160608082018452600183015482526002808401548388015260038401548386015285870192909252835180820185526004840154815260058401548188015260068401548186015285850152835180820185526007840154815260088401549681019690965260098301549386019390935291830193909352600a830154919291608084019160ff909116908111156134e157fe5b60028111156134ec57fe5b8152505093508360600151915083604001519050613653565b6012858154811061351257fe5b600091825260209182902060408051610140810182526013909302909101805460e08401908152600182015461010085015260028083015461012086015290845282516060818101855260038401548252600484015482880152600584015482860152858701919091528351808201855260068401548152600784015481880152600884015481860152858501528351808201855260098401548152600a84015481880152600b840154818601528186015283518082018552600c8401548152600d84015481880152600e84015481860152608086015283519081018452600f830154815260108301549581019590955260118201549285019290925260a0830193909352601283015491929160c084019160ff9091169081111561363357fe5b600281111561363e57fe5b8152505092508260a001519150826080015190505b6040820151600190811215613669575060408201515b808360200151131561367c575060208201515b808360400151131561368f575060408201515b60408a01805160010190819052600512156136f75780620f42406136b1613343565b63ffffffff16816136be57fe5b0663ffffffff1612156136e8576136e16136db84620f4240612feb565b8261301e565b92506136f7565b50965061082f95505050505050565b6136ff6142dd565b600088600181111561370d57fe5b14156137255761371e8b878b613a57565b9050613733565b6137308b868b613aec565b90505b6137448361025561021c8785613baa565b9b9a5050505050505050505050565b61375b6142dd565b60405180606001604052806137738460000151613be8565b81526020016137858460200151613be8565b81526020016137978460400151613be8565b905292915050565b60008080808080805b6011548110156138c2576000613890601183815481106137c457fe5b60009182526020918290206040805160a081018252600b90930290910180548352815160608082018452600183015482526002808401548388015260038401548386015285870192909252835180820185526004840154815260058401548188015260068401548186015285850152835180820185526007840154815260088401549681019690965260098301549386019390935291830193909352600a830154919291608084019160ff9091169081111561387c57fe5b600281111561388757fe5b9052508a613c13565b90506000811380156138a957508415806138a957508481125b156138b957809450600093508192505b506001016137a8565b5060005b601254811015613a49576000613a17601283815481106138e257fe5b600091825260209182902060408051610140810182526013909302909101805460e08401908152600182015461010085015260028083015461012086015290845282516060818101855260038401548252600484015482880152600584015482860152858701919091528351808201855260068401548152600784015481880152600884015481860152858501528351808201855260098401548152600a84015481880152600b840154818601528186015283518082018552600c8401548152600d84015481880152600e84015481860152608086015283519081018452600f830154815260108301549581019590955260118201549285019290925260a0830193909352601283015491929160c084019160ff90911690811115613a0357fe5b6002811115613a0e57fe5b9052508a613cbb565b9050600081138015613a305750841580613a3057508481125b15613a4057809450600193508192505b506001016138c6565b509196909550909350915050565b613a5f6142dd565b6000613a7a856000015161025561021c886020015187612feb565b90506000613a8f61020e8387602001516132cd565b9050600085608001516002811115613aa357fe5b1415613ae1576000613ab9828860200151613e0c565b12613acd57613aca81600019612feb565b90505b613ad8868383613e31565b9250505061320b565b613ad8868383613fc1565b613af46142dd565b6000613b0f856000015161025561021c886020015187612feb565b6060860151909150620a2c2a9015613b2757506216e3605b6000620f4240613b3f87606001518960200151613e0c565b81613b4657fe5b05905060008112613b55576000035b64e8d4a5100081800281038380020281900590036000811215613b8c57613b8188858960600151613fc1565b94505050505061320b565b613b9e88858960600151868686614039565b98975050505050505050565b613bb26142dd565b50604080516060810182528251845102815260208084015181860151029082015291810151928101519092029181019190915290565b600080821215613bfa5750600061082f565b620f4240821315613c0f5750620f424061082f565b5090565b600080613c28846020015184600001516132cd565b90506000620f4240613c3e838660200151613e0c565b81613c4557fe5b865191900591506000908002613c5b8480613e0c565b838402030190506000811215613c775760009350505050610555565b613c808161330c565b90506103e88183031315613c9957900391506105559050565b6103e88183011315613caf570191506105559050565b50600095945050505050565b600080613cd0846020015185600001516132cd565b90506000613ce6856040015186600001516132cd565b90506000613cf8856020015183612ef7565b90506000620f4240613d0a8584613e0c565b81613d1157fe5b0590506103e71981138015613d2757506103e881125b15613d39576000945050505050610555565b85518751600091613d49916132cd565b9050600082613d588386613e0c565b81613d5f57fe5b0590506000811280613d735750620f424081135b15613d875760009650505050505050610555565b6000613d938388612ef7565b9050600084613da68b6020015184613e0c565b81613dad57fe5b0590506000811280613dc35750620f4240818401135b15613dd957600098505050505050505050610555565b600085613de68985613e0c565b81613ded57fe5b0590506103e88112156137445760009950505050505050505050610555565b6040808201519083015160208084015190850151845186510291020191020192915050565b613e396142dd565b6000620f424080613e48613343565b63ffffffff1681613e5557fe5b0663ffffffff16625fdfb00281613e6857fe5b0590506000620f4240613e79613343565b63ffffffff1681613e8657fe5b0663ffffffff1690506000613e9a8261330c565b6103e8029050613ea86142dd565b620186a0613eb98760000151614216565b1315613ee657604051806060016040528060008152602001620f4240815260200160008152509050613f09565b6040518060600160405280620f4240815260200160008152602001600081525090505b613f1661020e8288612ef7565b90506000613f2761020e8884612ef7565b9050613f7f61020e613f64613f5285620f424088613f448c61422e565b0281613f4c57fe5b05612feb565b61025585620f424089613f448d61424e565b6102558a613f7689620f42400361330c565b6103e802612feb565b9150613fb460405180608001604052808a81526020018481526020018b6040015181526020018b60600151151581525061336c565b9998505050505050505050565b613fc96142dd565b6000613ffb61020e8660200151613ff686620f4240613fec898c60200151613e0c565b60020281613f4c57fe5b6132cd565b90506140306040518060800160405280868152602001838152602001876040015181526020018760600151151581525061336c565b95945050505050565b6140416142dd565b60608701516000199015614053575060015b600061408961020e61021c61406c8c602001518a612feb565b613ff68b6140798a61330c565b620f42408c8e0205018802612feb565b60608a0151909150620f42408601906140ba57620f42406140aa838a613e0c565b816140b157fe5b05620f42400390505b60408a0151619c406c0c9f2c9cd04674edea40000000620ea6008480028502850285020205019060021261415e5761412a61411f60405180608001604052808d81526020018681526020018e6040015181526020018e6060015115151581525061336c565b82620f424003612feb565b92506141448361025561413e8e8e8e613fc1565b84612feb565b925061415383620f424061301e565b94505050505061420c565b600281056203d09001620f4240614173613343565b63ffffffff168161418057fe5b0663ffffffff1612156141b2576141536141a461419e8d8d8d613fc1565b83612feb565b600283056203d0900161301e565b6142056141f76141ec60405180608001604052808e81526020018781526020018f6040015181526020018f6060015115151581525061336c565b83620f424003612feb565b60028305620b71b00361301e565b9450505050505b9695505050505050565b60008082131561422757508061082f565b5060000390565b60008061423a8361424e565b905061320b81820264e8d4a510000361330c565b60005b600082121561426757625fdfb082019150614251565b5b625fdfb0821261427f57625fdfb082039150614268565b6001828160025b818313156142d457818385028161429957fe5b0585019450620f4240808788860202816142af57fe5b05816142b757fe5b600095909503940592506001810181029190910290600201614286565b50505050919050565b60405180606001604052806000815260200160008152602001600081525090565b50805460018160011615610100020316600290046000825580601f106143245750614342565b601f0160209004906000526020600020908101906143429190614401565b50565b50805460008255600b02906000526020600020908101906143429190614416565b50805460008255601302906000526020600020908101906143429190614475565b6040518060a00160405280600081526020016143a16142dd565b81526020016143ae6142dd565b81526020016143bb6142dd565b81526020016000905290565b6040518060e001604052806143da6142dd565b81526020016143e76142dd565b81526020016143f46142dd565b81526020016143a16142dd565b5b80821115613c0f5760008155600101614402565b5b80821115613c0f57600080825560018201819055600282018190556003820181905560048201819055600582018190556006820181905560078201819055600882018190556009820155600a8101805460ff19169055600b01614417565b5b80821115613c0f576000808255600182018190556002820181905560038201819055600482018190556005820181905560068201819055600782018190556008820181905560098201819055600a8201819055600b8201819055600c8201819055600d8201819055600e8201819055600f820181905560108201819055601182015560128101805460ff1916905560130161447656fea2646970667358221220037024f5647853879c58fbcc61ac3616455f6f731cc6e84f91eb5a3b4e06c00464736f6c63430007060033 \ No newline at end of file diff --git a/bins/revme/src/cmd/bench/snailtracer.rs b/bins/revme/src/cmd/bench/snailtracer.rs new file mode 100644 index 0000000000..0228b3df4c --- /dev/null +++ b/bins/revme/src/cmd/bench/snailtracer.rs @@ -0,0 +1,55 @@ +use context::TxEnv; +use criterion::Criterion; +use database::{BenchmarkDB, BENCH_CALLER, BENCH_TARGET}; +use inspector::CountInspector; +use revm::{ + bytecode::Bytecode, + primitives::{bytes, hex, Bytes, TxKind}, + Context, ExecuteEvm, InspectEvm, MainBuilder, MainContext, +}; + +pub fn run(criterion: &mut Criterion) { + let bytecode = Bytecode::new_raw(Bytes::from(hex::decode(BYTES).unwrap())); + + let mut evm = Context::mainnet() + .with_db(BenchmarkDB::new_bytecode(bytecode.clone())) + .modify_cfg_chained(|c| c.disable_nonce_check = true) + .build_mainnet() + .with_inspector(CountInspector::new()); + + let tx = TxEnv::builder() + .caller(BENCH_CALLER) + .kind(TxKind::Call(BENCH_TARGET)) + .data(bytes!("30627b7c")) + .gas_limit(1_000_000_000) + .build() + .unwrap(); + + criterion.bench_function("snailtracer", |b| { + b.iter_batched( + || { + // create a transaction input + tx.clone() + }, + |input| { + let _ = evm.transact_one(input).unwrap(); + }, + criterion::BatchSize::SmallInput, + ); + }); + + criterion.bench_function("analysis-inspector", |b| { + b.iter_batched( + || { + // create a transaction input + tx.clone() + }, + |input| { + let _ = evm.inspect_one_tx(input); + }, + criterion::BatchSize::SmallInput, + ); + }); +} + +const BYTES: &str = include_str!("snailtracer.hex"); diff --git a/bins/revme/src/cmd/bench/transfer.rs b/bins/revme/src/cmd/bench/transfer.rs new file mode 100644 index 0000000000..0914eff60d --- /dev/null +++ b/bins/revme/src/cmd/bench/transfer.rs @@ -0,0 +1,65 @@ +use context::{ContextTr, TxEnv}; +use criterion::Criterion; +use database::{BenchmarkDB, BENCH_CALLER, BENCH_TARGET, BENCH_TARGET_BALANCE}; +use revm::{ + bytecode::Bytecode, + context_interface::JournalTr, + primitives::{TxKind, U256}, + Context, ExecuteEvm, MainBuilder, MainContext, +}; + +pub fn run(criterion: &mut Criterion) { + let mut evm = Context::mainnet() + .with_db(BenchmarkDB::new_bytecode(Bytecode::new())) + .modify_cfg_chained(|cfg| cfg.disable_nonce_check = true) + .build_mainnet(); + + let tx = TxEnv::builder() + .caller(BENCH_CALLER) + .kind(TxKind::Call(BENCH_TARGET)) + .value(U256::from(1)) + .gas_price(1) + .gas_priority_fee(None) + .build() + .unwrap(); + + evm.ctx.tx = tx.clone(); + + let mut i = 0; + criterion.bench_function("transfer", |b| { + b.iter_batched( + || { + // create a transfer input + tx.clone() + }, + |input| { + i += 1; + evm.transact_one(input).unwrap(); + }, + criterion::BatchSize::SmallInput, + ); + }); + + let balance = evm + .journal_mut() + .load_account(BENCH_TARGET) + .unwrap() + .data + .info + .balance; + + if balance != BENCH_TARGET_BALANCE + U256::from(i) { + panic!("balance of transfers is not correct"); + } + + // drop the journal + let _ = evm.finalize(); + + evm.modify_cfg(|cfg| cfg.disable_nonce_check = false); + + criterion.bench_function("transfer_finalize", |b| { + b.iter(|| { + let _ = evm.replay().unwrap(); + }) + }); +} diff --git a/bins/revme/src/cmd/bench/transfer_multi.rs b/bins/revme/src/cmd/bench/transfer_multi.rs new file mode 100644 index 0000000000..9c3e85eefb --- /dev/null +++ b/bins/revme/src/cmd/bench/transfer_multi.rs @@ -0,0 +1,85 @@ +use context::TxEnv; +use criterion::Criterion; +use database::{InMemoryDB, BENCH_CALLER, BENCH_TARGET}; +use revm::{ + interpreter::instructions::utility::IntoAddress, + primitives::{TxKind, U256}, + Context, ExecuteCommitEvm, ExecuteEvm, MainBuilder, MainContext, +}; +use state::AccountInfo; + +pub fn run(criterion: &mut Criterion) { + let mut db = InMemoryDB::default(); + + let address = U256::from(10000); + for i in 0..10000 { + db.insert_account_info( + (address + U256::from(i)).into_address(), + AccountInfo::from_balance(U256::from(3_000_000_000u32)), + ); + } + db.insert_account_info( + BENCH_TARGET, + AccountInfo::from_balance(U256::from(3_000_000_000u32)), + ); + + db.insert_account_info( + BENCH_CALLER, + AccountInfo::from_balance(U256::from(3_000_000_000u32)), + ); + + let mut evm = Context::mainnet() + .with_db(db) + .modify_cfg_chained(|cfg| cfg.disable_nonce_check = true) + .build_mainnet(); + + let target = U256::from(10000); + let mut txs = Vec::with_capacity(1000); + + for i in 0..1000 { + let tx = TxEnv::builder() + .caller(BENCH_CALLER) + .kind(TxKind::Call((target + U256::from(i)).into_address())) + .value(U256::from(1)) + .gas_price(0) + .gas_priority_fee(None) + .gas_limit(30_000) + .build() + .unwrap(); + txs.push(tx); + } + + criterion.bench_function("transact_commit_1000txs", |b| { + b.iter_batched( + || { + // create transaction inputs + txs.clone() + }, + |inputs| { + for tx in inputs { + let _ = evm.transact_commit(tx).unwrap(); + } + }, + criterion::BatchSize::SmallInput, + ); + }); + + criterion.bench_function("transact_1000tx_commit_inner_every_40", |b| { + b.iter_batched( + || { + // create transaction inputs + txs.clone() + }, + |inputs| { + for (i, tx) in inputs.into_iter().enumerate() { + let _ = evm.transact_one(tx).unwrap(); + if i % 40 == 0 { + evm.commit_inner(); + } + } + evm.commit_inner(); + }, + criterion::BatchSize::SmallInput, + ); + }); +} diff --git a/bins/revme/src/cmd/bytecode.rs b/bins/revme/src/cmd/bytecode.rs index 9bc8a92e15..ae5d5c89f8 100644 --- a/bins/revme/src/cmd/bytecode.rs +++ b/bins/revme/src/cmd/bytecode.rs @@ -1,39 +1,59 @@ -use revm::{ - interpreter::opcode::eof_printer::print_eof_code, - primitives::{Bytes, Eof}, -}; -use structopt::StructOpt; - -/// Statetest command -#[derive(StructOpt, Debug)] +use clap::Parser; +use revm::primitives::{hex, Bytes}; + +/// `bytecode` subcommand - simplified to handle legacy bytecode only. +#[derive(Parser, Debug)] pub struct Cmd { - /// EOF bytecode in hex format. It bytes start with 0xFE it will be interpreted as a EOF. - /// Otherwise, it will be interpreted as a EOF bytecode. - #[structopt(required = true)] - bytes: String, + /// Bytecode in hex format string. + #[arg()] + bytes: Option, +} + +#[inline] +fn trim_decode(input: &str) -> Option { + let trimmed = input.trim().trim_start_matches("0x"); + hex::decode(trimmed).ok().map(Into::into) } impl Cmd { - /// Run statetest command. + /// Runs bytecode command. pub fn run(&self) { - let trimmed = self.bytes.trim_start_matches("0x"); - let Ok(bytes) = hex::decode(trimmed) else { - eprintln!("Invalid hex string"); - return; - }; - let bytes: Bytes = bytes.into(); - if bytes.is_empty() { - eprintln!("Empty hex string"); - return; - } - if bytes[0] == 0xEF { - let Ok(eof) = Eof::decode(bytes) else { - eprintln!("Invalid EOF bytecode"); + if let Some(input_bytes) = &self.bytes { + let Some(bytes) = trim_decode(input_bytes) else { + eprintln!("Invalid hex string"); return; }; - println!("{:#?}", eof); + + if bytes.starts_with(&[0xEF, 0x00]) { + eprintln!( + "EOF bytecode is not supported - EOF has been removed from ethereum plan." + ); + return; + } + + println!("Legacy bytecode:"); + println!(" Length: {} bytes", bytes.len()); + println!(" Hex: 0x{}", hex::encode(&bytes)); + + // Basic analysis + let mut opcodes = Vec::new(); + let mut i = 0; + while i < bytes.len() { + let opcode = bytes[i]; + opcodes.push(format!("{opcode:02x}")); + + // Skip immediate bytes for PUSH instructions + if (0x60..=0x7f).contains(&opcode) { + let push_size = (opcode - 0x5f) as usize; + i += push_size; + } + i += 1; + } + + println!(" Opcodes: {}", opcodes.join(" ")); } else { - print_eof_code(&bytes) + println!("No bytecode provided. EOF interactive mode has been removed."); + println!("Please provide bytecode as a hex string argument."); } } } diff --git a/bins/revme/src/cmd/evmrunner.rs b/bins/revme/src/cmd/evmrunner.rs index 8c93d3182b..8fda0fac16 100644 --- a/bins/revme/src/cmd/evmrunner.rs +++ b/bins/revme/src/cmd/evmrunner.rs @@ -1,17 +1,15 @@ +use clap::Parser; +use context::TxEnv; +use database::{BenchmarkDB, BENCH_CALLER, BENCH_TARGET}; +use inspector::{inspectors::TracerEip3155, InspectEvm}; use revm::{ - db::BenchmarkDB, - inspector_handle_register, - inspectors::TracerEip3155, - primitives::{Address, Bytecode, TransactTo}, - Evm, + bytecode::{Bytecode, BytecodeDecodeError}, + primitives::{hex, TxKind}, + Context, Database, ExecuteEvm, MainBuilder, MainContext, }; -use std::io::Error as IoError; use std::path::PathBuf; -use std::time::Duration; use std::{borrow::Cow, fs}; -use structopt::StructOpt; - -extern crate alloc; +use std::{io::Error as IoError, time::Instant}; #[derive(Debug, thiserror::Error)] pub enum Errors { @@ -24,104 +22,112 @@ pub enum Errors { #[error("EVM Error")] EVMError, #[error(transparent)] - Io(IoError), -} - -impl From for Errors { - fn from(e: IoError) -> Self { - Errors::Io(e) - } + Io(#[from] IoError), + #[error(transparent)] + BytecodeDecodeError(#[from] BytecodeDecodeError), } -/// Evm runner command allows running arbitrary evm bytecode. -/// Bytecode can be provided from cli or from file with --path option. -#[derive(StructOpt, Debug)] +/// Evm runner command allows running arbitrary evm bytecode +/// +/// Bytecode can be provided from cli or from file with `--path` option. +#[derive(Parser, Debug)] pub struct Cmd { - /// Bytecode to be executed. - #[structopt(default_value = "")] - bytecode: String, - /// Path to file containing the evm bytecode. - /// Overrides the bytecode option. - #[structopt(long)] + /// Hex-encoded EVM bytecode to be executed + #[arg(required_unless_present = "path")] + bytecode: Option, + /// Path to a file containing the hex-encoded EVM bytecode to be executed + /// + /// Overrides the positional `bytecode` argument. + #[arg(long)] path: Option, - /// Run in benchmarking mode. - #[structopt(long)] + /// Whether to run in benchmarking mode + #[arg(long)] bench: bool, - /// Input bytes. - #[structopt(long, default_value = "")] + /// Hex-encoded input/calldata bytes + #[arg(long, default_value = "")] input: String, - /// Print the state. - #[structopt(long)] + /// Whether to print the state + #[arg(long)] state: bool, - /// Print the trace. - #[structopt(long)] + /// Whether to print the trace + #[arg(long)] trace: bool, } impl Cmd { - /// Run statetest command. + /// Runs evm runner command. pub fn run(&self) -> Result<(), Errors> { let bytecode_str: Cow<'_, str> = if let Some(path) = &self.path { - // check if path exists. + // Check if path exists. if !path.exists() { return Err(Errors::PathNotExists); } - fs::read_to_string(path)?.to_owned().into() + fs::read_to_string(path)?.into() + } else if let Some(bytecode) = &self.bytecode { + bytecode.as_str().into() } else { - self.bytecode.as_str().into() + unreachable!() }; let bytecode = hex::decode(bytecode_str.trim()).map_err(|_| Errors::InvalidBytecode)?; let input = hex::decode(self.input.trim()) .map_err(|_| Errors::InvalidInput)? .into(); + + let mut db = BenchmarkDB::new_bytecode(Bytecode::new_raw_checked(bytecode.into())?); + + let nonce = db + .basic(BENCH_CALLER) + .unwrap() + .map_or(0, |account| account.nonce); + // BenchmarkDB is dummy state that implements Database trait. - // the bytecode is deployed at zero address. - let mut evm = Evm::builder() - .with_db(BenchmarkDB::new_bytecode(Bytecode::new_raw( - bytecode.into(), - ))) - .modify_tx_env(|tx| { - // execution globals block hash/gas_limit/coinbase/timestamp.. - tx.caller = "0x0000000000000000000000000000000000000001" - .parse() - .unwrap(); - tx.transact_to = TransactTo::Call(Address::ZERO); - tx.data = input; - }) - .build(); + // The bytecode is deployed at zero address. + let mut evm = Context::mainnet() + .with_db(db) + .build_mainnet_with_inspector(TracerEip3155::new(Box::new(std::io::stdout()))); - if self.bench { - // Microbenchmark - let bench_options = microbench::Options::default().time(Duration::from_secs(3)); + let tx = TxEnv::builder() + .caller(BENCH_CALLER) + .kind(TxKind::Call(BENCH_TARGET)) + .data(input) + .nonce(nonce) + .build() + .unwrap(); - microbench::bench(&bench_options, "Run bytecode", || { - let _ = evm.transact().unwrap(); + if self.bench { + let mut criterion = criterion::Criterion::default() + .warm_up_time(std::time::Duration::from_millis(300)) + .measurement_time(std::time::Duration::from_secs(2)) + .without_plots(); + let mut criterion_group = criterion.benchmark_group("revme"); + criterion_group.bench_function("evm", |b| { + b.iter(|| { + let _ = evm.transact(tx.clone()).unwrap(); + }) }); + criterion_group.finish(); return Ok(()); } - let out = if self.trace { - let mut evm = evm - .modify() - .reset_handler_with_external_context(TracerEip3155::new( - Box::new(std::io::stdout()), - )) - .append_handler_register(inspector_handle_register) - .build(); - - evm.transact().map_err(|_| Errors::EVMError)? + let time = Instant::now(); + let state = if self.trace { + evm.inspect_tx(tx.clone()) + .map_err(|_| Errors::EVMError)? + .state } else { - let out = evm.transact().map_err(|_| Errors::EVMError)?; + let out = evm.transact(tx.clone()).map_err(|_| Errors::EVMError)?; println!("Result: {:#?}", out.result); - out + out.state }; + let time = time.elapsed(); if self.state { - println!("State: {:#?}", out.state); + println!("State: {state:#?}"); } + println!("Elapsed: {time:?}"); Ok(()) } } diff --git a/bins/revme/src/cmd/format_kzg_setup.rs b/bins/revme/src/cmd/format_kzg_setup.rs deleted file mode 100644 index b2dfaa5b0e..0000000000 --- a/bins/revme/src/cmd/format_kzg_setup.rs +++ /dev/null @@ -1,59 +0,0 @@ -pub use revm::primitives::kzg::{parse_kzg_trusted_setup, G1Points, G2Points, KzgErrors}; -use std::{env, fs, path::PathBuf}; -use structopt::StructOpt; - -/// Statetest command -#[derive(StructOpt, Debug)] -pub struct Cmd { - /// Input path to the kzg trusted setup file. - #[structopt(required = true)] - path: PathBuf, - /// path to output g1 point in binary format. - #[structopt(long)] - g1: Option, - /// Path to output g2 point in binary format. - #[structopt(long)] - g2: Option, -} - -impl Cmd { - /// Run statetest command. - pub fn run(&self) -> Result<(), KzgErrors> { - // check if path exists. - if !self.path.exists() { - return Err(KzgErrors::PathNotExists); - } - - let out_dir = env::current_dir().map_err(|_| KzgErrors::FailedCurrentDirectory)?; - - let kzg_trusted_settings = - fs::read_to_string(&self.path).map_err(|_| KzgErrors::NotValidFile)?; - - // format points - let (g1, g2) = parse_kzg_trusted_setup(&kzg_trusted_settings)?; - - let g1_path = self - .g1 - .clone() - .unwrap_or_else(|| out_dir.join("g1_points.bin")); - - let g2_path = self - .g2 - .clone() - .unwrap_or_else(|| out_dir.join("g2_points.bin")); - - // output points - fs::write(&g1_path, flatten(&g1.0)).map_err(|_| KzgErrors::IOError)?; - fs::write(&g2_path, flatten(&g2.0)).map_err(|_| KzgErrors::IOError)?; - println!("Finished formatting kzg trusted setup into binary representation."); - println!("G1 points path: {:?}", g1_path); - println!("G2 points path: {:?}", g2_path); - Ok(()) - } -} - -fn flatten(x: &[[u8; N]; M]) -> &[u8] { - // SAFETY: `x` is a valid `[[u8; N]; M]` and `N * M` is the length of the - // returned slice. - unsafe { core::slice::from_raw_parts(x.as_ptr().cast(), N * M) } -} diff --git a/bins/revme/src/cmd/statetest.rs b/bins/revme/src/cmd/statetest.rs index cc082cb0d4..3094316d53 100644 --- a/bins/revme/src/cmd/statetest.rs +++ b/bins/revme/src/cmd/statetest.rs @@ -1,44 +1,66 @@ pub mod merkle_trie; -pub mod models; mod runner; pub mod utils; -pub use runner::TestError as Error; +pub use runner::{TestError as Error, TestErrorKind}; +use clap::Parser; use runner::{find_all_json_tests, run, TestError}; use std::path::PathBuf; -use structopt::StructOpt; -/// Statetest command -#[derive(StructOpt, Debug)] +/// `statetest` subcommand +#[derive(Parser, Debug)] pub struct Cmd { - /// Path to folder or file containing the tests. If multiple paths are specified - /// they will be run in sequence. + /// Path to folder or file containing the tests + /// + /// If multiple paths are specified they will be run in sequence. /// /// Folders will be searched recursively for files with the extension `.json`. - #[structopt(required = true)] - path: Vec, - /// Run tests in a single thread. - #[structopt(short = "s", long)] + #[arg(required = true, num_args = 1..)] + paths: Vec, + /// Run tests in a single thread + #[arg(short = 's', long)] single_thread: bool, - /// Output results in JSON format. + /// Output results in JSON format + /// /// It will stop second run of evm on failure. - #[structopt(long)] + #[arg(long)] json: bool, - /// Output outcome in JSON format. If json is true, this is implied. - /// It will stop second run of evm on failure. - #[structopt(short = "o", long)] + /// Output outcome in JSON format + /// + /// If `--json` is true, this is implied. + /// + /// It will stop second run of EVM on failure. + #[arg(short = 'o', long)] json_outcome: bool, - #[structopt(long, alias = "no-fail-fast")] + /// Keep going after a test failure + #[arg(long, alias = "no-fail-fast")] keep_going: bool, } impl Cmd { - /// Run statetest command. + /// Runs `statetest` command. pub fn run(&self) -> Result<(), TestError> { - for path in &self.path { + for path in &self.paths { + if !path.exists() { + return Err(TestError { + name: "Path validation".to_string(), + path: path.display().to_string(), + kind: TestErrorKind::InvalidPath, + }); + } + println!("\nRunning tests in {}...", path.display()); let test_files = find_all_json_tests(path); + + if test_files.is_empty() { + return Err(TestError { + name: "Path validation".to_string(), + path: path.display().to_string(), + kind: TestErrorKind::NoJsonFiles, + }); + } + run( test_files, self.single_thread, diff --git a/bins/revme/src/cmd/statetest/merkle_trie.rs b/bins/revme/src/cmd/statetest/merkle_trie.rs index c869938bf0..c6b6418787 100644 --- a/bins/revme/src/cmd/statetest/merkle_trie.rs +++ b/bins/revme/src/cmd/statetest/merkle_trie.rs @@ -1,12 +1,28 @@ +use std::convert::Infallible; + use alloy_rlp::{RlpEncodable, RlpMaxEncodedLen}; +use context::result::{EVMError, ExecutionResult, HaltReason, InvalidTransaction}; +use database::{EmptyDB, PlainAccount, State}; use hash_db::Hasher; use plain_hasher::PlainHasher; -use revm::{ - db::PlainAccount, - primitives::{keccak256, Address, Log, B256, U256}, -}; +use revm::primitives::{keccak256, Address, Log, B256, U256}; use triehash::sec_trie_root; +pub struct TestValidationResult { + pub logs_root: B256, + pub state_root: B256, +} + +pub fn compute_test_roots( + exec_result: &Result, EVMError>, + db: &State, +) -> TestValidationResult { + TestValidationResult { + logs_root: log_rlp_hash(exec_result.as_ref().map(|r| r.logs()).unwrap_or_default()), + state_root: state_merkle_trie_root(db.cache.trie_account()), + } +} + pub fn log_rlp_hash(logs: &[Log]) -> B256 { let mut out = Vec::with_capacity(alloy_rlp::list_length(logs)); alloy_rlp::encode_list(logs, &mut out); @@ -40,7 +56,7 @@ impl TrieAccount { root_hash: sec_trie_root::( acc.storage .iter() - .filter(|(_k, &v)| v != U256::ZERO) + .filter(|(_k, &v)| !v.is_zero()) .map(|(k, v)| (k.to_be_bytes::<32>(), alloy_rlp::encode_fixed_size(v))), ), code_hash: acc.info.code_hash, diff --git a/bins/revme/src/cmd/statetest/models/mod.rs b/bins/revme/src/cmd/statetest/models/mod.rs deleted file mode 100644 index 0225daaccc..0000000000 --- a/bins/revme/src/cmd/statetest/models/mod.rs +++ /dev/null @@ -1,163 +0,0 @@ -use revm::primitives::{Address, Bytes, HashMap, B256, U256}; -use serde::{Deserialize, Serialize}; -use std::collections::BTreeMap; - -mod deserializer; -use deserializer::*; - -mod spec; -pub use self::spec::SpecName; - -#[derive(Debug, PartialEq, Eq, Deserialize)] -pub struct TestSuite(pub BTreeMap); - -#[derive(Debug, PartialEq, Eq, Deserialize)] -#[serde(deny_unknown_fields)] -pub struct TestUnit { - /// Test info is optional - #[serde(default, rename = "_info")] - pub info: Option, - - pub env: Env, - pub pre: HashMap, - pub post: BTreeMap>, - pub transaction: TransactionParts, - #[serde(default)] - pub out: Option, -} - -/// State test indexed state result deserialization. -#[derive(Debug, PartialEq, Eq, Deserialize)] -#[serde(rename_all = "camelCase", deny_unknown_fields)] -pub struct Test { - pub expect_exception: Option, - - /// Indexes - pub indexes: TxPartIndices, - /// Post state hash - pub hash: B256, - /// Post state - #[serde(default)] - pub post_state: HashMap, - - /// Logs root - pub logs: B256, - - /// Tx bytes - pub txbytes: Option, -} - -#[derive(Debug, PartialEq, Eq, Deserialize)] -#[serde(rename_all = "camelCase", deny_unknown_fields)] -pub struct TxPartIndices { - pub data: usize, - pub gas: usize, - pub value: usize, -} - -#[derive(Clone, Debug, PartialEq, Eq, Deserialize)] -#[serde(rename_all = "camelCase", deny_unknown_fields)] -pub struct AccountInfo { - pub balance: U256, - pub code: Bytes, - #[serde(deserialize_with = "deserialize_str_as_u64")] - pub nonce: u64, - pub storage: HashMap, -} - -#[derive(Debug, PartialEq, Eq, Deserialize)] -#[serde(rename_all = "camelCase", deny_unknown_fields)] -pub struct Env { - pub current_coinbase: Address, - pub current_difficulty: U256, - pub current_gas_limit: U256, - pub current_number: U256, - pub current_timestamp: U256, - pub current_base_fee: Option, - pub previous_hash: Option, - - pub current_random: Option, - pub current_beacon_root: Option, - pub current_withdrawals_root: Option, - - pub parent_blob_gas_used: Option, - pub parent_excess_blob_gas: Option, - pub current_excess_blob_gas: Option, -} - -#[derive(Debug, Default, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase", deny_unknown_fields)] -pub struct TransactionParts { - pub data: Vec, - pub gas_limit: Vec, - pub gas_price: Option, - pub nonce: U256, - pub secret_key: B256, - /// if sender is not present we need to derive it from secret key. - #[serde(default)] - pub sender: Option
, - #[serde(deserialize_with = "deserialize_maybe_empty")] - pub to: Option
, - pub value: Vec, - pub max_fee_per_gas: Option, - pub max_priority_fee_per_gas: Option, - - #[serde(default)] - pub access_lists: Vec>, - - #[serde(default)] - pub blob_versioned_hashes: Vec, - pub max_fee_per_blob_gas: Option, -} - -#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone)] -#[serde(rename_all = "camelCase", deny_unknown_fields)] -pub struct AccessListItem { - pub address: Address, - pub storage_keys: Vec, -} - -pub type AccessList = Vec; - -#[cfg(test)] -mod tests { - - use super::*; - use serde_json::Error; - - #[test] - pub fn serialize_u256() -> Result<(), Error> { - let json = r#"{"_item":"0x10"}"#; - - #[derive(Deserialize, Debug)] - pub struct Test { - _item: Option, - } - - let out: Test = serde_json::from_str(json)?; - println!("out:{out:?}"); - Ok(()) - } - - #[test] - pub fn deserialize_minimal_transaction_parts() -> Result<(), Error> { - let json = r#"{"data":[],"gasLimit":[],"nonce":"0x0","secretKey":"0x0000000000000000000000000000000000000000000000000000000000000000","to":"","value":[]}"#; - - let _: TransactionParts = serde_json::from_str(json)?; - Ok(()) - } - - #[test] - pub fn serialize_b160() -> Result<(), Error> { - let json = r#"{"_item":"0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"}"#; - - #[derive(Deserialize, Debug)] - pub struct Test { - _item: Address, - } - - let out: Test = serde_json::from_str(json)?; - println!("out:{out:?}"); - Ok(()) - } -} diff --git a/bins/revme/src/cmd/statetest/runner.rs b/bins/revme/src/cmd/statetest/runner.rs index 85764f6aef..f989daa614 100644 --- a/bins/revme/src/cmd/statetest/runner.rs +++ b/bins/revme/src/cmd/statetest/runner.rs @@ -1,23 +1,24 @@ -use super::{ - merkle_trie::{log_rlp_hash, state_merkle_trie_root}, - models::{SpecName, Test, TestSuite}, - utils::recover_address, -}; +use crate::cmd::statetest::merkle_trie::{compute_test_roots, TestValidationResult}; +use database::State; use indicatif::{ProgressBar, ProgressDrawTarget}; +use inspector::{inspectors::TracerEip3155, InspectCommitEvm}; +use primitives::U256; use revm::{ - db::EmptyDB, - inspector_handle_register, - inspectors::TracerEip3155, - primitives::{ - calc_excess_blob_gas, keccak256, Bytecode, Bytes, EVMResultGeneric, Env, ExecutionResult, - SpecId, TransactTo, B256, U256, + context::{block::BlockEnv, cfg::CfgEnv, tx::TxEnv}, + context_interface::{ + result::{EVMError, ExecutionResult, HaltReason, InvalidTransaction}, + Cfg, }, - Evm, State, + database_interface::EmptyDB, + primitives::{hardfork::SpecId, Bytes, B256}, + Context, ExecuteCommitEvm, MainBuilder, MainContext, }; use serde_json::json; +use statetest_types::{SpecName, Test, TestSuite, TestUnit}; use std::{ convert::Infallible, - io::{stderr, stdout}, + fmt::Debug, + io::stderr, path::{Path, PathBuf}, sync::{ atomic::{AtomicBool, AtomicUsize, Ordering}, @@ -28,13 +29,16 @@ use std::{ use thiserror::Error; use walkdir::{DirEntry, WalkDir}; +/// Error that occurs during test execution #[derive(Debug, Error)] -#[error("Test {name} failed: {kind}")] +#[error("Path: {path}\nName: {name}\nError: {kind}")] pub struct TestError { pub name: String, + pub path: String, pub kind: TestErrorKind, } +/// Specific kind of error that occurred during test execution #[derive(Debug, Error)] pub enum TestErrorKind { #[error("logs root mismatch: got {got}, expected {expected}")] @@ -57,8 +61,15 @@ pub enum TestErrorKind { SerdeDeserialize(#[from] serde_json::Error), #[error("thread panicked")] Panic, + #[error("path does not exist")] + InvalidPath, + #[error("no JSON test files found in path")] + NoJsonFiles, } +/// Find all JSON test files in the given path +/// If path is a file, returns it in a vector +/// If path is a directory, recursively finds all .json files pub fn find_all_json_tests(path: &Path) -> Vec { if path.is_file() { vec![path.to_path_buf()] @@ -72,39 +83,16 @@ pub fn find_all_json_tests(path: &Path) -> Vec { } } +/// Check if a test should be skipped based on its filename +/// Some tests are known to be problematic or take too long fn skip_test(path: &Path) -> bool { - let path_str = path.to_str().expect("Path is not valid UTF-8"); let name = path.file_name().unwrap().to_str().unwrap(); matches!( name, - // funky test with `bigint 0x00` value in json :) not possible to happen on mainnet and require - // custom json parser. https://github.com/ethereum/tests/issues/971 - |"ValueOverflow.json"| "ValueOverflowParis.json" - - // precompiles having storage is not possible - | "RevertPrecompiledTouch_storage.json" - | "RevertPrecompiledTouch.json" - - // txbyte is of type 02 and we don't parse tx bytes for this test to fail. - | "typeTwoBerlin.json" - - // Need to handle Test errors - | "transactionIntinsicBug.json" - // Test check if gas price overflows, we handle this correctly but does not match tests specific exception. - | "HighGasPrice.json" - | "CREATE_HighNonce.json" - | "CREATE_HighNonceMinus1.json" | "CreateTransactionHighNonce.json" - // Skip test where basefee/accesslist/difficulty is present but it shouldn't be supported in - // London/Berlin/TheMerge. https://github.com/ethereum/tests/blob/5b7e1ab3ffaf026d99d20b17bb30f533a2c80c8b/GeneralStateTests/stExample/eip1559.json#L130 - // It is expected to not execute these tests. - | "basefeeExample.json" - | "eip1559.json" - | "mergeTest.json" - // Test with some storage check. | "RevertInCreateInInit_Paris.json" | "RevertInCreateInInit.json" @@ -117,126 +105,184 @@ fn skip_test(path: &Path) -> bool { | "InitCollision.json" | "InitCollisionParis.json" + // Malformed value. + | "ValueOverflow.json" + | "ValueOverflowParis.json" + // These tests are passing, but they take a lot of time to execute so we are going to skip them. - | "loopExp.json" | "Call50000_sha256.json" | "static_Call50000_sha256.json" | "loopMul.json" | "CALLBlake2f_MaxRounds.json" - ) || path_str.contains("stEOF") + ) } -fn check_evm_execution( +struct TestExecutionContext<'a> { + name: &'a str, + unit: &'a TestUnit, + test: &'a Test, + cfg: &'a CfgEnv, + block: &'a BlockEnv, + tx: &'a TxEnv, + cache_state: &'a database::CacheState, + elapsed: &'a Arc>, + trace: bool, + print_json_outcome: bool, +} + +struct DebugContext<'a> { + name: &'a str, + path: &'a str, + index: usize, + test: &'a Test, + cfg: &'a CfgEnv, + block: &'a BlockEnv, + tx: &'a TxEnv, + cache_state: &'a database::CacheState, + error: &'a TestErrorKind, +} + +fn build_json_output( + test: &Test, + test_name: &str, + exec_result: &Result, EVMError>, + validation: &TestValidationResult, + spec: SpecId, + error: Option, +) -> serde_json::Value { + json!({ + "stateRoot": validation.state_root, + "logsRoot": validation.logs_root, + "output": exec_result.as_ref().ok().and_then(|r| r.output().cloned()).unwrap_or_default(), + "gasUsed": exec_result.as_ref().ok().map(|r| r.gas_used()).unwrap_or_default(), + "pass": error.is_none(), + "errorMsg": error.unwrap_or_default(), + "evmResult": format_evm_result(exec_result), + "postLogsHash": validation.logs_root, + "fork": spec, + "test": test_name, + "d": test.indexes.data, + "g": test.indexes.gas, + "v": test.indexes.value, + }) +} + +fn format_evm_result( + exec_result: &Result, EVMError>, +) -> String { + match exec_result { + Ok(r) => match r { + ExecutionResult::Success { reason, .. } => format!("Success: {reason:?}"), + ExecutionResult::Revert { .. } => "Revert".to_string(), + ExecutionResult::Halt { reason, .. } => format!("Halt: {reason:?}"), + }, + Err(e) => e.to_string(), + } +} + +fn validate_exception( + test: &Test, + exec_result: &Result, EVMError>, +) -> Result { + match (&test.expect_exception, exec_result) { + (None, Ok(_)) => Ok(false), // No exception expected, execution succeeded + (Some(_), Err(_)) => Ok(true), // Exception expected and occurred + _ => Err(TestErrorKind::UnexpectedException { + expected_exception: test.expect_exception.clone(), + got_exception: exec_result.as_ref().err().map(|e| e.to_string()), + }), + } +} + +fn validate_output( + expected_output: Option<&Bytes>, + actual_result: &ExecutionResult, +) -> Result<(), TestErrorKind> { + if let Some((expected, actual)) = expected_output.zip(actual_result.output()) { + if expected != actual { + return Err(TestErrorKind::UnexpectedOutput { + expected_output: Some(expected.clone()), + got_output: actual_result.output().cloned(), + }); + } + } + Ok(()) +} + +fn check_evm_execution( test: &Test, expected_output: Option<&Bytes>, test_name: &str, - exec_result: &EVMResultGeneric, - evm: &Evm<'_, EXT, &mut State>, + exec_result: &Result, EVMError>, + db: &mut State, + spec: SpecId, print_json_outcome: bool, -) -> Result<(), TestError> { - let logs_root = log_rlp_hash(exec_result.as_ref().map(|r| r.logs()).unwrap_or_default()); - let state_root = state_merkle_trie_root(evm.context.evm.db.cache.trie_account()); +) -> Result<(), TestErrorKind> { + let validation = compute_test_roots(exec_result, db); - let print_json_output = |error: Option| { + let print_json = |error: Option<&TestErrorKind>| { if print_json_outcome { - let json = json!({ - "stateRoot": state_root, - "logsRoot": logs_root, - "output": exec_result.as_ref().ok().and_then(|r| r.output().cloned()).unwrap_or_default(), - "gasUsed": exec_result.as_ref().ok().map(|r| r.gas_used()).unwrap_or_default(), - "pass": error.is_none(), - "errorMsg": error.unwrap_or_default(), - "evmResult": match exec_result { - Ok(r) => match r { - ExecutionResult::Success { reason, .. } => format!("Success: {reason:?}"), - ExecutionResult::Revert { .. } => "Revert".to_string(), - ExecutionResult::Halt { reason, .. } => format!("Halt: {reason:?}"), - }, - Err(e) => e.to_string(), - }, - "postLogsHash": logs_root, - "fork": evm.handler.cfg().spec_id, - "test": test_name, - "d": test.indexes.data, - "g": test.indexes.gas, - "v": test.indexes.value, - }); + let json = build_json_output( + test, + test_name, + exec_result, + &validation, + spec, + error.map(|e| e.to_string()), + ); eprintln!("{json}"); } }; - // If we expect exception revm should return error from execution. - // So we do not check logs and state root. - // - // Note that some tests that have exception and run tests from before state clear - // would touch the caller account and make it appear in state root calculation. - // This is not something that we would expect as invalid tx should not touch state. - // but as this is a cleanup of invalid tx it is not properly defined and in the end - // it does not matter. - // Test where this happens: `tests/GeneralStateTests/stTransactionTest/NoSrcAccountCreate.json` - // and you can check that we have only two "hash" values for before and after state clear. - match (&test.expect_exception, exec_result) { - // do nothing - (None, Ok(result)) => { - // check output - if let Some((expected_output, output)) = expected_output.zip(result.output()) { - if expected_output != output { - let kind = TestErrorKind::UnexpectedOutput { - expected_output: Some(expected_output.clone()), - got_output: result.output().cloned(), - }; - print_json_output(Some(kind.to_string())); - return Err(TestError { - name: test_name.to_string(), - kind, - }); - } - } - } - // return okay, exception is expected. - (Some(_), Err(_)) => return Ok(()), - _ => { - let kind = TestErrorKind::UnexpectedException { - expected_exception: test.expect_exception.clone(), - got_exception: exec_result.clone().err().map(|e| e.to_string()), - }; - print_json_output(Some(kind.to_string())); - return Err(TestError { - name: test_name.to_string(), - kind, - }); - } + // Check if exception handling is correct + let exception_expected = validate_exception(test, exec_result).inspect_err(|e| { + print_json(Some(e)); + })?; + + // If exception was expected and occurred, we're done + if exception_expected { + print_json(None); + return Ok(()); + } + + // Validate output if execution succeeded + if let Ok(result) = exec_result { + validate_output(expected_output, result).inspect_err(|e| { + print_json(Some(e)); + })?; } - if logs_root != test.logs { - let kind = TestErrorKind::LogsRootMismatch { - got: logs_root, + // Validate logs root + if validation.logs_root != test.logs { + let error = TestErrorKind::LogsRootMismatch { + got: validation.logs_root, expected: test.logs, }; - print_json_output(Some(kind.to_string())); - return Err(TestError { - name: test_name.to_string(), - kind, - }); + print_json(Some(&error)); + return Err(error); } - if state_root != test.hash { - let kind = TestErrorKind::StateRootMismatch { - got: state_root, + // Validate state root + if validation.state_root != test.hash { + let error = TestErrorKind::StateRootMismatch { + got: validation.state_root, expected: test.hash, }; - print_json_output(Some(kind.to_string())); - return Err(TestError { - name: test_name.to_string(), - kind, - }); + print_json(Some(&error)); + return Err(error); } - print_json_output(None); - + print_json(None); Ok(()) } +/// Execute a single test suite file containing multiple tests +/// +/// # Arguments +/// * `path` - Path to the JSON test file +/// * `elapsed` - Shared counter for total execution time +/// * `trace` - Whether to enable EVM tracing +/// * `print_json_outcome` - Whether to print JSON formatted results pub fn execute_test_suite( path: &Path, elapsed: &Arc>, @@ -248,295 +294,315 @@ pub fn execute_test_suite( } let s = std::fs::read_to_string(path).unwrap(); + let path = path.to_string_lossy().into_owned(); let suite: TestSuite = serde_json::from_str(&s).map_err(|e| TestError { - name: path.to_string_lossy().into_owned(), + name: "Unknown".to_string(), + path: path.clone(), kind: e.into(), })?; for (name, unit) in suite.0 { - // Create database and insert cache - let mut cache_state = revm::CacheState::new(false); - for (address, info) in unit.pre { - let acc_info = revm::primitives::AccountInfo { - balance: info.balance, - code_hash: keccak256(&info.code), - code: Some(Bytecode::new_raw(info.code)), - nonce: info.nonce, - }; - cache_state.insert_account_with_storage(address, acc_info, info.storage); - } + // Prepare initial state + let cache_state = unit.state(); + + // Setup base configuration + let mut cfg = CfgEnv::default(); + cfg.chain_id = unit + .env + .current_chain_id + .unwrap_or(U256::ONE) + .try_into() + .unwrap_or(1); + + // Post and execution + for (spec_name, tests) in &unit.post { + // Skip Constantinople spec + if *spec_name == SpecName::Constantinople { + continue; + } - let mut env = Box::::default(); - // for mainnet - env.cfg.chain_id = 1; - // env.cfg.spec_id is set down the road - - // block env - env.block.number = unit.env.current_number; - env.block.coinbase = unit.env.current_coinbase; - env.block.timestamp = unit.env.current_timestamp; - env.block.gas_limit = unit.env.current_gas_limit; - env.block.basefee = unit.env.current_base_fee.unwrap_or_default(); - env.block.difficulty = unit.env.current_difficulty; - // after the Merge prevrandao replaces mix_hash field in block and replaced difficulty opcode in EVM. - env.block.prevrandao = unit.env.current_random; - // EIP-4844 - if let Some(current_excess_blob_gas) = unit.env.current_excess_blob_gas { - env.block - .set_blob_excess_gas_and_price(current_excess_blob_gas.to()); - } else if let (Some(parent_blob_gas_used), Some(parent_excess_blob_gas)) = ( - unit.env.parent_blob_gas_used, - unit.env.parent_excess_blob_gas, - ) { - env.block - .set_blob_excess_gas_and_price(calc_excess_blob_gas( - parent_blob_gas_used.to(), - parent_excess_blob_gas.to(), - )); - } + cfg.spec = spec_name.to_spec_id(); - // tx env - env.tx.caller = if let Some(address) = unit.transaction.sender { - address - } else { - recover_address(unit.transaction.secret_key.as_slice()).ok_or_else(|| TestError { - name: name.clone(), - kind: TestErrorKind::UnknownPrivateKey(unit.transaction.secret_key), - })? - }; - env.tx.gas_price = unit - .transaction - .gas_price - .or(unit.transaction.max_fee_per_gas) - .unwrap_or_default(); - env.tx.gas_priority_fee = unit.transaction.max_priority_fee_per_gas; - // EIP-4844 - env.tx.blob_hashes = unit.transaction.blob_versioned_hashes; - env.tx.max_fee_per_blob_gas = unit.transaction.max_fee_per_blob_gas; - - // post and execution - for (spec_name, tests) in unit.post { - if matches!( - spec_name, - SpecName::ByzantiumToConstantinopleAt5 - | SpecName::Constantinople - | SpecName::Unknown - ) { - continue; + // Configure max blobs per spec + if cfg.spec.is_enabled_in(SpecId::OSAKA) { + cfg.set_max_blobs_per_tx(6); + } else if cfg.spec.is_enabled_in(SpecId::PRAGUE) { + cfg.set_max_blobs_per_tx(9); + } else { + cfg.set_max_blobs_per_tx(6); } - let spec_id = spec_name.to_spec_id(); - - for (index, test) in tests.into_iter().enumerate() { - env.tx.gas_limit = unit.transaction.gas_limit[test.indexes.gas].saturating_to(); - - env.tx.data = unit - .transaction - .data - .get(test.indexes.data) - .unwrap() - .clone(); - env.tx.value = unit.transaction.value[test.indexes.value]; - - env.tx.access_list = unit - .transaction - .access_lists - .get(test.indexes.data) - .and_then(Option::as_deref) - .unwrap_or_default() - .iter() - .map(|item| { - ( - item.address, - item.storage_keys - .iter() - .map(|key| U256::from_be_bytes(key.0)) - .collect::>(), - ) - }) - .collect(); - - let to = match unit.transaction.to { - Some(add) => TransactTo::Call(add), - None => TransactTo::Create, - }; - env.tx.transact_to = to; - - let mut cache = cache_state.clone(); - cache.set_state_clear_flag(SpecId::enabled( - spec_id, - revm::primitives::SpecId::SPURIOUS_DRAGON, - )); - let mut state = revm::db::State::builder() - .with_cached_prestate(cache) - .with_bundle_update() - .build(); - let mut evm = Evm::builder() - .with_db(&mut state) - .modify_env(|e| e.clone_from(&env)) - .with_spec_id(spec_id) - .build(); - - // do the deed - let (e, exec_result) = if trace { - let mut evm = evm - .modify() - .reset_handler_with_external_context( - TracerEip3155::new(Box::new(stderr())).without_summary(), - ) - .append_handler_register(inspector_handle_register) - .build(); - - let timer = Instant::now(); - let res = evm.transact_commit(); - *elapsed.lock().unwrap() += timer.elapsed(); - - let Err(e) = check_evm_execution( - &test, - unit.out.as_ref(), - &name, - &res, - &evm, - print_json_outcome, - ) else { - continue; - }; - // reset external context - (e, res) - } else { - let timer = Instant::now(); - let res = evm.transact_commit(); - *elapsed.lock().unwrap() += timer.elapsed(); - - // dump state and traces if test failed - let output = check_evm_execution( - &test, - unit.out.as_ref(), - &name, - &res, - &evm, - print_json_outcome, - ); - let Err(e) = output else { - continue; - }; - (e, res) + // Setup block environment for this spec + let block = unit.block_env(&cfg); + + for (index, test) in tests.iter().enumerate() { + // Setup transaction environment + let tx = match test.tx_env(&unit) { + Ok(tx) => tx, + Err(_) if test.expect_exception.is_some() => continue, + Err(_) => { + return Err(TestError { + name: name.clone(), + path: path.clone(), + kind: TestErrorKind::UnknownPrivateKey(unit.transaction.secret_key), + }); + } }; - // print only once or - // if we are already in trace mode, just return error - static FAILED: AtomicBool = AtomicBool::new(false); - if trace || FAILED.swap(true, Ordering::SeqCst) { - return Err(e); - } + // Execute the test + let result = execute_single_test(TestExecutionContext { + name: &name, + unit: &unit, + test, + cfg: &cfg, + block: &block, + tx: &tx, + cache_state: &cache_state, + elapsed, + trace, + print_json_outcome, + }); + + if let Err(e) = result { + // Handle error with debug trace if needed + static FAILED: AtomicBool = AtomicBool::new(false); + if print_json_outcome || FAILED.swap(true, Ordering::SeqCst) { + return Err(TestError { + name: name.clone(), + path: path.clone(), + kind: e, + }); + } + + // Re-run with trace for debugging + debug_failed_test(DebugContext { + name: &name, + path: &path, + index, + test, + cfg: &cfg, + block: &block, + tx: &tx, + cache_state: &cache_state, + error: &e, + }); - // re build to run with tracing - let mut cache = cache_state.clone(); - cache.set_state_clear_flag(SpecId::enabled( - spec_id, - revm::primitives::SpecId::SPURIOUS_DRAGON, - )); - let state = revm::db::State::builder() - .with_cached_prestate(cache) - .with_bundle_update() - .build(); - - let path = path.display(); - println!("\nTraces:"); - let mut evm = Evm::builder() - .with_spec_id(spec_id) - .with_db(state) - .with_env(env.clone()) - .with_external_context(TracerEip3155::new(Box::new(stdout())).without_summary()) - .append_handler_register(inspector_handle_register) - .build(); - let _ = evm.transact_commit(); - - println!("\nExecution result: {exec_result:#?}"); - println!("\nExpected exception: {:?}", test.expect_exception); - println!("\nState before: {cache_state:#?}"); - println!("\nState after: {:#?}", evm.context.evm.db.cache); - println!("\nSpecification: {spec_id:?}"); - println!("\nEnvironment: {env:#?}"); - println!("\nTest name: {name:?} (index: {index}, path: {path}) failed:\n{e}"); - - return Err(e); + return Err(TestError { + path: path.clone(), + name: name.clone(), + kind: e, + }); + } } } } Ok(()) } -pub fn run( - test_files: Vec, - mut single_thread: bool, +fn execute_single_test(ctx: TestExecutionContext) -> Result<(), TestErrorKind> { + // Prepare state + let mut cache = ctx.cache_state.clone(); + cache.set_state_clear_flag(ctx.cfg.spec.is_enabled_in(SpecId::SPURIOUS_DRAGON)); + let mut state = database::State::builder() + .with_cached_prestate(cache) + .with_bundle_update() + .build(); + + let evm_context = Context::mainnet() + .with_block(ctx.block) + .with_tx(ctx.tx) + .with_cfg(ctx.cfg) + .with_db(&mut state); + + // Execute + let timer = Instant::now(); + let (db, exec_result) = if ctx.trace { + let mut evm = evm_context + .build_mainnet_with_inspector(TracerEip3155::buffered(stderr()).without_summary()); + let res = evm.inspect_tx_commit(ctx.tx); + let db = evm.ctx.journaled_state.database; + (db, res) + } else { + let mut evm = evm_context.build_mainnet(); + let res = evm.transact_commit(ctx.tx); + let db = evm.ctx.journaled_state.database; + (db, res) + }; + *ctx.elapsed.lock().unwrap() += timer.elapsed(); + + // Check results + check_evm_execution( + ctx.test, + ctx.unit.out.as_ref(), + ctx.name, + &exec_result, + db, + ctx.cfg.spec(), + ctx.print_json_outcome, + ) +} + +fn debug_failed_test(ctx: DebugContext) { + println!("\nTraces:"); + + // Re-run with tracing + let mut cache = ctx.cache_state.clone(); + cache.set_state_clear_flag(ctx.cfg.spec.is_enabled_in(SpecId::SPURIOUS_DRAGON)); + let mut state = database::State::builder() + .with_cached_prestate(cache) + .with_bundle_update() + .build(); + + let mut evm = Context::mainnet() + .with_db(&mut state) + .with_block(ctx.block) + .with_tx(ctx.tx) + .with_cfg(ctx.cfg) + .build_mainnet_with_inspector(TracerEip3155::buffered(stderr()).without_summary()); + + let exec_result = evm.inspect_tx_commit(ctx.tx); + + println!("\nExecution result: {exec_result:#?}"); + println!("\nExpected exception: {:?}", ctx.test.expect_exception); + println!("\nState before: {:#?}", ctx.cache_state); + println!( + "\nState after: {:#?}", + evm.ctx.journaled_state.database.cache + ); + println!("\nSpecification: {:?}", ctx.cfg.spec); + println!("\nTx: {:#?}", ctx.tx); + println!("Block: {:#?}", ctx.block); + println!("Cfg: {:#?}", ctx.cfg); + println!( + "\nTest name: {:?} (index: {}, path: {:?}) failed:\n{}", + ctx.name, ctx.index, ctx.path, ctx.error + ); +} + +#[derive(Clone, Copy)] +struct TestRunnerConfig { + single_thread: bool, trace: bool, - mut print_outcome: bool, + print_outcome: bool, keep_going: bool, -) -> Result<(), TestError> { - // trace implies print_outcome - if trace { - print_outcome = true; +} + +impl TestRunnerConfig { + fn new(single_thread: bool, trace: bool, print_outcome: bool, keep_going: bool) -> Self { + // Trace implies print_outcome + let print_outcome = print_outcome || trace; + // print_outcome or trace implies single_thread + let single_thread = single_thread || print_outcome; + + Self { + single_thread, + trace, + print_outcome, + keep_going, + } } - // print_outcome or trace implies single_thread - if print_outcome { - single_thread = true; +} + +#[derive(Clone)] +struct TestRunnerState { + n_errors: Arc, + console_bar: Arc, + queue: Arc)>>, + elapsed: Arc>, +} + +impl TestRunnerState { + fn new(test_files: Vec) -> Self { + let n_files = test_files.len(); + Self { + n_errors: Arc::new(AtomicUsize::new(0)), + console_bar: Arc::new(ProgressBar::with_draw_target( + Some(n_files as u64), + ProgressDrawTarget::stdout(), + )), + queue: Arc::new(Mutex::new((0usize, test_files))), + elapsed: Arc::new(Mutex::new(Duration::ZERO)), + } } - let n_files = test_files.len(); - let n_errors = Arc::new(AtomicUsize::new(0)); - let console_bar = Arc::new(ProgressBar::with_draw_target( - Some(n_files as u64), - ProgressDrawTarget::stdout(), - )); - let queue = Arc::new(Mutex::new((0usize, test_files))); - let elapsed = Arc::new(Mutex::new(std::time::Duration::ZERO)); + fn next_test(&self) -> Option { + let (current_idx, queue) = &mut *self.queue.lock().unwrap(); + let idx = *current_idx; + let test_path = queue.get(idx).cloned()?; + *current_idx = idx + 1; + Some(test_path) + } +} - let num_threads = match (single_thread, std::thread::available_parallelism()) { - (true, _) | (false, Err(_)) => 1, - (false, Ok(n)) => n.get(), - }; - let num_threads = num_threads.min(n_files); - let mut handles = Vec::with_capacity(num_threads); - for i in 0..num_threads { - let queue = queue.clone(); - let n_errors = n_errors.clone(); - let console_bar = console_bar.clone(); - let elapsed = elapsed.clone(); +fn run_test_worker(state: TestRunnerState, config: TestRunnerConfig) -> Result<(), TestError> { + loop { + if !config.keep_going && state.n_errors.load(Ordering::SeqCst) > 0 { + return Ok(()); + } + + let Some(test_path) = state.next_test() else { + return Ok(()); + }; + + let result = execute_test_suite( + &test_path, + &state.elapsed, + config.trace, + config.print_outcome, + ); - let thread = std::thread::Builder::new().name(format!("runner-{i}")); + state.console_bar.inc(1); - let f = move || loop { - if !keep_going && n_errors.load(Ordering::SeqCst) > 0 { - return Ok(()); + if let Err(err) = result { + state.n_errors.fetch_add(1, Ordering::SeqCst); + if !config.keep_going { + return Err(err); } + } + } +} - let (_index, test_path) = { - let (current_idx, queue) = &mut *queue.lock().unwrap(); - let prev_idx = *current_idx; - let Some(test_path) = queue.get(prev_idx).cloned() else { - return Ok(()); - }; - *current_idx = prev_idx + 1; - (prev_idx, test_path) - }; +fn determine_thread_count(single_thread: bool, n_files: usize) -> usize { + match (single_thread, std::thread::available_parallelism()) { + (true, _) | (false, Err(_)) => 1, + (false, Ok(n)) => n.get().min(n_files), + } +} - let result = execute_test_suite(&test_path, &elapsed, trace, print_outcome); +/// Run all test files in parallel or single-threaded mode +/// +/// # Arguments +/// * `test_files` - List of test files to execute +/// * `single_thread` - Force single-threaded execution +/// * `trace` - Enable EVM execution tracing +/// * `print_outcome` - Print test outcomes in JSON format +/// * `keep_going` - Continue running tests even if some fail +pub fn run( + test_files: Vec, + single_thread: bool, + trace: bool, + print_outcome: bool, + keep_going: bool, +) -> Result<(), TestError> { + let config = TestRunnerConfig::new(single_thread, trace, print_outcome, keep_going); + let n_files = test_files.len(); + let state = TestRunnerState::new(test_files); + let num_threads = determine_thread_count(config.single_thread, n_files); + + // Spawn worker threads + let mut handles = Vec::with_capacity(num_threads); + for i in 0..num_threads { + let state = state.clone(); - // Increment after the test is done. - console_bar.inc(1); + let thread = std::thread::Builder::new() + .name(format!("runner-{i}")) + .spawn(move || run_test_worker(state, config)) + .unwrap(); - if let Err(err) = result { - n_errors.fetch_add(1, Ordering::SeqCst); - if !keep_going { - return Err(err); - } - } - }; - handles.push(thread.spawn(f).unwrap()); + handles.push(thread); } - // join all threads before returning an error + // Collect results from all threads let mut thread_errors = Vec::new(); for (i, handle) in handles.into_iter().enumerate() { match handle.join() { @@ -544,19 +610,23 @@ pub fn run( Ok(Err(e)) => thread_errors.push(e), Err(_) => thread_errors.push(TestError { name: format!("thread {i} panicked"), + path: String::new(), kind: TestErrorKind::Panic, }), } } - console_bar.finish(); + state.console_bar.finish(); + + // Print summary println!( "Finished execution. Total CPU time: {:.6}s", - elapsed.lock().unwrap().as_secs_f64() + state.elapsed.lock().unwrap().as_secs_f64() ); - let n_errors = n_errors.load(Ordering::SeqCst); + let n_errors = state.n_errors.load(Ordering::SeqCst); let n_thread_errors = thread_errors.len(); + if n_errors == 0 && n_thread_errors == 0 { println!("All tests passed!"); Ok(()) diff --git a/bins/revme/src/cmd/statetest/utils.rs b/bins/revme/src/cmd/statetest/utils.rs index c06310aaf8..3ecc89594a 100644 --- a/bins/revme/src/cmd/statetest/utils.rs +++ b/bins/revme/src/cmd/statetest/utils.rs @@ -1,7 +1,7 @@ use k256::ecdsa::SigningKey; use revm::primitives::Address; -/// Recover the address from a private key (SigningKey). +/// Recover the address from a private key ([SigningKey]). pub fn recover_address(private_key: &[u8]) -> Option
{ let key = SigningKey::from_slice(private_key).ok()?; let public_key = key.verifying_key().to_encoded_point(false); diff --git a/bins/revme/src/dir_utils.rs b/bins/revme/src/dir_utils.rs new file mode 100644 index 0000000000..09406cdd93 --- /dev/null +++ b/bins/revme/src/dir_utils.rs @@ -0,0 +1,16 @@ +use std::path::{Path, PathBuf}; +use walkdir::{DirEntry, WalkDir}; + +pub fn find_all_json_tests(path: &Path) -> Vec { + WalkDir::new(path) + .into_iter() + .filter_map(|e| e.ok()) + .filter(|e| { + e.path() + .extension() + .map(|ext| ext == "json") + .unwrap_or(false) + }) + .map(DirEntry::into_path) + .collect::>() +} diff --git a/bins/revme/src/lib.rs b/bins/revme/src/lib.rs index 52958ec91f..ac10a2022f 100644 --- a/bins/revme/src/lib.rs +++ b/bins/revme/src/lib.rs @@ -1 +1,2 @@ pub mod cmd; +pub mod dir_utils; diff --git a/bins/revme/src/main.rs b/bins/revme/src/main.rs index 4662057476..a509243c22 100644 --- a/bins/revme/src/main.rs +++ b/bins/revme/src/main.rs @@ -1,11 +1,22 @@ +use clap::Parser; use revme::cmd::{Error, MainCmd}; -use structopt::StructOpt; -pub fn main() -> Result<(), Error> { - let cmd = MainCmd::from_args(); - if let Err(e) = cmd.run() { - println!("{:?}", e); - return Err(e); - } - Ok(()) +fn main() -> Result<(), Error> { + set_thread_panic_hook(); + MainCmd::parse().run().inspect_err(|e| println!("{e:?}")) +} + +/// Sets thread panic hook, useful for having tests that panic. +fn set_thread_panic_hook() { + use std::{ + backtrace::Backtrace, + panic::{set_hook, take_hook}, + process::exit, + }; + let orig_hook = take_hook(); + set_hook(Box::new(move |panic_info| { + println!("Custom backtrace: {}", Backtrace::capture()); + orig_hook(panic_info); + exit(1); + })); } diff --git a/book.toml b/book.toml index 8395e94b05..1856280131 100644 --- a/book.toml +++ b/book.toml @@ -1,10 +1,10 @@ [book] -authors = ["Colin Roberts, Waylon Jepsen", "Dragan Rakita"] +authors = ["Dragan Rakita"] language = "en" multilingual = false -src = "documentation/src" -title = "Rust EVM" +src = "book/src" +title = "Revm - Rust Ethereum Virtual Machine" [output.linkcheck] optional = true -follow-web-links = true +follow-web-links = false diff --git a/crates/README.md b/crates/README.md new file mode 100644 index 0000000000..8bb52201fc --- /dev/null +++ b/crates/README.md @@ -0,0 +1,15 @@ +Crates version and their description: +* ![revm](https://img.shields.io/crates/v/revm?height=50?label=revm) main crate, it reexports all other crates. +* ![revm-primitives](https://img.shields.io/crates/v/revm-primitives?label=revm-primitives) contains constants and primitives types that revm uses (alloy-primitives) +* ![revm-interpreter](https://img.shields.io/crates/v/revm-interpreter?label=revm-interpreter) biggest crate in the project, it contains all instructions +* ![revm-precompile](https://img.shields.io/crates/v/revm-precompile?label=revm-precompile) Precompiles defined by ethereum +* ![revm-database-interface](https://img.shields.io/crates/v/revm-database-interface?label=revm-database-interface) Interfaces for database implementation, database is used to fetch runtime state data (accounts, storages and block hash) +* ![revm-database](https://img.shields.io/crates/v/revm-database?label=revm-database) A few structures that implement database interface +* ![revm-bytecode](https://img.shields.io/crates/v/revm-bytecode?label=revm-bytecode) Bytecode legacy analysis and EOF validation. Crate contains opcode tables. +* ![revm-state](https://img.shields.io/crates/v/revm-state?label=revm-state) Small crate with accounts and storage types. +* ![revm-context-interface](https://img.shields.io/crates/v/revm-context-interface?label=revm-context-interface) traits for Block/Transaction/Cfg/Journal. +* ![revm-context](https://img.shields.io/crates/v/revm-context?label=revm-context) default implementation for traits from context interface. +* ![revm-handler](https://img.shields.io/crates/v/revm-handler?label=revm-handler) Contains logic around validation, pre and post execution and handling of call frames. +* ![revm-inspector](https://img.shields.io/crates/v/revm-inspector?label=revm-inspector) Adds support for inspector and implements EIP-3155 tracer. +* ![op-revm](https://img.shields.io/crates/v/op-revm?label=op-revm) Uses revm to create Optimism EVM. +* ![revm-statetest-types](https://img.shields.io/crates/v/revm-statetest-types?label=revm-statetest-types) helpful structs for state test usage. diff --git a/crates/bytecode/CHANGELOG.md b/crates/bytecode/CHANGELOG.md new file mode 100644 index 0000000000..1a20ca601d --- /dev/null +++ b/crates/bytecode/CHANGELOG.md @@ -0,0 +1,251 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [6.2.1](https://github.com/bluealloy/revm/compare/revm-bytecode-v6.2.0...revm-bytecode-v6.2.1) - 2025-08-12 + +### Other + +- Revert "feat: removed padding in case last opcode is terminal ([#2816](https://github.com/bluealloy/revm/pull/2816))" ([#2883](https://github.com/bluealloy/revm/pull/2883)) +- *(bytecode)* remove unused Debug import ([#2879](https://github.com/bluealloy/revm/pull/2879)) +- update outdated opcode memory reference link ([#2859](https://github.com/bluealloy/revm/pull/2859)) + +## [6.2.0](https://github.com/bluealloy/revm/compare/revm-bytecode-v6.1.0...revm-bytecode-v6.2.0) - 2025-08-06 + +### Added + +- removed padding in case last opcode is terminating or unknown ([#2816](https://github.com/bluealloy/revm/pull/2816)) + +### Fixed + +- correct various typos in documentation and comments ([#2855](https://github.com/bluealloy/revm/pull/2855)) + +### Other + +- *(OpCode)* add is_valid ([#2847](https://github.com/bluealloy/revm/pull/2847)) +- update README.md ([#2842](https://github.com/bluealloy/revm/pull/2842)) +- *(benches)* clean up criterion callsites ([#2833](https://github.com/bluealloy/revm/pull/2833)) +- improve ExtBytecode hash handling ([#2826](https://github.com/bluealloy/revm/pull/2826)) +- add rust-version and note about MSRV ([#2789](https://github.com/bluealloy/revm/pull/2789)) +- add OnceLock re-export with no_std support ([#2787](https://github.com/bluealloy/revm/pull/2787)) + +## [6.1.0](https://github.com/bluealloy/revm/compare/revm-bytecode-v6.0.1...revm-bytecode-v6.1.0) - 2025-07-23 + +### Added + +- *(bytecode)* add version getter + make versoin dynamic ([#2751](https://github.com/bluealloy/revm/pull/2751)) + +### Fixed + +- fully deprecate serde-json ([#2767](https://github.com/bluealloy/revm/pull/2767)) + +### Other + +- clean up jump map ([#2764](https://github.com/bluealloy/revm/pull/2764)) +- clean up bytecode analysis ([#2763](https://github.com/bluealloy/revm/pull/2763)) +- Fix typo in EIP-7702 bytecode format comment (magic byte) ([#2733](https://github.com/bluealloy/revm/pull/2733)) + +## [6.0.1](https://github.com/bluealloy/revm/compare/revm-bytecode-v6.0.0...revm-bytecode-v6.0.1) - 2025-07-03 + +### Other + +- add PartialEq u8 ([#2688](https://github.com/bluealloy/revm/pull/2688)) + +## [6.0.0](https://github.com/bluealloy/revm/compare/revm-bytecode-v5.0.0...revm-bytecode-v6.0.0) - 2025-06-30 + +### Fixed + +- implement `PartialEq` for `JumpTable` correctly ([#2654](https://github.com/bluealloy/revm/pull/2654)) + +### Other + +- cargo clippy --fix --all ([#2671](https://github.com/bluealloy/revm/pull/2671)) + +## [5.0.0](https://github.com/bluealloy/revm/compare/revm-bytecode-v4.1.0...revm-bytecode-v5.0.0) - 2025-06-19 + +### Added + +- remove EOF ([#2644](https://github.com/bluealloy/revm/pull/2644)) +- configurable contract size limit ([#2611](https://github.com/bluealloy/revm/pull/2611)) ([#2642](https://github.com/bluealloy/revm/pull/2642)) +- *(precompile)* rug/gmp-based modexp ([#2596](https://github.com/bluealloy/revm/pull/2596)) +- add clz opcode ([#2598](https://github.com/bluealloy/revm/pull/2598)) + +### Other + +- *(tests)* extend test for is_valid jumptable ([#2622](https://github.com/bluealloy/revm/pull/2622)) +- faster JumpTable bits lookup ([#2618](https://github.com/bluealloy/revm/pull/2618)) + +## [4.1.0](https://github.com/bluealloy/revm/compare/revm-bytecode-v4.0.1...revm-bytecode-v4.1.0) - 2025-06-06 + +### Added + +- transact multi tx ([#2517](https://github.com/bluealloy/revm/pull/2517)) + +## [4.0.1](https://github.com/bluealloy/revm/compare/revm-bytecode-v4.0.0...revm-bytecode-v4.0.1) - 2025-05-22 + +### Other + +- make crates.io version badge clickable ([#2526](https://github.com/bluealloy/revm/pull/2526)) + +## [4.0.0](https://github.com/bluealloy/revm/compare/revm-bytecode-v3.0.0...revm-bytecode-v4.0.0) - 2025-05-07 + +### Added + +- *(EOF)* Changes needed for devnet-1 ([#2377](https://github.com/bluealloy/revm/pull/2377)) +- *(bytecode)* improve legacy bytecode padding ([#2423](https://github.com/bluealloy/revm/pull/2423)) + +### Other + +- typos ([#2474](https://github.com/bluealloy/revm/pull/2474)) +- copy edit The Book ([#2463](https://github.com/bluealloy/revm/pull/2463)) +- simplify opcode iter ([#2458](https://github.com/bluealloy/revm/pull/2458)) +- make OPCODE_INFO a static ([#2459](https://github.com/bluealloy/revm/pull/2459)) +- simplify reading signed integers ([#2456](https://github.com/bluealloy/revm/pull/2456)) +- cache and use JumpTable::default ([#2439](https://github.com/bluealloy/revm/pull/2439)) +- bump dependency version ([#2431](https://github.com/bluealloy/revm/pull/2431)) +- fixed broken link ([#2421](https://github.com/bluealloy/revm/pull/2421)) +- *(lints)* revm-context lints ([#2404](https://github.com/bluealloy/revm/pull/2404)) + +## [3.0.0](https://github.com/bluealloy/revm/compare/revm-bytecode-v2.0.0...revm-bytecode-v3.0.0) - 2025-04-09 + +### Added + +- Iteration of bytecode opcodes ([#2349](https://github.com/bluealloy/revm/pull/2349)) + +### Other + +- add 0x prefix to b256! and address! calls ([#2345](https://github.com/bluealloy/revm/pull/2345)) + +## [2.0.0](https://github.com/bluealloy/revm/compare/revm-bytecode-v1.0.0...revm-bytecode-v2.0.0) - 2025-03-28 + +### Fixed + +- fix typo ([#2333](https://github.com/bluealloy/revm/pull/2333)) + +### Other + +- move Eof::new to first place && add doc for some pub functions ([#2334](https://github.com/bluealloy/revm/pull/2334)) +- remove outdated TODO comments ([#2325](https://github.com/bluealloy/revm/pull/2325)) + +## [1.0.0 ](https://github.com/bluealloy/revm/compare/revm-bytecode-v1.0.0-alpha.5...revm-bytecode-v1.0.0) - 2025-03-24 + +Stable version + +## [1.0.0-alpha.5](https://github.com/bluealloy/revm/compare/revm-bytecode-v1.0.0-alpha.4...revm-bytecode-v1.0.0-alpha.5) - 2025-03-21 + +### Other + +- updated the following local packages: revm-primitives + +## [1.0.0-alpha.4](https://github.com/bluealloy/revm/compare/revm-bytecode-v1.0.0-alpha.3...revm-bytecode-v1.0.0-alpha.4) - 2025-03-16 + +### Fixed + +- JumpMap from_slice requires len ([#2203](https://github.com/bluealloy/revm/pull/2203)) + +## [1.0.0-alpha.3](https://github.com/bluealloy/revm/compare/revm-bytecode-v1.0.0-alpha.2...revm-bytecode-v1.0.0-alpha.3) - 2025-03-11 + +### Fixed + +- correct propagate features ([#2177](https://github.com/bluealloy/revm/pull/2177)) + +## [1.0.0-alpha.2](https://github.com/bluealloy/revm/compare/revm-bytecode-v1.0.0-alpha.1...revm-bytecode-v1.0.0-alpha.2) - 2025-03-10 + +### Added + +- remove specification crate ([#2165](https://github.com/bluealloy/revm/pull/2165)) + +### Fixed + +- relax jumptable len check ([#2149](https://github.com/bluealloy/revm/pull/2149)) + +### Other + +- Add docs to revm-bytecode crate ([#2108](https://github.com/bluealloy/revm/pull/2108)) +- move all dependencies to workspace ([#2092](https://github.com/bluealloy/revm/pull/2092)) + +## [1.0.0-alpha.1](https://github.com/bluealloy/revm/releases/tag/revm-bytecode-v1.0.0-alpha.1) - 2025-02-16 + +### Added + +- Add essential EIP-7756 tracing fields (#2023) +- EthHandler trait (#2001) +- *(eip7702)* apply latest EIP-7702 changes, backport from v52 (#1969) +- *(database)* implement order-independent equality for Reverts (#1827) +- Restucturing Part7 Handler and Context rework (#1865) +- restructuring Part6 transaction crate (#1814) +- Merge validation/analyzis with Bytecode (#1793) +- restructure Part2 database crate (#1784) +- project restructuring Part1 (#1776) +- *(examples)* generate block traces (#895) +- implement EIP-4844 (#668) +- *(Shanghai)* All EIPs: push0, warm coinbase, limit/measure initcode (#376) +- Migrate `primitive_types::U256` to `ruint::Uint<256, 4>` (#239) +- Introduce ByteCode format, Update Readme (#156) + +### Fixed + +- fix typos ([#620](https://github.com/bluealloy/revm/pull/620)) + +### Other + +- set alpha.1 version +- Bump licence year to 2025 (#2058) +- align crates versions (#1983) +- fix comments and docs into more sensible (#1920) +- *(crates/bytecode)* fix some comments (#1851) +- some no_std cleanup (#1834) +- fix `constants` module typo (#1801) +- Bump new logo (#1735) +- *(README)* add rbuilder to used-by (#1585) +- added simular to used-by (#1521) +- add Trin to used by list (#1393) +- Fix typo in readme ([#1185](https://github.com/bluealloy/revm/pull/1185)) +- Add Hardhat to the "Used by" list ([#1164](https://github.com/bluealloy/revm/pull/1164)) +- Add VERBS to used by list ([#1141](https://github.com/bluealloy/revm/pull/1141)) +- license date and revm docs (#1080) +- *(docs)* Update the benchmark docs to point to revm package (#906) +- *(docs)* Update top-level benchmark docs (#894) +- clang requirement (#784) +- Readme Updates (#756) +- Logo (#743) +- book workflow ([#537](https://github.com/bluealloy/revm/pull/537)) +- add example to revm crate ([#468](https://github.com/bluealloy/revm/pull/468)) +- Update README.md ([#424](https://github.com/bluealloy/revm/pull/424)) +- add no_std to primitives ([#366](https://github.com/bluealloy/revm/pull/366)) +- revm-precompiles to revm-precompile +- Bump v20, changelog ([#350](https://github.com/bluealloy/revm/pull/350)) +- typos (#232) +- Add support for old forks. ([#191](https://github.com/bluealloy/revm/pull/191)) +- revm bump 1.8. update libs. snailtracer rename ([#159](https://github.com/bluealloy/revm/pull/159)) +- typo fixes +- fix readme typo +- Big Refactor. Machine to Interpreter. refactor instructions. call/create struct ([#52](https://github.com/bluealloy/revm/pull/52)) +- readme. debuger update +- Bump revm v0.3.0. README updated +- readme +- Add time elapsed for tests +- readme updated +- Include Basefee into cost calc. readme change +- Initialize precompile accounts +- Status update. Taking a break +- Merkle calc. Tweaks and debugging for eip158 +- Replace aurora bn lib with parity's. All Bn128Add/Mul/Pair tests passes +- TEMP +- one tab removed +- readme +- README Example simplified +- Gas calculation for Call/Create. Example Added +- readme usage +- README changes +- Static gas cost added +- Subroutine changelogs and reverts +- Readme postulates +- Spelling +- Restructure project +- First iteration. Machine is looking okay diff --git a/crates/bytecode/Cargo.toml b/crates/bytecode/Cargo.toml new file mode 100644 index 0000000000..822ad5ba15 --- /dev/null +++ b/crates/bytecode/Cargo.toml @@ -0,0 +1,46 @@ +[package] +name = "revm-bytecode" +description = "EVM Bytecodes" +version = "6.2.1" +authors.workspace = true +edition.workspace = true +keywords.workspace = true +license.workspace = true +repository.workspace = true +readme.workspace = true + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] + +[lints] +workspace = true + +[dependencies] +# revm +primitives.workspace = true + +# Jumpmap +bitvec = { workspace = true, features = ["alloc"] } + +# Optional +serde = { workspace = true, features = ["derive", "rc"], optional = true } + +# parse opcode feature +paste = { workspace = true, optional = true } +phf = { workspace = true, features = ["macros"], optional = true } + +[features] +default = ["std", "parse"] +std = [ + "serde?/std", + "primitives/std", + "bitvec/std", + "phf?/std", +] +hashbrown = ["primitives/hashbrown"] +serde = ["dep:serde", "primitives/serde", "bitvec/serde", "phf?/serde"] +parse = ["phf", "paste"] + +# Deprecated, please use `serde` feature instead. +serde-json = ["serde"] diff --git a/bins/revm-test/LICENSE b/crates/bytecode/LICENSE similarity index 96% rename from bins/revm-test/LICENSE rename to crates/bytecode/LICENSE index ad98ff22cc..be6d350ebe 100644 --- a/bins/revm-test/LICENSE +++ b/crates/bytecode/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2021-2024 draganrakita +Copyright (c) 2021-2025 draganrakita Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/crates/bytecode/src/bytecode.rs b/crates/bytecode/src/bytecode.rs new file mode 100644 index 0000000000..a6f09b7aa5 --- /dev/null +++ b/crates/bytecode/src/bytecode.rs @@ -0,0 +1,185 @@ +//! Module that contains the bytecode enum with all variants supported by Ethereum mainnet. +//! +//! Those are: +//! - Legacy bytecode with jump table analysis. Found in [`LegacyAnalyzedBytecode`] +//! - EIP-7702 bytecode, introduces in Prague and contains address to delegated account. + +use crate::{ + eip7702::{Eip7702Bytecode, EIP7702_MAGIC_BYTES}, + BytecodeDecodeError, JumpTable, LegacyAnalyzedBytecode, LegacyRawBytecode, +}; +use primitives::{keccak256, Address, Bytes, B256, KECCAK_EMPTY}; + +/// Main bytecode structure with all variants. +#[derive(Clone, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub enum Bytecode { + /// EIP-7702 delegated bytecode + Eip7702(Eip7702Bytecode), + /// The bytecode has been analyzed for valid jump destinations. + LegacyAnalyzed(LegacyAnalyzedBytecode), +} + +impl Default for Bytecode { + #[inline] + fn default() -> Self { + Self::new() + } +} + +impl Bytecode { + /// Creates a new legacy analyzed [`Bytecode`] with exactly one STOP opcode. + #[inline] + pub fn new() -> Self { + Self::LegacyAnalyzed(LegacyAnalyzedBytecode::default()) + } + + /// Returns jump table if bytecode is analyzed. + #[inline] + pub fn legacy_jump_table(&self) -> Option<&JumpTable> { + match &self { + Self::LegacyAnalyzed(analyzed) => Some(analyzed.jump_table()), + _ => None, + } + } + + /// Calculates hash of the bytecode. + #[inline] + pub fn hash_slow(&self) -> B256 { + if self.is_empty() { + KECCAK_EMPTY + } else { + keccak256(self.original_byte_slice()) + } + } + + /// Returns `true` if bytecode is EIP-7702. + #[inline] + pub const fn is_eip7702(&self) -> bool { + matches!(self, Self::Eip7702(_)) + } + + /// Creates a new legacy [`Bytecode`]. + #[inline] + pub fn new_legacy(raw: Bytes) -> Self { + Self::LegacyAnalyzed(LegacyRawBytecode(raw).into_analyzed()) + } + + /// Creates a new raw [`Bytecode`]. + /// + /// # Panics + /// + /// Panics if bytecode is in incorrect format. If you want to handle errors use [`Self::new_raw_checked`]. + #[inline] + pub fn new_raw(bytecode: Bytes) -> Self { + Self::new_raw_checked(bytecode).expect("Expect correct bytecode") + } + + /// Creates a new EIP-7702 [`Bytecode`] from [`Address`]. + #[inline] + pub fn new_eip7702(address: Address) -> Self { + Self::Eip7702(Eip7702Bytecode::new(address)) + } + + /// Creates a new raw [`Bytecode`]. + /// + /// Returns an error on incorrect bytecode format. + #[inline] + pub fn new_raw_checked(bytes: Bytes) -> Result { + let prefix = bytes.get(..2); + match prefix { + Some(prefix) if prefix == &EIP7702_MAGIC_BYTES => { + let eip7702 = Eip7702Bytecode::new_raw(bytes)?; + Ok(Self::Eip7702(eip7702)) + } + _ => Ok(Self::new_legacy(bytes)), + } + } + + /// Create new checked bytecode. + /// + /// # Panics + /// + /// For possible panics see [`LegacyAnalyzedBytecode::new`]. + #[inline] + pub fn new_analyzed(bytecode: Bytes, original_len: usize, jump_table: JumpTable) -> Self { + Self::LegacyAnalyzed(LegacyAnalyzedBytecode::new( + bytecode, + original_len, + jump_table, + )) + } + + /// Returns a reference to the bytecode. + #[inline] + pub fn bytecode(&self) -> &Bytes { + match self { + Self::LegacyAnalyzed(analyzed) => analyzed.bytecode(), + Self::Eip7702(code) => code.raw(), + } + } + + /// Pointer to the executable bytecode. + #[inline] + pub fn bytecode_ptr(&self) -> *const u8 { + self.bytecode().as_ptr() + } + + /// Returns bytes. + #[inline] + pub fn bytes(&self) -> Bytes { + self.bytes_ref().clone() + } + + /// Returns raw bytes reference. + #[inline] + pub fn bytes_ref(&self) -> &Bytes { + match self { + Self::LegacyAnalyzed(analyzed) => analyzed.bytecode(), + Self::Eip7702(code) => code.raw(), + } + } + + /// Returns raw bytes slice. + #[inline] + pub fn bytes_slice(&self) -> &[u8] { + self.bytes_ref() + } + + /// Returns the original bytecode. + #[inline] + pub fn original_bytes(&self) -> Bytes { + match self { + Self::LegacyAnalyzed(analyzed) => analyzed.original_bytes(), + Self::Eip7702(eip7702) => eip7702.raw().clone(), + } + } + + /// Returns the original bytecode as a byte slice. + #[inline] + pub fn original_byte_slice(&self) -> &[u8] { + match self { + Self::LegacyAnalyzed(analyzed) => analyzed.original_byte_slice(), + Self::Eip7702(eip7702) => eip7702.raw(), + } + } + + /// Returns the length of the original bytes. + #[inline] + pub fn len(&self) -> usize { + self.original_byte_slice().len() + } + + /// Returns whether the bytecode is empty. + #[inline] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Returns an iterator over the opcodes in this bytecode, skipping immediates. + /// This is useful if you want to ignore immediates and just see what opcodes are inside. + #[inline] + pub fn iter_opcodes(&self) -> crate::BytecodeIterator<'_> { + crate::BytecodeIterator::new(self) + } +} diff --git a/crates/bytecode/src/decode_errors.rs b/crates/bytecode/src/decode_errors.rs new file mode 100644 index 0000000000..f281e4f355 --- /dev/null +++ b/crates/bytecode/src/decode_errors.rs @@ -0,0 +1,27 @@ +use crate::eip7702::Eip7702DecodeError; +use core::fmt::Debug; +use std::fmt; + +/// Bytecode decode errors +#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub enum BytecodeDecodeError { + /// EIP-7702 decode error + Eip7702(Eip7702DecodeError), +} + +impl From for BytecodeDecodeError { + fn from(error: Eip7702DecodeError) -> Self { + Self::Eip7702(error) + } +} + +impl core::error::Error for BytecodeDecodeError {} + +impl fmt::Display for BytecodeDecodeError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Eip7702(e) => fmt::Display::fmt(e, f), + } + } +} diff --git a/crates/bytecode/src/eip7702.rs b/crates/bytecode/src/eip7702.rs new file mode 100644 index 0000000000..f2c7ef8855 --- /dev/null +++ b/crates/bytecode/src/eip7702.rs @@ -0,0 +1,157 @@ +use core::fmt; +use primitives::{b256, bytes, Address, Bytes, B256}; + +/// Hash of EF01 bytes that is used for EXTCODEHASH when called from legacy bytecode. +pub const EIP7702_MAGIC_HASH: B256 = + b256!("0xeadcdba66a79ab5dce91622d1d75c8cff5cff0b96944c3bf1072cd08ce018329"); + +/// EIP-7702 Version Magic in u16 form +pub const EIP7702_MAGIC: u16 = 0xEF01; + +/// EIP-7702 magic number in array form +pub static EIP7702_MAGIC_BYTES: Bytes = bytes!("ef01"); + +/// EIP-7702 first version of bytecode +pub const EIP7702_VERSION: u8 = 0; + +/// Bytecode of delegated account, specified in EIP-7702 +/// +/// Format of EIP-7702 bytecode consist of: +/// `0xEF01` (MAGIC) + `0x00` (VERSION) + 20 bytes of address. +#[derive(Clone, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct Eip7702Bytecode { + /// Address of the delegated account. + pub delegated_address: Address, + /// Version of the EIP-7702 bytecode. Currently only version 0 is supported. + pub version: u8, + /// Raw bytecode. + pub raw: Bytes, +} + +impl Eip7702Bytecode { + /// Creates a new EIP-7702 bytecode or returns None if the raw bytecode is invalid. + #[inline] + pub fn new_raw(raw: Bytes) -> Result { + if raw.len() != 23 { + return Err(Eip7702DecodeError::InvalidLength); + } + if !raw.starts_with(&EIP7702_MAGIC_BYTES) { + return Err(Eip7702DecodeError::InvalidMagic); + } + + // Only supported version is version 0. + if raw[2] != EIP7702_VERSION { + return Err(Eip7702DecodeError::UnsupportedVersion); + } + + Ok(Self { + delegated_address: Address::new(raw[3..].try_into().unwrap()), + version: raw[2], + raw, + }) + } + + /// Creates a new EIP-7702 bytecode with the given address. + pub fn new(address: Address) -> Self { + let mut raw = EIP7702_MAGIC_BYTES.to_vec(); + raw.push(EIP7702_VERSION); + raw.extend(&address); + Self { + delegated_address: address, + version: EIP7702_VERSION, + raw: raw.into(), + } + } + + /// Returns the raw bytecode with version MAGIC number. + #[inline] + pub fn raw(&self) -> &Bytes { + &self.raw + } + + /// Returns the address of the delegated contract. + #[inline] + pub fn address(&self) -> Address { + self.delegated_address + } + + /// Returns the EIP7702 version of the delegated contract. + #[inline] + pub fn version(&self) -> u8 { + self.version + } +} + +/// Bytecode errors +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub enum Eip7702DecodeError { + /// Invalid length of the raw bytecode + /// + /// It should be 23 bytes. + InvalidLength, + /// Invalid magic number + /// + /// All Eip7702 bytecodes should start with the magic number 0xEF01. + InvalidMagic, + /// Unsupported version + /// + /// Only supported version is version 0x00 + UnsupportedVersion, +} + +impl fmt::Display for Eip7702DecodeError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let s = match self { + Self::InvalidLength => "Eip7702 is not 23 bytes long", + Self::InvalidMagic => "Bytecode is not starting with 0xEF01", + Self::UnsupportedVersion => "Unsupported Eip7702 version.", + }; + f.write_str(s) + } +} + +impl core::error::Error for Eip7702DecodeError {} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn sanity_decode() { + let raw = bytes!("ef01deadbeef"); + assert_eq!( + Eip7702Bytecode::new_raw(raw), + Err(Eip7702DecodeError::InvalidLength) + ); + + let raw = bytes!("ef0101deadbeef00000000000000000000000000000000"); + assert_eq!( + Eip7702Bytecode::new_raw(raw), + Err(Eip7702DecodeError::UnsupportedVersion) + ); + + let raw = bytes!("ef0100deadbeef00000000000000000000000000000000"); + let address = raw[3..].try_into().unwrap(); + assert_eq!( + Eip7702Bytecode::new_raw(raw.clone()), + Ok(Eip7702Bytecode { + delegated_address: address, + version: 0, + raw, + }) + ); + } + + #[test] + fn create_eip7702_bytecode_from_address() { + let address = Address::new([0x01; 20]); + let bytecode = Eip7702Bytecode::new(address); + assert_eq!(bytecode.delegated_address, address); + assert_eq!( + bytecode.raw, + bytes!("ef01000101010101010101010101010101010101010101") + ); + } +} diff --git a/crates/bytecode/src/iter.rs b/crates/bytecode/src/iter.rs new file mode 100644 index 0000000000..17d47ac4d1 --- /dev/null +++ b/crates/bytecode/src/iter.rs @@ -0,0 +1,290 @@ +use crate::{opcode, Bytecode, OpCode}; + +/// Iterator over opcodes in a bytecode, skipping immediates. +/// +/// This allows you to iterate through the actual opcodes in the bytecode, +/// without dealing with the immediate values that follow instructions. +#[derive(Debug, Clone)] +pub struct BytecodeIterator<'a> { + /// Iterator over the bytecode bytes. + bytes: core::slice::Iter<'a, u8>, + /// Start pointer of the bytecode. Only used to calculate [`position`](Self::position). + start: *const u8, +} + +impl<'a> BytecodeIterator<'a> { + /// Creates a new iterator from a bytecode reference. + #[inline] + pub fn new(bytecode: &'a Bytecode) -> Self { + let bytes = match bytecode { + Bytecode::LegacyAnalyzed(_) => &bytecode.bytecode()[..], + Bytecode::Eip7702(_) => &[], + }; + Self { + bytes: bytes.iter(), + start: bytes.as_ptr(), + } + } + + /// Skips to the next opcode, taking into account PUSH instructions. + pub fn skip_to_next_opcode(&mut self) { + self.next(); + } + + /// Returns the remaining bytes in the bytecode as a slice. + #[inline] + pub fn as_slice(&self) -> &[u8] { + self.bytes.as_slice() + } + + /// Returns the current position in the bytecode. + #[inline] + pub fn position(&self) -> usize { + // SAFETY: `start` always points to the start of the bytecode. + unsafe { self.bytes.as_slice().as_ptr().offset_from(self.start) as usize } + } + + #[inline] + fn skip_immediate(&mut self, opcode: u8) { + // Get base immediate size from opcode info + let immediate_size = opcode::OPCODE_INFO[opcode as usize] + .map(|info| info.immediate_size() as usize) + .unwrap_or_default(); + + // Advance the iterator by the immediate size + if immediate_size > 0 { + self.bytes = self + .bytes + .as_slice() + .get(immediate_size..) + .unwrap_or_default() + .iter(); + } + } + + /// Returns the current opcode without advancing the iterator. + #[inline] + pub fn peek(&self) -> Option { + self.bytes.as_slice().first().copied() + } + + /// Returns the current opcode wrapped in OpCode without advancing the iterator. + #[inline] + pub fn peek_opcode(&self) -> Option { + self.peek().and_then(OpCode::new) + } +} + +impl Iterator for BytecodeIterator<'_> { + type Item = u8; + + #[inline] + fn next(&mut self) -> Option { + self.bytes + .next() + .copied() + .inspect(|¤t| self.skip_immediate(current)) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + // Lower bound is 0 if empty, 1 if not empty as it depends on the bytes. + let byte_len = self.bytes.len(); + (byte_len.min(1), Some(byte_len)) + } +} + +impl core::iter::FusedIterator for BytecodeIterator<'_> {} + +#[cfg(test)] +mod tests { + use super::*; + use crate::LegacyRawBytecode; + use primitives::Bytes; + + #[test] + fn test_simple_bytecode_iteration() { + // Create a simple bytecode: PUSH1 0x01 PUSH1 0x02 ADD STOP + let bytecode_data = vec![ + opcode::PUSH1, + 0x01, + opcode::PUSH1, + 0x02, + opcode::ADD, + opcode::STOP, + ]; + let raw_bytecode = LegacyRawBytecode(Bytes::from(bytecode_data)); + let bytecode = Bytecode::LegacyAnalyzed(raw_bytecode.into_analyzed()); + let opcodes: Vec = bytecode.iter_opcodes().collect(); + // We should only see the opcodes, not the immediates + assert_eq!( + opcodes, + vec![opcode::PUSH1, opcode::PUSH1, opcode::ADD, opcode::STOP] + ); + } + + #[test] + fn test_bytecode_with_various_push_sizes() { + // PUSH1 0x01, PUSH2 0x0203, PUSH3 0x040506, STOP + let bytecode_data = vec![ + opcode::PUSH1, + 0x01, + opcode::PUSH2, + 0x02, + 0x03, + opcode::PUSH3, + 0x04, + 0x05, + 0x06, + opcode::STOP, + ]; + let raw_bytecode = LegacyRawBytecode(Bytes::from(bytecode_data)); + let bytecode = Bytecode::LegacyAnalyzed(raw_bytecode.into_analyzed()); + + let opcodes: Vec = bytecode.iter_opcodes().collect(); + + // We should only see the opcodes, not the immediates + assert_eq!( + opcodes, + vec![opcode::PUSH1, opcode::PUSH2, opcode::PUSH3, opcode::STOP] + ); + } + + #[test] + fn test_bytecode_skips_immediates() { + // Create a bytecode with various PUSH operations + let bytecode_data = vec![ + opcode::PUSH1, + 0x01, // PUSH1 0x01 + opcode::PUSH2, + 0x02, + 0x03, // PUSH2 0x0203 + opcode::ADD, // ADD + opcode::PUSH3, + 0x04, + 0x05, + 0x06, // PUSH3 0x040506 + opcode::PUSH32, + 0x10, + 0x11, + 0x12, + 0x13, // PUSH32 with 32 bytes of immediate data + 0x14, + 0x15, + 0x16, + 0x17, + 0x18, + 0x19, + 0x1a, + 0x1b, + 0x1c, + 0x1d, + 0x1e, + 0x1f, + 0x20, + 0x21, + 0x22, + 0x23, + 0x24, + 0x25, + 0x26, + 0x27, + 0x28, + 0x29, + 0x2a, + 0x2b, + 0x2c, + 0x2d, + 0x2e, + 0x2f, + opcode::MUL, // MUL + opcode::STOP, // STOP + ]; + + let raw_bytecode = LegacyRawBytecode(Bytes::from(bytecode_data)); + let bytecode = Bytecode::LegacyAnalyzed(raw_bytecode.into_analyzed()); + + // Use the iterator directly + let iter = BytecodeIterator::new(&bytecode); + let opcodes: Vec = iter.collect(); + + // Should only include the opcodes, not the immediates + assert_eq!( + opcodes, + vec![ + opcode::PUSH1, + opcode::PUSH2, + opcode::ADD, + opcode::PUSH3, + opcode::PUSH32, + opcode::MUL, + opcode::STOP, + ] + ); + + // Use the method on the bytecode struct + let opcodes: Vec = bytecode.iter_opcodes().collect(); + assert_eq!( + opcodes, + vec![ + opcode::PUSH1, + opcode::PUSH2, + opcode::ADD, + opcode::PUSH3, + opcode::PUSH32, + opcode::MUL, + opcode::STOP, + ] + ); + } + + #[test] + fn test_position_tracking() { + // PUSH1 0x01, PUSH1 0x02, ADD, STOP + let bytecode_data = vec![ + opcode::PUSH1, + 0x01, + opcode::PUSH1, + 0x02, + opcode::ADD, + opcode::STOP, + ]; + let raw_bytecode = LegacyRawBytecode(Bytes::from(bytecode_data)); + let bytecode = Bytecode::LegacyAnalyzed(raw_bytecode.into_analyzed()); + + let mut iter = bytecode.iter_opcodes(); + + // Start at position 0 + assert_eq!(iter.position(), 0); + assert_eq!(iter.next(), Some(opcode::PUSH1)); + // After PUSH1, position should be 2 (PUSH1 + immediate) + assert_eq!(iter.position(), 2); + + assert_eq!(iter.next(), Some(opcode::PUSH1)); + // After second PUSH1, position should be 4 (2 + PUSH1 + immediate) + assert_eq!(iter.position(), 4); + + assert_eq!(iter.next(), Some(opcode::ADD)); + // After ADD, position should be 5 (4 + ADD) + assert_eq!(iter.position(), 5); + + assert_eq!(iter.next(), Some(opcode::STOP)); + // After STOP, position should be 6 (5 + STOP) + assert_eq!(iter.position(), 6); + + // No more opcodes + assert_eq!(iter.next(), None); + assert_eq!(iter.position(), 6); + } + + #[test] + fn test_empty_bytecode() { + // Empty bytecode (just STOP) + let bytecode_data = vec![opcode::STOP]; + let raw_bytecode = LegacyRawBytecode(Bytes::from(bytecode_data)); + let bytecode = Bytecode::LegacyAnalyzed(raw_bytecode.into_analyzed()); + + let opcodes: Vec = bytecode.iter_opcodes().collect(); + assert_eq!(opcodes, vec![opcode::STOP]); + } +} diff --git a/crates/bytecode/src/legacy.rs b/crates/bytecode/src/legacy.rs new file mode 100644 index 0000000000..71a6117bb3 --- /dev/null +++ b/crates/bytecode/src/legacy.rs @@ -0,0 +1,9 @@ +mod analysis; +mod analyzed; +mod jump_map; +mod raw; + +pub use analysis::analyze_legacy; +pub use analyzed::LegacyAnalyzedBytecode; +pub use jump_map::JumpTable; +pub use raw::LegacyRawBytecode; diff --git a/crates/bytecode/src/legacy/analysis.rs b/crates/bytecode/src/legacy/analysis.rs new file mode 100644 index 0000000000..193b188642 --- /dev/null +++ b/crates/bytecode/src/legacy/analysis.rs @@ -0,0 +1,176 @@ +use super::JumpTable; +use crate::opcode; +use bitvec::{bitvec, order::Lsb0, vec::BitVec}; +use primitives::Bytes; +use std::vec::Vec; + +/// Analyzes the bytecode for use in [`LegacyAnalyzedBytecode`](crate::LegacyAnalyzedBytecode). +/// +/// See [`LegacyAnalyzedBytecode`](crate::LegacyAnalyzedBytecode) for more details. +/// +/// Prefer using [`LegacyAnalyzedBytecode::analyze`](crate::LegacyAnalyzedBytecode::analyze) instead. +pub fn analyze_legacy(bytecode: Bytes) -> (JumpTable, Bytes) { + if bytecode.is_empty() { + return (JumpTable::default(), Bytes::from_static(&[opcode::STOP])); + } + + let mut jumps: BitVec = bitvec![u8, Lsb0; 0; bytecode.len()]; + let range = bytecode.as_ptr_range(); + let start = range.start; + let mut iterator = start; + let end = range.end; + let mut opcode = 0; + + while iterator < end { + opcode = unsafe { *iterator }; + if opcode == opcode::JUMPDEST { + // SAFETY: Jumps are max length of the code + unsafe { jumps.set_unchecked(iterator.offset_from(start) as usize, true) } + iterator = unsafe { iterator.add(1) }; + } else { + let push_offset = opcode.wrapping_sub(opcode::PUSH1); + if push_offset < 32 { + // SAFETY: Iterator access range is checked in the while loop + iterator = unsafe { iterator.add(push_offset as usize + 2) }; + } else { + // SAFETY: Iterator access range is checked in the while loop + iterator = unsafe { iterator.add(1) }; + } + } + } + + let padding = (iterator as usize) - (end as usize) + (opcode != opcode::STOP) as usize; + let bytecode = if padding > 0 { + let mut padded = Vec::with_capacity(bytecode.len() + padding); + padded.extend_from_slice(&bytecode); + padded.resize(padded.len() + padding, 0); + Bytes::from(padded) + } else { + bytecode + }; + + (JumpTable::new(jumps), bytecode) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_bytecode_ends_with_stop_no_padding_needed() { + let bytecode = vec![ + opcode::PUSH1, + 0x01, + opcode::PUSH1, + 0x02, + opcode::ADD, + opcode::STOP, + ]; + let (_, padded_bytecode) = analyze_legacy(bytecode.clone().into()); + assert_eq!(padded_bytecode.len(), bytecode.len()); + } + + #[test] + fn test_bytecode_ends_without_stop_requires_padding() { + let bytecode = vec![opcode::PUSH1, 0x01, opcode::PUSH1, 0x02, opcode::ADD]; + let (_, padded_bytecode) = analyze_legacy(bytecode.clone().into()); + assert_eq!(padded_bytecode.len(), bytecode.len() + 1); + } + + #[test] + fn test_bytecode_ends_with_push16_requires_17_bytes_padding() { + let bytecode = vec![opcode::PUSH1, 0x01, opcode::PUSH16]; + let (_, padded_bytecode) = analyze_legacy(bytecode.clone().into()); + assert_eq!(padded_bytecode.len(), bytecode.len() + 17); + } + + #[test] + fn test_bytecode_ends_with_push2_requires_2_bytes_padding() { + let bytecode = vec![opcode::PUSH1, 0x01, opcode::PUSH2, 0x02]; + let (_, padded_bytecode) = analyze_legacy(bytecode.clone().into()); + assert_eq!(padded_bytecode.len(), bytecode.len() + 2); + } + + #[test] + fn test_empty_bytecode_requires_stop() { + let bytecode = vec![]; + let (_, padded_bytecode) = analyze_legacy(bytecode.clone().into()); + assert_eq!(padded_bytecode.len(), 1); // Just STOP + } + + #[test] + fn test_bytecode_with_jumpdest_at_start() { + let bytecode = vec![opcode::JUMPDEST, opcode::PUSH1, 0x01, opcode::STOP]; + let (jump_table, _) = analyze_legacy(bytecode.clone().into()); + assert!(jump_table.is_valid(0)); // First byte should be a valid jumpdest + } + + #[test] + fn test_bytecode_with_jumpdest_after_push() { + let bytecode = vec![opcode::PUSH1, 0x01, opcode::JUMPDEST, opcode::STOP]; + let (jump_table, _) = analyze_legacy(bytecode.clone().into()); + assert!(jump_table.is_valid(2)); // JUMPDEST should be at position 2 + } + + #[test] + fn test_bytecode_with_multiple_jumpdests() { + let bytecode = vec![ + opcode::JUMPDEST, + opcode::PUSH1, + 0x01, + opcode::JUMPDEST, + opcode::STOP, + ]; + let (jump_table, _) = analyze_legacy(bytecode.clone().into()); + assert!(jump_table.is_valid(0)); // First JUMPDEST + assert!(jump_table.is_valid(3)); // Second JUMPDEST + } + + #[test] + fn test_bytecode_with_max_push32() { + let bytecode = vec![opcode::PUSH32]; + let (_, padded_bytecode) = analyze_legacy(bytecode.clone().into()); + assert_eq!(padded_bytecode.len(), bytecode.len() + 33); // PUSH32 + 32 bytes + STOP + } + + #[test] + fn test_bytecode_with_invalid_opcode() { + let bytecode = vec![0xFF, opcode::STOP]; // 0xFF is an invalid opcode + let (jump_table, _) = analyze_legacy(bytecode.clone().into()); + assert!(!jump_table.is_valid(0)); // Invalid opcode should not be a jumpdest + } + + #[test] + fn test_bytecode_with_sequential_pushes() { + let bytecode = vec![ + opcode::PUSH1, + 0x01, + opcode::PUSH2, + 0x02, + 0x03, + opcode::PUSH4, + 0x04, + 0x05, + 0x06, + 0x07, + opcode::STOP, + ]; + let (jump_table, padded_bytecode) = analyze_legacy(bytecode.clone().into()); + assert_eq!(padded_bytecode.len(), bytecode.len()); + assert!(!jump_table.is_valid(0)); // PUSH1 + assert!(!jump_table.is_valid(2)); // PUSH2 + assert!(!jump_table.is_valid(5)); // PUSH4 + } + + #[test] + fn test_bytecode_with_jumpdest_in_push_data() { + let bytecode = vec![ + opcode::PUSH2, + opcode::JUMPDEST, // This should not be treated as a JUMPDEST + 0x02, + opcode::STOP, + ]; + let (jump_table, _) = analyze_legacy(bytecode.clone().into()); + assert!(!jump_table.is_valid(1)); // JUMPDEST in push data should not be valid + } +} diff --git a/crates/bytecode/src/legacy/analyzed.rs b/crates/bytecode/src/legacy/analyzed.rs new file mode 100644 index 0000000000..72b0a43069 --- /dev/null +++ b/crates/bytecode/src/legacy/analyzed.rs @@ -0,0 +1,155 @@ +use super::JumpTable; +use primitives::Bytes; + +/// Legacy analyzed bytecode represents the original bytecode format used in Ethereum. +/// +/// # Jump Table +/// +/// A jump table maps valid jump destinations in the bytecode. +/// +/// While other EVM implementations typically analyze bytecode and cache jump tables at runtime, +/// Revm requires the jump table to be pre-computed and contained alongside the code, +/// and present with the bytecode when executing. +/// +/// # Bytecode Padding +/// +/// Legacy bytecode can be padded with up to 33 zero bytes at the end. This padding ensures that: +/// - the bytecode always ends with a valid STOP (0x00) opcode. +/// - there aren't incomplete immediates, meaning we can skip bounds checks in `PUSH*` instructions. +/// +/// The non-padded length is stored in order to be able to copy the original bytecode. +/// +/// # Gas safety +/// +/// When bytecode is created through CREATE, CREATE2, or contract creation transactions, it undergoes +/// analysis to generate its jump table. This analysis is O(n) on side of bytecode that is expensive, +/// but the high gas cost required to store bytecode in the database is high enough to cover the +/// expense of doing analysis and generate the jump table. +#[derive(Clone, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct LegacyAnalyzedBytecode { + /// The potentially padded bytecode. + bytecode: Bytes, + /// The original bytecode length. + original_len: usize, + /// The jump table. + jump_table: JumpTable, +} + +impl Default for LegacyAnalyzedBytecode { + #[inline] + fn default() -> Self { + Self { + bytecode: Bytes::from_static(&[0]), + original_len: 0, + jump_table: JumpTable::default(), + } + } +} + +impl LegacyAnalyzedBytecode { + /// Analyzes the bytecode. + /// + /// See [`LegacyAnalyzedBytecode`] for more details. + pub fn analyze(bytecode: Bytes) -> Self { + let original_len = bytecode.len(); + let (jump_table, padded_bytecode) = super::analysis::analyze_legacy(bytecode); + Self::new(padded_bytecode, original_len, jump_table) + } + + /// Creates new analyzed bytecode. + /// + /// Prefer instantiating using [`analyze`](Self::analyze) instead. + /// + /// # Panics + /// + /// * If `original_len` is greater than `bytecode.len()` + /// * If jump table length is less than `original_len`. + /// * If bytecode is empty. + pub fn new(bytecode: Bytes, original_len: usize, jump_table: JumpTable) -> Self { + assert!( + original_len <= bytecode.len(), + "original_len is greater than bytecode length" + ); + assert!( + original_len <= jump_table.len(), + "jump table length is less than original length" + ); + assert!(!bytecode.is_empty(), "bytecode cannot be empty"); + Self { + bytecode, + original_len, + jump_table, + } + } + + /// Returns a reference to the bytecode. + /// + /// The bytecode is padded with 32 zero bytes. + pub fn bytecode(&self) -> &Bytes { + &self.bytecode + } + + /// Returns original bytes length. + pub fn original_len(&self) -> usize { + self.original_len + } + + /// Returns original bytes without padding. + pub fn original_bytes(&self) -> Bytes { + self.bytecode.slice(..self.original_len) + } + + /// Returns original bytes without padding. + pub fn original_byte_slice(&self) -> &[u8] { + &self.bytecode[..self.original_len] + } + + /// Returns [JumpTable] of analyzed bytes. + pub fn jump_table(&self) -> &JumpTable { + &self.jump_table + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{opcode, LegacyRawBytecode}; + use bitvec::{bitvec, order::Lsb0}; + + #[test] + fn test_bytecode_new() { + let bytecode = Bytes::from_static(&[opcode::PUSH1, 0x01]); + let bytecode = LegacyRawBytecode(bytecode).into_analyzed(); + let _ = LegacyAnalyzedBytecode::new( + bytecode.bytecode, + bytecode.original_len, + bytecode.jump_table, + ); + } + + #[test] + #[should_panic(expected = "original_len is greater than bytecode length")] + fn test_panic_on_large_original_len() { + let bytecode = Bytes::from_static(&[opcode::PUSH1, 0x01]); + let bytecode = LegacyRawBytecode(bytecode).into_analyzed(); + let _ = LegacyAnalyzedBytecode::new(bytecode.bytecode, 100, bytecode.jump_table); + } + + #[test] + #[should_panic(expected = "jump table length is less than original length")] + fn test_panic_on_short_jump_table() { + let bytecode = Bytes::from_static(&[opcode::PUSH1, 0x01]); + let bytecode = LegacyRawBytecode(bytecode).into_analyzed(); + let jump_table = JumpTable::new(bitvec![u8, Lsb0; 0; 1]); + let _ = LegacyAnalyzedBytecode::new(bytecode.bytecode, bytecode.original_len, jump_table); + } + + #[test] + #[should_panic(expected = "bytecode cannot be empty")] + fn test_panic_on_empty_bytecode() { + let bytecode = Bytes::from_static(&[]); + let jump_table = JumpTable::new(bitvec![u8, Lsb0; 0; 0]); + let _ = LegacyAnalyzedBytecode::new(bytecode, 0, jump_table); + } +} diff --git a/crates/bytecode/src/legacy/jump_map.rs b/crates/bytecode/src/legacy/jump_map.rs new file mode 100644 index 0000000000..b4a99ebd7f --- /dev/null +++ b/crates/bytecode/src/legacy/jump_map.rs @@ -0,0 +1,332 @@ +use bitvec::vec::BitVec; +use core::{ + cmp::Ordering, + hash::{Hash, Hasher}, +}; +use primitives::{hex, OnceLock}; +use std::{fmt::Debug, sync::Arc}; + +/// A table of valid `jump` destinations. +/// +/// It is immutable, cheap to clone and memory efficient, with one bit per byte in the bytecode. +#[derive(Clone, Eq)] +pub struct JumpTable { + /// Pointer into `table` to avoid `Arc` overhead on lookup. + table_ptr: *const u8, + /// Number of bits in the table. + len: usize, + /// Actual bit vec + table: Arc>, +} + +// SAFETY: BitVec data is immutable through Arc, pointer won't be invalidated +unsafe impl Send for JumpTable {} +unsafe impl Sync for JumpTable {} + +impl PartialEq for JumpTable { + fn eq(&self, other: &Self) -> bool { + self.table.eq(&other.table) + } +} + +impl Hash for JumpTable { + fn hash(&self, state: &mut H) { + self.table.hash(state); + } +} + +impl PartialOrd for JumpTable { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for JumpTable { + fn cmp(&self, other: &Self) -> Ordering { + self.table.cmp(&other.table) + } +} + +#[cfg(feature = "serde")] +impl serde::Serialize for JumpTable { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + self.table.serialize(serializer) + } +} + +#[cfg(feature = "serde")] +impl<'de> serde::Deserialize<'de> for JumpTable { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let bitvec = BitVec::deserialize(deserializer)?; + Ok(Self::new(bitvec)) + } +} + +impl Debug for JumpTable { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_struct("JumpTable") + .field("map", &hex::encode(self.table.as_raw_slice())) + .finish() + } +} + +impl Default for JumpTable { + #[inline] + fn default() -> Self { + static DEFAULT: OnceLock = OnceLock::new(); + DEFAULT.get_or_init(|| Self::new(BitVec::default())).clone() + } +} + +impl JumpTable { + /// Create new JumpTable directly from an existing BitVec. + pub fn new(jumps: BitVec) -> Self { + let table = Arc::new(jumps); + let table_ptr = table.as_raw_slice().as_ptr(); + let len = table.len(); + + Self { + table, + table_ptr, + len, + } + } + + /// Gets the raw bytes of the jump map. + #[inline] + pub fn as_slice(&self) -> &[u8] { + self.table.as_raw_slice() + } + + /// Gets the length of the jump map. + #[inline] + pub fn len(&self) -> usize { + self.len + } + + /// Returns true if the jump map is empty. + #[inline] + pub fn is_empty(&self) -> bool { + self.len == 0 + } + + /// Constructs a jump map from raw bytes and length. + /// + /// Bit length represents number of used bits inside slice. + /// + /// # Panics + /// + /// Panics if number of bits in slice is less than bit_len. + #[inline] + pub fn from_slice(slice: &[u8], bit_len: usize) -> Self { + const BYTE_LEN: usize = 8; + assert!( + slice.len() * BYTE_LEN >= bit_len, + "slice bit length {} is less than bit_len {}", + slice.len() * BYTE_LEN, + bit_len + ); + let mut bitvec = BitVec::from_slice(slice); + unsafe { bitvec.set_len(bit_len) }; + Self::new(bitvec) + } + + /// Checks if `pc` is a valid jump destination. + /// Uses cached pointer and bit operations for faster access + #[inline] + pub fn is_valid(&self, pc: usize) -> bool { + pc < self.len && unsafe { *self.table_ptr.add(pc >> 3) & (1 << (pc & 7)) != 0 } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + #[should_panic(expected = "slice bit length 8 is less than bit_len 10")] + fn test_jump_table_from_slice_panic() { + let slice = &[0x00]; + let _ = JumpTable::from_slice(slice, 10); + } + + #[test] + fn test_jump_table_from_slice() { + let slice = &[0x00]; + let jumptable = JumpTable::from_slice(slice, 3); + assert_eq!(jumptable.len, 3); + } + + #[test] + fn test_is_valid() { + let jump_table = JumpTable::from_slice(&[0x0D, 0x06], 13); + + assert_eq!(jump_table.len, 13); + + assert!(jump_table.is_valid(0)); // valid + assert!(!jump_table.is_valid(1)); + assert!(jump_table.is_valid(2)); // valid + assert!(jump_table.is_valid(3)); // valid + assert!(!jump_table.is_valid(4)); + assert!(!jump_table.is_valid(5)); + assert!(!jump_table.is_valid(6)); + assert!(!jump_table.is_valid(7)); + assert!(!jump_table.is_valid(8)); + assert!(jump_table.is_valid(9)); // valid + assert!(jump_table.is_valid(10)); // valid + assert!(!jump_table.is_valid(11)); + assert!(!jump_table.is_valid(12)); + } +} + +#[cfg(test)] +mod bench_is_valid { + use super::*; + use std::time::Instant; + + const ITERATIONS: usize = 1_000_000; + const TEST_SIZE: usize = 10_000; + + fn create_test_table() -> BitVec { + let mut bitvec = BitVec::from_vec(vec![0u8; TEST_SIZE.div_ceil(8)]); + bitvec.resize(TEST_SIZE, false); + for i in (0..TEST_SIZE).step_by(3) { + bitvec.set(i, true); + } + bitvec + } + + #[derive(Clone)] + pub(super) struct JumpTableWithArcDeref(pub Arc>); + + impl JumpTableWithArcDeref { + #[inline] + pub(super) fn is_valid(&self, pc: usize) -> bool { + pc < self.0.len() && unsafe { *self.0.get_unchecked(pc) } + } + } + + fn benchmark_implementation(name: &str, table: &F, test_fn: impl Fn(&F, usize) -> bool) + where + F: Clone, + { + // Warmup + for i in 0..10_000 { + std::hint::black_box(test_fn(table, i % TEST_SIZE)); + } + + let start = Instant::now(); + let mut count = 0; + + for i in 0..ITERATIONS { + if test_fn(table, i % TEST_SIZE) { + count += 1; + } + } + + let duration = start.elapsed(); + let ns_per_op = duration.as_nanos() as f64 / ITERATIONS as f64; + let ops_per_sec = ITERATIONS as f64 / duration.as_secs_f64(); + + println!("{name} Performance:"); + println!(" Time per op: {ns_per_op:.2} ns"); + println!(" Ops per sec: {ops_per_sec:.0}"); + println!(" True count: {count}"); + println!(); + + std::hint::black_box(count); + } + + #[test] + fn bench_is_valid() { + println!("JumpTable is_valid() Benchmark Comparison"); + println!("========================================="); + + let bitvec = create_test_table(); + + // Test cached pointer implementation + let cached_table = JumpTable::new(bitvec.clone()); + benchmark_implementation("JumpTable (Cached Pointer)", &cached_table, |table, pc| { + table.is_valid(pc) + }); + + // Test Arc deref implementation + let arc_table = JumpTableWithArcDeref(Arc::new(bitvec)); + benchmark_implementation("JumpTableWithArcDeref (Arc)", &arc_table, |table, pc| { + table.is_valid(pc) + }); + + println!("Benchmark completed successfully!"); + } + + #[test] + fn bench_different_access_patterns() { + let bitvec = create_test_table(); + let cached_table = JumpTable::new(bitvec.clone()); + let arc_table = JumpTableWithArcDeref(Arc::new(bitvec)); + + println!("Access Pattern Comparison"); + println!("========================"); + + // Sequential access + let start = Instant::now(); + for i in 0..ITERATIONS { + std::hint::black_box(cached_table.is_valid(i % TEST_SIZE)); + } + let cached_sequential = start.elapsed(); + + let start = Instant::now(); + for i in 0..ITERATIONS { + std::hint::black_box(arc_table.is_valid(i % TEST_SIZE)); + } + let arc_sequential = start.elapsed(); + + // Random access + let start = Instant::now(); + for i in 0..ITERATIONS { + std::hint::black_box(cached_table.is_valid((i * 17) % TEST_SIZE)); + } + let cached_random = start.elapsed(); + + let start = Instant::now(); + for i in 0..ITERATIONS { + std::hint::black_box(arc_table.is_valid((i * 17) % TEST_SIZE)); + } + let arc_random = start.elapsed(); + + println!("Sequential Access:"); + println!( + " Cached: {:.2} ns/op", + cached_sequential.as_nanos() as f64 / ITERATIONS as f64 + ); + println!( + " Arc: {:.2} ns/op", + arc_sequential.as_nanos() as f64 / ITERATIONS as f64 + ); + println!( + " Speedup: {:.1}x", + arc_sequential.as_nanos() as f64 / cached_sequential.as_nanos() as f64 + ); + + println!(); + println!("Random Access:"); + println!( + " Cached: {:.2} ns/op", + cached_random.as_nanos() as f64 / ITERATIONS as f64 + ); + println!( + " Arc: {:.2} ns/op", + arc_random.as_nanos() as f64 / ITERATIONS as f64 + ); + println!( + " Speedup: {:.1}x", + arc_random.as_nanos() as f64 / cached_random.as_nanos() as f64 + ); + } +} diff --git a/crates/bytecode/src/legacy/raw.rs b/crates/bytecode/src/legacy/raw.rs new file mode 100644 index 0000000000..20ef7ba885 --- /dev/null +++ b/crates/bytecode/src/legacy/raw.rs @@ -0,0 +1,37 @@ +use super::LegacyAnalyzedBytecode; +use core::ops::Deref; +use primitives::Bytes; + +/// Used only as intermediate representation for legacy bytecode. +/// +/// See [`LegacyAnalyzedBytecode`] for the main structure that is used in Revm. +#[derive(Clone, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct LegacyRawBytecode(pub Bytes); + +impl LegacyRawBytecode { + /// Analyzes the bytecode, instantiating a [`LegacyAnalyzedBytecode`]. + pub fn into_analyzed(self) -> LegacyAnalyzedBytecode { + LegacyAnalyzedBytecode::analyze(self.0) + } +} + +impl From for LegacyRawBytecode { + fn from(bytes: Bytes) -> Self { + Self(bytes) + } +} + +impl From<[u8; N]> for LegacyRawBytecode { + fn from(bytes: [u8; N]) -> Self { + Self(bytes.into()) + } +} + +impl Deref for LegacyRawBytecode { + type Target = Bytes; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} diff --git a/crates/bytecode/src/lib.rs b/crates/bytecode/src/lib.rs new file mode 100644 index 0000000000..0a2435e186 --- /dev/null +++ b/crates/bytecode/src/lib.rs @@ -0,0 +1,29 @@ +//! Crate that contains bytecode types and opcode constants. +//! +//! Legacy bytecode will always contain a jump table. +//! +//! While EIP-7702 bytecode must contains a Address. +#![cfg_attr(not(test), warn(unused_crate_dependencies))] +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(not(feature = "std"))] +extern crate alloc as std; + +pub mod bytecode; +mod decode_errors; +/// EIP-7702 bytecode. +pub mod eip7702; +/// Iterator for the bytecode. +mod iter; +/// Legacy bytecode. +pub mod legacy; +pub mod opcode; +pub mod utils; + +/// Re-export of bitvec crate, used to store legacy bytecode jump table. +pub use bitvec; +pub use bytecode::Bytecode; +pub use decode_errors::BytecodeDecodeError; +pub use iter::BytecodeIterator; +pub use legacy::{JumpTable, LegacyAnalyzedBytecode, LegacyRawBytecode}; +pub use opcode::OpCode; diff --git a/crates/bytecode/src/opcode.rs b/crates/bytecode/src/opcode.rs new file mode 100644 index 0000000000..20a0aaad55 --- /dev/null +++ b/crates/bytecode/src/opcode.rs @@ -0,0 +1,776 @@ +//! EVM opcode definitions and utilities. It contains opcode information and utilities to work with opcodes. + +#[cfg(feature = "parse")] +pub mod parse; + +use core::{fmt, ptr::NonNull}; + +/// An EVM opcode +/// +/// This is always a valid opcode, as declared in the [`opcode`][self] module or the +/// [`OPCODE_INFO`] constant. +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[repr(transparent)] +pub struct OpCode(u8); + +impl fmt::Display for OpCode { + /// Formats the opcode as a string + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let n = self.get(); + if let Some(val) = OPCODE_INFO[n as usize] { + f.write_str(val.name()) + } else { + write!(f, "UNKNOWN(0x{n:02X})") + } + } +} + +impl OpCode { + /// Instantiates a new opcode from a u8. + /// + /// Returns None if the opcode is not valid. + #[inline] + pub const fn new(opcode: u8) -> Option { + match OPCODE_INFO[opcode as usize] { + Some(_) => Some(Self(opcode)), + None => None, + } + } + + /// Returns true if the opcode is a jump destination. + #[inline] + pub const fn is_jumpdest(&self) -> bool { + self.0 == JUMPDEST + } + + /// Takes a u8 and returns true if it is a jump destination. + #[inline] + pub const fn is_jumpdest_by_op(opcode: u8) -> bool { + if let Some(opcode) = Self::new(opcode) { + opcode.is_jumpdest() + } else { + false + } + } + + /// Returns true if the opcode is a legacy jump instruction. + #[inline] + pub const fn is_jump(self) -> bool { + self.0 == JUMP + } + + /// Takes a u8 and returns true if it is a jump instruction. + #[inline] + pub const fn is_jump_by_op(opcode: u8) -> bool { + if let Some(opcode) = Self::new(opcode) { + opcode.is_jump() + } else { + false + } + } + + /// Returns true if the opcode is a `PUSH` instruction. + #[inline] + pub const fn is_push(self) -> bool { + self.0 >= PUSH1 && self.0 <= PUSH32 + } + + /// Takes a u8 and returns true if it is a push instruction. + #[inline] + pub fn is_push_by_op(opcode: u8) -> bool { + if let Some(opcode) = Self::new(opcode) { + opcode.is_push() + } else { + false + } + } + + /// Instantiates a new opcode from a u8 without checking if it is valid. + /// + /// # Safety + /// + /// All code using `Opcode` values assume that they are valid opcodes, so providing an invalid + /// opcode may cause undefined behavior. + #[inline] + pub unsafe fn new_unchecked(opcode: u8) -> Self { + Self(opcode) + } + + /// Returns the opcode as a string. This is the inverse of [`parse`](Self::parse). + #[doc(alias = "name")] + #[inline] + pub const fn as_str(self) -> &'static str { + self.info().name() + } + + /// Returns the opcode name. + #[inline] + pub const fn name_by_op(opcode: u8) -> &'static str { + if let Some(opcode) = Self::new(opcode) { + opcode.as_str() + } else { + "Unknown" + } + } + + /// Returns the number of input stack elements. + #[inline] + pub const fn inputs(&self) -> u8 { + self.info().inputs() + } + + /// Returns the number of output stack elements. + #[inline] + pub const fn outputs(&self) -> u8 { + self.info().outputs() + } + + /// Calculates the difference between the number of input and output stack elements. + #[inline] + pub const fn io_diff(&self) -> i16 { + self.info().io_diff() + } + + /// Returns the opcode information for the given opcode. + /// Check [OpCodeInfo] for more information. + #[inline] + pub const fn info_by_op(opcode: u8) -> Option { + if let Some(opcode) = Self::new(opcode) { + Some(opcode.info()) + } else { + None + } + } + + /// Returns the opcode as a usize. + #[inline] + pub const fn as_usize(&self) -> usize { + self.0 as usize + } + + /// Returns the opcode information. + #[inline] + pub const fn info(&self) -> OpCodeInfo { + if let Some(t) = OPCODE_INFO[self.0 as usize] { + t + } else { + panic!("opcode not found") + } + } + + /// Returns the number of both input and output stack elements. + /// + /// Can be slightly faster than calling `inputs` and `outputs` separately. + pub const fn input_output(&self) -> (u8, u8) { + let info = self.info(); + (info.inputs, info.outputs) + } + + /// Returns the opcode as a u8. + #[inline] + pub const fn get(self) -> u8 { + self.0 + } + + /// Returns true if the opcode modifies memory. + /// + /// + /// + /// + #[inline] + pub const fn modifies_memory(&self) -> bool { + matches!( + *self, + OpCode::EXTCODECOPY + | OpCode::MLOAD + | OpCode::MSTORE + | OpCode::MSTORE8 + | OpCode::MCOPY + | OpCode::CODECOPY + | OpCode::CALLDATACOPY + | OpCode::RETURNDATACOPY + | OpCode::CALL + | OpCode::CALLCODE + | OpCode::DELEGATECALL + | OpCode::STATICCALL + ) + } + + /// Returns true if the opcode is valid + #[inline] + pub const fn is_valid(&self) -> bool { + OPCODE_INFO[self.0 as usize].is_some() + } +} + +impl PartialEq for OpCode { + fn eq(&self, other: &u8) -> bool { + self.get().eq(other) + } +} + +/// Information about opcode, such as name, and stack inputs and outputs +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct OpCodeInfo { + /// Invariant: `(name_ptr, name_len)` is a [`&'static str`][str]. + /// + /// It is a shorted variant of [`str`] as + /// the name length is always less than 256 characters. + name_ptr: NonNull, + name_len: u8, + /// Stack inputs + inputs: u8, + /// Stack outputs + outputs: u8, + /// Number of intermediate bytes + immediate_size: u8, + /// If the opcode stops execution. aka STOP, RETURN, .. + terminating: bool, +} + +// SAFETY: The `NonNull` is just a `&'static str`. +unsafe impl Send for OpCodeInfo {} +unsafe impl Sync for OpCodeInfo {} + +impl fmt::Debug for OpCodeInfo { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("OpCodeInfo") + .field("name", &self.name()) + .field("inputs", &self.inputs()) + .field("outputs", &self.outputs()) + .field("terminating", &self.is_terminating()) + .field("immediate_size", &self.immediate_size()) + .finish() + } +} + +impl OpCodeInfo { + /// Creates a new opcode info with the given name and default values. + pub const fn new(name: &'static str) -> Self { + assert!(name.len() < 256, "opcode name is too long"); + Self { + name_ptr: unsafe { NonNull::new_unchecked(name.as_ptr().cast_mut()) }, + name_len: name.len() as u8, + inputs: 0, + outputs: 0, + terminating: false, + immediate_size: 0, + } + } + + /// Returns the opcode name. + #[inline] + pub const fn name(&self) -> &'static str { + // SAFETY: `self.name_*` can only be initialized with a valid `&'static str`. + unsafe { + let slice = std::slice::from_raw_parts(self.name_ptr.as_ptr(), self.name_len as usize); + core::str::from_utf8_unchecked(slice) + } + } + + /// Calculates the difference between the number of input and output stack elements. + #[inline] + pub const fn io_diff(&self) -> i16 { + self.outputs as i16 - self.inputs as i16 + } + + /// Returns the number of input stack elements. + #[inline] + pub const fn inputs(&self) -> u8 { + self.inputs + } + + /// Returns the number of output stack elements. + #[inline] + pub const fn outputs(&self) -> u8 { + self.outputs + } + + /// Returns whether this opcode terminates execution, e.g. `STOP`, `RETURN`, etc. + #[inline] + pub const fn is_terminating(&self) -> bool { + self.terminating + } + + /// Returns the size of the immediate value in bytes. + #[inline] + pub const fn immediate_size(&self) -> u8 { + self.immediate_size + } +} + +/// Used for [`OPCODE_INFO`] to set the immediate bytes number in the [`OpCodeInfo`]. +#[inline] +pub const fn immediate_size(mut op: OpCodeInfo, n: u8) -> OpCodeInfo { + op.immediate_size = n; + op +} + +/// Used for [`OPCODE_INFO`] to set the terminating flag to true in the [`OpCodeInfo`]. +#[inline] +pub const fn terminating(mut op: OpCodeInfo) -> OpCodeInfo { + op.terminating = true; + op +} + +/// Use for [`OPCODE_INFO`] to sets the number of stack inputs and outputs in the [`OpCodeInfo`]. +#[inline] +pub const fn stack_io(mut op: OpCodeInfo, inputs: u8, outputs: u8) -> OpCodeInfo { + op.inputs = inputs; + op.outputs = outputs; + op +} + +/// Alias for the [`JUMPDEST`] opcode +pub const NOP: u8 = JUMPDEST; + +/// Created all opcodes constants and two maps: +/// * `OPCODE_INFO` maps opcode number to the opcode info +/// * `NAME_TO_OPCODE` that maps opcode name to the opcode number. +macro_rules! opcodes { + ($($val:literal => $name:ident => $($modifier:ident $(( $($modifier_arg:expr),* ))?),*);* $(;)?) => { + // Constants for each opcode. This also takes care of duplicate names. + $( + #[doc = concat!("The `", stringify!($val), "` (\"", stringify!($name),"\") opcode.")] + pub const $name: u8 = $val; + )* + impl OpCode {$( + #[doc = concat!("The `", stringify!($val), "` (\"", stringify!($name),"\") opcode.")] + pub const $name: Self = Self($val); + )*} + + /// Maps each opcode to its info. + pub static OPCODE_INFO: [Option; 256] = { + let mut map = [None; 256]; + let mut prev: u8 = 0; + $( + let val: u8 = $val; + assert!(val == 0 || val > prev, "opcodes must be sorted in ascending order"); + prev = val; + let info = OpCodeInfo::new(stringify!($name)); + $( + let info = $modifier(info, $($($modifier_arg),*)?); + )* + map[$val] = Some(info); + )* + let _ = prev; + map + }; + + + /// Maps each name to its opcode. + #[cfg(feature = "parse")] + pub(crate) static NAME_TO_OPCODE: phf::Map<&'static str, OpCode> = stringify_with_cb! { phf_map_cb; $($name)* }; + }; +} + +/// Callback for creating a [`phf`] map with `stringify_with_cb`. +#[cfg(feature = "parse")] +macro_rules! phf_map_cb { + ($(#[doc = $s:literal] $id:ident)*) => { + phf::phf_map! { + $($s => OpCode::$id),* + } + }; +} + +/// Stringifies identifiers with `paste` so that they are available as literals. +/// +/// This doesn't work with [`stringify!`] because it cannot be expanded inside of another macro. +#[cfg(feature = "parse")] +macro_rules! stringify_with_cb { + ($callback:ident; $($id:ident)*) => { paste::paste! { + $callback! { $(#[doc = "" $id ""] $id)* } + }}; +} + +// When adding new opcodes: +// 1. add the opcode to the list below; make sure it's sorted by opcode value +// 2. implement the opcode in the corresponding module; +// the function signature must be the exact same as the others +opcodes! { + 0x00 => STOP => stack_io(0, 0), terminating; + 0x01 => ADD => stack_io(2, 1); + 0x02 => MUL => stack_io(2, 1); + 0x03 => SUB => stack_io(2, 1); + 0x04 => DIV => stack_io(2, 1); + 0x05 => SDIV => stack_io(2, 1); + 0x06 => MOD => stack_io(2, 1); + 0x07 => SMOD => stack_io(2, 1); + 0x08 => ADDMOD => stack_io(3, 1); + 0x09 => MULMOD => stack_io(3, 1); + 0x0A => EXP => stack_io(2, 1); + 0x0B => SIGNEXTEND => stack_io(2, 1); + // 0x0C + // 0x0D + // 0x0E + // 0x0F + 0x10 => LT => stack_io(2, 1); + 0x11 => GT => stack_io(2, 1); + 0x12 => SLT => stack_io(2, 1); + 0x13 => SGT => stack_io(2, 1); + 0x14 => EQ => stack_io(2, 1); + 0x15 => ISZERO => stack_io(1, 1); + 0x16 => AND => stack_io(2, 1); + 0x17 => OR => stack_io(2, 1); + 0x18 => XOR => stack_io(2, 1); + 0x19 => NOT => stack_io(1, 1); + 0x1A => BYTE => stack_io(2, 1); + 0x1B => SHL => stack_io(2, 1); + 0x1C => SHR => stack_io(2, 1); + 0x1D => SAR => stack_io(2, 1); + 0x1E => CLZ => stack_io(1, 1); + // 0x1F + 0x20 => KECCAK256 => stack_io(2, 1); + // 0x21 + // 0x22 + // 0x23 + // 0x24 + // 0x25 + // 0x26 + // 0x27 + // 0x28 + // 0x29 + // 0x2A + // 0x2B + // 0x2C + // 0x2D + // 0x2E + // 0x2F + 0x30 => ADDRESS => stack_io(0, 1); + 0x31 => BALANCE => stack_io(1, 1); + 0x32 => ORIGIN => stack_io(0, 1); + 0x33 => CALLER => stack_io(0, 1); + 0x34 => CALLVALUE => stack_io(0, 1); + 0x35 => CALLDATALOAD => stack_io(1, 1); + 0x36 => CALLDATASIZE => stack_io(0, 1); + 0x37 => CALLDATACOPY => stack_io(3, 0); + 0x38 => CODESIZE => stack_io(0, 1); + 0x39 => CODECOPY => stack_io(3, 0); + + 0x3A => GASPRICE => stack_io(0, 1); + 0x3B => EXTCODESIZE => stack_io(1, 1); + 0x3C => EXTCODECOPY => stack_io(4, 0); + 0x3D => RETURNDATASIZE => stack_io(0, 1); + 0x3E => RETURNDATACOPY => stack_io(3, 0); + 0x3F => EXTCODEHASH => stack_io(1, 1); + 0x40 => BLOCKHASH => stack_io(1, 1); + 0x41 => COINBASE => stack_io(0, 1); + 0x42 => TIMESTAMP => stack_io(0, 1); + 0x43 => NUMBER => stack_io(0, 1); + 0x44 => DIFFICULTY => stack_io(0, 1); + 0x45 => GASLIMIT => stack_io(0, 1); + 0x46 => CHAINID => stack_io(0, 1); + 0x47 => SELFBALANCE => stack_io(0, 1); + 0x48 => BASEFEE => stack_io(0, 1); + 0x49 => BLOBHASH => stack_io(1, 1); + 0x4A => BLOBBASEFEE => stack_io(0, 1); + // 0x4B + // 0x4C + // 0x4D + // 0x4E + // 0x4F + 0x50 => POP => stack_io(1, 0); + 0x51 => MLOAD => stack_io(1, 1); + 0x52 => MSTORE => stack_io(2, 0); + 0x53 => MSTORE8 => stack_io(2, 0); + 0x54 => SLOAD => stack_io(1, 1); + 0x55 => SSTORE => stack_io(2, 0); + 0x56 => JUMP => stack_io(1, 0); + 0x57 => JUMPI => stack_io(2, 0); + 0x58 => PC => stack_io(0, 1); + 0x59 => MSIZE => stack_io(0, 1); + 0x5A => GAS => stack_io(0, 1); + 0x5B => JUMPDEST => stack_io(0, 0); + 0x5C => TLOAD => stack_io(1, 1); + 0x5D => TSTORE => stack_io(2, 0); + 0x5E => MCOPY => stack_io(3, 0); + + 0x5F => PUSH0 => stack_io(0, 1); + 0x60 => PUSH1 => stack_io(0, 1), immediate_size(1); + 0x61 => PUSH2 => stack_io(0, 1), immediate_size(2); + 0x62 => PUSH3 => stack_io(0, 1), immediate_size(3); + 0x63 => PUSH4 => stack_io(0, 1), immediate_size(4); + 0x64 => PUSH5 => stack_io(0, 1), immediate_size(5); + 0x65 => PUSH6 => stack_io(0, 1), immediate_size(6); + 0x66 => PUSH7 => stack_io(0, 1), immediate_size(7); + 0x67 => PUSH8 => stack_io(0, 1), immediate_size(8); + 0x68 => PUSH9 => stack_io(0, 1), immediate_size(9); + 0x69 => PUSH10 => stack_io(0, 1), immediate_size(10); + 0x6A => PUSH11 => stack_io(0, 1), immediate_size(11); + 0x6B => PUSH12 => stack_io(0, 1), immediate_size(12); + 0x6C => PUSH13 => stack_io(0, 1), immediate_size(13); + 0x6D => PUSH14 => stack_io(0, 1), immediate_size(14); + 0x6E => PUSH15 => stack_io(0, 1), immediate_size(15); + 0x6F => PUSH16 => stack_io(0, 1), immediate_size(16); + 0x70 => PUSH17 => stack_io(0, 1), immediate_size(17); + 0x71 => PUSH18 => stack_io(0, 1), immediate_size(18); + 0x72 => PUSH19 => stack_io(0, 1), immediate_size(19); + 0x73 => PUSH20 => stack_io(0, 1), immediate_size(20); + 0x74 => PUSH21 => stack_io(0, 1), immediate_size(21); + 0x75 => PUSH22 => stack_io(0, 1), immediate_size(22); + 0x76 => PUSH23 => stack_io(0, 1), immediate_size(23); + 0x77 => PUSH24 => stack_io(0, 1), immediate_size(24); + 0x78 => PUSH25 => stack_io(0, 1), immediate_size(25); + 0x79 => PUSH26 => stack_io(0, 1), immediate_size(26); + 0x7A => PUSH27 => stack_io(0, 1), immediate_size(27); + 0x7B => PUSH28 => stack_io(0, 1), immediate_size(28); + 0x7C => PUSH29 => stack_io(0, 1), immediate_size(29); + 0x7D => PUSH30 => stack_io(0, 1), immediate_size(30); + 0x7E => PUSH31 => stack_io(0, 1), immediate_size(31); + 0x7F => PUSH32 => stack_io(0, 1), immediate_size(32); + + 0x80 => DUP1 => stack_io(1, 2); + 0x81 => DUP2 => stack_io(2, 3); + 0x82 => DUP3 => stack_io(3, 4); + 0x83 => DUP4 => stack_io(4, 5); + 0x84 => DUP5 => stack_io(5, 6); + 0x85 => DUP6 => stack_io(6, 7); + 0x86 => DUP7 => stack_io(7, 8); + 0x87 => DUP8 => stack_io(8, 9); + 0x88 => DUP9 => stack_io(9, 10); + 0x89 => DUP10 => stack_io(10, 11); + 0x8A => DUP11 => stack_io(11, 12); + 0x8B => DUP12 => stack_io(12, 13); + 0x8C => DUP13 => stack_io(13, 14); + 0x8D => DUP14 => stack_io(14, 15); + 0x8E => DUP15 => stack_io(15, 16); + 0x8F => DUP16 => stack_io(16, 17); + + 0x90 => SWAP1 => stack_io(2, 2); + 0x91 => SWAP2 => stack_io(3, 3); + 0x92 => SWAP3 => stack_io(4, 4); + 0x93 => SWAP4 => stack_io(5, 5); + 0x94 => SWAP5 => stack_io(6, 6); + 0x95 => SWAP6 => stack_io(7, 7); + 0x96 => SWAP7 => stack_io(8, 8); + 0x97 => SWAP8 => stack_io(9, 9); + 0x98 => SWAP9 => stack_io(10, 10); + 0x99 => SWAP10 => stack_io(11, 11); + 0x9A => SWAP11 => stack_io(12, 12); + 0x9B => SWAP12 => stack_io(13, 13); + 0x9C => SWAP13 => stack_io(14, 14); + 0x9D => SWAP14 => stack_io(15, 15); + 0x9E => SWAP15 => stack_io(16, 16); + 0x9F => SWAP16 => stack_io(17, 17); + + 0xA0 => LOG0 => stack_io(2, 0); + 0xA1 => LOG1 => stack_io(3, 0); + 0xA2 => LOG2 => stack_io(4, 0); + 0xA3 => LOG3 => stack_io(5, 0); + 0xA4 => LOG4 => stack_io(6, 0); + // 0xA5 + // 0xA6 + // 0xA7 + // 0xA8 + // 0xA9 + // 0xAA + // 0xAB + // 0xAC + // 0xAD + // 0xAE + // 0xAF + // 0xB0 + // 0xB1 + // 0xB2 + // 0xB3 + // 0xB4 + // 0xB5 + // 0xB6 + // 0xB7 + // 0xB8 + // 0xB9 + // 0xBA + // 0xBB + // 0xBC + // 0xBD + // 0xBE + // 0xBF + // 0xC0 + // 0xC1 + // 0xC2 + // 0xC3 + // 0xC4 + // 0xC5 + // 0xC6 + // 0xC7 + // 0xC8 + // 0xC9 + // 0xCA + // 0xCB + // 0xCC + // 0xCD + // 0xCE + // 0xCF + // 0xD0 + // 0xD1 + // 0xD2 + // 0xD3 + // 0xD4 + // 0xD5 + // 0xD6 + // 0xD7 + // 0xD8 + // 0xD9 + // 0xDA + // 0xDB + // 0xDC + // 0xDD + // 0xDE + // 0xDF + // 0xE0 + // 0xE1 + // 0xE2 + // 0xE3 + // 0xE4 + // 0xE5 + // 0xE6 + // 0xE7 + // 0xE8 + // 0xE9 + // 0xEA + // 0xEB + // 0xEC + // 0xED + // 0xEE + // 0xEF + 0xF0 => CREATE => stack_io(3, 1); + 0xF1 => CALL => stack_io(7, 1); + 0xF2 => CALLCODE => stack_io(7, 1); + 0xF3 => RETURN => stack_io(2, 0), terminating; + 0xF4 => DELEGATECALL => stack_io(6, 1); + 0xF5 => CREATE2 => stack_io(4, 1); + // 0xF6 + // 0xF7 + // 0xF8 + // 0xF9 + 0xFA => STATICCALL => stack_io(6, 1); + // 0xFB + // 0xFC + 0xFD => REVERT => stack_io(2, 0), terminating; + 0xFE => INVALID => stack_io(0, 0), terminating; + 0xFF => SELFDESTRUCT => stack_io(1, 0), terminating; +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_opcode() { + let opcode = OpCode::new(0x00).unwrap(); + assert!(!opcode.is_jumpdest()); + assert!(!opcode.is_jump()); + assert!(!opcode.is_push()); + assert_eq!(opcode.as_str(), "STOP"); + assert_eq!(opcode.get(), 0x00); + } + + #[test] + fn test_immediate_size() { + let mut expected = [0u8; 256]; + // PUSH opcodes + for push in PUSH1..=PUSH32 { + expected[push as usize] = push - PUSH1 + 1; + } + + for (i, opcode) in OPCODE_INFO.iter().enumerate() { + if let Some(opcode) = opcode { + assert_eq!( + opcode.immediate_size(), + expected[i], + "immediate_size check failed for {opcode:#?}", + ); + } + } + } + + #[test] + fn test_enabled_opcodes() { + // List obtained from https://eips.ethereum.org/EIPS/eip-3670 + let opcodes = [ + 0x10..=0x1d, + 0x20..=0x20, + 0x30..=0x3f, + 0x40..=0x48, + 0x50..=0x5b, + 0x54..=0x5f, + 0x60..=0x6f, + 0x70..=0x7f, + 0x80..=0x8f, + 0x90..=0x9f, + 0xa0..=0xa4, + 0xf0..=0xf5, + 0xfa..=0xfa, + 0xfd..=0xfd, + //0xfe, + 0xff..=0xff, + ]; + for i in opcodes { + for opcode in i { + OpCode::new(opcode).expect("Opcode should be valid and enabled"); + } + } + } + + #[test] + fn count_opcodes() { + let mut opcode_num = 0; + for _ in OPCODE_INFO.into_iter().flatten() { + opcode_num += 1; + } + assert_eq!(opcode_num, 150); + } + + #[test] + fn test_terminating_opcodes() { + let terminating = [REVERT, RETURN, INVALID, SELFDESTRUCT, STOP]; + let mut opcodes = [false; 256]; + for terminating in terminating.iter() { + opcodes[*terminating as usize] = true; + } + + for (i, opcode) in OPCODE_INFO.into_iter().enumerate() { + assert_eq!( + opcode.map(|opcode| opcode.terminating).unwrap_or_default(), + opcodes[i], + "Opcode {opcode:?} terminating check failed." + ); + } + } + + #[test] + #[cfg(feature = "parse")] + fn test_parsing() { + for i in 0..=u8::MAX { + if let Some(op) = OpCode::new(i) { + assert_eq!(OpCode::parse(op.as_str()), Some(op)); + } + } + } + + #[test] + #[should_panic(expected = "opcode not found")] + fn test_new_unchecked_invalid() { + let op = unsafe { OpCode::new_unchecked(0x0C) }; + op.info(); + } + + #[test] + fn test_op_code_valid() { + let op1 = OpCode::new(ADD).unwrap(); + let op2 = OpCode::new(MUL).unwrap(); + assert!(op1.is_valid()); + assert!(op2.is_valid()); + + let op3 = unsafe { OpCode::new_unchecked(0x0C) }; + assert!(!op3.is_valid()); + } + + #[test] + fn test_modifies_memory() { + assert!(OpCode::new(MLOAD).unwrap().modifies_memory()); + assert!(OpCode::new(MSTORE).unwrap().modifies_memory()); + assert!(!OpCode::new(ADD).unwrap().modifies_memory()); + } +} diff --git a/crates/bytecode/src/opcode/parse.rs b/crates/bytecode/src/opcode/parse.rs new file mode 100644 index 0000000000..aee2a7a47c --- /dev/null +++ b/crates/bytecode/src/opcode/parse.rs @@ -0,0 +1,39 @@ +//! Parsing opcodes from strings. +//! +//! This module provides a function to parse opcodes from strings. +//! It is a utility function that needs to be enabled with `parse` feature. + +use super::OpCode; +use crate::opcode::NAME_TO_OPCODE; +use core::fmt; + +/// An error indicating that an opcode is invalid +#[derive(Debug, PartialEq, Eq)] +pub struct OpCodeError(()); + +impl fmt::Display for OpCodeError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("invalid opcode") + } +} + +impl core::error::Error for OpCodeError {} + +impl core::str::FromStr for OpCode { + type Err = OpCodeError; + + #[inline] + fn from_str(s: &str) -> Result { + Self::parse(s).ok_or(OpCodeError(())) + } +} + +impl OpCode { + /// Parses an opcode from a string. + /// + /// This is the inverse of [`as_str`](Self::as_str). + #[inline] + pub fn parse(s: &str) -> Option { + NAME_TO_OPCODE.get(s).copied() + } +} diff --git a/crates/bytecode/src/utils.rs b/crates/bytecode/src/utils.rs new file mode 100644 index 0000000000..4ff1245696 --- /dev/null +++ b/crates/bytecode/src/utils.rs @@ -0,0 +1,21 @@ +//! Various utilities for the bytecode + +/// Reads a big-endian `i16` from a `u8` pointer. +/// +/// # Safety +/// +/// The pointer must point to at least 2 bytes. +#[inline] +pub unsafe fn read_i16(ptr: *const u8) -> i16 { + read_u16(ptr) as i16 +} + +/// Reads a big-endian `u16` from a `u8` pointer. +/// +/// # Safety +/// +/// The pointer must point to at least 2 bytes. +#[inline] +pub unsafe fn read_u16(ptr: *const u8) -> u16 { + u16::from_be_bytes(unsafe { ptr.cast::<[u8; 2]>().read() }) +} diff --git a/crates/context/CHANGELOG.md b/crates/context/CHANGELOG.md new file mode 100644 index 0000000000..70646c5757 --- /dev/null +++ b/crates/context/CHANGELOG.md @@ -0,0 +1,335 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [8.0.4](https://github.com/bluealloy/revm/compare/revm-context-v8.0.3...revm-context-v8.0.4) - 2025-07-23 + +### Fixed + +- fully deprecate serde-json ([#2767](https://github.com/bluealloy/revm/pull/2767)) + +### Other + +- un-Box frames ([#2761](https://github.com/bluealloy/revm/pull/2761)) +- discard generic host implementation ([#2738](https://github.com/bluealloy/revm/pull/2738)) + +## [8.0.3](https://github.com/bluealloy/revm/compare/revm-context-v8.0.2...revm-context-v8.0.3) - 2025-07-14 + +### Fixed + +- fix typo: Rename is_created_globaly to is_created_globally ([#2692](https://github.com/bluealloy/revm/pull/2692)) + +### Other + +- add comprehensive tests for TxEnvBuilder ([#2690](https://github.com/bluealloy/revm/pull/2690)) + +## [8.0.2](https://github.com/bluealloy/revm/compare/revm-context-v8.0.1...revm-context-v8.0.2) - 2025-07-03 + +### Other + +- updated the following local packages: revm-bytecode, revm-state, revm-database-interface, revm-context-interface + +## [8.0.1](https://github.com/bluealloy/revm/compare/revm-context-v7.0.1...revm-context-v8.0.1) - 2025-06-30 + +### Added + +- implement `Transaction` for `Either` ([#2662](https://github.com/bluealloy/revm/pull/2662)) +- optional_eip3541 ([#2661](https://github.com/bluealloy/revm/pull/2661)) + +### Other + +- use TxEnv::builder ([#2652](https://github.com/bluealloy/revm/pull/2652)) +- fix copy-pasted inner doc comments ([#2663](https://github.com/bluealloy/revm/pull/2663)) + +## [7.0.1](https://github.com/bluealloy/revm/compare/revm-context-v7.0.0...revm-context-v7.0.1) - 2025-06-20 + +### Fixed + +- call stack_frame.clear() at end ([#2656](https://github.com/bluealloy/revm/pull/2656)) + +## [7.0.0](https://github.com/bluealloy/revm/compare/revm-context-v6.0.0...revm-context-v7.0.0) - 2025-06-19 + +### Added + +- remove EOF ([#2644](https://github.com/bluealloy/revm/pull/2644)) +- configurable contract size limit ([#2611](https://github.com/bluealloy/revm/pull/2611)) ([#2642](https://github.com/bluealloy/revm/pull/2642)) +- *(precompile)* rug/gmp-based modexp ([#2596](https://github.com/bluealloy/revm/pull/2596)) +- change blob_max_count to max_blobs_per_tx ([#2608](https://github.com/bluealloy/revm/pull/2608)) +- add optional priority fee check configuration ([#2588](https://github.com/bluealloy/revm/pull/2588)) + +### Other + +- bump all deps ([#2647](https://github.com/bluealloy/revm/pull/2647)) +- include local context as generic ([#2645](https://github.com/bluealloy/revm/pull/2645)) +- re-use frame allocation ([#2636](https://github.com/bluealloy/revm/pull/2636)) +- store coinbase address separately to avoid cloning warm addresses in the common case ([#2634](https://github.com/bluealloy/revm/pull/2634)) +- optimize warm_preloaded_addresses reset ([#2625](https://github.com/bluealloy/revm/pull/2625)) +- rename `transact` methods ([#2616](https://github.com/bluealloy/revm/pull/2616)) + +## [6.0.0](https://github.com/bluealloy/revm/compare/revm-context-v5.0.1...revm-context-v6.0.0) - 2025-06-06 + +### Added + +- *(Osaka)* EIP-7825 tx limit cap ([#2575](https://github.com/bluealloy/revm/pull/2575)) +- added TxEnv::new_bench() add util function ([#2556](https://github.com/bluealloy/revm/pull/2556)) +- Config blob basefee fraction ([#2551](https://github.com/bluealloy/revm/pull/2551)) +- expand timestamp/block_number to u256 ([#2546](https://github.com/bluealloy/revm/pull/2546)) +- transact multi tx ([#2517](https://github.com/bluealloy/revm/pull/2517)) + +### Fixed + +- *(multitx)* Add local flags for create and selfdestruct ([#2581](https://github.com/bluealloy/revm/pull/2581)) + +### Other + +- tag v75 revm v24.0.1 ([#2563](https://github.com/bluealloy/revm/pull/2563)) ([#2589](https://github.com/bluealloy/revm/pull/2589)) +- support functions for eip7918 ([#2579](https://github.com/bluealloy/revm/pull/2579)) +- *(docs)* add lints to database-interface and op-revm crates ([#2568](https://github.com/bluealloy/revm/pull/2568)) +- *(docs)* context crate lints ([#2565](https://github.com/bluealloy/revm/pull/2565)) +- unify calling of journal account loading ([#2561](https://github.com/bluealloy/revm/pull/2561)) +- ContextTr rm *_ref, and add *_mut fn ([#2560](https://github.com/bluealloy/revm/pull/2560)) +- *(cfg)* add tx_chain_id_check fields. Optimize effective gas cost calc ([#2557](https://github.com/bluealloy/revm/pull/2557)) +- add dot to trigger ci ([#2552](https://github.com/bluealloy/revm/pull/2552)) + +## [5.0.1](https://github.com/bluealloy/revm/compare/revm-context-v5.0.0...revm-context-v5.0.1) - 2025-05-31 + +### Other + +- unify calling of journal account loading + +## [5.0.0](https://github.com/bluealloy/revm/compare/revm-context-v4.1.0...revm-context-v5.0.0) - 2025-05-22 + +### Added + +- make blob max number optional ([#2532](https://github.com/bluealloy/revm/pull/2532)) +- add builder pattern for TxEnv ([#2518](https://github.com/bluealloy/revm/pull/2518)) +- make Journal::set_code to be EIP-7702 zero address bytecode aware ([#2511](https://github.com/bluealloy/revm/pull/2511)) + +### Other + +- add TxEnvBuilder::build_fill ([#2536](https://github.com/bluealloy/revm/pull/2536)) +- make crates.io version badge clickable ([#2526](https://github.com/bluealloy/revm/pull/2526)) +- Storage Types Alias ([#2461](https://github.com/bluealloy/revm/pull/2461)) + +## [4.1.0](https://github.com/bluealloy/revm/compare/revm-context-v4.0.0...revm-context-v4.1.0) - 2025-05-07 + +Dependency bump + +## [4.0.0](https://github.com/bluealloy/revm/compare/revm-context-v3.0.1...revm-context-v4.0.0) - 2025-05-07 + +### Added + +- *(Osaka)* disable EOF ([#2480](https://github.com/bluealloy/revm/pull/2480)) +- skip cloning of call input from shared memory ([#2462](https://github.com/bluealloy/revm/pull/2462)) +- Add a custom address to the CreateScheme. ([#2464](https://github.com/bluealloy/revm/pull/2464)) +- *(Handler)* merge state validation with deduct_caller ([#2460](https://github.com/bluealloy/revm/pull/2460)) +- add chain_ref method to ContextTr trait ([#2450](https://github.com/bluealloy/revm/pull/2450)) +- *(tx)* Add Either RecoveredAuthorization ([#2448](https://github.com/bluealloy/revm/pull/2448)) +- *(EOF)* Changes needed for devnet-1 ([#2377](https://github.com/bluealloy/revm/pull/2377)) +- Move SharedMemory buffer to context ([#2382](https://github.com/bluealloy/revm/pull/2382)) + +### Fixed + +- use HashMap::default in LocalContext ([#2451](https://github.com/bluealloy/revm/pull/2451)) + +### Other + +- typos ([#2474](https://github.com/bluealloy/revm/pull/2474)) +- copy edit The Book ([#2463](https://github.com/bluealloy/revm/pull/2463)) +- remove default capacity on journal reverts ([#2449](https://github.com/bluealloy/revm/pull/2449)) +- *(journal)* flatten journal entries ([#2440](https://github.com/bluealloy/revm/pull/2440)) +- clone_from precompile addresses ([#2438](https://github.com/bluealloy/revm/pull/2438)) +- bump dependency version ([#2431](https://github.com/bluealloy/revm/pull/2431)) +- fixed broken link ([#2421](https://github.com/bluealloy/revm/pull/2421)) +- backport from release branch ([#2415](https://github.com/bluealloy/revm/pull/2415)) ([#2416](https://github.com/bluealloy/revm/pull/2416)) +- *(lints)* revm-context lints ([#2404](https://github.com/bluealloy/revm/pull/2404)) + +## [3.0.1](https://github.com/bluealloy/revm/compare/revm-context-v3.0.0...revm-context-v3.0.1) - 2025-04-15 + +### Other + +## [3.0.0](https://github.com/bluealloy/revm/compare/revm-context-v2.0.0...revm-context-v3.0.0) - 2025-04-09 + +### Fixed + +- Effective gas price should check tx type ([#2375](https://github.com/bluealloy/revm/pull/2375)) + +### Other + +- make blob params u64 ([#2385](https://github.com/bluealloy/revm/pull/2385)) +- set gas_priority_fee to None in TxEnv ([#2371](https://github.com/bluealloy/revm/pull/2371)) + +## [2.0.0](https://github.com/bluealloy/revm/compare/revm-context-v1.0.0...revm-context-v2.0.0) - 2025-03-28 + +### Added + +- cache precompile warming ([#2317](https://github.com/bluealloy/revm/pull/2317)) +- Add JournalInner ([#2311](https://github.com/bluealloy/revm/pull/2311)) + +### Other + +- Remove LATEST variant from SpecId enum ([#2299](https://github.com/bluealloy/revm/pull/2299)) + +## [1.0.0](https://github.com/bluealloy/revm/compare/revm-context-v1.0.0-alpha.6...revm-context-v1.0.0) - 2025-03-24 + +### Other + +- updated the following local packages: revm-database + +## [1.0.0-alpha.6](https://github.com/bluealloy/revm/compare/revm-context-v1.0.0-alpha.5...revm-context-v1.0.0-alpha.6) - 2025-03-21 + +### Added + +- InspectEvm fn renames, inspector docs, book cleanup ([#2275](https://github.com/bluealloy/revm/pull/2275)) + +### Fixed + +- remove duplicated load_account() ([#2225](https://github.com/bluealloy/revm/pull/2225)) + +### Other + +- remove wrong `&mut` and duplicated spec ([#2276](https://github.com/bluealloy/revm/pull/2276)) +- Add custom instruction example ([#2261](https://github.com/bluealloy/revm/pull/2261)) +- fix clippy ([#2238](https://github.com/bluealloy/revm/pull/2238)) +- use AccessListItem associated type instead of AccessList ([#2214](https://github.com/bluealloy/revm/pull/2214)) + +## [1.0.0-alpha.5](https://github.com/bluealloy/revm/compare/revm-context-v1.0.0-alpha.4...revm-context-v1.0.0-alpha.5) - 2025-03-16 + +### Added + +- *(docs)* MyEvm example and book cleanup ([#2218](https://github.com/bluealloy/revm/pull/2218)) + +## [1.0.0-alpha.4](https://github.com/bluealloy/revm/compare/revm-context-v1.0.0-alpha.3...revm-context-v1.0.0-alpha.4) - 2025-03-12 + +### Added + +- add custom error to context ([#2197](https://github.com/bluealloy/revm/pull/2197)) +- Add tx/block to EvmExecution trait ([#2195](https://github.com/bluealloy/revm/pull/2195)) + +## [1.0.0-alpha.3](https://github.com/bluealloy/revm/compare/revm-context-v1.0.0-alpha.2...revm-context-v1.0.0-alpha.3) - 2025-03-11 + +### Fixed + +- correct propagate features ([#2177](https://github.com/bluealloy/revm/pull/2177)) + +## [1.0.0-alpha.2](https://github.com/bluealloy/revm/compare/revm-context-v1.0.0-alpha.1...revm-context-v1.0.0-alpha.2) - 2025-03-10 + +### Added + +- added with_ref_db fn to Context ([#2164](https://github.com/bluealloy/revm/pull/2164)) +- remove specification crate ([#2165](https://github.com/bluealloy/revm/pull/2165)) +- make journal entries generic ([#2154](https://github.com/bluealloy/revm/pull/2154)) +- Standalone Host, remove default fn from context ([#2147](https://github.com/bluealloy/revm/pull/2147)) +- add constructor with hardfork ([#2135](https://github.com/bluealloy/revm/pull/2135)) +- allow host to be implemented on custom context ([#2112](https://github.com/bluealloy/revm/pull/2112)) +- add the debug impl for Evm and EvmData type ([#2126](https://github.com/bluealloy/revm/pull/2126)) + +### Other + +- pre EIP-7702 does not need to load code ([#2162](https://github.com/bluealloy/revm/pull/2162)) +- JournalTr, JournalOutput, op only using revm crate ([#2155](https://github.com/bluealloy/revm/pull/2155)) +- rename transact_previous to replay, move EvmTr traits ([#2153](https://github.com/bluealloy/revm/pull/2153)) +- move mainnet builder to handler crate ([#2138](https://github.com/bluealloy/revm/pull/2138)) +- remove `optional_gas_refund` as unused ([#2132](https://github.com/bluealloy/revm/pull/2132)) +- Adding function derive_tx_type to TxEnv ([#2118](https://github.com/bluealloy/revm/pull/2118)) +- remove wrong `&mut`/`TODO`, and avoid useless `get_mut` ([#2111](https://github.com/bluealloy/revm/pull/2111)) +- export eip2930 eip7702 types from one place ([#2097](https://github.com/bluealloy/revm/pull/2097)) +- move all dependencies to workspace ([#2092](https://github.com/bluealloy/revm/pull/2092)) +- re-export all crates from `revm` ([#2088](https://github.com/bluealloy/revm/pull/2088)) + +## [1.0.0-alpha.1](https://github.com/bluealloy/revm/releases/tag/revm-context-v1.0.0-alpha.1) - 2025-02-16 + +### Added + +- Split Inspector trait from EthHandler into standalone crate (#2075) +- Introduce Auth and AccessList traits (#2079) +- integrate alloy-eips (#2078) +- *(eip7702)* devnet6 changes and bump eest tests (#2055) +- Evm structure (Cached Instructions and Precompiles) (#2049) +- Context execution (#2013) +- EthHandler trait (#2001) +- *(EIP-7840)* Add blob schedule to execution client cfg (#1980) +- *(eip7702)* apply latest EIP-7702 changes, backport from v52 (#1969) +- simplify Transaction trait (#1959) +- align Block trait (#1957) +- expose precompile address in Journal, DB::Error: StdError (#1956) +- Make Ctx journal generic (#1933) +- Restucturing Part7 Handler and Context rework (#1865) +- restructuring Part6 transaction crate (#1814) +- *(examples)* generate block traces (#895) +- implement EIP-4844 (#668) +- *(Shanghai)* All EIPs: push0, warm coinbase, limit/measure initcode (#376) +- Migrate `primitive_types::U256` to `ruint::Uint<256, 4>` (#239) +- Introduce ByteCode format, Update Readme (#156) + +### Fixed + +- clear JournalState and set first journal vec (#1929) +- Clear journal (#1927) +- *(revme)* include correct bytecode for snailtracer (#1917) +- fix typos ([#620](https://github.com/bluealloy/revm/pull/620)) + +### Other + +- set alpha.1 version +- Add helpers with_inspector with_precompile (#2063) +- simplify some generics (#2032) +- Add helper functions for JournalInit #1879 (#1961) +- fix journal naming for inc/dec balance (#1976) +- Make inspector use generics, rm associated types (#1934) +- fix comments and docs into more sensible (#1920) +- tie journal database with database getter (#1923) +- Move CfgEnv from context-interface to context crate (#1910) +- Bump new logo (#1735) +- *(README)* add rbuilder to used-by (#1585) +- added simular to used-by (#1521) +- add Trin to used by list (#1393) +- Fix typo in readme ([#1185](https://github.com/bluealloy/revm/pull/1185)) +- Add Hardhat to the "Used by" list ([#1164](https://github.com/bluealloy/revm/pull/1164)) +- Add VERBS to used by list ([#1141](https://github.com/bluealloy/revm/pull/1141)) +- license date and revm docs (#1080) +- *(docs)* Update the benchmark docs to point to revm package (#906) +- *(docs)* Update top-level benchmark docs (#894) +- clang requirement (#784) +- Readme Updates (#756) +- Logo (#743) +- book workflow ([#537](https://github.com/bluealloy/revm/pull/537)) +- add example to revm crate ([#468](https://github.com/bluealloy/revm/pull/468)) +- Update README.md ([#424](https://github.com/bluealloy/revm/pull/424)) +- add no_std to primitives ([#366](https://github.com/bluealloy/revm/pull/366)) +- revm-precompiles to revm-precompile +- Bump v20, changelog ([#350](https://github.com/bluealloy/revm/pull/350)) +- typos (#232) +- Add support for old forks. ([#191](https://github.com/bluealloy/revm/pull/191)) +- revm bump 1.8. update libs. snailtracer rename ([#159](https://github.com/bluealloy/revm/pull/159)) +- typo fixes +- fix readme typo +- Big Refactor. Machine to Interpreter. refactor instructions. call/create struct ([#52](https://github.com/bluealloy/revm/pull/52)) +- readme. debuger update +- Bump revm v0.3.0. README updated +- readme +- Add time elapsed for tests +- readme updated +- Include Basefee into cost calc. readme change +- Initialize precompile accounts +- Status update. Taking a break +- Merkle calc. Tweaks and debugging for eip158 +- Replace aurora bn lib with parity's. All Bn128Add/Mul/Pair tests passes +- TEMP +- one tab removed +- readme +- README Example simplified +- Gas calculation for Call/Create. Example Added +- readme usage +- README changes +- Static gas cost added +- Subroutine changelogs and reverts +- Readme postulates +- Spelling +- Restructure project +- First iteration. Machine is looking okay diff --git a/crates/context/Cargo.toml b/crates/context/Cargo.toml new file mode 100644 index 0000000000..6da5d5496d --- /dev/null +++ b/crates/context/Cargo.toml @@ -0,0 +1,73 @@ +[package] +name = "revm-context" +description = "Revm context crates" +version = "8.0.4" +authors.workspace = true +edition.workspace = true +keywords.workspace = true +license.workspace = true +repository.workspace = true +readme.workspace = true + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] + +[lints] +workspace = true + +[dependencies] +# revm +context-interface.workspace = true +primitives.workspace = true +database-interface.workspace = true +state.workspace = true +bytecode.workspace = true + +# misc +derive-where.workspace = true +cfg-if.workspace = true + +# Optional +serde = { workspace = true, features = ["derive", "rc"], optional = true } + +[dev-dependencies] +database.workspace = true + +[features] +default = ["std"] +std = [ + "serde?/std", + "bytecode/std", + "context-interface/std", + "database/std", + "database-interface/std", + "primitives/std", + "state/std", +] +serde = [ + "dep:serde", + "primitives/serde", + "state/serde", + "context-interface/serde", + "bytecode/serde", + "database/serde", + "database-interface/serde", + "derive-where/serde", +] +dev = [ + "memory_limit", + "optional_balance_check", + "optional_block_gas_limit", + "optional_eip3541", + "optional_eip3607", + "optional_no_base_fee", + "optional_priority_fee_check", +] +memory_limit = [] +optional_balance_check = [] +optional_block_gas_limit = [] +optional_eip3541 = [] +optional_eip3607 = [] +optional_no_base_fee = [] +optional_priority_fee_check = [] diff --git a/crates/context/LICENSE b/crates/context/LICENSE new file mode 100644 index 0000000000..be6d350ebe --- /dev/null +++ b/crates/context/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021-2025 draganrakita + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/crates/context/interface/CHANGELOG.md b/crates/context/interface/CHANGELOG.md new file mode 100644 index 0000000000..0cf77dcb7e --- /dev/null +++ b/crates/context/interface/CHANGELOG.md @@ -0,0 +1,268 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [9.0.0](https://github.com/bluealloy/revm/compare/revm-context-interface-v8.0.1...revm-context-interface-v9.0.0) - 2025-07-23 + +### Fixed + +- fully deprecate serde-json ([#2767](https://github.com/bluealloy/revm/pull/2767)) + +### Other + +- un-Box frames ([#2761](https://github.com/bluealloy/revm/pull/2761)) +- discard generic host implementation ([#2738](https://github.com/bluealloy/revm/pull/2738)) + +## [8.0.1](https://github.com/bluealloy/revm/compare/revm-context-interface-v8.0.0...revm-context-interface-v8.0.1) - 2025-07-03 + +### Other + +- updated the following local packages: revm-state, revm-database-interface + +## [8.0.0](https://github.com/bluealloy/revm/compare/revm-context-interface-v7.0.1...revm-context-interface-v8.0.0) - 2025-06-30 + +### Added + +- implement `Transaction` for `Either` ([#2662](https://github.com/bluealloy/revm/pull/2662)) +- optional_eip3541 ([#2661](https://github.com/bluealloy/revm/pull/2661)) + +### Other + +- fix copy-pasted inner doc comments ([#2663](https://github.com/bluealloy/revm/pull/2663)) + +## [7.0.1](https://github.com/bluealloy/revm/compare/revm-context-interface-v7.0.0...revm-context-interface-v7.0.1) - 2025-06-20 + +### Fixed + +- call stack_frame.clear() at end ([#2656](https://github.com/bluealloy/revm/pull/2656)) + +## [7.0.0](https://github.com/bluealloy/revm/compare/revm-context-interface-v6.0.0...revm-context-interface-v7.0.0) - 2025-06-19 + +### Added + +- remove EOF ([#2644](https://github.com/bluealloy/revm/pull/2644)) +- configurable contract size limit ([#2611](https://github.com/bluealloy/revm/pull/2611)) ([#2642](https://github.com/bluealloy/revm/pull/2642)) +- *(precompile)* rug/gmp-based modexp ([#2596](https://github.com/bluealloy/revm/pull/2596)) +- change blob_max_count to max_blobs_per_tx ([#2608](https://github.com/bluealloy/revm/pull/2608)) +- add optional priority fee check configuration ([#2588](https://github.com/bluealloy/revm/pull/2588)) + +### Other + +- re-use frame allocation ([#2636](https://github.com/bluealloy/revm/pull/2636)) +- store coinbase address separately to avoid cloning warm addresses in the common case ([#2634](https://github.com/bluealloy/revm/pull/2634)) +- rename `transact` methods ([#2616](https://github.com/bluealloy/revm/pull/2616)) + +## [6.0.0](https://github.com/bluealloy/revm/compare/revm-context-interface-v5.0.0...revm-context-interface-v6.0.0) - 2025-06-06 + +### Added + +- *(Osaka)* EIP-7825 tx limit cap ([#2575](https://github.com/bluealloy/revm/pull/2575)) +- Config blob basefee fraction ([#2551](https://github.com/bluealloy/revm/pull/2551)) +- expand timestamp/block_number to u256 ([#2546](https://github.com/bluealloy/revm/pull/2546)) +- transact multi tx ([#2517](https://github.com/bluealloy/revm/pull/2517)) + +### Other + +- support functions for eip7918 ([#2579](https://github.com/bluealloy/revm/pull/2579)) +- *(docs)* add lints to database-interface and op-revm crates ([#2568](https://github.com/bluealloy/revm/pull/2568)) +- *(docs)* context crate lints ([#2565](https://github.com/bluealloy/revm/pull/2565)) +- ContextTr rm *_ref, and add *_mut fn ([#2560](https://github.com/bluealloy/revm/pull/2560)) +- *(cfg)* add tx_chain_id_check fields. Optimize effective gas cost calc ([#2557](https://github.com/bluealloy/revm/pull/2557)) + +## [5.0.0](https://github.com/bluealloy/revm/compare/revm-context-interface-v4.1.0...revm-context-interface-v5.0.0) - 2025-05-22 + +### Added + +- make blob max number optional ([#2532](https://github.com/bluealloy/revm/pull/2532)) + +### Other + +- add TxEnvBuilder::build_fill ([#2536](https://github.com/bluealloy/revm/pull/2536)) +- make crates.io version badge clickable ([#2526](https://github.com/bluealloy/revm/pull/2526)) +- Storage Types Alias ([#2461](https://github.com/bluealloy/revm/pull/2461)) + +## [4.1.0](https://github.com/bluealloy/revm/compare/revm-context-interface-v4.0.0...revm-context-interface-v4.1.0) - 2025-05-07 + +Dependency bump + +## [4.0.0](https://github.com/bluealloy/revm/compare/revm-context-interface-v3.0.0...revm-context-interface-v4.0.0) - 2025-05-07 + +### Added + +- *(Osaka)* disable EOF ([#2480](https://github.com/bluealloy/revm/pull/2480)) +- skip cloning of call input from shared memory ([#2462](https://github.com/bluealloy/revm/pull/2462)) +- Add a custom address to the CreateScheme. ([#2464](https://github.com/bluealloy/revm/pull/2464)) +- *(Handler)* merge state validation with deduct_caller ([#2460](https://github.com/bluealloy/revm/pull/2460)) +- add chain_ref method to ContextTr trait ([#2450](https://github.com/bluealloy/revm/pull/2450)) +- *(tx)* Add Either RecoveredAuthorization ([#2448](https://github.com/bluealloy/revm/pull/2448)) +- *(EOF)* Changes needed for devnet-1 ([#2377](https://github.com/bluealloy/revm/pull/2377)) +- Move SharedMemory buffer to context ([#2382](https://github.com/bluealloy/revm/pull/2382)) + +### Other + +- copy edit The Book ([#2463](https://github.com/bluealloy/revm/pull/2463)) +- bump dependency version ([#2431](https://github.com/bluealloy/revm/pull/2431)) +- fixed broken link ([#2421](https://github.com/bluealloy/revm/pull/2421)) + +## [3.0.0](https://github.com/bluealloy/revm/compare/revm-context-interface-v2.0.0...revm-context-interface-v3.0.0) - 2025-04-09 + +### Fixed + +- Effective gas price should check tx type ([#2375](https://github.com/bluealloy/revm/pull/2375)) + +### Other + +- make blob params u64 ([#2385](https://github.com/bluealloy/revm/pull/2385)) + +## [2.0.0](https://github.com/bluealloy/revm/compare/revm-context-interface-v1.0.0...revm-context-interface-v2.0.0) - 2025-03-28 + +### Added + +- Add JournalInner ([#2311](https://github.com/bluealloy/revm/pull/2311)) + +## [1.0.0](https://github.com/bluealloy/revm/compare/revm-context-interface-v1.0.0-alpha.5...revm-context-interface-v1.0.0) - 2025-03-24 + +Stable version + +## [1.0.0-alpha.6](https://github.com/bluealloy/revm/compare/revm-context-interface-v1.0.0-alpha.5...revm-context-interface-v1.0.0-alpha.6) - 2025-03-21 + +### Added + +- Remove PrecompileError from PrecompileProvider ([#2233](https://github.com/bluealloy/revm/pull/2233)) +- allow reuse of API for calculating initial tx gas for tx ([#2215](https://github.com/bluealloy/revm/pull/2215)) + +### Other + +- use AccessListItem associated type instead of AccessList ([#2214](https://github.com/bluealloy/revm/pull/2214)) + +## [1.0.0-alpha.5](https://github.com/bluealloy/revm/compare/revm-context-interface-v1.0.0-alpha.4...revm-context-interface-v1.0.0-alpha.5) - 2025-03-16 + +### Added + +- *(docs)* MyEvm example and book cleanup ([#2218](https://github.com/bluealloy/revm/pull/2218)) + +## [1.0.0-alpha.4](https://github.com/bluealloy/revm/compare/revm-context-interface-v1.0.0-alpha.3...revm-context-interface-v1.0.0-alpha.4) - 2025-03-12 + +### Added + +- add custom error to context ([#2197](https://github.com/bluealloy/revm/pull/2197)) +- Add tx/block to EvmExecution trait ([#2195](https://github.com/bluealloy/revm/pull/2195)) + +## [1.0.0-alpha.3](https://github.com/bluealloy/revm/compare/revm-context-interface-v1.0.0-alpha.2...revm-context-interface-v1.0.0-alpha.3) - 2025-03-11 + +### Fixed + +- correct propagate features ([#2177](https://github.com/bluealloy/revm/pull/2177)) + +### Other + +- Add comments to handler methods ([#2188](https://github.com/bluealloy/revm/pull/2188)) + +## [1.0.0-alpha.2](https://github.com/bluealloy/revm/compare/revm-context-interface-v1.0.0-alpha.1...revm-context-interface-v1.0.0-alpha.2) - 2025-03-10 + +### Added + +- remove specification crate ([#2165](https://github.com/bluealloy/revm/pull/2165)) +- Standalone Host, remove default fn from context ([#2147](https://github.com/bluealloy/revm/pull/2147)) +- implement AccessListTr for Vec ([#2136](https://github.com/bluealloy/revm/pull/2136)) +- allow host to be implemented on custom context ([#2112](https://github.com/bluealloy/revm/pull/2112)) + +### Other + +- JournalTr, JournalOutput, op only using revm crate ([#2155](https://github.com/bluealloy/revm/pull/2155)) +- remove `optional_gas_refund` as unused ([#2132](https://github.com/bluealloy/revm/pull/2132)) +- fix eofcreate error typo ([#2120](https://github.com/bluealloy/revm/pull/2120)) +- Add docs to revm-bytecode crate ([#2108](https://github.com/bluealloy/revm/pull/2108)) +- export eip2930 eip7702 types from one place ([#2097](https://github.com/bluealloy/revm/pull/2097)) +- move all dependencies to workspace ([#2092](https://github.com/bluealloy/revm/pull/2092)) + +## [1.0.0-alpha.1](https://github.com/bluealloy/revm/releases/tag/revm-context-interface-v1.0.0-alpha.1) - 2025-02-16 + +### Added + +- Introduce Auth and AccessList traits (#2079) +- Evm structure (Cached Instructions and Precompiles) (#2049) +- Context execution (#2013) +- EthHandler trait (#2001) +- *(EIP-7840)* Add blob schedule to execution client cfg (#1980) +- *(eip7702)* apply latest EIP-7702 changes, backport from v52 (#1969) +- *(EIP-7623)* Increase calldata cost. backport from rel/v51 (#1965) +- simplify Transaction trait (#1959) +- align Block trait (#1957) +- expose precompile address in Journal, DB::Error: StdError (#1956) +- Make Ctx journal generic (#1933) +- Restucturing Part7 Handler and Context rework (#1865) +- *(examples)* generate block traces (#895) +- implement EIP-4844 (#668) +- *(Shanghai)* All EIPs: push0, warm coinbase, limit/measure initcode (#376) +- Migrate `primitive_types::U256` to `ruint::Uint<256, 4>` (#239) +- Introduce ByteCode format, Update Readme (#156) + +### Fixed + +- Clear journal (#1927) +- fix typos ([#620](https://github.com/bluealloy/revm/pull/620)) + +### Other + +- set alpha.1 version +- API cleanup (#2067) +- relax halt reason bounds (#2041) +- simplify some generics (#2032) +- Make inspector use generics, rm associated types (#1934) +- fix comments and docs into more sensible (#1920) +- tie journal database with database getter (#1923) +- Move CfgEnv from context-interface to context crate (#1910) +- Bump new logo (#1735) +- *(README)* add rbuilder to used-by (#1585) +- added simular to used-by (#1521) +- add Trin to used by list (#1393) +- Fix typo in readme ([#1185](https://github.com/bluealloy/revm/pull/1185)) +- Add Hardhat to the "Used by" list ([#1164](https://github.com/bluealloy/revm/pull/1164)) +- Add VERBS to used by list ([#1141](https://github.com/bluealloy/revm/pull/1141)) +- license date and revm docs (#1080) +- *(docs)* Update the benchmark docs to point to revm package (#906) +- *(docs)* Update top-level benchmark docs (#894) +- clang requirement (#784) +- Readme Updates (#756) +- Logo (#743) +- book workflow ([#537](https://github.com/bluealloy/revm/pull/537)) +- add example to revm crate ([#468](https://github.com/bluealloy/revm/pull/468)) +- Update README.md ([#424](https://github.com/bluealloy/revm/pull/424)) +- add no_std to primitives ([#366](https://github.com/bluealloy/revm/pull/366)) +- revm-precompiles to revm-precompile +- Bump v20, changelog ([#350](https://github.com/bluealloy/revm/pull/350)) +- typos (#232) +- Add support for old forks. ([#191](https://github.com/bluealloy/revm/pull/191)) +- revm bump 1.8. update libs. snailtracer rename ([#159](https://github.com/bluealloy/revm/pull/159)) +- typo fixes +- fix readme typo +- Big Refactor. Machine to Interpreter. refactor instructions. call/create struct ([#52](https://github.com/bluealloy/revm/pull/52)) +- readme. debuger update +- Bump revm v0.3.0. README updated +- readme +- Add time elapsed for tests +- readme updated +- Include Basefee into cost calc. readme change +- Initialize precompile accounts +- Status update. Taking a break +- Merkle calc. Tweaks and debugging for eip158 +- Replace aurora bn lib with parity's. All Bn128Add/Mul/Pair tests passes +- TEMP +- one tab removed +- readme +- README Example simplified +- Gas calculation for Call/Create. Example Added +- readme usage +- README changes +- Static gas cost added +- Subroutine changelogs and reverts +- Readme postulates +- Spelling +- Restructure project +- First iteration. Machine is looking okay diff --git a/crates/context/interface/Cargo.toml b/crates/context/interface/Cargo.toml new file mode 100644 index 0000000000..de26f16d8d --- /dev/null +++ b/crates/context/interface/Cargo.toml @@ -0,0 +1,59 @@ +[package] +name = "revm-context-interface" +description = "Revm context interface crates" +version = "9.0.0" +authors.workspace = true +edition.workspace = true +keywords.workspace = true +license.workspace = true +repository.workspace = true +readme.workspace = true + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] + +[lints] +workspace = true + +[dependencies] +# revm +primitives.workspace = true +database-interface.workspace = true +state.workspace = true +alloy-eip7702 = { workspace = true, features = ["k256"] } +alloy-eip2930.workspace = true + +# misc +auto_impl.workspace = true +either.workspace = true + +# Optional +serde = { version = "1.0", default-features = false, features = [ + "derive", + "rc", +], optional = true } + +[features] +default = ["std"] +std = [ + "serde?/std", + "alloy-eip7702/std", + "alloy-eip2930/std", + "database-interface/std", + "primitives/std", + "state/std", + "either/std", +] +serde = [ + "dep:serde", + "primitives/serde", + "state/serde", + "alloy-eip7702/serde", + "alloy-eip2930/serde", + "database-interface/serde", + "either/serde", +] + +# Deprecated, please use `serde` feature instead. +serde-json = ["serde"] diff --git a/crates/context/interface/LICENSE b/crates/context/interface/LICENSE new file mode 100644 index 0000000000..be6d350ebe --- /dev/null +++ b/crates/context/interface/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021-2025 draganrakita + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/crates/context/interface/src/block.rs b/crates/context/interface/src/block.rs new file mode 100644 index 0000000000..dcc4c53af2 --- /dev/null +++ b/crates/context/interface/src/block.rs @@ -0,0 +1,75 @@ +//! Block related types and functions. +//! +//! [`Block`] trait is used to retrieve block information required for execution. +pub mod blob; + +pub use blob::{ + calc_blob_gasprice, calc_excess_blob_gas, calc_excess_blob_gas_osaka, BlobExcessGasAndPrice, +}; + +use auto_impl::auto_impl; +use primitives::{Address, B256, U256}; + +/// Trait for retrieving block information required for execution. +#[auto_impl(&, &mut, Box, Arc)] +pub trait Block { + /// The number of ancestor blocks of this block (block height). + fn number(&self) -> U256; + + /// Beneficiary (Coinbase, miner) is a address that have signed the block. + /// + /// This is the receiver address of priority gas rewards. + fn beneficiary(&self) -> Address; + + /// The timestamp of the block in seconds since the UNIX epoch. + fn timestamp(&self) -> U256; + + /// The gas limit of the block. + fn gas_limit(&self) -> u64; + + /// The base fee per gas, added in the London upgrade with [EIP-1559]. + /// + /// [EIP-1559]: https://eips.ethereum.org/EIPS/eip-1559 + fn basefee(&self) -> u64; + + /// The difficulty of the block. + /// + /// Unused after the Paris (AKA the merge) upgrade, and replaced by `prevrandao`. + fn difficulty(&self) -> U256; + + /// The output of the randomness beacon provided by the beacon chain. + /// + /// Replaces `difficulty` after the Paris (AKA the merge) upgrade with [EIP-4399]. + /// + /// Note: `prevrandao` can be found in a block in place of `mix_hash`. + /// + /// [EIP-4399]: https://eips.ethereum.org/EIPS/eip-4399 + fn prevrandao(&self) -> Option; + + /// Excess blob gas and blob gasprice. + /// See also [`calc_excess_blob_gas`] + /// and [`calc_blob_gasprice`]. + /// + /// Incorporated as part of the Cancun upgrade via [EIP-4844]. + /// + /// [EIP-4844]: https://eips.ethereum.org/EIPS/eip-4844 + fn blob_excess_gas_and_price(&self) -> Option; + + /// See [EIP-4844] and [`calc_blob_gasprice`]. + /// + /// Returns `None` if `Cancun` is not enabled. + /// + /// [EIP-4844]: https://eips.ethereum.org/EIPS/eip-4844 + fn blob_gasprice(&self) -> Option { + self.blob_excess_gas_and_price().map(|a| a.blob_gasprice) + } + + /// Return `blob_excess_gas` header field. See [EIP-4844]. + /// + /// Returns `None` if `Cancun` is not enabled. + /// + /// [EIP-4844]: https://eips.ethereum.org/EIPS/eip-4844 + fn blob_excess_gas(&self) -> Option { + self.blob_excess_gas_and_price().map(|a| a.excess_blob_gas) + } +} diff --git a/crates/context/interface/src/block/blob.rs b/crates/context/interface/src/block/blob.rs new file mode 100644 index 0000000000..fab7bc10e3 --- /dev/null +++ b/crates/context/interface/src/block/blob.rs @@ -0,0 +1,296 @@ +//! Blob (EIP-4844) related functions and types. [`BlobExcessGasAndPrice`] is struct that helps with +//! calculating blob gas price and excess blob gas. +//! +//! See also [the EIP-4844 helpers](https://eips.ethereum.org/EIPS/eip-4844#helpers). +//! +//! [`calc_blob_gasprice`] and [`calc_excess_blob_gas`] are used to calculate the blob gas price and +//! excess blob gas. +//! +//! [`BlobExcessGasAndPrice`] is used to store the blob gas price and excess blob gas.s +use primitives::{ + eip4844::{GAS_PER_BLOB, MIN_BLOB_GASPRICE}, + eip7918, +}; + +/// Structure holding block blob excess gas and it calculates blob fee +/// +/// Incorporated as part of the Cancun upgrade via [EIP-4844]. +/// +/// [EIP-4844]: https://eips.ethereum.org/EIPS/eip-4844 +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct BlobExcessGasAndPrice { + /// The excess blob gas of the block + pub excess_blob_gas: u64, + /// The calculated blob gas price based on the `excess_blob_gas` + /// + /// See [calc_blob_gasprice] + pub blob_gasprice: u128, +} + +impl BlobExcessGasAndPrice { + /// Creates a new instance by calculating the blob gas price with [`calc_blob_gasprice`]. + /// + /// `excess_blob_gas` is the excess blob gas of the block, it can be calculated with [`calc_excess_blob_gas`]. + pub fn new(excess_blob_gas: u64, blob_base_fee_update_fraction: u64) -> Self { + let blob_gasprice = calc_blob_gasprice(excess_blob_gas, blob_base_fee_update_fraction); + Self { + excess_blob_gas, + blob_gasprice, + } + } + + /// Calculate this block excess gas and price from the parent excess gas and gas used + /// and the target blob gas per block. + /// + /// This fields will be used to calculate `excess_blob_gas` with [`calc_excess_blob_gas`] func. + #[deprecated( + note = "Use `calc_excess_blob_gas` and `BlobExcessGasAndPrice::new` instead. Only works for forks before Osaka." + )] + pub fn from_parent_and_target( + parent_excess_blob_gas: u64, + parent_blob_gas_used: u64, + parent_target_blob_gas_per_block: u64, + blob_base_fee_update_fraction: u64, + ) -> Self { + Self::new( + calc_excess_blob_gas( + parent_excess_blob_gas, + parent_blob_gas_used, + parent_target_blob_gas_per_block, + ), + blob_base_fee_update_fraction, + ) + } +} + +/// Calculates the `excess_blob_gas` from the parent header's `blob_gas_used` and `excess_blob_gas`. +/// uses [`calc_excess_blob_gas`] internally. +#[inline] +pub fn calc_excess_blob_gas( + parent_excess_blob_gas: u64, + parent_blob_gas_used: u64, + parent_target_blob_gas_per_block: u64, +) -> u64 { + calc_excess_blob_gas_osaka( + parent_excess_blob_gas, + parent_blob_gas_used, + parent_target_blob_gas_per_block, + false, + 0, + 0, + 0, + 0, + 0, + ) +} + +/// Calculates the `excess_blob_gas` from the parent header's `blob_gas_used` and `excess_blob_gas`. +/// +/// See also [the EIP-4844 helpers] +/// (`calc_excess_blob_gas`). +/// +/// [EIP-7918: Blob base fee bounded by execution cost](https://eips.ethereum.org/EIPS/eip-7918) +/// +/// `blob_base_cost` is introduced in EIP-7918 in Osaka fork. All fields after is_osaka input are not needed before Osaka. +#[allow(clippy::too_many_arguments)] +#[inline] +pub fn calc_excess_blob_gas_osaka( + parent_excess_blob_gas: u64, + parent_blob_gas_used: u64, + parent_target_blob_gas_per_block: u64, + is_osaka: bool, + parent_base_fee_per_gas: u64, + parent_blob_base_fee_per_gas: u64, + parent_blob_base_fee_update_fraction: u64, + max_blob_count: u64, + target_blob_count: u64, +) -> u64 { + let excess_and_used = parent_excess_blob_gas.saturating_add(parent_blob_gas_used); + + if is_osaka { + if excess_and_used < parent_target_blob_gas_per_block { + return 0; + } + + if (eip7918::BLOB_BASE_COST.saturating_mul(parent_base_fee_per_gas) as u128) + > (GAS_PER_BLOB as u128).saturating_mul(get_base_fee_per_blob_gas( + parent_blob_base_fee_per_gas, + parent_blob_base_fee_update_fraction, + )) + { + return excess_and_used.saturating_add( + parent_blob_gas_used.saturating_mul(max_blob_count - target_blob_count) + / max_blob_count, + ); + } + } + + excess_and_used.saturating_sub(parent_target_blob_gas_per_block) +} + +/// Calculates the blob gas price from the header's excess blob gas field. +/// +/// See also [the EIP-4844 helpers](https://eips.ethereum.org/EIPS/eip-4844#helpers) +/// (`get_blob_gasprice`). +#[inline] +pub fn calc_blob_gasprice(excess_blob_gas: u64, blob_base_fee_update_fraction: u64) -> u128 { + fake_exponential( + MIN_BLOB_GASPRICE, + excess_blob_gas, + blob_base_fee_update_fraction, + ) +} + +/// Calculates the base fee per blob gas. Calls [`calc_blob_gasprice`] internally. +/// Name of the function is aligned with EIP-4844 spec. +pub fn get_base_fee_per_blob_gas(excess_blob_gas: u64, blob_base_fee_update_fraction: u64) -> u128 { + calc_blob_gasprice(excess_blob_gas, blob_base_fee_update_fraction) +} + +/// Approximates `factor * e ** (numerator / denominator)` using Taylor expansion. +/// +/// This is used to calculate the blob price. +/// +/// See also [the EIP-4844 helpers](https://eips.ethereum.org/EIPS/eip-4844#helpers) +/// (`fake_exponential`). +/// +/// # Panics +/// +/// This function panics if `denominator` is zero. +#[inline] +pub fn fake_exponential(factor: u64, numerator: u64, denominator: u64) -> u128 { + assert_ne!(denominator, 0, "attempt to divide by zero"); + let factor = factor as u128; + let numerator = numerator as u128; + let denominator = denominator as u128; + + let mut i = 1; + let mut output = 0; + let mut numerator_accum = factor * denominator; + while numerator_accum > 0 { + output += numerator_accum; + + // Denominator is asserted as not zero at the start of the function. + numerator_accum = (numerator_accum * numerator) / (denominator * i); + i += 1; + } + output / denominator +} + +#[cfg(test)] +mod tests { + use super::*; + use primitives::eip4844::{ + self, BLOB_BASE_FEE_UPDATE_FRACTION_CANCUN, GAS_PER_BLOB, + TARGET_BLOB_GAS_PER_BLOCK_CANCUN as TARGET_BLOB_GAS_PER_BLOCK, + }; + + // https://github.com/ethereum/go-ethereum/blob/28857080d732857030eda80c69b9ba2c8926f221/consensus/misc/eip4844/eip4844_test.go#L27 + #[test] + fn test_calc_excess_blob_gas() { + for t @ &(excess, blobs, expected) in &[ + // The excess blob gas should not increase from zero if the used blob + // slots are below - or equal - to the target. + (0, 0, 0), + (0, 1, 0), + (0, TARGET_BLOB_GAS_PER_BLOCK / GAS_PER_BLOB, 0), + // If the target blob gas is exceeded, the excessBlobGas should increase + // by however much it was overshot + ( + 0, + (TARGET_BLOB_GAS_PER_BLOCK / GAS_PER_BLOB) + 1, + GAS_PER_BLOB, + ), + ( + 1, + (TARGET_BLOB_GAS_PER_BLOCK / GAS_PER_BLOB) + 1, + GAS_PER_BLOB + 1, + ), + ( + 1, + (TARGET_BLOB_GAS_PER_BLOCK / GAS_PER_BLOB) + 2, + 2 * GAS_PER_BLOB + 1, + ), + // The excess blob gas should decrease by however much the target was + // under-shot, capped at zero. + ( + TARGET_BLOB_GAS_PER_BLOCK, + TARGET_BLOB_GAS_PER_BLOCK / GAS_PER_BLOB, + TARGET_BLOB_GAS_PER_BLOCK, + ), + ( + TARGET_BLOB_GAS_PER_BLOCK, + (TARGET_BLOB_GAS_PER_BLOCK / GAS_PER_BLOB) - 1, + TARGET_BLOB_GAS_PER_BLOCK - GAS_PER_BLOB, + ), + ( + TARGET_BLOB_GAS_PER_BLOCK, + (TARGET_BLOB_GAS_PER_BLOCK / GAS_PER_BLOB) - 2, + TARGET_BLOB_GAS_PER_BLOCK - (2 * GAS_PER_BLOB), + ), + ( + GAS_PER_BLOB - 1, + (TARGET_BLOB_GAS_PER_BLOCK / GAS_PER_BLOB) - 1, + 0, + ), + ] { + let actual = calc_excess_blob_gas( + excess, + blobs * GAS_PER_BLOB, + eip4844::TARGET_BLOB_GAS_PER_BLOCK_CANCUN, + ); + assert_eq!(actual, expected, "test: {t:?}"); + } + } + + // https://github.com/ethereum/go-ethereum/blob/28857080d732857030eda80c69b9ba2c8926f221/consensus/misc/eip4844/eip4844_test.go#L60 + #[test] + fn test_calc_blob_fee_cancun() { + let blob_fee_vectors = &[ + (0, 1), + (2314057, 1), + (2314058, 2), + (10 * 1024 * 1024, 23), + // `calc_blob_gasprice` approximates `e ** (excess_blob_gas / BLOB_BASE_FEE_UPDATE_FRACTION)` using Taylor expansion + // + // to roughly find where boundaries will be hit: + // 2 ** bits = e ** (excess_blob_gas / BLOB_BASE_FEE_UPDATE_FRACTION) + // excess_blob_gas = ln(2 ** bits) * BLOB_BASE_FEE_UPDATE_FRACTION + (148099578, 18446739238971471609), // output is just below the overflow + (148099579, 18446744762204311910), // output is just after the overflow + (161087488, 902580055246494526580), + ]; + + for &(excess, expected) in blob_fee_vectors { + let actual = calc_blob_gasprice(excess, BLOB_BASE_FEE_UPDATE_FRACTION_CANCUN); + assert_eq!(actual, expected, "test: {excess}"); + } + } + + // https://github.com/ethereum/go-ethereum/blob/28857080d732857030eda80c69b9ba2c8926f221/consensus/misc/eip4844/eip4844_test.go#L78 + #[test] + fn fake_exp() { + for t @ &(factor, numerator, denominator, expected) in &[ + (1u64, 0u64, 1u64, 1u128), + (38493, 0, 1000, 38493), + (0, 1234, 2345, 0), + (1, 2, 1, 6), // approximate 7.389 + (1, 4, 2, 6), + (1, 3, 1, 16), // approximate 20.09 + (1, 6, 2, 18), + (1, 4, 1, 49), // approximate 54.60 + (1, 8, 2, 50), + (10, 8, 2, 542), // approximate 540.598 + (11, 8, 2, 596), // approximate 600.58 + (1, 5, 1, 136), // approximate 148.4 + (1, 5, 2, 11), // approximate 12.18 + (2, 5, 2, 23), // approximate 24.36 + (1, 50000000, 2225652, 5709098764), + (1, 380928, BLOB_BASE_FEE_UPDATE_FRACTION_CANCUN, 1), + ] { + let actual = fake_exponential(factor, numerator, denominator); + assert_eq!(actual, expected, "test: {t:?}"); + } + } +} diff --git a/crates/context/interface/src/cfg.rs b/crates/context/interface/src/cfg.rs new file mode 100644 index 0000000000..3212b81520 --- /dev/null +++ b/crates/context/interface/src/cfg.rs @@ -0,0 +1,94 @@ +//! Configuration for the EVM. Containing [`SpecId`]. +use auto_impl::auto_impl; +use core::fmt::Debug; +use core::hash::Hash; +use primitives::{hardfork::SpecId, Address, TxKind, U256}; + +/// Configuration for the EVM. +#[auto_impl(&, &mut, Box, Arc)] +pub trait Cfg { + /// Specification id type, in requires to be convertible to `SpecId` so it can be used + /// by default in mainnet. + type Spec: Into + Clone; + + /// Returns the chain ID of the EVM that is compared with the transaction's chain ID. + fn chain_id(&self) -> u64; + + /// Returns whether the transaction's chain ID check is enabled. + fn tx_chain_id_check(&self) -> bool; + + /// Returns the gas limit cap for the transaction. + /// + /// Cap is introduced in [`EIP-7825: Transaction Gas Limit Cap`](https://eips.ethereum.org/EIPS/eip-7825) + /// with initial cap of 30M gas. + /// + /// Value before EIP-7825 is `u64::MAX`. + fn tx_gas_limit_cap(&self) -> u64; + + /// Specification id + fn spec(&self) -> Self::Spec; + + /// Returns the maximum number of blobs allowed per transaction. + /// If it is None, check for max count will be skipped. + fn max_blobs_per_tx(&self) -> Option; + + /// Returns the maximum code size for the given spec id. + fn max_code_size(&self) -> usize; + + /// Returns the max initcode size for the given spec id. + fn max_initcode_size(&self) -> usize; + + /// Returns whether the EIP-3607 (account clearing) is disabled. + fn is_eip3607_disabled(&self) -> bool; + + /// Returns whether the EIP-3541 (disallowing new contracts with 0xEF prefix) is disabled. + fn is_eip3541_disabled(&self) -> bool; + + /// Returns whether the balance check is disabled. + fn is_balance_check_disabled(&self) -> bool; + + /// Returns whether the block gas limit check is disabled. + fn is_block_gas_limit_disabled(&self) -> bool; + + /// Returns whether the nonce check is disabled. + fn is_nonce_check_disabled(&self) -> bool; + + /// Returns whether the base fee check is disabled. + fn is_base_fee_check_disabled(&self) -> bool; + + /// Returns whether the priority fee check is disabled. + fn is_priority_fee_check_disabled(&self) -> bool; +} + +/// What bytecode analysis to perform +#[derive(Clone, Default, Debug, Eq, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub enum AnalysisKind { + /// Do not perform bytecode analysis + Raw, + /// Perform bytecode analysis + #[default] + Analyse, +} + +/// Transaction destination +pub type TransactTo = TxKind; + +/// Create scheme +#[derive(Clone, Copy, Default, Debug, Eq, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub enum CreateScheme { + /// Legacy create scheme of `CREATE` + #[default] + Create, + /// Create scheme of `CREATE2` + Create2 { + /// Salt + salt: U256, + }, + /// Custom scheme where we set up the original address + Custom { + /// Custom contract creation address. + address: Address, + }, +} diff --git a/crates/context/interface/src/context.rs b/crates/context/interface/src/context.rs new file mode 100644 index 0000000000..bbf1311a18 --- /dev/null +++ b/crates/context/interface/src/context.rs @@ -0,0 +1,174 @@ +//! Context trait and related types. +pub use crate::journaled_state::StateLoad; +use crate::{ + result::FromStringError, Block, Cfg, Database, Host, JournalTr, LocalContextTr, Transaction, +}; +use auto_impl::auto_impl; +use primitives::StorageValue; +use std::string::String; + +/// Trait that defines the context of the EVM execution. +/// +/// This trait is used to access the environment and state of the EVM. +/// It is used to access the transaction, block, configuration, database, journal, and chain. +/// It is also used to set the error of the EVM. +/// +/// All function has a `*_mut` variant except the function for [`ContextTr::tx`] and [`ContextTr::block`]. +#[auto_impl(&mut, Box)] +pub trait ContextTr: Host { + /// Block type + type Block: Block; + /// Transaction type + type Tx: Transaction; + /// Configuration type + type Cfg: Cfg; + /// Database type + type Db: Database; + /// Journal type + type Journal: JournalTr; + /// Chain type + type Chain; + /// Local context type + type Local: LocalContextTr; + + /// Get the transaction + fn tx(&self) -> &Self::Tx; + /// Get the block + fn block(&self) -> &Self::Block; + /// Get the configuration + fn cfg(&self) -> &Self::Cfg; + /// Get the journal + fn journal(&self) -> &Self::Journal; + /// Get the journal mutably + fn journal_mut(&mut self) -> &mut Self::Journal; + /// Get the journal reference + fn journal_ref(&self) -> &Self::Journal { + self.journal() + } + /// Get the database + fn db(&self) -> &Self::Db; + /// Get the database mutably + fn db_mut(&mut self) -> &mut Self::Db; + /// Get the database reference + fn db_ref(&self) -> &Self::Db { + self.db() + } + /// Get the chain + fn chain(&self) -> &Self::Chain; + /// Get the chain mutably + fn chain_mut(&mut self) -> &mut Self::Chain; + /// Get the chain reference + fn chain_ref(&self) -> &Self::Chain { + self.chain() + } + /// Get the local context + fn local(&self) -> &Self::Local; + /// Get the local context mutably + fn local_mut(&mut self) -> &mut Self::Local; + /// Get the local context reference + fn local_ref(&self) -> &Self::Local { + self.local() + } + /// Get the error + fn error(&mut self) -> &mut Result<(), ContextError<::Error>>; + /// Get the transaction and journal. It is used to efficiently load access list + /// into journal without copying them from transaction. + fn tx_journal_mut(&mut self) -> (&Self::Tx, &mut Self::Journal); + /// Get the transaction and local context. It is used to efficiently load initcode + /// into local context without copying them from transaction. + fn tx_local_mut(&mut self) -> (&Self::Tx, &mut Self::Local); +} + +/// Inner Context error used for Interpreter to set error without returning it frm instruction +#[derive(Clone, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub enum ContextError { + /// Database error. + Db(DbError), + /// Custom string error. + Custom(String), +} + +impl FromStringError for ContextError { + fn from_string(value: String) -> Self { + Self::Custom(value) + } +} + +impl From for ContextError { + fn from(value: DbError) -> Self { + Self::Db(value) + } +} + +/// Represents the result of an `sstore` operation. +#[derive(Clone, Debug, Default, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct SStoreResult { + /// Value of the storage when it is first read + pub original_value: StorageValue, + /// Current value of the storage + pub present_value: StorageValue, + /// New value that is set + pub new_value: StorageValue, +} + +impl SStoreResult { + /// Returns `true` if the new value is equal to the present value. + #[inline] + pub fn is_new_eq_present(&self) -> bool { + self.new_value == self.present_value + } + + /// Returns `true` if the original value is equal to the present value. + #[inline] + pub fn is_original_eq_present(&self) -> bool { + self.original_value == self.present_value + } + + /// Returns `true` if the original value is equal to the new value. + #[inline] + pub fn is_original_eq_new(&self) -> bool { + self.original_value == self.new_value + } + + /// Returns `true` if the original value is zero. + #[inline] + pub fn is_original_zero(&self) -> bool { + self.original_value.is_zero() + } + + /// Returns `true` if the present value is zero. + #[inline] + pub fn is_present_zero(&self) -> bool { + self.present_value.is_zero() + } + + /// Returns `true` if the new value is zero. + #[inline] + pub fn is_new_zero(&self) -> bool { + self.new_value.is_zero() + } +} + +/// Result of a selfdestruct action +/// +/// Value returned are needed to calculate the gas spent. +#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct SelfDestructResult { + /// Whether the account had a value. + pub had_value: bool, + /// Whether the target account exists. + pub target_exists: bool, + /// Whether the account was previously destroyed. + pub previously_destroyed: bool, +} + +/// Trait for setting the transaction and block in the context. +pub trait ContextSetters: ContextTr { + /// Set the transaction + fn set_tx(&mut self, tx: Self::Tx); + /// Set the block + fn set_block(&mut self, block: Self::Block); +} diff --git a/crates/context/interface/src/host.rs b/crates/context/interface/src/host.rs new file mode 100644 index 0000000000..636a5eb4dc --- /dev/null +++ b/crates/context/interface/src/host.rs @@ -0,0 +1,197 @@ +//! Host interface for external blockchain state access. + +use crate::{ + context::{SStoreResult, SelfDestructResult, StateLoad}, + journaled_state::AccountLoad, +}; +use auto_impl::auto_impl; +use primitives::{Address, Bytes, Log, StorageKey, StorageValue, B256, U256}; + +/// Host trait with all methods that are needed by the Interpreter. +/// +/// This trait is implemented for all types that have `ContextTr` trait. +/// +/// There are few groups of functions which are Block, Transaction, Config, Database and Journal functions. +#[auto_impl(&mut, Box)] +pub trait Host { + /* Block */ + + /// Block basefee, calls ContextTr::block().basefee() + fn basefee(&self) -> U256; + /// Block blob gasprice, calls `ContextTr::block().blob_gasprice()` + fn blob_gasprice(&self) -> U256; + /// Block gas limit, calls ContextTr::block().gas_limit() + fn gas_limit(&self) -> U256; + /// Block difficulty, calls ContextTr::block().difficulty() + fn difficulty(&self) -> U256; + /// Block prevrandao, calls ContextTr::block().prevrandao() + fn prevrandao(&self) -> Option; + /// Block number, calls ContextTr::block().number() + fn block_number(&self) -> U256; + /// Block timestamp, calls ContextTr::block().timestamp() + fn timestamp(&self) -> U256; + /// Block beneficiary, calls ContextTr::block().beneficiary() + fn beneficiary(&self) -> Address; + /// Chain id, calls ContextTr::cfg().chain_id() + fn chain_id(&self) -> U256; + + /* Transaction */ + + /// Transaction effective gas price, calls `ContextTr::tx().effective_gas_price(basefee as u128)` + fn effective_gas_price(&self) -> U256; + /// Transaction caller, calls `ContextTr::tx().caller()` + fn caller(&self) -> Address; + /// Transaction blob hash, calls `ContextTr::tx().blob_hash(number)` + fn blob_hash(&self, number: usize) -> Option; + + /* Config */ + + /// Max initcode size, calls `ContextTr::cfg().max_code_size().saturating_mul(2)` + fn max_initcode_size(&self) -> usize; + + /* Database */ + + /// Block hash, calls `ContextTr::journal_mut().db().block_hash(number)` + fn block_hash(&mut self, number: u64) -> Option; + + /* Journal */ + + /// Selfdestruct account, calls `ContextTr::journal_mut().selfdestruct(address, target)` + fn selfdestruct( + &mut self, + address: Address, + target: Address, + ) -> Option>; + + /// Log, calls `ContextTr::journal_mut().log(log)` + fn log(&mut self, log: Log); + /// Sstore, calls `ContextTr::journal_mut().sstore(address, key, value)` + fn sstore( + &mut self, + address: Address, + key: StorageKey, + value: StorageValue, + ) -> Option>; + + /// Sload, calls `ContextTr::journal_mut().sload(address, key)` + fn sload(&mut self, address: Address, key: StorageKey) -> Option>; + /// Tstore, calls `ContextTr::journal_mut().tstore(address, key, value)` + fn tstore(&mut self, address: Address, key: StorageKey, value: StorageValue); + /// Tload, calls `ContextTr::journal_mut().tload(address, key)` + fn tload(&mut self, address: Address, key: StorageKey) -> StorageValue; + /// Balance, calls `ContextTr::journal_mut().load_account(address)` + fn balance(&mut self, address: Address) -> Option>; + /// Load account delegated, calls `ContextTr::journal_mut().load_account_delegated(address)` + fn load_account_delegated(&mut self, address: Address) -> Option>; + /// Load account code, calls `ContextTr::journal_mut().load_account_code(address)` + fn load_account_code(&mut self, address: Address) -> Option>; + /// Load account code hash, calls `ContextTr::journal_mut().code_hash(address)` + fn load_account_code_hash(&mut self, address: Address) -> Option>; +} + +/// Dummy host that implements [`Host`] trait and returns all default values. +#[derive(Debug)] +pub struct DummyHost; + +impl Host for DummyHost { + fn basefee(&self) -> U256 { + U256::ZERO + } + + fn blob_gasprice(&self) -> U256 { + U256::ZERO + } + + fn gas_limit(&self) -> U256 { + U256::ZERO + } + + fn difficulty(&self) -> U256 { + U256::ZERO + } + + fn prevrandao(&self) -> Option { + None + } + + fn block_number(&self) -> U256 { + U256::ZERO + } + + fn timestamp(&self) -> U256 { + U256::ZERO + } + + fn beneficiary(&self) -> Address { + Address::ZERO + } + + fn chain_id(&self) -> U256 { + U256::ZERO + } + + fn effective_gas_price(&self) -> U256 { + U256::ZERO + } + + fn caller(&self) -> Address { + Address::ZERO + } + + fn blob_hash(&self, _number: usize) -> Option { + None + } + + fn max_initcode_size(&self) -> usize { + 0 + } + + fn block_hash(&mut self, _number: u64) -> Option { + None + } + + fn selfdestruct( + &mut self, + _address: Address, + _target: Address, + ) -> Option> { + None + } + + fn log(&mut self, _log: Log) {} + + fn sstore( + &mut self, + _address: Address, + _key: StorageKey, + _value: StorageValue, + ) -> Option> { + None + } + + fn sload(&mut self, _address: Address, _key: StorageKey) -> Option> { + None + } + + fn tstore(&mut self, _address: Address, _key: StorageKey, _value: StorageValue) {} + + fn tload(&mut self, _address: Address, _key: StorageKey) -> StorageValue { + StorageValue::ZERO + } + + fn balance(&mut self, _address: Address) -> Option> { + None + } + + fn load_account_delegated(&mut self, _address: Address) -> Option> { + None + } + + fn load_account_code(&mut self, _address: Address) -> Option> { + None + } + + fn load_account_code_hash(&mut self, _address: Address) -> Option> { + None + } +} diff --git a/crates/context/interface/src/journaled_state.rs b/crates/context/interface/src/journaled_state.rs new file mode 100644 index 0000000000..1cf9900624 --- /dev/null +++ b/crates/context/interface/src/journaled_state.rs @@ -0,0 +1,287 @@ +//! Journaled state trait [`JournalTr`] and related types. +use crate::context::{SStoreResult, SelfDestructResult}; +use core::ops::{Deref, DerefMut}; +use database_interface::Database; +use primitives::{ + hardfork::SpecId, Address, Bytes, HashSet, Log, StorageKey, StorageValue, B256, U256, +}; +use state::{Account, Bytecode}; +use std::vec::Vec; + +/// Trait that contains database and journal of all changes that were made to the state. +pub trait JournalTr { + /// Database type that is used in the journal. + type Database: Database; + /// State type that is returned by the journal after finalization. + type State; + + /// Creates new Journaled state. + /// + /// Dont forget to set spec_id. + fn new(database: Self::Database) -> Self; + + /// Returns the database. + fn db_mut(&mut self) -> &mut Self::Database; + + /// Returns the mutable database. + fn db(&self) -> &Self::Database; + + /// Returns the storage value from Journal state. + /// + /// Loads the storage from database if not found in Journal state. + fn sload( + &mut self, + address: Address, + key: StorageKey, + ) -> Result, ::Error>; + + /// Stores the storage value in Journal state. + fn sstore( + &mut self, + address: Address, + key: StorageKey, + value: StorageValue, + ) -> Result, ::Error>; + + /// Loads transient storage value. + fn tload(&mut self, address: Address, key: StorageKey) -> StorageValue; + + /// Stores transient storage value. + fn tstore(&mut self, address: Address, key: StorageKey, value: StorageValue); + + /// Logs the log in Journal state. + fn log(&mut self, log: Log); + + /// Marks the account for selfdestruction and transfers all the balance to the target. + fn selfdestruct( + &mut self, + address: Address, + target: Address, + ) -> Result, ::Error>; + + /// Warms the account and storage. + fn warm_account_and_storage( + &mut self, + address: Address, + storage_keys: impl IntoIterator, + ) -> Result<(), ::Error>; + + /// Warms the account. + fn warm_account(&mut self, address: Address); + + /// Warms the coinbase account. + fn warm_coinbase_account(&mut self, address: Address); + + /// Warms the precompiles. + fn warm_precompiles(&mut self, addresses: HashSet
); + + /// Returns the addresses of the precompiles. + fn precompile_addresses(&self) -> &HashSet
; + + /// Sets the spec id. + fn set_spec_id(&mut self, spec_id: SpecId); + + /// Touches the account. + fn touch_account(&mut self, address: Address); + + /// Transfers the balance from one account to another. + fn transfer( + &mut self, + from: Address, + to: Address, + balance: U256, + ) -> Result, ::Error>; + + /// Increments the balance of the account. + fn caller_accounting_journal_entry( + &mut self, + address: Address, + old_balance: U256, + bump_nonce: bool, + ); + + /// Increments the balance of the account. + fn balance_incr( + &mut self, + address: Address, + balance: U256, + ) -> Result<(), ::Error>; + + /// Increments the nonce of the account. + fn nonce_bump_journal_entry(&mut self, address: Address); + + /// Loads the account. + fn load_account( + &mut self, + address: Address, + ) -> Result, ::Error>; + + /// Loads the account code. + fn load_account_code( + &mut self, + address: Address, + ) -> Result, ::Error>; + + /// Loads the account delegated. + fn load_account_delegated( + &mut self, + address: Address, + ) -> Result, ::Error>; + + /// Sets bytecode with hash. Assume that account is warm. + fn set_code_with_hash(&mut self, address: Address, code: Bytecode, hash: B256); + + /// Sets bytecode and calculates hash. + /// + /// Assume account is warm. + #[inline] + fn set_code(&mut self, address: Address, code: Bytecode) { + let hash = code.hash_slow(); + self.set_code_with_hash(address, code, hash); + } + + /// Returns account code bytes and if address is cold loaded. + #[inline] + fn code( + &mut self, + address: Address, + ) -> Result, ::Error> { + let a = self.load_account_code(address)?; + // SAFETY: Safe to unwrap as load_code will insert code if it is empty. + let code = a.info.code.as_ref().unwrap(); + let code = code.original_bytes(); + + Ok(StateLoad::new(code, a.is_cold)) + } + + /// Gets code hash of account. + fn code_hash( + &mut self, + address: Address, + ) -> Result, ::Error> { + let acc = self.load_account_code(address)?; + if acc.is_empty() { + return Ok(StateLoad::new(B256::ZERO, acc.is_cold)); + } + // SAFETY: Safe to unwrap as load_code will insert code if it is empty. + let _code = acc.info.code.as_ref().unwrap(); + + let hash = acc.info.code_hash; + + Ok(StateLoad::new(hash, acc.is_cold)) + } + + /// Called at the end of the transaction to clean all residue data from journal. + fn clear(&mut self) { + let _ = self.finalize(); + } + + /// Creates a checkpoint of the current state. State can be revert to this point + /// if needed. + fn checkpoint(&mut self) -> JournalCheckpoint; + + /// Commits the changes made since the last checkpoint. + fn checkpoint_commit(&mut self); + + /// Reverts the changes made since the last checkpoint. + fn checkpoint_revert(&mut self, checkpoint: JournalCheckpoint); + + /// Creates a checkpoint of the account creation. + fn create_account_checkpoint( + &mut self, + caller: Address, + address: Address, + balance: U256, + spec_id: SpecId, + ) -> Result; + + /// Returns the depth of the journal. + fn depth(&self) -> usize; + + /// Take logs from journal. + fn take_logs(&mut self) -> Vec; + + /// Commit current transaction journal and returns transaction logs. + fn commit_tx(&mut self); + + /// Discard current transaction journal by removing journal entries and logs and incrementing the transaction id. + /// + /// This function is useful to discard intermediate state that is interrupted by error and it will not revert + /// any already committed changes and it is safe to call it multiple times. + fn discard_tx(&mut self); + + /// Clear current journal resetting it to initial state and return changes state. + fn finalize(&mut self) -> Self::State; +} + +/// Transfer and creation result +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum TransferError { + /// Caller does not have enough funds + OutOfFunds, + /// Overflow in target account + OverflowPayment, + /// Create collision. + CreateCollision, +} + +/// SubRoutine checkpoint that will help us to go back from this +#[derive(Debug, Default, Copy, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct JournalCheckpoint { + /// Checkpoint to where on revert we will go back to. + pub log_i: usize, + /// Checkpoint to where on revert we will go back to and revert other journal entries. + pub journal_i: usize, +} + +/// State load information that contains the data and if the account or storage is cold loaded +#[derive(Clone, Debug, Default, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct StateLoad { + /// Returned data + pub data: T, + /// Is account is cold loaded + pub is_cold: bool, +} + +impl Deref for StateLoad { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.data + } +} + +impl DerefMut for StateLoad { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.data + } +} + +impl StateLoad { + /// Returns a new [`StateLoad`] with the given data and cold load status. + pub fn new(data: T, is_cold: bool) -> Self { + Self { data, is_cold } + } + + /// Maps the data of the [`StateLoad`] to a new value. + /// + /// Useful for transforming the data of the [`StateLoad`] without changing the cold load status. + pub fn map(self, f: F) -> StateLoad + where + F: FnOnce(T) -> B, + { + StateLoad::new(f(self.data), self.is_cold) + } +} + +/// Result of the account load from Journal state +#[derive(Clone, Debug, Default, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct AccountLoad { + /// Does account have delegate code and delegated account is cold loaded + pub is_delegate_account_cold: Option, + /// Is account empty, if `true` account is not created + pub is_empty: bool, +} diff --git a/crates/context/interface/src/lib.rs b/crates/context/interface/src/lib.rs new file mode 100644 index 0000000000..0e66071368 --- /dev/null +++ b/crates/context/interface/src/lib.rs @@ -0,0 +1,25 @@ +//! EVM execution context interface. +#![cfg_attr(not(test), warn(unused_crate_dependencies))] +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(not(feature = "std"))] +extern crate alloc as std; + +pub mod block; +pub mod cfg; +pub mod context; +pub mod host; +pub mod journaled_state; +pub mod local; +pub mod result; +pub mod transaction; + +pub use block::Block; +pub use cfg::{Cfg, CreateScheme, TransactTo}; +pub use context::{ContextError, ContextSetters, ContextTr}; +pub use database_interface::{DBErrorMarker, Database}; +pub use either; +pub use host::{DummyHost, Host}; +pub use journaled_state::JournalTr; +pub use local::{FrameStack, FrameToken, LocalContextTr, OutFrame}; +pub use transaction::{Transaction, TransactionType}; diff --git a/crates/context/interface/src/local.rs b/crates/context/interface/src/local.rs new file mode 100644 index 0000000000..56c4832842 --- /dev/null +++ b/crates/context/interface/src/local.rs @@ -0,0 +1,238 @@ +//! Local context trait [`LocalContextTr`] and related types. +use core::{ + cell::{Ref, RefCell}, + ops::Range, +}; +use std::{rc::Rc, vec::Vec}; + +/// Non-empty, item-pooling Vec. +#[derive(Debug, Clone)] +pub struct FrameStack { + stack: Vec, + index: Option, +} + +impl Default for FrameStack { + fn default() -> Self { + Self::new() + } +} + +impl FrameStack { + /// Creates a new, empty stack. It must be initialized with init before use. + pub fn new() -> Self { + Self { + stack: Vec::with_capacity(4), + index: None, + } + } + + /// Initializes the stack with a single item. + #[inline] + pub fn start_init(&mut self) -> OutFrame<'_, T> { + self.index = None; + if self.stack.is_empty() { + self.stack.reserve(1); + } + self.out_frame_at(0) + } + + /// Finishes initialization. + #[inline] + pub fn end_init(&mut self, token: FrameToken) { + token.assert(); + if self.stack.is_empty() { + unsafe { self.stack.set_len(1) }; + } + self.index = Some(0); + } + + /// Returns the current index of the stack. + #[inline] + pub fn index(&self) -> Option { + self.index + } + + /// Increments the index. + #[inline] + pub fn push(&mut self, token: FrameToken) { + token.assert(); + let index = self.index.as_mut().unwrap(); + if *index + 1 == self.stack.len() { + unsafe { self.stack.set_len(self.stack.len() + 1) }; + self.stack.reserve(1); + } + *index += 1; + } + + /// Clears the stack by setting the index to 0. + /// It does not destroy the stack. + #[inline] + pub fn clear(&mut self) { + self.index = None; + } + + /// Decrements the index. + #[inline] + pub fn pop(&mut self) { + self.index = self.index.unwrap_or(0).checked_sub(1); + } + + /// Returns the current item. + #[inline] + pub fn get(&mut self) -> &mut T { + debug_assert!(self.stack.capacity() > self.index.unwrap() + 1); + unsafe { &mut *self.stack.as_mut_ptr().add(self.index.unwrap()) } + } + + /// Get next uninitialized item. + #[inline] + pub fn get_next(&mut self) -> OutFrame<'_, T> { + self.out_frame_at(self.index.unwrap() + 1) + } + + fn out_frame_at(&mut self, idx: usize) -> OutFrame<'_, T> { + unsafe { + OutFrame::new_maybe_uninit(self.stack.as_mut_ptr().add(idx), idx < self.stack.len()) + } + } +} + +/// A potentially initialized frame. Used when initializing a new frame in the main loop. +#[allow(missing_debug_implementations)] +pub struct OutFrame<'a, T> { + ptr: *mut T, + init: bool, + lt: core::marker::PhantomData<&'a mut T>, +} + +impl<'a, T> OutFrame<'a, T> { + /// Creates a new initialized `OutFrame` from a mutable reference to a type `T`. + pub fn new_init(slot: &'a mut T) -> Self { + unsafe { Self::new_maybe_uninit(slot, true) } + } + + /// Creates a new uninitialized `OutFrame` from a mutable reference to a `MaybeUninit`. + pub fn new_uninit(slot: &'a mut core::mem::MaybeUninit) -> Self { + unsafe { Self::new_maybe_uninit(slot.as_mut_ptr(), false) } + } + + /// Creates a new `OutFrame` from a raw pointer to a type `T`. + /// + /// # Safety + /// + /// This method is unsafe because it assumes that the pointer is valid and points to a location + /// where a type `T` can be stored. It also assumes that the `init` flag correctly reflects whether + /// the type `T` has been initialized or not. + pub unsafe fn new_maybe_uninit(ptr: *mut T, init: bool) -> Self { + Self { + ptr, + init, + lt: Default::default(), + } + } + + /// Returns a mutable reference to the type `T`, initializing it if it hasn't been initialized yet. + pub fn get(&mut self, f: impl FnOnce() -> T) -> &mut T { + if !self.init { + self.do_init(f); + } + unsafe { &mut *self.ptr } + } + + #[inline(never)] + #[cold] + fn do_init(&mut self, f: impl FnOnce() -> T) { + unsafe { + self.init = true; + self.ptr.write(f()); + } + } + + /// Returns a mutable reference to the type `T`, without checking if it has been initialized. + /// + /// # Safety + /// + /// This method is unsafe because it assumes that the `OutFrame` has been initialized before use. + pub unsafe fn get_unchecked(&mut self) -> &mut T { + debug_assert!(self.init, "OutFrame must be initialized before use"); + unsafe { &mut *self.ptr } + } + + /// Consumes the `OutFrame`, returning a `FrameToken` that indicates the frame has been initialized. + pub fn consume(self) -> FrameToken { + FrameToken(self.init) + } +} + +/// Used to guarantee that a frame is initialized before use. +#[allow(missing_debug_implementations)] +pub struct FrameToken(bool); + +impl FrameToken { + /// Asserts that the frame token is initialized. + #[cfg_attr(debug_assertions, track_caller)] + pub fn assert(self) { + assert!(self.0, "FrameToken must be initialized before use"); + } +} + +/// Local context used for caching initcode from Initcode transactions. +pub trait LocalContextTr { + /// Interpreter shared memory buffer. A reused memory buffer for calls. + fn shared_memory_buffer(&self) -> &Rc>>; + + /// Slice of the shared memory buffer returns None if range is not valid or buffer can't be borrowed. + fn shared_memory_buffer_slice(&self, range: Range) -> Option> { + let buffer = self.shared_memory_buffer(); + buffer.borrow().get(range.clone())?; + Some(Ref::map(buffer.borrow(), |b| { + b.get(range).unwrap_or_default() + })) + } + + /// Clear the local context. + fn clear(&mut self); +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn frame_stack() { + let mut stack = FrameStack::new(); + let mut frame = stack.start_init(); + frame.get(|| 1); + let token = frame.consume(); + stack.end_init(token); + + assert_eq!(stack.index(), Some(0)); + assert_eq!(stack.stack.len(), 1); + + let a = stack.get(); + assert_eq!(a, &mut 1); + let mut b = stack.get_next(); + assert!(!b.init); + assert_eq!(b.get(|| 2), &mut 2); + let token = b.consume(); // TODO: remove + stack.push(token); + + assert_eq!(stack.index(), Some(1)); + assert_eq!(stack.stack.len(), 2); + let a = stack.get(); + assert_eq!(a, &mut 2); + let b = stack.get_next(); + assert!(!b.init); + + stack.pop(); + + assert_eq!(stack.index(), Some(0)); + assert_eq!(stack.stack.len(), 2); + let a = stack.get(); + assert_eq!(a, &mut 1); + let mut b = stack.get_next(); + assert!(b.init); + assert_eq!(unsafe { b.get_unchecked() }, &mut 2); + } +} diff --git a/crates/context/interface/src/result.rs b/crates/context/interface/src/result.rs new file mode 100644 index 0000000000..e9dd33769b --- /dev/null +++ b/crates/context/interface/src/result.rs @@ -0,0 +1,633 @@ +//! Result of the EVM execution. Containing both execution result, state and errors. +//! +//! [`ExecutionResult`] is the result of the EVM execution. +//! +//! [`InvalidTransaction`] is the error that is returned when the transaction is invalid. +//! +//! [`InvalidHeader`] is the error that is returned when the header is invalid. +//! +//! [`SuccessReason`] is the reason that the transaction successfully completed. +use crate::{context::ContextError, transaction::TransactionError}; +use core::fmt::{self, Debug}; +use database_interface::DBErrorMarker; +use primitives::{Address, Bytes, Log, U256}; +use state::EvmState; +use std::{boxed::Box, string::String, vec::Vec}; + +/// Trait for the halt reason. +pub trait HaltReasonTr: Clone + Debug + PartialEq + Eq + From {} + +impl HaltReasonTr for T where T: Clone + Debug + PartialEq + Eq + From {} + +/// Tuple containing evm execution result and state.s +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct ExecResultAndState { + /// Execution result + pub result: R, + /// Output State. + pub state: S, +} + +/// Type alias for backwards compatibility. +pub type ResultAndState = ExecResultAndState>; + +/// Tuple containing multiple execution results and state. +pub type ResultVecAndState = ExecResultAndState, S>; + +impl ExecResultAndState { + /// Creates new ResultAndState. + pub fn new(result: R, state: S) -> Self { + Self { result, state } + } +} + +/// Result of a transaction execution +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub enum ExecutionResult { + /// Returned successfully + Success { + /// Reason for the success. + reason: SuccessReason, + /// Gas used by the transaction.s + gas_used: u64, + /// Gas refunded by the transaction. + gas_refunded: u64, + /// Logs emitted by the transaction. + logs: Vec, + /// Output of the transaction. + output: Output, + }, + /// Reverted by `REVERT` opcode that doesn't spend all gas + Revert { + /// Gas used by the transaction. + gas_used: u64, + /// Output of the transaction. + output: Bytes, + }, + /// Reverted for various reasons and spend all gas + Halt { + /// Reason for the halt. + reason: HaltReasonTy, + /// Gas used by the transaction. + /// + /// Halting will spend all the gas, and will be equal to gas_limit. + gas_used: u64, + }, +} + +impl ExecutionResult { + /// Returns if transaction execution is successful. + /// + /// 1 indicates success, 0 indicates revert. + /// + /// + pub fn is_success(&self) -> bool { + matches!(self, Self::Success { .. }) + } + + /// Maps a `DBError` to a new error type using the provided closure, leaving other variants unchanged. + pub fn map_haltreason(self, op: F) -> ExecutionResult + where + F: FnOnce(HaltReasonTy) -> OHR, + { + match self { + Self::Success { + reason, + gas_used, + gas_refunded, + logs, + output, + } => ExecutionResult::Success { + reason, + gas_used, + gas_refunded, + logs, + output, + }, + Self::Revert { gas_used, output } => ExecutionResult::Revert { gas_used, output }, + Self::Halt { reason, gas_used } => ExecutionResult::Halt { + reason: op(reason), + gas_used, + }, + } + } + + /// Returns created address if execution is Create transaction + /// and Contract was created. + pub fn created_address(&self) -> Option
{ + match self { + Self::Success { output, .. } => output.address().cloned(), + _ => None, + } + } + + /// Returns true if execution result is a Halt. + pub fn is_halt(&self) -> bool { + matches!(self, Self::Halt { .. }) + } + + /// Returns the output data of the execution. + /// + /// Returns [`None`] if the execution was halted. + pub fn output(&self) -> Option<&Bytes> { + match self { + Self::Success { output, .. } => Some(output.data()), + Self::Revert { output, .. } => Some(output), + _ => None, + } + } + + /// Consumes the type and returns the output data of the execution. + /// + /// Returns [`None`] if the execution was halted. + pub fn into_output(self) -> Option { + match self { + Self::Success { output, .. } => Some(output.into_data()), + Self::Revert { output, .. } => Some(output), + _ => None, + } + } + + /// Returns the logs if execution is successful, or an empty list otherwise. + pub fn logs(&self) -> &[Log] { + match self { + Self::Success { logs, .. } => logs.as_slice(), + _ => &[], + } + } + + /// Consumes [`self`] and returns the logs if execution is successful, or an empty list otherwise. + pub fn into_logs(self) -> Vec { + match self { + Self::Success { logs, .. } => logs, + _ => Vec::new(), + } + } + + /// Returns the gas used. + pub fn gas_used(&self) -> u64 { + match *self { + Self::Success { gas_used, .. } + | Self::Revert { gas_used, .. } + | Self::Halt { gas_used, .. } => gas_used, + } + } +} + +/// Output of a transaction execution +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub enum Output { + /// Output of a call. + Call(Bytes), + /// Output of a create. + Create(Bytes, Option
), +} + +impl Output { + /// Returns the output data of the execution output. + pub fn into_data(self) -> Bytes { + match self { + Output::Call(data) => data, + Output::Create(data, _) => data, + } + } + + /// Returns the output data of the execution output. + pub fn data(&self) -> &Bytes { + match self { + Output::Call(data) => data, + Output::Create(data, _) => data, + } + } + + /// Returns the created address, if any. + pub fn address(&self) -> Option<&Address> { + match self { + Output::Call(_) => None, + Output::Create(_, address) => address.as_ref(), + } + } +} + +/// Main EVM error +#[derive(Debug, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub enum EVMError { + /// Transaction validation error + Transaction(TransactionError), + /// Header validation error + Header(InvalidHeader), + /// Database error + Database(DBError), + /// Custom error + /// + /// Useful for handler registers where custom logic would want to return their own custom error. + Custom(String), +} + +impl From> + for EVMError +{ + fn from(value: ContextError) -> Self { + match value { + ContextError::Db(e) => Self::Database(e), + ContextError::Custom(e) => Self::Custom(e), + } + } +} + +impl From for EVMError { + fn from(value: DBError) -> Self { + Self::Database(value) + } +} + +/// Trait for converting a string to an [`EVMError::Custom`] error. +pub trait FromStringError { + /// Converts a string to an [`EVMError::Custom`] error. + fn from_string(value: String) -> Self; +} + +impl FromStringError for EVMError { + fn from_string(value: String) -> Self { + Self::Custom(value) + } +} + +impl> From for EVMError { + fn from(value: InvalidTransaction) -> Self { + Self::Transaction(TXE::from(value)) + } +} + +impl EVMError { + /// Maps a `DBError` to a new error type using the provided closure, leaving other variants unchanged. + pub fn map_db_err(self, op: F) -> EVMError + where + F: FnOnce(DBError) -> E, + { + match self { + Self::Transaction(e) => EVMError::Transaction(e), + Self::Header(e) => EVMError::Header(e), + Self::Database(e) => EVMError::Database(op(e)), + Self::Custom(e) => EVMError::Custom(e), + } + } +} + +impl core::error::Error + for EVMError +where + DBError: core::error::Error + 'static, + TransactionValidationErrorT: core::error::Error + 'static, +{ + fn source(&self) -> Option<&(dyn core::error::Error + 'static)> { + match self { + Self::Transaction(e) => Some(e), + Self::Header(e) => Some(e), + Self::Database(e) => Some(e), + Self::Custom(_) => None, + } + } +} + +impl fmt::Display + for EVMError +where + DBError: fmt::Display, + TransactionValidationErrorT: fmt::Display, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Transaction(e) => write!(f, "transaction validation error: {e}"), + Self::Header(e) => write!(f, "header validation error: {e}"), + Self::Database(e) => write!(f, "database error: {e}"), + Self::Custom(e) => f.write_str(e), + } + } +} + +impl From + for EVMError +{ + fn from(value: InvalidHeader) -> Self { + Self::Header(value) + } +} + +/// Transaction validation error. +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub enum InvalidTransaction { + /// When using the EIP-1559 fee model introduced in the London upgrade, transactions specify two primary fee fields: + /// - `gas_max_fee`: The maximum total fee a user is willing to pay, inclusive of both base fee and priority fee. + /// - `gas_priority_fee`: The extra amount a user is willing to give directly to the miner, often referred to as the "tip". + /// + /// Provided `gas_priority_fee` exceeds the total `gas_max_fee`. + PriorityFeeGreaterThanMaxFee, + /// EIP-1559: `gas_price` is less than `basefee`. + GasPriceLessThanBasefee, + /// `gas_limit` in the tx is bigger than `block_gas_limit`. + CallerGasLimitMoreThanBlock, + /// Initial gas for a Call is bigger than `gas_limit`. + /// + /// Initial gas for a Call contains: + /// - initial stipend gas + /// - gas for access list and input data + CallGasCostMoreThanGasLimit { + /// Initial gas for a Call. + initial_gas: u64, + /// Gas limit for the transaction. + gas_limit: u64, + }, + /// Gas floor calculated from EIP-7623 Increase calldata cost + /// is more than the gas limit. + /// + /// Tx data is too large to be executed. + GasFloorMoreThanGasLimit { + /// Gas floor calculated from EIP-7623 Increase calldata cost. + gas_floor: u64, + /// Gas limit for the transaction. + gas_limit: u64, + }, + /// EIP-3607 Reject transactions from senders with deployed code + RejectCallerWithCode, + /// Transaction account does not have enough amount of ether to cover transferred value and gas_limit*gas_price. + LackOfFundForMaxFee { + /// Fee for the transaction. + fee: Box, + /// Balance of the sender. + balance: Box, + }, + /// Overflow payment in transaction. + OverflowPaymentInTransaction, + /// Nonce overflows in transaction. + NonceOverflowInTransaction, + /// Nonce is too high. + NonceTooHigh { + /// Nonce of the transaction. + tx: u64, + /// Nonce of the state. + state: u64, + }, + /// Nonce is too low. + NonceTooLow { + /// Nonce of the transaction. + tx: u64, + /// Nonce of the state. + state: u64, + }, + /// EIP-3860: Limit and meter initcode + CreateInitCodeSizeLimit, + /// Transaction chain id does not match the config chain id. + InvalidChainId, + /// Missing chain id. + MissingChainId, + /// Transaction gas limit is greater than the cap. + TxGasLimitGreaterThanCap { + /// Transaction gas limit. + gas_limit: u64, + /// Gas limit cap. + cap: u64, + }, + /// Access list is not supported for blocks before the Berlin hardfork. + AccessListNotSupported, + /// `max_fee_per_blob_gas` is not supported for blocks before the Cancun hardfork. + MaxFeePerBlobGasNotSupported, + /// `blob_hashes`/`blob_versioned_hashes` is not supported for blocks before the Cancun hardfork. + BlobVersionedHashesNotSupported, + /// Block `blob_gas_price` is greater than tx-specified `max_fee_per_blob_gas` after Cancun. + BlobGasPriceGreaterThanMax, + /// There should be at least one blob in Blob transaction. + EmptyBlobs, + /// Blob transaction can't be a create transaction. + /// + /// `to` must be present + BlobCreateTransaction, + /// Transaction has more then `max` blobs + TooManyBlobs { + /// Maximum number of blobs allowed. + max: usize, + /// Number of blobs in the transaction. + have: usize, + }, + /// Blob transaction contains a versioned hash with an incorrect version + BlobVersionNotSupported, + /// EIP-7702 is not enabled. + AuthorizationListNotSupported, + /// EIP-7702 transaction has invalid fields set. + AuthorizationListInvalidFields, + /// Empty Authorization List is not allowed. + EmptyAuthorizationList, + /// EIP-2930 is not supported. + Eip2930NotSupported, + /// EIP-1559 is not supported. + Eip1559NotSupported, + /// EIP-4844 is not supported. + Eip4844NotSupported, + /// EIP-7702 is not supported. + Eip7702NotSupported, + /// EIP-7873 is not supported. + Eip7873NotSupported, + /// EIP-7873 initcode transaction should have `to` address. + Eip7873MissingTarget, +} + +impl TransactionError for InvalidTransaction {} + +impl core::error::Error for InvalidTransaction {} + +impl fmt::Display for InvalidTransaction { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::PriorityFeeGreaterThanMaxFee => { + write!(f, "priority fee is greater than max fee") + } + Self::GasPriceLessThanBasefee => { + write!(f, "gas price is less than basefee") + } + Self::CallerGasLimitMoreThanBlock => { + write!(f, "caller gas limit exceeds the block gas limit") + } + Self::TxGasLimitGreaterThanCap { gas_limit, cap } => { + write!( + f, + "transaction gas limit ({gas_limit}) is greater than the cap ({cap})" + ) + } + Self::CallGasCostMoreThanGasLimit { + initial_gas, + gas_limit, + } => { + write!( + f, + "call gas cost ({initial_gas}) exceeds the gas limit ({gas_limit})" + ) + } + Self::GasFloorMoreThanGasLimit { + gas_floor, + gas_limit, + } => { + write!( + f, + "gas floor ({gas_floor}) exceeds the gas limit ({gas_limit})" + ) + } + Self::RejectCallerWithCode => { + write!(f, "reject transactions from senders with deployed code") + } + Self::LackOfFundForMaxFee { fee, balance } => { + write!(f, "lack of funds ({balance}) for max fee ({fee})") + } + Self::OverflowPaymentInTransaction => { + write!(f, "overflow payment in transaction") + } + Self::NonceOverflowInTransaction => { + write!(f, "nonce overflow in transaction") + } + Self::NonceTooHigh { tx, state } => { + write!(f, "nonce {tx} too high, expected {state}") + } + Self::NonceTooLow { tx, state } => { + write!(f, "nonce {tx} too low, expected {state}") + } + Self::CreateInitCodeSizeLimit => { + write!(f, "create initcode size limit") + } + Self::InvalidChainId => write!(f, "invalid chain ID"), + Self::MissingChainId => write!(f, "missing chain ID"), + Self::AccessListNotSupported => write!(f, "access list not supported"), + Self::MaxFeePerBlobGasNotSupported => { + write!(f, "max fee per blob gas not supported") + } + Self::BlobVersionedHashesNotSupported => { + write!(f, "blob versioned hashes not supported") + } + Self::BlobGasPriceGreaterThanMax => { + write!(f, "blob gas price is greater than max fee per blob gas") + } + Self::EmptyBlobs => write!(f, "empty blobs"), + Self::BlobCreateTransaction => write!(f, "blob create transaction"), + Self::TooManyBlobs { max, have } => { + write!(f, "too many blobs, have {have}, max {max}") + } + Self::BlobVersionNotSupported => write!(f, "blob version not supported"), + Self::AuthorizationListNotSupported => write!(f, "authorization list not supported"), + Self::AuthorizationListInvalidFields => { + write!(f, "authorization list tx has invalid fields") + } + Self::EmptyAuthorizationList => write!(f, "empty authorization list"), + Self::Eip2930NotSupported => write!(f, "Eip2930 is not supported"), + Self::Eip1559NotSupported => write!(f, "Eip1559 is not supported"), + Self::Eip4844NotSupported => write!(f, "Eip4844 is not supported"), + Self::Eip7702NotSupported => write!(f, "Eip7702 is not supported"), + Self::Eip7873NotSupported => write!(f, "Eip7873 is not supported"), + Self::Eip7873MissingTarget => { + write!(f, "Eip7873 initcode transaction should have `to` address") + } + } + } +} + +/// Errors related to misconfiguration of a [`crate::Block`]. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub enum InvalidHeader { + /// `prevrandao` is not set for Merge and above. + PrevrandaoNotSet, + /// `excess_blob_gas` is not set for Cancun and above. + ExcessBlobGasNotSet, +} + +impl core::error::Error for InvalidHeader {} + +impl fmt::Display for InvalidHeader { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::PrevrandaoNotSet => write!(f, "`prevrandao` not set"), + Self::ExcessBlobGasNotSet => write!(f, "`excess_blob_gas` not set"), + } + } +} + +/// Reason a transaction successfully completed. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub enum SuccessReason { + /// Stop [`state::bytecode::opcode::STOP`] opcode. + Stop, + /// Return [`state::bytecode::opcode::RETURN`] opcode. + Return, + /// Self destruct opcode. + SelfDestruct, +} + +/// Indicates that the EVM has experienced an exceptional halt. +/// +/// This causes execution to immediately end with all gas being consumed. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub enum HaltReason { + /// Out of gas error. + OutOfGas(OutOfGasError), + /// Opcode not found error. + OpcodeNotFound, + /// Invalid FE opcode error. + InvalidFEOpcode, + /// Invalid jump destination. + InvalidJump, + /// The feature or opcode is not activated in hardfork. + NotActivated, + /// Attempting to pop a value from an empty stack. + StackUnderflow, + /// Attempting to push a value onto a full stack. + StackOverflow, + /// Invalid memory or storage offset for [`state::bytecode::opcode::RETURNDATACOPY`]. + OutOfOffset, + /// Address collision during contract creation. + CreateCollision, + /// Precompile error. + PrecompileError, + /// Nonce overflow. + NonceOverflow, + /// Create init code size exceeds limit (runtime). + CreateContractSizeLimit, + /// Error on created contract that begins with EF + CreateContractStartingWithEF, + /// EIP-3860: Limit and meter initcode. Initcode size limit exceeded. + CreateInitCodeSizeLimit, + + /* Internal Halts that can be only found inside Inspector */ + /// Overflow payment. Not possible to happen on mainnet. + OverflowPayment, + /// State change during static call. + StateChangeDuringStaticCall, + /// Call not allowed inside static call. + CallNotAllowedInsideStatic, + /// Out of funds to pay for the call. + OutOfFunds, + /// Call is too deep. + CallTooDeep, +} + +/// Out of gas errors. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub enum OutOfGasError { + /// Basic OOG error. Not enough gas to execute the opcode. + Basic, + /// Tried to expand past memory limit. + MemoryLimit, + /// Basic OOG error from memory expansion + Memory, + /// Precompile threw OOG error + Precompile, + /// When performing something that takes a U256 and casts down to a u64, if its too large this would fire + /// i.e. in `as_usize_or_fail` + InvalidOperand, + /// When performing SSTORE the gasleft is less than or equal to 2300 + ReentrancySentry, +} diff --git a/crates/context/interface/src/transaction.rs b/crates/context/interface/src/transaction.rs new file mode 100644 index 0000000000..091512df3e --- /dev/null +++ b/crates/context/interface/src/transaction.rs @@ -0,0 +1,213 @@ +//! Transaction trait [`Transaction`] and associated types. +mod alloy_types; +pub mod eip2930; +pub mod eip7702; +mod either; +pub mod transaction_type; + +pub use alloy_types::{ + AccessList, AccessListItem, Authorization, RecoveredAuthority, RecoveredAuthorization, + SignedAuthorization, +}; +pub use eip2930::AccessListItemTr; +pub use eip7702::AuthorizationTr; +pub use transaction_type::TransactionType; + +use crate::result::InvalidTransaction; +use auto_impl::auto_impl; +use core::cmp::min; +use core::fmt::Debug; +use primitives::{eip4844::GAS_PER_BLOB, Address, Bytes, TxKind, B256, U256}; + +/// Transaction validity error types. +pub trait TransactionError: Debug + core::error::Error {} + +/// Main Transaction trait that abstracts and specifies all transaction currently supported by Ethereum +/// +/// Access to any associated type is gated behind [`tx_type`][Transaction::tx_type] function. +/// +/// It can be extended to support new transaction types and only transaction types can be +/// deprecated by not returning tx_type. +#[auto_impl(&, Box, Arc, Rc)] +pub trait Transaction { + /// EIP-2930 Access list item type. + type AccessListItem<'a>: AccessListItemTr + where + Self: 'a; + + /// EIP-7702 Authorization type. + type Authorization<'a>: AuthorizationTr + where + Self: 'a; + + /// Returns the transaction type. + /// + /// Depending on this field other functions should be called. + fn tx_type(&self) -> u8; + + /// Caller aka Author aka transaction signer. + /// + /// Note : Common field for all transactions. + fn caller(&self) -> Address; + + /// The maximum amount of gas the transaction can use. + /// + /// Note : Common field for all transactions. + fn gas_limit(&self) -> u64; + + /// The value sent to the receiver of [`TxKind::Call`][primitives::TxKind::Call]. + /// + /// Note : Common field for all transactions. + fn value(&self) -> U256; + + /// Returns the input data of the transaction. + /// + /// Note : Common field for all transactions. + fn input(&self) -> &Bytes; + + /// The nonce of the transaction. + /// + /// Note : Common field for all transactions. + fn nonce(&self) -> u64; + + /// Transaction kind. It can be Call or Create. + /// + /// Kind is applicable for: Legacy, EIP-2930, EIP-1559 + /// And is Call for EIP-4844 and EIP-7702 transactions. + fn kind(&self) -> TxKind; + + /// Chain Id is optional for legacy transactions. + /// + /// As it was introduced in EIP-155. + fn chain_id(&self) -> Option; + + /// Gas price for the transaction. + /// It is only applicable for Legacy and EIP-2930 transactions. + /// For Eip1559 it is max_fee_per_gas. + fn gas_price(&self) -> u128; + + /// Access list for the transaction. + /// + /// Introduced in EIP-2930. + fn access_list(&self) -> Option>>; + + /// Returns vector of fixed size hash(32 bytes) + /// + /// Note : EIP-4844 transaction field. + fn blob_versioned_hashes(&self) -> &[B256]; + + /// Max fee per data gas + /// + /// Note : EIP-4844 transaction field. + fn max_fee_per_blob_gas(&self) -> u128; + + /// Total gas for all blobs. Max number of blocks is already checked + /// so we dont need to check for overflow. + fn total_blob_gas(&self) -> u64 { + GAS_PER_BLOB * self.blob_versioned_hashes().len() as u64 + } + + /// Calculates the maximum [EIP-4844] `data_fee` of the transaction. + /// + /// This is used for ensuring that the user has at least enough funds to pay the + /// `max_fee_per_blob_gas * total_blob_gas`, on top of regular gas costs. + /// + /// See EIP-4844: + /// + fn calc_max_data_fee(&self) -> U256 { + U256::from((self.total_blob_gas() as u128).saturating_mul(self.max_fee_per_blob_gas())) + } + + /// Returns length of the authorization list. + /// + /// # Note + /// + /// Transaction is considered invalid if list is empty. + fn authorization_list_len(&self) -> usize; + + /// List of authorizations, that contains the signature that authorizes this + /// caller to place the code to signer account. + /// + /// Set EOA account code for one transaction + /// + /// [EIP-Set EOA account code for one transaction](https://eips.ethereum.org/EIPS/eip-7702) + fn authorization_list(&self) -> impl Iterator>; + + /// Returns maximum fee that can be paid for the transaction. + fn max_fee_per_gas(&self) -> u128 { + self.gas_price() + } + + /// Maximum priority fee per gas. + fn max_priority_fee_per_gas(&self) -> Option; + + /// Returns effective gas price is gas price field for Legacy and Eip2930 transaction. + /// + /// While for transactions after Eip1559 it is minimum of max_fee and `base + max_priority_fee`. + fn effective_gas_price(&self, base_fee: u128) -> u128 { + if self.tx_type() == TransactionType::Legacy as u8 + || self.tx_type() == TransactionType::Eip2930 as u8 + { + return self.gas_price(); + } + + // for EIP-1559 tx and onwards gas_price represents maximum price. + let max_price = self.gas_price(); + let Some(max_priority_fee) = self.max_priority_fee_per_gas() else { + return max_price; + }; + min(max_price, base_fee.saturating_add(max_priority_fee)) + } + + /// Returns the maximum balance that can be spent by the transaction. + /// + /// Return U256 or error if all values overflow U256 number. + fn max_balance_spending(&self) -> Result { + // gas_limit * max_fee + value + additional_gas_cost + let mut max_balance_spending = (self.gas_limit() as u128) + .checked_mul(self.max_fee_per_gas()) + .and_then(|gas_cost| U256::from(gas_cost).checked_add(self.value())) + .ok_or(InvalidTransaction::OverflowPaymentInTransaction)?; + + // add blob fee + if self.tx_type() == TransactionType::Eip4844 { + let data_fee = self.calc_max_data_fee(); + max_balance_spending = max_balance_spending + .checked_add(data_fee) + .ok_or(InvalidTransaction::OverflowPaymentInTransaction)?; + } + Ok(max_balance_spending) + } + + /// Returns the effective balance that is going to be spent that depends on base_fee + /// Multiplication for gas are done in u128 type (saturated) and value is added as U256 type. + /// + /// # Reason + /// + /// This is done for performance reasons and it is known to be safe as there is no more that u128::MAX value of eth in existence. + /// + /// This is always strictly less than [`Self::max_balance_spending`]. + /// + /// Return U256 or error if all values overflow U256 number. + fn effective_balance_spending( + &self, + base_fee: u128, + blob_price: u128, + ) -> Result { + // gas_limit * max_fee + value + additional_gas_cost + let mut effective_balance_spending = (self.gas_limit() as u128) + .checked_mul(self.effective_gas_price(base_fee)) + .and_then(|gas_cost| U256::from(gas_cost).checked_add(self.value())) + .ok_or(InvalidTransaction::OverflowPaymentInTransaction)?; + + // add blob fee + if self.tx_type() == TransactionType::Eip4844 { + let blob_gas = self.total_blob_gas() as u128; + effective_balance_spending = effective_balance_spending + .checked_add(U256::from(blob_price.saturating_mul(blob_gas))) + .ok_or(InvalidTransaction::OverflowPaymentInTransaction)?; + } + + Ok(effective_balance_spending) + } +} diff --git a/crates/context/interface/src/transaction/alloy_types.rs b/crates/context/interface/src/transaction/alloy_types.rs new file mode 100644 index 0000000000..a1ebc07d10 --- /dev/null +++ b/crates/context/interface/src/transaction/alloy_types.rs @@ -0,0 +1,72 @@ +use super::{AccessListItemTr, AuthorizationTr}; +use either::{for_both, Either}; +use primitives::{Address, B256, U256}; + +pub use alloy_eip2930::{AccessList, AccessListItem}; +pub use alloy_eip7702::{ + Authorization, RecoveredAuthority, RecoveredAuthorization, SignedAuthorization, +}; + +impl AccessListItemTr for AccessListItem { + fn address(&self) -> &Address { + &self.address + } + + fn storage_slots(&self) -> impl Iterator { + self.storage_keys.iter() + } +} + +impl AuthorizationTr for SignedAuthorization { + fn authority(&self) -> Option
{ + self.recover_authority().ok() + } + + fn chain_id(&self) -> U256 { + self.chain_id + } + + fn nonce(&self) -> u64 { + self.nonce + } + + fn address(&self) -> Address { + self.address + } +} + +impl AuthorizationTr for RecoveredAuthorization { + fn authority(&self) -> Option
{ + self.authority() + } + + fn chain_id(&self) -> U256 { + self.chain_id + } + + fn nonce(&self) -> u64 { + self.nonce + } + + fn address(&self) -> Address { + self.address + } +} + +impl AuthorizationTr for Either { + fn authority(&self) -> Option
{ + for_both!(self, s => s.authority()) + } + + fn chain_id(&self) -> U256 { + for_both!(self, s => s.chain_id()) + } + + fn nonce(&self) -> u64 { + for_both!(self, s => s.nonce()) + } + + fn address(&self) -> Address { + for_both!(self, s => s.address()) + } +} diff --git a/crates/context/interface/src/transaction/eip2930.rs b/crates/context/interface/src/transaction/eip2930.rs new file mode 100644 index 0000000000..916048f937 --- /dev/null +++ b/crates/context/interface/src/transaction/eip2930.rs @@ -0,0 +1,19 @@ +//! EIP-2930 Access list transaction interface. +use auto_impl::auto_impl; +use primitives::{Address, B256}; + +/// Access list type is introduced in EIP-2930, and every +/// transaction after it contains access list. +/// +/// **Note**: Iterator over access list returns account address and storage slot keys that +/// are warm loaded before transaction execution. +/// +/// Number of account and storage slots is used to calculate initial tx gas cost. +#[auto_impl(&, Box, Arc, Rc)] +pub trait AccessListItemTr { + /// Returns account address. + fn address(&self) -> &Address; + + /// Returns storage slot keys. + fn storage_slots(&self) -> impl Iterator; +} diff --git a/crates/context/interface/src/transaction/eip7702.rs b/crates/context/interface/src/transaction/eip7702.rs new file mode 100644 index 0000000000..b92ba7d47b --- /dev/null +++ b/crates/context/interface/src/transaction/eip7702.rs @@ -0,0 +1,32 @@ +//! EIP-7702 Account Abstraction transaction interface. +use auto_impl::auto_impl; +use primitives::{Address, U256}; + +/// Authorization trait. +#[auto_impl(&, Box, Arc, Rc)] +pub trait AuthorizationTr { + /// Authority address. + /// + /// # Note + /// + /// Authority signature can be invalid, so this method returns None if the authority + /// could not be recovered. + /// + /// Valid signature Parity should be 0 or 1 and + /// signature s-value should be less than SECP256K1N_HALF. + fn authority(&self) -> Option
; + + /// Returns authorization the chain id. + fn chain_id(&self) -> U256; + + /// Returns the nonce. + /// + /// # Note + /// + /// If nonce is not same as the nonce of the signer account, + /// the authorization is skipped. + fn nonce(&self) -> u64; + + /// Returns the address that this account is delegated to. + fn address(&self) -> Address; +} diff --git a/crates/context/interface/src/transaction/either.rs b/crates/context/interface/src/transaction/either.rs new file mode 100644 index 0000000000..46eb43cebe --- /dev/null +++ b/crates/context/interface/src/transaction/either.rs @@ -0,0 +1,127 @@ +use super::Transaction; +use either::Either; +use primitives::{Address, Bytes, TxKind, B256, U256}; + +impl Transaction for Either +where + L: Transaction + 'static, + R: for<'a> Transaction< + AccessListItem<'a> = L::AccessListItem<'a>, + Authorization<'a> = L::Authorization<'a>, + > + 'static, +{ + type AccessListItem<'a> + = L::AccessListItem<'a> + where + Self: 'a; + + type Authorization<'a> + = L::Authorization<'a> + where + Self: 'a; + + fn tx_type(&self) -> u8 { + match self { + Either::Left(l) => l.tx_type(), + Either::Right(r) => r.tx_type(), + } + } + + fn caller(&self) -> Address { + match self { + Either::Left(l) => l.caller(), + Either::Right(r) => r.caller(), + } + } + + fn gas_limit(&self) -> u64 { + match self { + Either::Left(l) => l.gas_limit(), + Either::Right(r) => r.gas_limit(), + } + } + + fn value(&self) -> U256 { + match self { + Either::Left(l) => l.value(), + Either::Right(r) => r.value(), + } + } + + fn input(&self) -> &Bytes { + match self { + Either::Left(l) => l.input(), + Either::Right(r) => r.input(), + } + } + + fn nonce(&self) -> u64 { + match self { + Either::Left(l) => l.nonce(), + Either::Right(r) => r.nonce(), + } + } + + fn kind(&self) -> TxKind { + match self { + Either::Left(l) => l.kind(), + Either::Right(r) => r.kind(), + } + } + + fn chain_id(&self) -> Option { + match self { + Either::Left(l) => l.chain_id(), + Either::Right(r) => r.chain_id(), + } + } + + fn gas_price(&self) -> u128 { + match self { + Either::Left(l) => l.gas_price(), + Either::Right(r) => r.gas_price(), + } + } + + fn access_list(&self) -> Option>> { + match self { + Either::Left(l) => l.access_list().map(Either::Left), + Either::Right(r) => r.access_list().map(Either::Right), + } + } + + fn blob_versioned_hashes(&self) -> &[B256] { + match self { + Either::Left(l) => l.blob_versioned_hashes(), + Either::Right(r) => r.blob_versioned_hashes(), + } + } + + fn max_fee_per_blob_gas(&self) -> u128 { + match self { + Either::Left(l) => l.max_fee_per_blob_gas(), + Either::Right(r) => r.max_fee_per_blob_gas(), + } + } + + fn authorization_list_len(&self) -> usize { + match self { + Either::Left(l) => l.authorization_list_len(), + Either::Right(r) => r.authorization_list_len(), + } + } + + fn authorization_list(&self) -> impl Iterator> { + match self { + Either::Left(l) => Either::Left(l.authorization_list()), + Either::Right(r) => Either::Right(r.authorization_list()), + } + } + + fn max_priority_fee_per_gas(&self) -> Option { + match self { + Either::Left(l) => l.max_priority_fee_per_gas(), + Either::Right(r) => r.max_priority_fee_per_gas(), + } + } +} diff --git a/crates/context/interface/src/transaction/transaction_type.rs b/crates/context/interface/src/transaction/transaction_type.rs new file mode 100644 index 0000000000..1946c6647f --- /dev/null +++ b/crates/context/interface/src/transaction/transaction_type.rs @@ -0,0 +1,63 @@ +//! Transaction type enum. + +/// Transaction types of all Ethereum transaction +#[repr(u8)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub enum TransactionType { + /// Legacy transaction type + Legacy = 0, + /// EIP-2930 Access List transaction type + Eip2930 = 1, + /// EIP-1559 Fee market change transaction type + Eip1559 = 2, + /// EIP-4844 Blob transaction type + Eip4844 = 3, + /// EIP-7702 Set EOA account code transaction type + Eip7702 = 4, + /// Custom type means that the transaction trait was extended and has custom types + Custom = 0xFF, +} + +impl TransactionType { + /// Returns true if the transaction type is legacy. + pub fn is_legacy(&self) -> bool { + matches!(self, Self::Legacy) + } + + /// Returns true if the transaction type is custom. + pub fn is_custom(&self) -> bool { + matches!(self, Self::Custom) + } +} + +impl PartialEq for TransactionType { + fn eq(&self, other: &u8) -> bool { + (*self as u8) == *other + } +} + +impl PartialEq for u8 { + fn eq(&self, other: &TransactionType) -> bool { + *self == (*other as u8) + } +} + +impl From for u8 { + fn from(tx_type: TransactionType) -> u8 { + tx_type as u8 + } +} + +impl From for TransactionType { + fn from(value: u8) -> Self { + match value { + 0 => Self::Legacy, + 1 => Self::Eip2930, + 2 => Self::Eip1559, + 3 => Self::Eip4844, + 4 => Self::Eip7702, + _ => Self::Custom, + } + } +} diff --git a/crates/context/src/block.rs b/crates/context/src/block.rs new file mode 100644 index 0000000000..7676030f31 --- /dev/null +++ b/crates/context/src/block.rs @@ -0,0 +1,120 @@ +//! This module contains [`BlockEnv`] and it implements [`Block`] trait. +use context_interface::block::{BlobExcessGasAndPrice, Block}; +use primitives::{eip4844::BLOB_BASE_FEE_UPDATE_FRACTION_PRAGUE, Address, B256, U256}; + +/// The block environment +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct BlockEnv { + /// The number of ancestor blocks of this block (block height). + pub number: U256, + /// Beneficiary (Coinbase or miner) is a address that have signed the block. + /// + /// This is the receiver address of all the gas spent in the block. + pub beneficiary: Address, + + /// The timestamp of the block in seconds since the UNIX epoch + pub timestamp: U256, + /// The gas limit of the block + pub gas_limit: u64, + /// The base fee per gas, added in the London upgrade with [EIP-1559] + /// + /// [EIP-1559]: https://eips.ethereum.org/EIPS/eip-1559 + pub basefee: u64, + /// The difficulty of the block + /// + /// Unused after the Paris (AKA the merge) upgrade, and replaced by `prevrandao`. + pub difficulty: U256, + /// The output of the randomness beacon provided by the beacon chain + /// + /// Replaces `difficulty` after the Paris (AKA the merge) upgrade with [EIP-4399]. + /// + /// Note: `prevrandao` can be found in a block in place of `mix_hash`. + /// + /// [EIP-4399]: https://eips.ethereum.org/EIPS/eip-4399 + pub prevrandao: Option, + /// Excess blob gas and blob gasprice + /// + /// See also [`calc_excess_blob_gas`][context_interface::block::calc_excess_blob_gas] + /// and [`calc_blob_gasprice`][context_interface::block::blob::calc_blob_gasprice]. + /// + /// Incorporated as part of the Cancun upgrade via [EIP-4844]. + /// + /// [EIP-4844]: https://eips.ethereum.org/EIPS/eip-4844 + pub blob_excess_gas_and_price: Option, +} + +impl BlockEnv { + /// Takes `blob_excess_gas` saves it inside env + /// and calculates `blob_fee` with [`BlobExcessGasAndPrice`]. + pub fn set_blob_excess_gas_and_price( + &mut self, + excess_blob_gas: u64, + base_fee_update_fraction: u64, + ) { + self.blob_excess_gas_and_price = Some(BlobExcessGasAndPrice::new( + excess_blob_gas, + base_fee_update_fraction, + )); + } +} + +impl Block for BlockEnv { + #[inline] + fn number(&self) -> U256 { + self.number + } + + #[inline] + fn beneficiary(&self) -> Address { + self.beneficiary + } + + #[inline] + fn timestamp(&self) -> U256 { + self.timestamp + } + + #[inline] + fn gas_limit(&self) -> u64 { + self.gas_limit + } + + #[inline] + fn basefee(&self) -> u64 { + self.basefee + } + + #[inline] + fn difficulty(&self) -> U256 { + self.difficulty + } + + #[inline] + fn prevrandao(&self) -> Option { + self.prevrandao + } + + #[inline] + fn blob_excess_gas_and_price(&self) -> Option { + self.blob_excess_gas_and_price + } +} + +impl Default for BlockEnv { + fn default() -> Self { + Self { + number: U256::ZERO, + beneficiary: Address::ZERO, + timestamp: U256::ONE, + gas_limit: u64::MAX, + basefee: 0, + difficulty: U256::ZERO, + prevrandao: Some(B256::ZERO), + blob_excess_gas_and_price: Some(BlobExcessGasAndPrice::new( + 0, + BLOB_BASE_FEE_UPDATE_FRACTION_PRAGUE, + )), + } + } +} diff --git a/crates/context/src/cfg.rs b/crates/context/src/cfg.rs new file mode 100644 index 0000000000..788b358cfc --- /dev/null +++ b/crates/context/src/cfg.rs @@ -0,0 +1,364 @@ +//! This module contains [`CfgEnv`] and implements [`Cfg`] trait for it. +pub use context_interface::Cfg; + +use primitives::{eip170, eip3860, eip7825, hardfork::SpecId}; +/// EVM configuration +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[derive(Clone, Debug, Eq, PartialEq)] +#[non_exhaustive] +pub struct CfgEnv { + /// Chain ID of the EVM. Used in CHAINID opcode and transaction's chain ID check. + /// + /// Chain ID is introduced EIP-155. + pub chain_id: u64, + + /// Whether to check the transaction's chain ID. + /// + /// If set to `false`, the transaction's chain ID check will be skipped. + pub tx_chain_id_check: bool, + + /// Specification for EVM represent the hardfork + pub spec: SPEC, + /// Contract code size limit override. + /// + /// If None, the limit will be determined by the SpecId (EIP-170 or EIP-7907) at runtime. + /// If Some, this specific limit will be used regardless of SpecId. + /// + /// Useful to increase this because of tests. + pub limit_contract_code_size: Option, + /// Contract initcode size limit override. + /// + /// If None, the limit will check if `limit_contract_code_size` is set. + /// If it is set, it will double it for a limit. + /// If it is not set, the limit will be determined by the SpecId (EIP-170 or EIP-7907) at runtime. + /// + /// Useful to increase this because of tests. + pub limit_contract_initcode_size: Option, + /// Skips the nonce validation against the account's nonce + pub disable_nonce_check: bool, + /// Blob max count. EIP-7840 Add blob schedule to EL config files. + /// + /// If this config is not set, the check for max blobs will be skipped. + pub max_blobs_per_tx: Option, + /// Blob base fee update fraction. EIP-4844 Blob base fee update fraction. + /// + /// If this config is not set, the blob base fee update fraction will be set to the default value. + /// See also [CfgEnv::blob_base_fee_update_fraction]. + /// + /// Default values for Cancun is [`primitives::eip4844::BLOB_BASE_FEE_UPDATE_FRACTION_CANCUN`] + /// and for Prague is [`primitives::eip4844::BLOB_BASE_FEE_UPDATE_FRACTION_PRAGUE`]. + pub blob_base_fee_update_fraction: Option, + /// Configures the gas limit cap for the transaction. + /// + /// If `None`, default value defined by spec will be used. + /// + /// Introduced in Osaka in [EIP-7825: Transaction Gas Limit Cap](https://eips.ethereum.org/EIPS/eip-7825) + /// with initials cap of 30M. + pub tx_gas_limit_cap: Option, + /// A hard memory limit in bytes beyond which + /// [OutOfGasError::Memory][context_interface::result::OutOfGasError::Memory] cannot be resized. + /// + /// In cases where the gas limit may be extraordinarily high, it is recommended to set this to + /// a sane value to prevent memory allocation panics. + /// + /// Defaults to `2^32 - 1` bytes per EIP-1985. + #[cfg(feature = "memory_limit")] + pub memory_limit: u64, + /// Skip balance checks if `true` + /// + /// Adds transaction cost to balance to ensure execution doesn't fail. + /// + /// By default, it is set to `false`. + #[cfg(feature = "optional_balance_check")] + pub disable_balance_check: bool, + /// There are use cases where it's allowed to provide a gas limit that's higher than a block's gas limit. + /// + /// To that end, you can disable the block gas limit validation. + /// + /// By default, it is set to `false`. + #[cfg(feature = "optional_block_gas_limit")] + pub disable_block_gas_limit: bool, + /// EIP-3541 rejects the creation of contracts that starts with 0xEF + /// + /// This is useful for chains that do not implement EIP-3541. + /// + /// By default, it is set to `false`. + #[cfg(feature = "optional_eip3541")] + pub disable_eip3541: bool, + /// EIP-3607 rejects transactions from senders with deployed code + /// + /// In development, it can be desirable to simulate calls from contracts, which this setting allows. + /// + /// By default, it is set to `false`. + #[cfg(feature = "optional_eip3607")] + pub disable_eip3607: bool, + /// Disables base fee checks for EIP-1559 transactions + /// + /// This is useful for testing method calls with zero gas price. + /// + /// By default, it is set to `false`. + #[cfg(feature = "optional_no_base_fee")] + pub disable_base_fee: bool, + /// Disables "max fee must be less than or equal to max priority fee" check for EIP-1559 transactions. + /// This is useful because some chains (e.g. Arbitrum) do not enforce this check. + /// By default, it is set to `false`. + #[cfg(feature = "optional_priority_fee_check")] + pub disable_priority_fee_check: bool, +} + +impl CfgEnv { + /// Creates new `CfgEnv` with default values. + pub fn new() -> Self { + Self::default() + } +} + +impl + Copy> CfgEnv { + /// Returns the blob base fee update fraction from [CfgEnv::blob_base_fee_update_fraction]. + /// + /// If this field is not set, return the default value for the spec. + /// + /// Default values for Cancun is [`primitives::eip4844::BLOB_BASE_FEE_UPDATE_FRACTION_CANCUN`] + /// and for Prague is [`primitives::eip4844::BLOB_BASE_FEE_UPDATE_FRACTION_PRAGUE`]. + pub fn blob_base_fee_update_fraction(&mut self) -> u64 { + self.blob_base_fee_update_fraction.unwrap_or_else(|| { + let spec: SpecId = self.spec.into(); + if spec.is_enabled_in(SpecId::PRAGUE) { + primitives::eip4844::BLOB_BASE_FEE_UPDATE_FRACTION_PRAGUE + } else { + primitives::eip4844::BLOB_BASE_FEE_UPDATE_FRACTION_CANCUN + } + }) + } +} + +impl CfgEnv { + /// Create new `CfgEnv` with default values and specified spec. + pub fn new_with_spec(spec: SPEC) -> Self { + Self { + chain_id: 1, + tx_chain_id_check: false, + limit_contract_code_size: None, + limit_contract_initcode_size: None, + spec, + disable_nonce_check: false, + max_blobs_per_tx: None, + tx_gas_limit_cap: None, + blob_base_fee_update_fraction: None, + #[cfg(feature = "memory_limit")] + memory_limit: (1 << 32) - 1, + #[cfg(feature = "optional_balance_check")] + disable_balance_check: false, + #[cfg(feature = "optional_block_gas_limit")] + disable_block_gas_limit: false, + #[cfg(feature = "optional_eip3541")] + disable_eip3541: false, + #[cfg(feature = "optional_eip3607")] + disable_eip3607: false, + #[cfg(feature = "optional_no_base_fee")] + disable_base_fee: false, + #[cfg(feature = "optional_priority_fee_check")] + disable_priority_fee_check: false, + } + } + + /// Consumes `self` and returns a new `CfgEnv` with the specified chain ID. + pub fn with_chain_id(mut self, chain_id: u64) -> Self { + self.chain_id = chain_id; + self + } + + /// Enables the transaction's chain ID check. + pub fn enable_tx_chain_id_check(mut self) -> Self { + self.tx_chain_id_check = true; + self + } + + /// Disables the transaction's chain ID check. + pub fn disable_tx_chain_id_check(mut self) -> Self { + self.tx_chain_id_check = false; + self + } + + /// Consumes `self` and returns a new `CfgEnv` with the specified spec. + pub fn with_spec>(self, spec: OSPEC) -> CfgEnv { + CfgEnv { + chain_id: self.chain_id, + tx_chain_id_check: self.tx_chain_id_check, + limit_contract_code_size: self.limit_contract_code_size, + limit_contract_initcode_size: self.limit_contract_initcode_size, + spec, + disable_nonce_check: self.disable_nonce_check, + tx_gas_limit_cap: self.tx_gas_limit_cap, + max_blobs_per_tx: self.max_blobs_per_tx, + blob_base_fee_update_fraction: self.blob_base_fee_update_fraction, + #[cfg(feature = "memory_limit")] + memory_limit: self.memory_limit, + #[cfg(feature = "optional_balance_check")] + disable_balance_check: self.disable_balance_check, + #[cfg(feature = "optional_block_gas_limit")] + disable_block_gas_limit: self.disable_block_gas_limit, + #[cfg(feature = "optional_eip3541")] + disable_eip3541: self.disable_eip3541, + #[cfg(feature = "optional_eip3607")] + disable_eip3607: self.disable_eip3607, + #[cfg(feature = "optional_no_base_fee")] + disable_base_fee: self.disable_base_fee, + #[cfg(feature = "optional_priority_fee_check")] + disable_priority_fee_check: self.disable_priority_fee_check, + } + } + + /// Sets the blob target + pub fn with_max_blobs_per_tx(mut self, max_blobs_per_tx: u64) -> Self { + self.set_max_blobs_per_tx(max_blobs_per_tx); + self + } + + /// Sets the blob target + pub fn set_max_blobs_per_tx(&mut self, max_blobs_per_tx: u64) { + self.max_blobs_per_tx = Some(max_blobs_per_tx); + } + + /// Clears the blob target and max count over hardforks. + pub fn clear_max_blobs_per_tx(&mut self) { + self.max_blobs_per_tx = None; + } + + /// Sets the disable priority fee check flag. + #[cfg(feature = "optional_priority_fee_check")] + pub fn with_disable_priority_fee_check(mut self, disable: bool) -> Self { + self.disable_priority_fee_check = disable; + self + } +} + +impl + Copy> Cfg for CfgEnv { + type Spec = SPEC; + + #[inline] + fn chain_id(&self) -> u64 { + self.chain_id + } + + #[inline] + fn spec(&self) -> Self::Spec { + self.spec + } + + #[inline] + fn tx_chain_id_check(&self) -> bool { + self.tx_chain_id_check + } + + #[inline] + fn tx_gas_limit_cap(&self) -> u64 { + self.tx_gas_limit_cap + .unwrap_or(if self.spec.into().is_enabled_in(SpecId::OSAKA) { + eip7825::TX_GAS_LIMIT_CAP + } else { + u64::MAX + }) + } + + #[inline] + fn max_blobs_per_tx(&self) -> Option { + self.max_blobs_per_tx + } + + fn max_code_size(&self) -> usize { + self.limit_contract_code_size + .unwrap_or(eip170::MAX_CODE_SIZE) + } + + fn max_initcode_size(&self) -> usize { + self.limit_contract_initcode_size + .or_else(|| { + self.limit_contract_code_size + .map(|size| size.saturating_mul(2)) + }) + .unwrap_or(eip3860::MAX_INITCODE_SIZE) + } + + fn is_eip3541_disabled(&self) -> bool { + cfg_if::cfg_if! { + if #[cfg(feature = "optional_eip3541")] { + self.disable_eip3541 + } else { + false + } + } + } + + fn is_eip3607_disabled(&self) -> bool { + cfg_if::cfg_if! { + if #[cfg(feature = "optional_eip3607")] { + self.disable_eip3607 + } else { + false + } + } + } + + fn is_balance_check_disabled(&self) -> bool { + cfg_if::cfg_if! { + if #[cfg(feature = "optional_balance_check")] { + self.disable_balance_check + } else { + false + } + } + } + + /// Returns `true` if the block gas limit is disabled. + fn is_block_gas_limit_disabled(&self) -> bool { + cfg_if::cfg_if! { + if #[cfg(feature = "optional_block_gas_limit")] { + self.disable_block_gas_limit + } else { + false + } + } + } + + fn is_nonce_check_disabled(&self) -> bool { + self.disable_nonce_check + } + + fn is_base_fee_check_disabled(&self) -> bool { + cfg_if::cfg_if! { + if #[cfg(feature = "optional_no_base_fee")] { + self.disable_base_fee + } else { + false + } + } + } + + fn is_priority_fee_check_disabled(&self) -> bool { + cfg_if::cfg_if! { + if #[cfg(feature = "optional_priority_fee_check")] { + self.disable_priority_fee_check + } else { + false + } + } + } +} + +impl Default for CfgEnv { + fn default() -> Self { + Self::new_with_spec(SPEC::default()) + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn blob_max_and_target_count() { + let cfg: CfgEnv = Default::default(); + assert_eq!(cfg.max_blobs_per_tx(), None); + } +} diff --git a/crates/context/src/context.rs b/crates/context/src/context.rs new file mode 100644 index 0000000000..9bbf417be1 --- /dev/null +++ b/crates/context/src/context.rs @@ -0,0 +1,628 @@ +//! This module contains [`Context`] struct and implements [`ContextTr`] trait for it. +use crate::{block::BlockEnv, cfg::CfgEnv, journal::Journal, tx::TxEnv, LocalContext}; +use context_interface::{ + context::{ContextError, ContextSetters, SStoreResult, SelfDestructResult, StateLoad}, + journaled_state::AccountLoad, + Block, Cfg, ContextTr, Host, JournalTr, LocalContextTr, Transaction, TransactionType, +}; +use database_interface::{Database, DatabaseRef, EmptyDB, WrapDatabaseRef}; +use derive_where::derive_where; +use primitives::{hardfork::SpecId, Address, Bytes, Log, StorageKey, StorageValue, B256, U256}; + +/// EVM context contains data that EVM needs for execution. +#[derive_where(Clone, Debug; BLOCK, CFG, CHAIN, TX, DB, JOURNAL, ::Error, LOCAL)] +pub struct Context< + BLOCK = BlockEnv, + TX = TxEnv, + CFG = CfgEnv, + DB: Database = EmptyDB, + JOURNAL: JournalTr = Journal, + CHAIN = (), + LOCAL: LocalContextTr = LocalContext, +> { + /// Block information. + pub block: BLOCK, + /// Transaction information. + pub tx: TX, + /// Configurations. + pub cfg: CFG, + /// EVM State with journaling support and database. + pub journaled_state: JOURNAL, + /// Inner context. + pub chain: CHAIN, + /// Local context that is filled by execution. + pub local: LOCAL, + /// Error that happened during execution. + pub error: Result<(), ContextError>, +} + +impl< + BLOCK: Block, + TX: Transaction, + DB: Database, + CFG: Cfg, + JOURNAL: JournalTr, + CHAIN, + LOCAL: LocalContextTr, + > ContextTr for Context +{ + type Block = BLOCK; + type Tx = TX; + type Cfg = CFG; + type Db = DB; + type Journal = JOURNAL; + type Chain = CHAIN; + type Local = LOCAL; + + #[inline] + fn tx(&self) -> &Self::Tx { + &self.tx + } + + #[inline] + fn block(&self) -> &Self::Block { + &self.block + } + + #[inline] + fn cfg(&self) -> &Self::Cfg { + &self.cfg + } + + #[inline] + fn journal(&self) -> &Self::Journal { + &self.journaled_state + } + + #[inline] + fn journal_mut(&mut self) -> &mut Self::Journal { + &mut self.journaled_state + } + + #[inline] + fn journal_ref(&self) -> &Self::Journal { + &self.journaled_state + } + + #[inline] + fn db(&self) -> &Self::Db { + self.journaled_state.db() + } + + #[inline] + fn db_mut(&mut self) -> &mut Self::Db { + self.journaled_state.db_mut() + } + + #[inline] + fn chain(&self) -> &Self::Chain { + &self.chain + } + + #[inline] + fn chain_mut(&mut self) -> &mut Self::Chain { + &mut self.chain + } + + #[inline] + fn local(&self) -> &Self::Local { + &self.local + } + + #[inline] + fn local_mut(&mut self) -> &mut Self::Local { + &mut self.local + } + + #[inline] + fn error(&mut self) -> &mut Result<(), ContextError<::Error>> { + &mut self.error + } + + #[inline] + fn tx_journal_mut(&mut self) -> (&Self::Tx, &mut Self::Journal) { + (&self.tx, &mut self.journaled_state) + } + + #[inline] + fn tx_local_mut(&mut self) -> (&Self::Tx, &mut Self::Local) { + (&self.tx, &mut self.local) + } +} + +impl< + BLOCK: Block, + TX: Transaction, + DB: Database, + CFG: Cfg, + JOURNAL: JournalTr, + CHAIN, + LOCAL: LocalContextTr, + > ContextSetters for Context +{ + fn set_tx(&mut self, tx: Self::Tx) { + self.tx = tx; + } + + fn set_block(&mut self, block: Self::Block) { + self.block = block; + } +} + +impl< + BLOCK: Block + Default, + TX: Transaction + Default, + DB: Database, + JOURNAL: JournalTr, + CHAIN: Default, + LOCAL: LocalContextTr + Default, + > Context +{ + /// Creates a new context with a new database type. + /// + /// This will create a new [`Journal`] object. + pub fn new(db: DB, spec: SpecId) -> Self { + let mut journaled_state = JOURNAL::new(db); + journaled_state.set_spec_id(spec); + Self { + tx: TX::default(), + block: BLOCK::default(), + cfg: CfgEnv { + spec, + ..Default::default() + }, + local: LOCAL::default(), + journaled_state, + chain: Default::default(), + error: Ok(()), + } + } +} + +impl Context +where + BLOCK: Block, + TX: Transaction, + CFG: Cfg, + DB: Database, + JOURNAL: JournalTr, + LOCAL: LocalContextTr, +{ + /// Creates a new context with a new journal type. New journal needs to have the same database type. + pub fn with_new_journal>( + self, + mut journal: OJOURNAL, + ) -> Context { + journal.set_spec_id(self.cfg.spec().into()); + Context { + tx: self.tx, + block: self.block, + cfg: self.cfg, + journaled_state: journal, + local: self.local, + chain: self.chain, + error: Ok(()), + } + } + + /// Creates a new context with a new database type. + /// + /// This will create a new [`Journal`] object. + pub fn with_db( + self, + db: ODB, + ) -> Context, CHAIN, LOCAL> { + let spec = self.cfg.spec().into(); + let mut journaled_state = Journal::new(db); + journaled_state.set_spec_id(spec); + Context { + tx: self.tx, + block: self.block, + cfg: self.cfg, + journaled_state, + local: self.local, + chain: self.chain, + error: Ok(()), + } + } + + /// Creates a new context with a new `DatabaseRef` type. + pub fn with_ref_db( + self, + db: ODB, + ) -> Context, Journal>, CHAIN, LOCAL> + { + let spec = self.cfg.spec().into(); + let mut journaled_state = Journal::new(WrapDatabaseRef(db)); + journaled_state.set_spec_id(spec); + Context { + tx: self.tx, + block: self.block, + cfg: self.cfg, + journaled_state, + local: self.local, + chain: self.chain, + error: Ok(()), + } + } + + /// Creates a new context with a new block type. + pub fn with_block( + self, + block: OB, + ) -> Context { + Context { + tx: self.tx, + block, + cfg: self.cfg, + journaled_state: self.journaled_state, + local: self.local, + chain: self.chain, + error: Ok(()), + } + } + /// Creates a new context with a new transaction type. + pub fn with_tx( + self, + tx: OTX, + ) -> Context { + Context { + tx, + block: self.block, + cfg: self.cfg, + journaled_state: self.journaled_state, + local: self.local, + chain: self.chain, + error: Ok(()), + } + } + + /// Creates a new context with a new chain type. + pub fn with_chain(self, chain: OC) -> Context { + Context { + tx: self.tx, + block: self.block, + cfg: self.cfg, + journaled_state: self.journaled_state, + local: self.local, + chain, + error: Ok(()), + } + } + + /// Creates a new context with a new chain type. + pub fn with_cfg( + mut self, + cfg: OCFG, + ) -> Context { + self.journaled_state.set_spec_id(cfg.spec().into()); + Context { + tx: self.tx, + block: self.block, + cfg, + journaled_state: self.journaled_state, + local: self.local, + chain: self.chain, + error: Ok(()), + } + } + + /// Creates a new context with a new local context type. + pub fn with_local( + self, + local: OL, + ) -> Context { + Context { + tx: self.tx, + block: self.block, + cfg: self.cfg, + journaled_state: self.journaled_state, + local, + chain: self.chain, + error: Ok(()), + } + } + + /// Modifies the context configuration. + #[must_use] + pub fn modify_cfg_chained(mut self, f: F) -> Self + where + F: FnOnce(&mut CFG), + { + f(&mut self.cfg); + self.journaled_state.set_spec_id(self.cfg.spec().into()); + self + } + + /// Modifies the context block. + #[must_use] + pub fn modify_block_chained(mut self, f: F) -> Self + where + F: FnOnce(&mut BLOCK), + { + self.modify_block(f); + self + } + + /// Modifies the context transaction. + #[must_use] + pub fn modify_tx_chained(mut self, f: F) -> Self + where + F: FnOnce(&mut TX), + { + self.modify_tx(f); + self + } + + /// Modifies the context chain. + #[must_use] + pub fn modify_chain_chained(mut self, f: F) -> Self + where + F: FnOnce(&mut CHAIN), + { + self.modify_chain(f); + self + } + + /// Modifies the context database. + #[must_use] + pub fn modify_db_chained(mut self, f: F) -> Self + where + F: FnOnce(&mut DB), + { + self.modify_db(f); + self + } + + /// Modifies the context journal. + #[must_use] + pub fn modify_journal_chained(mut self, f: F) -> Self + where + F: FnOnce(&mut JOURNAL), + { + self.modify_journal(f); + self + } + + /// Modifies the context block. + pub fn modify_block(&mut self, f: F) + where + F: FnOnce(&mut BLOCK), + { + f(&mut self.block); + } + + /// Modifies the context transaction. + pub fn modify_tx(&mut self, f: F) + where + F: FnOnce(&mut TX), + { + f(&mut self.tx); + } + + /// Modifies the context configuration. + pub fn modify_cfg(&mut self, f: F) + where + F: FnOnce(&mut CFG), + { + f(&mut self.cfg); + self.journaled_state.set_spec_id(self.cfg.spec().into()); + } + + /// Modifies the context chain. + pub fn modify_chain(&mut self, f: F) + where + F: FnOnce(&mut CHAIN), + { + f(&mut self.chain); + } + + /// Modifies the context database. + pub fn modify_db(&mut self, f: F) + where + F: FnOnce(&mut DB), + { + f(self.journaled_state.db_mut()); + } + + /// Modifies the context journal. + pub fn modify_journal(&mut self, f: F) + where + F: FnOnce(&mut JOURNAL), + { + f(&mut self.journaled_state); + } + + /// Modifies the local context. + pub fn modify_local(&mut self, f: F) + where + F: FnOnce(&mut LOCAL), + { + f(&mut self.local); + } +} + +impl< + BLOCK: Block, + TX: Transaction, + CFG: Cfg, + DB: Database, + JOURNAL: JournalTr, + CHAIN, + LOCAL: LocalContextTr, + > Host for Context +{ + /* Block */ + + fn basefee(&self) -> U256 { + U256::from(self.block().basefee()) + } + + fn blob_gasprice(&self) -> U256 { + U256::from(self.block().blob_gasprice().unwrap_or(0)) + } + + fn gas_limit(&self) -> U256 { + U256::from(self.block().gas_limit()) + } + + fn difficulty(&self) -> U256 { + self.block().difficulty() + } + + fn prevrandao(&self) -> Option { + self.block().prevrandao().map(|r| r.into()) + } + + fn block_number(&self) -> U256 { + self.block().number() + } + + fn timestamp(&self) -> U256 { + U256::from(self.block().timestamp()) + } + + fn beneficiary(&self) -> Address { + self.block().beneficiary() + } + + fn chain_id(&self) -> U256 { + U256::from(self.cfg().chain_id()) + } + + /* Transaction */ + + fn effective_gas_price(&self) -> U256 { + let basefee = self.block().basefee(); + U256::from(self.tx().effective_gas_price(basefee as u128)) + } + + fn caller(&self) -> Address { + self.tx().caller() + } + + fn blob_hash(&self, number: usize) -> Option { + let tx = &self.tx(); + if tx.tx_type() != TransactionType::Eip4844 { + return None; + } + tx.blob_versioned_hashes() + .get(number) + .map(|t| U256::from_be_bytes(t.0)) + } + + /* Config */ + + fn max_initcode_size(&self) -> usize { + self.cfg().max_initcode_size() + } + + /* Database */ + + fn block_hash(&mut self, requested_number: u64) -> Option { + self.db_mut() + .block_hash(requested_number) + .map_err(|e| { + *self.error() = Err(e.into()); + }) + .ok() + } + + /* Journal */ + + fn load_account_delegated(&mut self, address: Address) -> Option> { + self.journal_mut() + .load_account_delegated(address) + .map_err(|e| { + *self.error() = Err(e.into()); + }) + .ok() + } + + /// Gets balance of `address` and if the account is cold. + fn balance(&mut self, address: Address) -> Option> { + self.journal_mut() + .load_account(address) + .map(|acc| acc.map(|a| a.info.balance)) + .map_err(|e| { + *self.error() = Err(e.into()); + }) + .ok() + } + + /// Gets code of `address` and if the account is cold. + fn load_account_code(&mut self, address: Address) -> Option> { + self.journal_mut() + .code(address) + .map_err(|e| { + *self.error() = Err(e.into()); + }) + .ok() + } + + /// Gets code hash of `address` and if the account is cold. + fn load_account_code_hash(&mut self, address: Address) -> Option> { + self.journal_mut() + .code_hash(address) + .map_err(|e| { + *self.error() = Err(e.into()); + }) + .ok() + } + + /// Gets storage value of `address` at `index` and if the account is cold. + fn sload(&mut self, address: Address, index: StorageKey) -> Option> { + self.journal_mut() + .sload(address, index) + .map_err(|e| { + *self.error() = Err(e.into()); + }) + .ok() + } + + /// Sets storage value of account address at index. + /// + /// Returns [`StateLoad`] with [`SStoreResult`] that contains original/new/old storage value. + fn sstore( + &mut self, + address: Address, + index: StorageKey, + value: StorageValue, + ) -> Option> { + self.journal_mut() + .sstore(address, index, value) + .map_err(|e| { + *self.error() = Err(e.into()); + }) + .ok() + } + + /// Gets the transient storage value of `address` at `index`. + fn tload(&mut self, address: Address, index: StorageKey) -> StorageValue { + self.journal_mut().tload(address, index) + } + + /// Sets the transient storage value of `address` at `index`. + fn tstore(&mut self, address: Address, index: StorageKey, value: StorageValue) { + self.journal_mut().tstore(address, index, value) + } + + /// Emits a log owned by `address` with given `LogData`. + fn log(&mut self, log: Log) { + self.journal_mut().log(log); + } + + /// Marks `address` to be deleted, with funds transferred to `target`. + fn selfdestruct( + &mut self, + address: Address, + target: Address, + ) -> Option> { + self.journal_mut() + .selfdestruct(address, target) + .map_err(|e| { + *self.error() = Err(e.into()); + }) + .ok() + } +} diff --git a/crates/context/src/evm.rs b/crates/context/src/evm.rs new file mode 100644 index 0000000000..aed5313950 --- /dev/null +++ b/crates/context/src/evm.rs @@ -0,0 +1,95 @@ +//! This module contains [`Evm`] struct. +use core::fmt::Debug; +use core::ops::{Deref, DerefMut}; + +use context_interface::FrameStack; + +/// Main EVM structure that contains all data needed for execution. +#[derive(Debug, Clone)] +pub struct Evm { + /// [`context_interface::ContextTr`] of the EVM it is used to fetch data from database. + pub ctx: CTX, + /// Inspector of the EVM it is used to inspect the EVM. + /// Its trait are defined in revm-inspector crate. + pub inspector: INSP, + /// Instructions provider of the EVM it is used to execute instructions. + /// `InstructionProvider` trait is defined in revm-handler crate. + pub instruction: I, + /// Precompile provider of the EVM it is used to execute precompiles. + /// `PrecompileProvider` trait is defined in revm-handler crate. + pub precompiles: P, + /// Frame that is going to be executed. + pub frame_stack: FrameStack, +} + +impl Evm { + /// Create a new EVM instance with a given context, instruction set, and precompile provider. + /// + /// Inspector will be set to `()`. + pub fn new(ctx: CTX, instruction: I, precompiles: P) -> Self { + Evm { + ctx, + inspector: (), + instruction, + precompiles, + frame_stack: FrameStack::new(), + } + } +} + +impl Evm { + /// Create a new EVM instance with a given context, inspector, instruction set, and precompile provider. + pub fn new_with_inspector(ctx: CTX, inspector: INSP, instruction: I, precompiles: P) -> Self { + Evm { + ctx, + inspector, + instruction, + precompiles, + frame_stack: FrameStack::new(), + } + } +} + +impl Evm { + /// Consumed self and returns new Evm type with given Inspector. + pub fn with_inspector(self, inspector: OINSP) -> Evm { + Evm { + ctx: self.ctx, + inspector, + + instruction: self.instruction, + precompiles: self.precompiles, + frame_stack: self.frame_stack, + } + } + + /// Consumes self and returns new Evm type with given Precompiles. + pub fn with_precompiles(self, precompiles: OP) -> Evm { + Evm { + ctx: self.ctx, + inspector: self.inspector, + instruction: self.instruction, + precompiles, + frame_stack: self.frame_stack, + } + } + + /// Consumes self and returns inner Inspector. + pub fn into_inspector(self) -> INSP { + self.inspector + } +} + +impl Deref for Evm { + type Target = CTX; + + fn deref(&self) -> &Self::Target { + &self.ctx + } +} + +impl DerefMut for Evm { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.ctx + } +} diff --git a/crates/context/src/journal.rs b/crates/context/src/journal.rs new file mode 100644 index 0000000000..891b6907f3 --- /dev/null +++ b/crates/context/src/journal.rs @@ -0,0 +1,303 @@ +//! This module contains [`Journal`] struct and implements [`JournalTr`] trait for it. +//! +//! Entry submodule contains [`JournalEntry`] and [`JournalEntryTr`] traits. +//! and inner submodule contains [`JournalInner`] struct that contains state. +pub mod entry; +pub mod inner; + +pub use entry::{JournalEntry, JournalEntryTr}; +pub use inner::JournalInner; + +use bytecode::Bytecode; +use context_interface::{ + context::{SStoreResult, SelfDestructResult, StateLoad}, + journaled_state::{AccountLoad, JournalCheckpoint, JournalTr, TransferError}, +}; +use core::ops::{Deref, DerefMut}; +use database_interface::Database; +use primitives::{hardfork::SpecId, Address, HashSet, Log, StorageKey, StorageValue, B256, U256}; +use state::{Account, EvmState}; +use std::vec::Vec; + +/// A journal of state changes internal to the EVM +/// +/// On each additional call, the depth of the journaled state is increased (`depth`) and a new journal is added. +/// +/// The journal contains every state change that happens within that call, making it possible to revert changes made in a specific call. +#[derive(Debug, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct Journal +where + ENTRY: JournalEntryTr, +{ + /// Database + pub database: DB, + /// Inner journal state. + pub inner: JournalInner, +} + +impl Deref for Journal +where + ENTRY: JournalEntryTr, +{ + type Target = JournalInner; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl DerefMut for Journal +where + ENTRY: JournalEntryTr, +{ + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.inner + } +} + +impl Journal { + /// Creates a new JournaledState by copying state data from a JournalInit and provided database. + /// This allows reusing the state, logs, and other data from a previous execution context while + /// connecting it to a different database backend. + pub fn new_with_inner(database: DB, inner: JournalInner) -> Self { + Self { database, inner } + } + + /// Consumes the [`Journal`] and returns [`JournalInner`]. + /// + /// If you need to preserve the original journal, use [`Self::to_inner`] instead which clones the state. + pub fn into_init(self) -> JournalInner { + self.inner + } +} + +impl Journal { + /// Creates a new [`JournalInner`] by cloning all internal state data (state, storage, logs, etc) + /// This allows creating a new journaled state with the same state data but without + /// carrying over the original database. + /// + /// This is useful when you want to reuse the current state for a new transaction or + /// execution context, but want to start with a fresh database. + pub fn to_inner(&self) -> JournalInner { + self.inner.clone() + } +} + +impl JournalTr for Journal { + type Database = DB; + type State = EvmState; + + fn new(database: DB) -> Journal { + Self { + inner: JournalInner::new(), + database, + } + } + + fn db(&self) -> &Self::Database { + &self.database + } + + fn db_mut(&mut self) -> &mut Self::Database { + &mut self.database + } + + fn sload( + &mut self, + address: Address, + key: StorageKey, + ) -> Result, ::Error> { + self.inner.sload(&mut self.database, address, key) + } + + fn sstore( + &mut self, + address: Address, + key: StorageKey, + value: StorageValue, + ) -> Result, ::Error> { + self.inner.sstore(&mut self.database, address, key, value) + } + + fn tload(&mut self, address: Address, key: StorageKey) -> StorageValue { + self.inner.tload(address, key) + } + + fn tstore(&mut self, address: Address, key: StorageKey, value: StorageValue) { + self.inner.tstore(address, key, value) + } + + fn log(&mut self, log: Log) { + self.inner.log(log) + } + + fn selfdestruct( + &mut self, + address: Address, + target: Address, + ) -> Result, DB::Error> { + self.inner.selfdestruct(&mut self.database, address, target) + } + + fn warm_account(&mut self, address: Address) { + self.inner.warm_preloaded_addresses.insert(address); + } + + fn warm_coinbase_account(&mut self, address: Address) { + self.inner.warm_coinbase_address = Some(address); + } + + fn warm_precompiles(&mut self, precompiles: HashSet
) { + self.inner.precompiles = precompiles; + self.inner + .warm_preloaded_addresses + .clone_from(&self.inner.precompiles); + } + + #[inline] + fn precompile_addresses(&self) -> &HashSet
{ + &self.inner.precompiles + } + + /// Returns call depth. + #[inline] + fn depth(&self) -> usize { + self.inner.depth + } + + #[inline] + fn warm_account_and_storage( + &mut self, + address: Address, + storage_keys: impl IntoIterator, + ) -> Result<(), ::Error> { + self.inner + .load_account_optional(&mut self.database, address, false, storage_keys)?; + Ok(()) + } + + #[inline] + fn set_spec_id(&mut self, spec_id: SpecId) { + self.inner.spec = spec_id; + } + + #[inline] + fn transfer( + &mut self, + from: Address, + to: Address, + balance: U256, + ) -> Result, DB::Error> { + self.inner.transfer(&mut self.database, from, to, balance) + } + + #[inline] + fn touch_account(&mut self, address: Address) { + self.inner.touch(address); + } + + #[inline] + fn caller_accounting_journal_entry( + &mut self, + address: Address, + old_balance: U256, + bump_nonce: bool, + ) { + self.inner + .caller_accounting_journal_entry(address, old_balance, bump_nonce); + } + + /// Increments the balance of the account. + #[inline] + fn balance_incr( + &mut self, + address: Address, + balance: U256, + ) -> Result<(), ::Error> { + self.inner + .balance_incr(&mut self.database, address, balance) + } + + /// Increments the nonce of the account. + #[inline] + fn nonce_bump_journal_entry(&mut self, address: Address) { + self.inner.nonce_bump_journal_entry(address) + } + + #[inline] + fn load_account(&mut self, address: Address) -> Result, DB::Error> { + self.inner.load_account(&mut self.database, address) + } + + #[inline] + fn load_account_code( + &mut self, + address: Address, + ) -> Result, DB::Error> { + self.inner.load_code(&mut self.database, address) + } + + #[inline] + fn load_account_delegated( + &mut self, + address: Address, + ) -> Result, DB::Error> { + self.inner + .load_account_delegated(&mut self.database, address) + } + + #[inline] + fn checkpoint(&mut self) -> JournalCheckpoint { + self.inner.checkpoint() + } + + #[inline] + fn checkpoint_commit(&mut self) { + self.inner.checkpoint_commit() + } + + #[inline] + fn checkpoint_revert(&mut self, checkpoint: JournalCheckpoint) { + self.inner.checkpoint_revert(checkpoint) + } + + #[inline] + fn set_code_with_hash(&mut self, address: Address, code: Bytecode, hash: B256) { + self.inner.set_code_with_hash(address, code, hash); + } + + #[inline] + fn create_account_checkpoint( + &mut self, + caller: Address, + address: Address, + balance: U256, + spec_id: SpecId, + ) -> Result { + // Ignore error. + self.inner + .create_account_checkpoint(caller, address, balance, spec_id) + } + + #[inline] + fn take_logs(&mut self) -> Vec { + self.inner.take_logs() + } + + #[inline] + fn commit_tx(&mut self) { + self.inner.commit_tx() + } + + #[inline] + fn discard_tx(&mut self) { + self.inner.discard_tx(); + } + + /// Clear current journal resetting it to initial state and return changes state. + #[inline] + fn finalize(&mut self) -> Self::State { + self.inner.finalize() + } +} diff --git a/crates/context/src/journal/entry.rs b/crates/context/src/journal/entry.rs new file mode 100644 index 0000000000..00b5f17219 --- /dev/null +++ b/crates/context/src/journal/entry.rs @@ -0,0 +1,410 @@ +//! Contains the journal entry trait and implementations. +//! +//! Journal entries are used to track changes to the state and are used to revert it. +//! +//! They are created when there is change to the state from loading (making it warm), changes to the balance, +//! or removal of the storage slot. Check [`JournalEntryTr`] for more details. + +use primitives::{Address, StorageKey, StorageValue, KECCAK_EMPTY, PRECOMPILE3, U256}; +use state::{EvmState, TransientStorage}; + +/// Trait for tracking and reverting state changes in the EVM. +/// Journal entry contains information about state changes that can be reverted. +pub trait JournalEntryTr { + /// Creates a journal entry for when an account is accessed and marked as "warm" for gas metering + fn account_warmed(address: Address) -> Self; + + /// Creates a journal entry for when an account is destroyed via SELFDESTRUCT + /// Records the target address that received the destroyed account's balance, + /// whether the account was already destroyed, and its balance before destruction + /// on revert, the balance is transferred back to the original account + fn account_destroyed( + address: Address, + target: Address, + destroyed_status: SelfdestructionRevertStatus, + had_balance: U256, + ) -> Self; + + /// Creates a journal entry for when an account is "touched" - accessed in a way that may require saving it. + /// If account is empty and touch it will be removed from the state (EIP-161 state clear EIP) + fn account_touched(address: Address) -> Self; + + /// Creates a journal entry for a balance transfer between accounts + fn balance_transfer(from: Address, to: Address, balance: U256) -> Self; + + /// Creates a journal entry for when an account's balance is changed. + fn balance_changed(address: Address, old_balance: U256) -> Self; + + /// Creates a journal entry for when an account's nonce is incremented. + fn nonce_changed(address: Address) -> Self; + + /// Creates a journal entry for when a new account is created + fn account_created(address: Address, is_created_globally: bool) -> Self; + + /// Creates a journal entry for when a storage slot is modified + /// Records the previous value for reverting + fn storage_changed(address: Address, key: StorageKey, had_value: StorageValue) -> Self; + + /// Creates a journal entry for when a storage slot is accessed and marked as "warm" for gas metering + /// This is called with SLOAD opcode. + fn storage_warmed(address: Address, key: StorageKey) -> Self; + + /// Creates a journal entry for when a transient storage slot is modified (EIP-1153) + /// Records the previous value for reverting + fn transient_storage_changed( + address: Address, + key: StorageKey, + had_value: StorageValue, + ) -> Self; + + /// Creates a journal entry for when an account's code is modified + fn code_changed(address: Address) -> Self; + + /// Reverts the state change recorded by this journal entry + /// + /// More information on what is reverted can be found in [`JournalEntry`] enum. + /// + /// If transient storage is not provided, revert on transient storage will not be performed. + /// This is used when we revert whole transaction and know that transient storage is empty. + /// + /// # Notes + /// + /// The spurious dragon flag is used to skip revertion 0x000..0003 precompile. This + /// Behaviour is special and it caused by bug in Geth and Parity that is explained in [PR#716](https://github.com/ethereum/EIPs/issues/716). + /// + /// From yellow paper: + /// ```text + /// K.1. Deletion of an Account Despite Out-of-gas. At block 2675119, in the transaction 0xcf416c536ec1a19ed1fb89e + /// 4ec7ffb3cf73aa413b3aa9b77d60e4fd81a4296ba, an account at address 0x03 was called and an out-of-gas occurred during + /// the call. Against the equation (209), this added 0x03 in the set of touched addresses, and this transaction turned σ[0x03] + /// into ∅. + /// ``` + fn revert( + self, + state: &mut EvmState, + transient_storage: Option<&mut TransientStorage>, + is_spurious_dragon_enabled: bool, + ); +} + +/// Status of selfdestruction revert. +/// +/// Global selfdestruction means that selfdestruct is called for first time in global scope. +/// +/// Locally selfdesturction that selfdestruct is called for first time in one transaction scope. +/// +/// Repeated selfdestruction means local selfdesturction was already called in one transaction scope. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub enum SelfdestructionRevertStatus { + /// Selfdestruct is called for first time in global scope. + GloballySelfdestroyed, + /// Selfdestruct is called for first time in one transaction scope. + LocallySelfdestroyed, + /// Selfdestruct is called again in one transaction scope. + RepeatedSelfdestruction, +} + +/// Journal entries that are used to track changes to the state and are used to revert it. +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub enum JournalEntry { + /// Used to mark account that is warm inside EVM in regard to EIP-2929 AccessList. + /// Action: We will add Account to state. + /// Revert: we will remove account from state. + AccountWarmed { + /// Address of warmed account. + address: Address, + }, + /// Mark account to be destroyed and journal balance to be reverted + /// Action: Mark account and transfer the balance + /// Revert: Unmark the account and transfer balance back + AccountDestroyed { + /// Balance of account got transferred to target. + had_balance: U256, + /// Address of account to be destroyed. + address: Address, + /// Address of account that received the balance. + target: Address, + /// Status of selfdestruction revert. + destroyed_status: SelfdestructionRevertStatus, + }, + /// Loading account does not mean that account will need to be added to MerkleTree (touched). + /// Only when account is called (to execute contract or transfer balance) only then account is made touched. + /// Action: Mark account touched + /// Revert: Unmark account touched + AccountTouched { + /// Address of account that is touched. + address: Address, + }, + /// Balance changed + /// Action: Balance changed + /// Revert: Revert to previous balance + BalanceChange { + /// New balance of account. + old_balance: U256, + /// Address of account that had its balance changed. + address: Address, + }, + /// Transfer balance between two accounts + /// Action: Transfer balance + /// Revert: Transfer balance back + BalanceTransfer { + /// Balance that is transferred. + balance: U256, + /// Address of account that sent the balance. + from: Address, + /// Address of account that received the balance. + to: Address, + }, + /// Increment nonce + /// Action: Increment nonce by one + /// Revert: Decrement nonce by one + NonceChange { + /// Address of account that had its nonce changed. + /// Nonce is incremented by one. + address: Address, + }, + /// Create account: + /// Actions: Mark account as created + /// Revert: Unmark account as created and reset nonce to zero. + AccountCreated { + /// Address of account that is created. + /// On revert, this account will be set to empty. + address: Address, + /// If account is created globally for first time. + is_created_globally: bool, + }, + /// Entry used to track storage changes + /// Action: Storage change + /// Revert: Revert to previous value + StorageChanged { + /// Key of storage slot that is changed. + key: StorageKey, + /// Previous value of storage slot. + had_value: StorageValue, + /// Address of account that had its storage changed. + address: Address, + }, + /// Entry used to track storage warming introduced by EIP-2929. + /// Action: Storage warmed + /// Revert: Revert to cold state + StorageWarmed { + /// Key of storage slot that is warmed. + key: StorageKey, + /// Address of account that had its storage warmed. By SLOAD or SSTORE opcode. + address: Address, + }, + /// It is used to track an EIP-1153 transient storage change. + /// Action: Transient storage changed. + /// Revert: Revert to previous value. + TransientStorageChange { + /// Key of transient storage slot that is changed. + key: StorageKey, + /// Previous value of transient storage slot. + had_value: StorageValue, + /// Address of account that had its transient storage changed. + address: Address, + }, + /// Code changed + /// Action: Account code changed + /// Revert: Revert to previous bytecode. + CodeChange { + /// Address of account that had its code changed. + address: Address, + }, +} +impl JournalEntryTr for JournalEntry { + fn account_warmed(address: Address) -> Self { + JournalEntry::AccountWarmed { address } + } + + fn account_destroyed( + address: Address, + target: Address, + destroyed_status: SelfdestructionRevertStatus, + had_balance: StorageValue, + ) -> Self { + JournalEntry::AccountDestroyed { + address, + target, + destroyed_status, + had_balance, + } + } + + fn account_touched(address: Address) -> Self { + JournalEntry::AccountTouched { address } + } + + fn balance_changed(address: Address, old_balance: U256) -> Self { + JournalEntry::BalanceChange { + address, + old_balance, + } + } + + fn balance_transfer(from: Address, to: Address, balance: U256) -> Self { + JournalEntry::BalanceTransfer { from, to, balance } + } + + fn account_created(address: Address, is_created_globally: bool) -> Self { + JournalEntry::AccountCreated { + address, + is_created_globally, + } + } + + fn storage_changed(address: Address, key: StorageKey, had_value: StorageValue) -> Self { + JournalEntry::StorageChanged { + address, + key, + had_value, + } + } + + fn nonce_changed(address: Address) -> Self { + JournalEntry::NonceChange { address } + } + + fn storage_warmed(address: Address, key: StorageKey) -> Self { + JournalEntry::StorageWarmed { address, key } + } + + fn transient_storage_changed( + address: Address, + key: StorageKey, + had_value: StorageValue, + ) -> Self { + JournalEntry::TransientStorageChange { + address, + key, + had_value, + } + } + + fn code_changed(address: Address) -> Self { + JournalEntry::CodeChange { address } + } + + fn revert( + self, + state: &mut EvmState, + transient_storage: Option<&mut TransientStorage>, + is_spurious_dragon_enabled: bool, + ) { + match self { + JournalEntry::AccountWarmed { address } => { + state.get_mut(&address).unwrap().mark_cold(); + } + JournalEntry::AccountTouched { address } => { + if is_spurious_dragon_enabled && address == PRECOMPILE3 { + return; + } + // remove touched status + state.get_mut(&address).unwrap().unmark_touch(); + } + JournalEntry::AccountDestroyed { + address, + target, + destroyed_status, + had_balance, + } => { + let account = state.get_mut(&address).unwrap(); + // set previous state of selfdestructed flag, as there could be multiple + // selfdestructs in one transaction. + match destroyed_status { + SelfdestructionRevertStatus::GloballySelfdestroyed => { + account.unmark_selfdestruct(); + account.unmark_selfdestructed_locally(); + } + SelfdestructionRevertStatus::LocallySelfdestroyed => { + account.unmark_selfdestructed_locally(); + } + // do nothing on repeated selfdestruction + SelfdestructionRevertStatus::RepeatedSelfdestruction => (), + } + + account.info.balance += had_balance; + + if address != target { + let target = state.get_mut(&target).unwrap(); + target.info.balance -= had_balance; + } + } + JournalEntry::BalanceChange { + address, + old_balance, + } => { + let account = state.get_mut(&address).unwrap(); + account.info.balance = old_balance; + } + JournalEntry::BalanceTransfer { from, to, balance } => { + // we don't need to check overflow and underflow when adding and subtracting the balance. + let from = state.get_mut(&from).unwrap(); + from.info.balance += balance; + let to = state.get_mut(&to).unwrap(); + to.info.balance -= balance; + } + JournalEntry::NonceChange { address } => { + state.get_mut(&address).unwrap().info.nonce -= 1; + } + JournalEntry::AccountCreated { + address, + is_created_globally, + } => { + let account = &mut state.get_mut(&address).unwrap(); + account.unmark_created_locally(); + if is_created_globally { + account.unmark_created(); + } + // only account that have nonce == 0 can be created so it is safe to set it to 0. + account.info.nonce = 0; + } + JournalEntry::StorageWarmed { address, key } => { + state + .get_mut(&address) + .unwrap() + .storage + .get_mut(&key) + .unwrap() + .mark_cold(); + } + JournalEntry::StorageChanged { + address, + key, + had_value, + } => { + state + .get_mut(&address) + .unwrap() + .storage + .get_mut(&key) + .unwrap() + .present_value = had_value; + } + JournalEntry::TransientStorageChange { + address, + key, + had_value, + } => { + let Some(transient_storage) = transient_storage else { + return; + }; + let tkey = (address, key); + if had_value.is_zero() { + // if previous value is zero, remove it + transient_storage.remove(&tkey); + } else { + // if not zero, reinsert old value to transient storage. + transient_storage.insert(tkey, had_value); + } + } + JournalEntry::CodeChange { address } => { + let acc = state.get_mut(&address).unwrap(); + acc.info.code_hash = KECCAK_EMPTY; + acc.info.code = None; + } + } + } +} diff --git a/crates/context/src/journal/inner.rs b/crates/context/src/journal/inner.rs new file mode 100644 index 0000000000..fc45b372e2 --- /dev/null +++ b/crates/context/src/journal/inner.rs @@ -0,0 +1,896 @@ +//! Module containing the [`JournalInner`] that is part of [`crate::Journal`]. +use crate::entry::SelfdestructionRevertStatus; + +use super::JournalEntryTr; +use bytecode::Bytecode; +use context_interface::{ + context::{SStoreResult, SelfDestructResult, StateLoad}, + journaled_state::{AccountLoad, JournalCheckpoint, TransferError}, +}; +use core::mem; +use database_interface::Database; +use primitives::{ + hardfork::SpecId::{self, *}, + hash_map::Entry, + Address, HashMap, HashSet, Log, StorageKey, StorageValue, B256, KECCAK_EMPTY, U256, +}; +use state::{Account, EvmState, EvmStorageSlot, TransientStorage}; +use std::vec::Vec; +/// Inner journal state that contains journal and state changes. +/// +/// Spec Id is a essential information for the Journal. +#[derive(Debug, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct JournalInner { + /// The current state + pub state: EvmState, + /// Transient storage that is discarded after every transaction. + /// + /// See [EIP-1153](https://eips.ethereum.org/EIPS/eip-1153). + pub transient_storage: TransientStorage, + /// Emitted logs + pub logs: Vec, + /// The current call stack depth + pub depth: usize, + /// The journal of state changes, one for each transaction + pub journal: Vec, + /// Global transaction id that represent number of transactions executed (Including reverted ones). + /// It can be different from number of `journal_history` as some transaction could be + /// reverted or had a error on execution. + /// + /// This ID is used in `Self::state` to determine if account/storage is touched/warm/cold. + pub transaction_id: usize, + /// The spec ID for the EVM. Spec is required for some journal entries and needs to be set for + /// JournalInner to be functional. + /// + /// If spec is set it assumed that precompile addresses are set as well for this particular spec. + /// + /// This spec is used for two things: + /// + /// - [EIP-161]: Prior to this EIP, Ethereum had separate definitions for empty and non-existing accounts. + /// - [EIP-6780]: `SELFDESTRUCT` only in same transaction + /// + /// [EIP-161]: https://eips.ethereum.org/EIPS/eip-161 + /// [EIP-6780]: https://eips.ethereum.org/EIPS/eip-6780 + pub spec: SpecId, + /// Warm loaded addresses are used to check if loaded address + /// should be considered cold or warm loaded when the account + /// is first accessed. + /// + /// Note that this not include newly loaded accounts, account and storage + /// is considered warm if it is found in the `State`. + pub warm_preloaded_addresses: HashSet
, + /// Warm coinbase address, stored separately to avoid cloning preloaded addresses. + pub warm_coinbase_address: Option
, + /// Precompile addresses + pub precompiles: HashSet
, +} + +impl Default for JournalInner { + fn default() -> Self { + Self::new() + } +} + +impl JournalInner { + /// Creates new [`JournalInner`]. + /// + /// `warm_preloaded_addresses` is used to determine if address is considered warm loaded. + /// In ordinary case this is precompile or beneficiary. + pub fn new() -> JournalInner { + Self { + state: HashMap::default(), + transient_storage: TransientStorage::default(), + logs: Vec::new(), + journal: Vec::default(), + transaction_id: 0, + depth: 0, + spec: SpecId::default(), + warm_preloaded_addresses: HashSet::default(), + precompiles: HashSet::default(), + warm_coinbase_address: None, + } + } + + /// Returns the logs + #[inline] + pub fn take_logs(&mut self) -> Vec { + mem::take(&mut self.logs) + } + + /// Prepare for next transaction, by committing the current journal to history, incrementing the transaction id + /// and returning the logs. + /// + /// This function is used to prepare for next transaction. It will save the current journal + /// and clear the journal for the next transaction. + /// + /// `commit_tx` is used even for discarding transactions so transaction_id will be incremented. + pub fn commit_tx(&mut self) { + // Clears all field from JournalInner. Doing it this way to avoid + // missing any field. + let Self { + state, + transient_storage, + logs, + depth, + journal, + transaction_id, + spec, + warm_preloaded_addresses, + precompiles, + warm_coinbase_address, + } = self; + // Spec precompiles and state are not changed. It is always set again execution. + let _ = spec; + let _ = precompiles; + let _ = state; + transient_storage.clear(); + *depth = 0; + + // Do nothing with journal history so we can skip cloning present journal. + journal.clear(); + + // Clear coinbase address warming for next tx + *warm_coinbase_address = None; + // Load precompiles into warm_preloaded_addresses. + // TODO for precompiles we can use max transaction_id so they are always touched warm loaded. + // at least after state clear EIP. + reset_preloaded_addresses(warm_preloaded_addresses, precompiles); + // increment transaction id. + *transaction_id += 1; + logs.clear(); + } + + /// Discard the current transaction, by reverting the journal entries and incrementing the transaction id. + pub fn discard_tx(&mut self) { + // if there is no journal entries, there has not been any changes. + let Self { + state, + transient_storage, + logs, + depth, + journal, + transaction_id, + spec, + warm_preloaded_addresses, + warm_coinbase_address, + precompiles, + } = self; + + let is_spurious_dragon_enabled = spec.is_enabled_in(SPURIOUS_DRAGON); + // iterate over all journals entries and revert our global state + journal.drain(..).rev().for_each(|entry| { + entry.revert(state, None, is_spurious_dragon_enabled); + }); + transient_storage.clear(); + *depth = 0; + logs.clear(); + *transaction_id += 1; + // Clear coinbase address warming for next tx + *warm_coinbase_address = None; + reset_preloaded_addresses(warm_preloaded_addresses, precompiles); + } + + /// Take the [`EvmState`] and clears the journal by resetting it to initial state. + /// + /// Note: Precompile addresses and spec are preserved and initial state of + /// warm_preloaded_addresses will contain precompiles addresses. + #[inline] + pub fn finalize(&mut self) -> EvmState { + // Clears all field from JournalInner. Doing it this way to avoid + // missing any field. + let Self { + state, + transient_storage, + logs, + depth, + journal, + transaction_id, + spec, + warm_preloaded_addresses, + warm_coinbase_address, + precompiles, + } = self; + // Spec is not changed. And it is always set again in execution. + let _ = spec; + // Clear coinbase address warming for next tx + *warm_coinbase_address = None; + // Load precompiles into warm_preloaded_addresses. + reset_preloaded_addresses(warm_preloaded_addresses, precompiles); + + let state = mem::take(state); + logs.clear(); + transient_storage.clear(); + + // clear journal and journal history. + journal.clear(); + *depth = 0; + // reset transaction id. + *transaction_id = 0; + + state + } + + /// Return reference to state. + #[inline] + pub fn state(&mut self) -> &mut EvmState { + &mut self.state + } + + /// Sets SpecId. + #[inline] + pub fn set_spec_id(&mut self, spec: SpecId) { + self.spec = spec; + } + + /// Mark account as touched as only touched accounts will be added to state. + /// This is especially important for state clear where touched empty accounts needs to + /// be removed from state. + #[inline] + pub fn touch(&mut self, address: Address) { + if let Some(account) = self.state.get_mut(&address) { + Self::touch_account(&mut self.journal, address, account); + } + } + + /// Mark account as touched. + #[inline] + fn touch_account(journal: &mut Vec, address: Address, account: &mut Account) { + if !account.is_touched() { + journal.push(ENTRY::account_touched(address)); + account.mark_touch(); + } + } + + /// Returns the _loaded_ [Account] for the given address. + /// + /// This assumes that the account has already been loaded. + /// + /// # Panics + /// + /// Panics if the account has not been loaded and is missing from the state set. + #[inline] + pub fn account(&self, address: Address) -> &Account { + self.state + .get(&address) + .expect("Account expected to be loaded") // Always assume that acc is already loaded + } + + /// Set code and its hash to the account. + /// + /// Note: Assume account is warm and that hash is calculated from code. + #[inline] + pub fn set_code_with_hash(&mut self, address: Address, code: Bytecode, hash: B256) { + let account = self.state.get_mut(&address).unwrap(); + Self::touch_account(&mut self.journal, address, account); + + self.journal.push(ENTRY::code_changed(address)); + + account.info.code_hash = hash; + account.info.code = Some(code); + } + + /// Use it only if you know that acc is warm. + /// + /// Assume account is warm. + /// + /// In case of EIP-7702 code with zero address, the bytecode will be erased. + #[inline] + pub fn set_code(&mut self, address: Address, code: Bytecode) { + if let Bytecode::Eip7702(eip7702_bytecode) = &code { + if eip7702_bytecode.address().is_zero() { + self.set_code_with_hash(address, Bytecode::default(), KECCAK_EMPTY); + return; + } + } + + let hash = code.hash_slow(); + self.set_code_with_hash(address, code, hash) + } + + /// Add journal entry for caller accounting. + #[inline] + pub fn caller_accounting_journal_entry( + &mut self, + address: Address, + old_balance: U256, + bump_nonce: bool, + ) { + // account balance changed. + self.journal + .push(ENTRY::balance_changed(address, old_balance)); + // account is touched. + self.journal.push(ENTRY::account_touched(address)); + + if bump_nonce { + // nonce changed. + self.journal.push(ENTRY::nonce_changed(address)); + } + } + + /// Increments the balance of the account. + /// + /// Mark account as touched. + #[inline] + pub fn balance_incr( + &mut self, + db: &mut DB, + address: Address, + balance: U256, + ) -> Result<(), DB::Error> { + let account = self.load_account(db, address)?.data; + let old_balance = account.info.balance; + account.info.balance = account.info.balance.saturating_add(balance); + + // march account as touched. + if !account.is_touched() { + account.mark_touch(); + self.journal.push(ENTRY::account_touched(address)); + } + + // add journal entry for balance increment. + self.journal + .push(ENTRY::balance_changed(address, old_balance)); + Ok(()) + } + + /// Increments the nonce of the account. + #[inline] + pub fn nonce_bump_journal_entry(&mut self, address: Address) { + self.journal.push(ENTRY::nonce_changed(address)); + } + + /// Transfers balance from two accounts. Returns error if sender balance is not enough. + #[inline] + pub fn transfer( + &mut self, + db: &mut DB, + from: Address, + to: Address, + balance: U256, + ) -> Result, DB::Error> { + if balance.is_zero() { + self.load_account(db, to)?; + let to_account = self.state.get_mut(&to).unwrap(); + Self::touch_account(&mut self.journal, to, to_account); + return Ok(None); + } + // load accounts + self.load_account(db, from)?; + self.load_account(db, to)?; + + // sub balance from + let from_account = self.state.get_mut(&from).unwrap(); + Self::touch_account(&mut self.journal, from, from_account); + let from_balance = &mut from_account.info.balance; + + let Some(from_balance_decr) = from_balance.checked_sub(balance) else { + return Ok(Some(TransferError::OutOfFunds)); + }; + *from_balance = from_balance_decr; + + // add balance to + let to_account = &mut self.state.get_mut(&to).unwrap(); + Self::touch_account(&mut self.journal, to, to_account); + let to_balance = &mut to_account.info.balance; + let Some(to_balance_incr) = to_balance.checked_add(balance) else { + return Ok(Some(TransferError::OverflowPayment)); + }; + *to_balance = to_balance_incr; + // Overflow of U256 balance is not possible to happen on mainnet. We don't bother to return funds from from_acc. + + self.journal + .push(ENTRY::balance_transfer(from, to, balance)); + + Ok(None) + } + + /// Creates account or returns false if collision is detected. + /// + /// There are few steps done: + /// 1. Make created account warm loaded (AccessList) and this should + /// be done before subroutine checkpoint is created. + /// 2. Check if there is collision of newly created account with existing one. + /// 3. Mark created account as created. + /// 4. Add fund to created account + /// 5. Increment nonce of created account if SpuriousDragon is active + /// 6. Decrease balance of caller account. + /// + /// # Panics + /// + /// Panics if the caller is not loaded inside the EVM state. + /// This should have been done inside `create_inner`. + #[inline] + pub fn create_account_checkpoint( + &mut self, + caller: Address, + target_address: Address, + balance: U256, + spec_id: SpecId, + ) -> Result { + // Enter subroutine + let checkpoint = self.checkpoint(); + + // Fetch balance of caller. + let caller_balance = self.state.get(&caller).unwrap().info.balance; + // Check if caller has enough balance to send to the created contract. + if caller_balance < balance { + self.checkpoint_revert(checkpoint); + return Err(TransferError::OutOfFunds); + } + + // Newly created account is present, as we just loaded it. + let target_acc = self.state.get_mut(&target_address).unwrap(); + let last_journal = &mut self.journal; + + // New account can be created if: + // Bytecode is not empty. + // Nonce is not zero + // Account is not precompile. + if target_acc.info.code_hash != KECCAK_EMPTY || target_acc.info.nonce != 0 { + self.checkpoint_revert(checkpoint); + return Err(TransferError::CreateCollision); + } + + // set account status to create. + let is_created_globally = target_acc.mark_created_locally(); + + // this entry will revert set nonce. + last_journal.push(ENTRY::account_created(target_address, is_created_globally)); + target_acc.info.code = None; + // EIP-161: State trie clearing (invariant-preserving alternative) + if spec_id.is_enabled_in(SPURIOUS_DRAGON) { + // nonce is going to be reset to zero in AccountCreated journal entry. + target_acc.info.nonce = 1; + } + + // touch account. This is important as for pre SpuriousDragon account could be + // saved even empty. + Self::touch_account(last_journal, target_address, target_acc); + + // Add balance to created account, as we already have target here. + let Some(new_balance) = target_acc.info.balance.checked_add(balance) else { + self.checkpoint_revert(checkpoint); + return Err(TransferError::OverflowPayment); + }; + target_acc.info.balance = new_balance; + + // safe to decrement for the caller as balance check is already done. + self.state.get_mut(&caller).unwrap().info.balance -= balance; + + // add journal entry of transferred balance + last_journal.push(ENTRY::balance_transfer(caller, target_address, balance)); + + Ok(checkpoint) + } + + /// Makes a checkpoint that in case of Revert can bring back state to this point. + #[inline] + pub fn checkpoint(&mut self) -> JournalCheckpoint { + let checkpoint = JournalCheckpoint { + log_i: self.logs.len(), + journal_i: self.journal.len(), + }; + self.depth += 1; + checkpoint + } + + /// Commits the checkpoint. + #[inline] + pub fn checkpoint_commit(&mut self) { + self.depth -= 1; + } + + /// Reverts all changes to state until given checkpoint. + #[inline] + pub fn checkpoint_revert(&mut self, checkpoint: JournalCheckpoint) { + let is_spurious_dragon_enabled = self.spec.is_enabled_in(SPURIOUS_DRAGON); + let state = &mut self.state; + let transient_storage = &mut self.transient_storage; + self.depth -= 1; + self.logs.truncate(checkpoint.log_i); + + // iterate over last N journals sets and revert our global state + self.journal + .drain(checkpoint.journal_i..) + .rev() + .for_each(|entry| { + entry.revert(state, Some(transient_storage), is_spurious_dragon_enabled); + }); + } + + /// Performs selfdestruct action. + /// Transfers balance from address to target. Check if target exist/is_cold + /// + /// Note: Balance will be lost if address and target are the same BUT when + /// current spec enables Cancun, this happens only when the account associated to address + /// is created in the same tx + /// + /// # References: + /// * + /// * + /// * + #[inline] + pub fn selfdestruct( + &mut self, + db: &mut DB, + address: Address, + target: Address, + ) -> Result, DB::Error> { + let spec = self.spec; + let account_load = self.load_account(db, target)?; + let is_cold = account_load.is_cold; + let is_empty = account_load.state_clear_aware_is_empty(spec); + + if address != target { + // Both accounts are loaded before this point, `address` as we execute its contract. + // and `target` at the beginning of the function. + let acc_balance = self.state.get(&address).unwrap().info.balance; + + let target_account = self.state.get_mut(&target).unwrap(); + Self::touch_account(&mut self.journal, target, target_account); + target_account.info.balance += acc_balance; + } + + let acc = self.state.get_mut(&address).unwrap(); + let balance = acc.info.balance; + + let destroyed_status = if !acc.is_selfdestructed() { + SelfdestructionRevertStatus::GloballySelfdestroyed + } else if !acc.is_selfdestructed_locally() { + SelfdestructionRevertStatus::LocallySelfdestroyed + } else { + SelfdestructionRevertStatus::RepeatedSelfdestruction + }; + + let is_cancun_enabled = spec.is_enabled_in(CANCUN); + + // EIP-6780 (Cancun hard-fork): selfdestruct only if contract is created in the same tx + let journal_entry = if acc.is_created_locally() || !is_cancun_enabled { + acc.mark_selfdestructed_locally(); + acc.info.balance = U256::ZERO; + Some(ENTRY::account_destroyed( + address, + target, + destroyed_status, + balance, + )) + } else if address != target { + acc.info.balance = U256::ZERO; + Some(ENTRY::balance_transfer(address, target, balance)) + } else { + // State is not changed: + // * if we are after Cancun upgrade and + // * Selfdestruct account that is created in the same transaction and + // * Specify the target is same as selfdestructed account. The balance stays unchanged. + None + }; + + if let Some(entry) = journal_entry { + self.journal.push(entry); + }; + + Ok(StateLoad { + data: SelfDestructResult { + had_value: !balance.is_zero(), + target_exists: !is_empty, + previously_destroyed: destroyed_status + == SelfdestructionRevertStatus::RepeatedSelfdestruction, + }, + is_cold, + }) + } + + /// Loads account into memory. return if it is cold or warm accessed + #[inline] + pub fn load_account( + &mut self, + db: &mut DB, + address: Address, + ) -> Result, DB::Error> { + self.load_account_optional(db, address, false, []) + } + + /// Loads account into memory. If account is EIP-7702 type it will additionally + /// load delegated account. + /// + /// It will mark both this and delegated account as warm loaded. + /// + /// Returns information about the account (If it is empty or cold loaded) and if present the information + /// about the delegated account (If it is cold loaded). + #[inline] + pub fn load_account_delegated( + &mut self, + db: &mut DB, + address: Address, + ) -> Result, DB::Error> { + let spec = self.spec; + let is_eip7702_enabled = spec.is_enabled_in(SpecId::PRAGUE); + let account = self.load_account_optional(db, address, is_eip7702_enabled, [])?; + let is_empty = account.state_clear_aware_is_empty(spec); + + let mut account_load = StateLoad::new( + AccountLoad { + is_delegate_account_cold: None, + is_empty, + }, + account.is_cold, + ); + + // load delegate code if account is EIP-7702 + if let Some(Bytecode::Eip7702(code)) = &account.info.code { + let address = code.address(); + let delegate_account = self.load_account(db, address)?; + account_load.data.is_delegate_account_cold = Some(delegate_account.is_cold); + } + + Ok(account_load) + } + + /// Loads account and its code. If account is already loaded it will load its code. + /// + /// It will mark account as warm loaded. If not existing Database will be queried for data. + /// + /// In case of EIP-7702 delegated account will not be loaded, + /// [`Self::load_account_delegated`] should be used instead. + #[inline] + pub fn load_code( + &mut self, + db: &mut DB, + address: Address, + ) -> Result, DB::Error> { + self.load_account_optional(db, address, true, []) + } + + /// Loads account. If account is already loaded it will be marked as warm. + #[inline] + pub fn load_account_optional( + &mut self, + db: &mut DB, + address: Address, + load_code: bool, + storage_keys: impl IntoIterator, + ) -> Result, DB::Error> { + let load = match self.state.entry(address) { + Entry::Occupied(entry) => { + let account = entry.into_mut(); + let is_cold = account.mark_warm_with_transaction_id(self.transaction_id); + // if it is colad loaded we need to clear local flags that can interact with selfdestruct + if is_cold { + // if it is cold loaded and we have selfdestructed locally it means that + // account was selfdestructed in previous transaction and we need to clear its information and storage. + if account.is_selfdestructed_locally() { + account.selfdestruct(); + account.unmark_selfdestructed_locally(); + } + // unmark locally created + account.unmark_created_locally(); + } + StateLoad { + data: account, + is_cold, + } + } + Entry::Vacant(vac) => { + let account = if let Some(account) = db.basic(address)? { + account.into() + } else { + Account::new_not_existing(self.transaction_id) + }; + + // Precompiles among some other account(coinbase included) are warm loaded so we need to take that into account + let is_cold = !self.warm_preloaded_addresses.contains(&address) + && self.warm_coinbase_address.as_ref() != Some(&address); + + StateLoad { + data: vac.insert(account), + is_cold, + } + } + }; + + // journal loading of cold account. + if load.is_cold { + self.journal.push(ENTRY::account_warmed(address)); + } + if load_code { + let info = &mut load.data.info; + if info.code.is_none() { + let code = if info.code_hash == KECCAK_EMPTY { + Bytecode::default() + } else { + db.code_by_hash(info.code_hash)? + }; + info.code = Some(code); + } + } + + for storage_key in storage_keys.into_iter() { + sload_with_account( + load.data, + db, + &mut self.journal, + self.transaction_id, + address, + storage_key, + )?; + } + Ok(load) + } + + /// Loads storage slot. + /// + /// # Panics + /// + /// Panics if the account is not present in the state. + #[inline] + pub fn sload( + &mut self, + db: &mut DB, + address: Address, + key: StorageKey, + ) -> Result, DB::Error> { + // assume acc is warm + let account = self.state.get_mut(&address).unwrap(); + // only if account is created in this tx we can assume that storage is empty. + sload_with_account( + account, + db, + &mut self.journal, + self.transaction_id, + address, + key, + ) + } + + /// Stores storage slot. + /// + /// And returns (original,present,new) slot value. + /// + /// **Note**: Account should already be present in our state. + #[inline] + pub fn sstore( + &mut self, + db: &mut DB, + address: Address, + key: StorageKey, + new: StorageValue, + ) -> Result, DB::Error> { + // assume that acc exists and load the slot. + let present = self.sload(db, address, key)?; + let acc = self.state.get_mut(&address).unwrap(); + + // if there is no original value in dirty return present value, that is our original. + let slot = acc.storage.get_mut(&key).unwrap(); + + // new value is same as present, we don't need to do anything + if present.data == new { + return Ok(StateLoad::new( + SStoreResult { + original_value: slot.original_value(), + present_value: present.data, + new_value: new, + }, + present.is_cold, + )); + } + + self.journal + .push(ENTRY::storage_changed(address, key, present.data)); + // insert value into present state. + slot.present_value = new; + Ok(StateLoad::new( + SStoreResult { + original_value: slot.original_value(), + present_value: present.data, + new_value: new, + }, + present.is_cold, + )) + } + + /// Read transient storage tied to the account. + /// + /// EIP-1153: Transient storage opcodes + #[inline] + pub fn tload(&mut self, address: Address, key: StorageKey) -> StorageValue { + self.transient_storage + .get(&(address, key)) + .copied() + .unwrap_or_default() + } + + /// Store transient storage tied to the account. + /// + /// If values is different add entry to the journal + /// so that old state can be reverted if that action is needed. + /// + /// EIP-1153: Transient storage opcodes + #[inline] + pub fn tstore(&mut self, address: Address, key: StorageKey, new: StorageValue) { + let had_value = if new.is_zero() { + // if new values is zero, remove entry from transient storage. + // if previous values was some insert it inside journal. + // If it is none nothing should be inserted. + self.transient_storage.remove(&(address, key)) + } else { + // insert values + let previous_value = self + .transient_storage + .insert((address, key), new) + .unwrap_or_default(); + + // check if previous value is same + if previous_value != new { + // if it is different, insert previous values inside journal. + Some(previous_value) + } else { + None + } + }; + + if let Some(had_value) = had_value { + // insert in journal only if value was changed. + self.journal + .push(ENTRY::transient_storage_changed(address, key, had_value)); + } + } + + /// Pushes log into subroutine. + #[inline] + pub fn log(&mut self, log: Log) { + self.logs.push(log); + } +} + +/// Loads storage slot with account. +#[inline] +pub fn sload_with_account( + account: &mut Account, + db: &mut DB, + journal: &mut Vec, + transaction_id: usize, + address: Address, + key: StorageKey, +) -> Result, DB::Error> { + let is_newly_created = account.is_created(); + let (value, is_cold) = match account.storage.entry(key) { + Entry::Occupied(occ) => { + let slot = occ.into_mut(); + let is_cold = slot.mark_warm_with_transaction_id(transaction_id); + (slot.present_value, is_cold) + } + Entry::Vacant(vac) => { + // if storage was cleared, we don't need to ping db. + let value = if is_newly_created { + StorageValue::ZERO + } else { + db.storage(address, key)? + }; + + vac.insert(EvmStorageSlot::new(value, transaction_id)); + + (value, true) + } + }; + + if is_cold { + // add it to journal as cold loaded. + journal.push(ENTRY::storage_warmed(address, key)); + } + + Ok(StateLoad::new(value, is_cold)) +} + +fn reset_preloaded_addresses( + warm_preloaded_addresses: &mut HashSet
, + precompiles: &HashSet
, +) { + // `warm_preloaded_addresses` is append-only, and is initialized with `precompiles`. + // Avoid unnecessarily cloning if it hasn't changed. + if warm_preloaded_addresses.len() == precompiles.len() { + debug_assert_eq!(warm_preloaded_addresses, precompiles); + return; + } + warm_preloaded_addresses.clone_from(precompiles); +} diff --git a/crates/context/src/lib.rs b/crates/context/src/lib.rs new file mode 100644 index 0000000000..301f0ae073 --- /dev/null +++ b/crates/context/src/lib.rs @@ -0,0 +1,24 @@ +//! EVM execution context. +#![cfg_attr(not(test), warn(unused_crate_dependencies))] +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(not(feature = "std"))] +extern crate alloc as std; + +pub use context_interface::*; + +pub mod block; +pub mod cfg; +pub mod context; +pub mod evm; +pub mod journal; +pub mod local; +pub mod tx; + +pub use block::BlockEnv; +pub use cfg::{Cfg, CfgEnv}; +pub use context::*; +pub use evm::Evm; +pub use journal::*; +pub use local::LocalContext; +pub use tx::TxEnv; diff --git a/crates/context/src/local.rs b/crates/context/src/local.rs new file mode 100644 index 0000000000..47017e1978 --- /dev/null +++ b/crates/context/src/local.rs @@ -0,0 +1,37 @@ +//! Local context that is filled by execution. +use context_interface::LocalContextTr; +use core::cell::RefCell; +use std::{rc::Rc, vec::Vec}; + +/// Local context that is filled by execution. +#[derive(Clone, Debug)] +pub struct LocalContext { + /// Interpreter shared memory buffer. A reused memory buffer for calls. + pub shared_memory_buffer: Rc>>, +} + +impl Default for LocalContext { + fn default() -> Self { + Self { + shared_memory_buffer: Rc::new(RefCell::new(Vec::with_capacity(1024 * 4))), + } + } +} + +impl LocalContextTr for LocalContext { + fn clear(&mut self) { + // Sets len to 0 but it will not shrink to drop the capacity. + unsafe { self.shared_memory_buffer.borrow_mut().set_len(0) }; + } + + fn shared_memory_buffer(&self) -> &Rc>> { + &self.shared_memory_buffer + } +} + +impl LocalContext { + /// Creates a new local context, initcodes are hashes and added to the mapping. + pub fn new() -> Self { + Self::default() + } +} diff --git a/crates/context/src/setters.rs b/crates/context/src/setters.rs new file mode 100644 index 0000000000..278fd40d74 --- /dev/null +++ b/crates/context/src/setters.rs @@ -0,0 +1,39 @@ +use crate::Context; +use auto_impl::auto_impl; +use context_interface::{Block, Cfg, Database, JournalTr, Transaction}; + +/// Setters for the context. +#[auto_impl(&mut, Box)] +pub trait ContextSetters { + /// Transaction type. + type Tx: Transaction; + /// Block type. + type Block: Block; + + /// Set the transaction. + fn set_tx(&mut self, tx: Self::Tx); + + /// Set the block. + fn set_block(&mut self, block: Self::Block); +} + +impl ContextSetters + for Context +where + BLOCK: Block, + TX: Transaction, + CFG: Cfg, + DB: Database, + JOURNAL: JournalTr, +{ + type Tx = TX; + type Block = BLOCK; + + fn set_tx(&mut self, tx: Self::Tx) { + self.tx = tx; + } + + fn set_block(&mut self, block: Self::Block) { + self.block = block; + } +} diff --git a/crates/context/src/tx.rs b/crates/context/src/tx.rs new file mode 100644 index 0000000000..b7752a3aea --- /dev/null +++ b/crates/context/src/tx.rs @@ -0,0 +1,1166 @@ +//! This module contains [`TxEnv`] struct and implements [`Transaction`] trait for it. +use crate::TransactionType; +use context_interface::{ + either::Either, + transaction::{ + AccessList, AccessListItem, Authorization, RecoveredAuthority, RecoveredAuthorization, + SignedAuthorization, Transaction, + }, +}; +use core::fmt::Debug; +use database_interface::{BENCH_CALLER, BENCH_TARGET}; +use primitives::{eip7825, Address, Bytes, TxKind, B256, U256}; +use std::{vec, vec::Vec}; + +/// The Transaction Environment is a struct that contains all fields that can be found in all Ethereum transaction, +/// including EIP-4844, EIP-7702, EIP-7873, etc. It implements the [`Transaction`] trait, which is used inside the EVM to execute a transaction. +/// +/// [`TxEnvBuilder`] builder is recommended way to create a new [`TxEnv`] as it will automatically +/// set the transaction type based on the fields set. +#[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct TxEnv { + /// Transaction type + pub tx_type: u8, + /// Caller aka Author aka transaction signer + pub caller: Address, + /// The gas limit of the transaction. + pub gas_limit: u64, + /// The gas price of the transaction. + /// + /// For EIP-1559 transaction this represent max_gas_fee. + pub gas_price: u128, + /// The destination of the transaction + pub kind: TxKind, + /// The value sent to `transact_to` + pub value: U256, + /// The data of the transaction + pub data: Bytes, + + /// The nonce of the transaction + pub nonce: u64, + + /// The chain ID of the transaction + /// + /// Incorporated as part of the Spurious Dragon upgrade via [EIP-155]. + /// + /// [EIP-155]: https://eips.ethereum.org/EIPS/eip-155 + pub chain_id: Option, + + /// A list of addresses and storage keys that the transaction plans to access + /// + /// Added in [EIP-2930]. + /// + /// [EIP-2930]: https://eips.ethereum.org/EIPS/eip-2930 + pub access_list: AccessList, + + /// The priority fee per gas + /// + /// Incorporated as part of the London upgrade via [EIP-1559]. + /// + /// [EIP-1559]: https://eips.ethereum.org/EIPS/eip-1559 + pub gas_priority_fee: Option, + + /// The list of blob versioned hashes + /// + /// Per EIP there should be at least one blob present if [`max_fee_per_blob_gas`][Self::max_fee_per_blob_gas] is [`Some`]. + /// + /// Incorporated as part of the Cancun upgrade via [EIP-4844]. + /// + /// [EIP-4844]: https://eips.ethereum.org/EIPS/eip-4844 + pub blob_hashes: Vec, + + /// The max fee per blob gas + /// + /// Incorporated as part of the Cancun upgrade via [EIP-4844]. + /// + /// [EIP-4844]: https://eips.ethereum.org/EIPS/eip-4844 + pub max_fee_per_blob_gas: u128, + + /// List of authorizations + /// + /// `authorization_list` contains the signature that authorizes this + /// caller to place the code to signer account. + /// + /// Set EOA account code for one transaction via [EIP-7702]. + /// + /// [EIP-7702]: https://eips.ethereum.org/EIPS/eip-7702 + pub authorization_list: Vec>, +} + +impl Default for TxEnv { + fn default() -> Self { + Self::builder().build().unwrap() + } +} + +/// Error type for deriving transaction type used as error in [`TxEnv::derive_tx_type`] function. +#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub enum DeriveTxTypeError { + /// Missing target for EIP-4844 + MissingTargetForEip4844, + /// Missing target for EIP-7702 + MissingTargetForEip7702, + /// Missing target for EIP-7873 + MissingTargetForEip7873, +} + +impl TxEnv { + /// Creates a new TxEnv with benchmark-specific values. + pub fn new_bench() -> Self { + Self { + caller: BENCH_CALLER, + kind: TxKind::Call(BENCH_TARGET), + gas_limit: 1_000_000_000, + ..Default::default() + } + } + + /// Derives tx type from transaction fields and sets it to `tx_type`. + /// Returns error in case some fields were not set correctly. + pub fn derive_tx_type(&mut self) -> Result<(), DeriveTxTypeError> { + if !self.access_list.0.is_empty() { + self.tx_type = TransactionType::Eip2930 as u8; + } + + if self.gas_priority_fee.is_some() { + self.tx_type = TransactionType::Eip1559 as u8; + } + + if !self.blob_hashes.is_empty() || self.max_fee_per_blob_gas > 0 { + if let TxKind::Call(_) = self.kind { + self.tx_type = TransactionType::Eip4844 as u8; + return Ok(()); + } else { + return Err(DeriveTxTypeError::MissingTargetForEip4844); + } + } + + if !self.authorization_list.is_empty() { + if let TxKind::Call(_) = self.kind { + self.tx_type = TransactionType::Eip7702 as u8; + return Ok(()); + } else { + return Err(DeriveTxTypeError::MissingTargetForEip7702); + } + } + Ok(()) + } + + /// Insert a list of signed authorizations into the authorization list. + pub fn set_signed_authorization(&mut self, auth: Vec) { + self.authorization_list = auth.into_iter().map(Either::Left).collect(); + } + + /// Insert a list of recovered authorizations into the authorization list. + pub fn set_recovered_authorization(&mut self, auth: Vec) { + self.authorization_list = auth.into_iter().map(Either::Right).collect(); + } +} + +impl Transaction for TxEnv { + type AccessListItem<'a> = &'a AccessListItem; + type Authorization<'a> = &'a Either; + + fn tx_type(&self) -> u8 { + self.tx_type + } + + fn kind(&self) -> TxKind { + self.kind + } + + fn caller(&self) -> Address { + self.caller + } + + fn gas_limit(&self) -> u64 { + self.gas_limit + } + + fn gas_price(&self) -> u128 { + self.gas_price + } + + fn value(&self) -> U256 { + self.value + } + + fn nonce(&self) -> u64 { + self.nonce + } + + fn chain_id(&self) -> Option { + self.chain_id + } + + fn access_list(&self) -> Option>> { + Some(self.access_list.0.iter()) + } + + fn max_fee_per_gas(&self) -> u128 { + self.gas_price + } + + fn max_fee_per_blob_gas(&self) -> u128 { + self.max_fee_per_blob_gas + } + + fn authorization_list_len(&self) -> usize { + self.authorization_list.len() + } + + fn authorization_list(&self) -> impl Iterator> { + self.authorization_list.iter() + } + + fn input(&self) -> &Bytes { + &self.data + } + + fn blob_versioned_hashes(&self) -> &[B256] { + &self.blob_hashes + } + + fn max_priority_fee_per_gas(&self) -> Option { + self.gas_priority_fee + } +} + +/// Builder for constructing [`TxEnv`] instances +#[derive(Default, Debug)] +pub struct TxEnvBuilder { + tx_type: Option, + caller: Address, + gas_limit: u64, + gas_price: u128, + kind: TxKind, + value: U256, + data: Bytes, + nonce: u64, + chain_id: Option, + access_list: AccessList, + gas_priority_fee: Option, + blob_hashes: Vec, + max_fee_per_blob_gas: u128, + authorization_list: Vec>, +} + +impl TxEnvBuilder { + /// Create a new builder with default values + pub fn new() -> Self { + Self { + tx_type: None, + caller: Address::default(), + gas_limit: eip7825::TX_GAS_LIMIT_CAP, + gas_price: 0, + kind: TxKind::Call(Address::default()), + value: U256::ZERO, + data: Bytes::default(), + nonce: 0, + chain_id: Some(1), // Mainnet chain ID is 1 + access_list: Default::default(), + gas_priority_fee: None, + blob_hashes: Vec::new(), + max_fee_per_blob_gas: 0, + authorization_list: Vec::new(), + } + } + + /// Set the transaction type + pub fn tx_type(mut self, tx_type: Option) -> Self { + self.tx_type = tx_type; + self + } + + /// Get the transaction type + pub fn get_tx_type(&self) -> Option { + self.tx_type + } + + /// Set the caller address + pub fn caller(mut self, caller: Address) -> Self { + self.caller = caller; + self + } + + /// Set the gas limit + pub fn gas_limit(mut self, gas_limit: u64) -> Self { + self.gas_limit = gas_limit; + self + } + + /// Set the max fee per gas. + pub fn max_fee_per_gas(mut self, max_fee_per_gas: u128) -> Self { + self.gas_price = max_fee_per_gas; + self + } + + /// Set the gas price + pub fn gas_price(mut self, gas_price: u128) -> Self { + self.gas_price = gas_price; + self + } + + /// Set the transaction kind + pub fn kind(mut self, kind: TxKind) -> Self { + self.kind = kind; + self + } + + /// Set the transaction kind to call + pub fn call(mut self, target: Address) -> Self { + self.kind = TxKind::Call(target); + self + } + + /// Set the transaction kind to create + pub fn create(mut self) -> Self { + self.kind = TxKind::Create; + self + } + + /// Set the transaction kind to create + pub fn to(self, target: Address) -> Self { + self.call(target) + } + + /// Set the transaction value + pub fn value(mut self, value: U256) -> Self { + self.value = value; + self + } + + /// Set the transaction data + pub fn data(mut self, data: Bytes) -> Self { + self.data = data; + self + } + + /// Set the transaction nonce + pub fn nonce(mut self, nonce: u64) -> Self { + self.nonce = nonce; + self + } + + /// Set the chain ID + pub fn chain_id(mut self, chain_id: Option) -> Self { + self.chain_id = chain_id; + self + } + + /// Set the access list + pub fn access_list(mut self, access_list: AccessList) -> Self { + self.access_list = access_list; + self + } + + /// Set the gas priority fee + pub fn gas_priority_fee(mut self, gas_priority_fee: Option) -> Self { + self.gas_priority_fee = gas_priority_fee; + self + } + + /// Set the blob hashes + pub fn blob_hashes(mut self, blob_hashes: Vec) -> Self { + self.blob_hashes = blob_hashes; + self + } + + /// Set the max fee per blob gas + pub fn max_fee_per_blob_gas(mut self, max_fee_per_blob_gas: u128) -> Self { + self.max_fee_per_blob_gas = max_fee_per_blob_gas; + self + } + + /// Set the authorization list + pub fn authorization_list( + mut self, + authorization_list: Vec>, + ) -> Self { + self.authorization_list = authorization_list; + self + } + + /// Insert a list of signed authorizations into the authorization list. + pub fn authorization_list_signed(mut self, auth: Vec) -> Self { + self.authorization_list = auth.into_iter().map(Either::Left).collect(); + self + } + + /// Insert a list of recovered authorizations into the authorization list. + pub fn authorization_list_recovered(mut self, auth: Vec) -> Self { + self.authorization_list = auth.into_iter().map(Either::Right).collect(); + self + } + + /// Build the final [`TxEnv`] with default values for missing fields. + pub fn build_fill(mut self) -> TxEnv { + if let Some(tx_type) = self.tx_type { + match TransactionType::from(tx_type) { + TransactionType::Legacy => { + // do nothing + } + TransactionType::Eip2930 => { + // do nothing, all fields are set. Access list can be empty. + } + TransactionType::Eip1559 => { + // gas priority fee is required + if self.gas_priority_fee.is_none() { + self.gas_priority_fee = Some(0); + } + } + TransactionType::Eip4844 => { + // gas priority fee is required + if self.gas_priority_fee.is_none() { + self.gas_priority_fee = Some(0); + } + + // blob hashes can be empty + if self.blob_hashes.is_empty() { + self.blob_hashes = vec![B256::default()]; + } + + // target is required + if !self.kind.is_call() { + self.kind = TxKind::Call(Address::default()); + } + } + TransactionType::Eip7702 => { + // gas priority fee is required + if self.gas_priority_fee.is_none() { + self.gas_priority_fee = Some(0); + } + + // authorization list can be empty + if self.authorization_list.is_empty() { + // add dummy authorization + self.authorization_list = + vec![Either::Right(RecoveredAuthorization::new_unchecked( + Authorization { + chain_id: U256::from(self.chain_id.unwrap_or(1)), + address: self.caller, + nonce: self.nonce, + }, + RecoveredAuthority::Invalid, + ))]; + } + + // target is required + if !self.kind.is_call() { + self.kind = TxKind::Call(Address::default()); + } + } + TransactionType::Custom => { + // do nothing + } + } + } + + let mut tx = TxEnv { + tx_type: self.tx_type.unwrap_or(0), + caller: self.caller, + gas_limit: self.gas_limit, + gas_price: self.gas_price, + kind: self.kind, + value: self.value, + data: self.data, + nonce: self.nonce, + chain_id: self.chain_id, + access_list: self.access_list, + gas_priority_fee: self.gas_priority_fee, + blob_hashes: self.blob_hashes, + max_fee_per_blob_gas: self.max_fee_per_blob_gas, + authorization_list: self.authorization_list, + }; + + // if tx_type is not set, derive it from fields and fix errors. + if self.tx_type.is_none() { + match tx.derive_tx_type() { + Ok(_) => {} + Err(DeriveTxTypeError::MissingTargetForEip4844) => { + tx.kind = TxKind::Call(Address::default()); + } + Err(DeriveTxTypeError::MissingTargetForEip7702) => { + tx.kind = TxKind::Call(Address::default()); + } + Err(DeriveTxTypeError::MissingTargetForEip7873) => { + tx.kind = TxKind::Call(Address::default()); + } + } + } + + tx + } + + /// Build the final [`TxEnv`], returns error if some fields are wrongly set. + /// If it is fine to fill missing fields with default values, use [`TxEnvBuilder::build_fill`] instead. + pub fn build(self) -> Result { + // if tx_type is set, check if all needed fields are set correctly. + if let Some(tx_type) = self.tx_type { + match TransactionType::from(tx_type) { + TransactionType::Legacy => { + // do nothing + } + TransactionType::Eip2930 => { + // do nothing, all fields are set. Access list can be empty. + } + TransactionType::Eip1559 => { + // gas priority fee is required + if self.gas_priority_fee.is_none() { + return Err(TxEnvBuildError::MissingGasPriorityFeeForEip1559); + } + } + TransactionType::Eip4844 => { + // gas priority fee is required + if self.gas_priority_fee.is_none() { + return Err(TxEnvBuildError::MissingGasPriorityFeeForEip1559); + } + + // blob hashes can be empty + if self.blob_hashes.is_empty() { + return Err(TxEnvBuildError::MissingBlobHashesForEip4844); + } + + // target is required + if !self.kind.is_call() { + return Err(TxEnvBuildError::MissingTargetForEip4844); + } + } + TransactionType::Eip7702 => { + // gas priority fee is required + if self.gas_priority_fee.is_none() { + return Err(TxEnvBuildError::MissingGasPriorityFeeForEip1559); + } + + // authorization list can be empty + if self.authorization_list.is_empty() { + return Err(TxEnvBuildError::MissingAuthorizationListForEip7702); + } + + // target is required + if !self.kind.is_call() { + return Err(DeriveTxTypeError::MissingTargetForEip4844.into()); + } + } + TransactionType::Custom => { + // do nothing, custom transaction type is handled by the caller. + } + } + } + + let mut tx = TxEnv { + tx_type: self.tx_type.unwrap_or(0), + caller: self.caller, + gas_limit: self.gas_limit, + gas_price: self.gas_price, + kind: self.kind, + value: self.value, + data: self.data, + nonce: self.nonce, + chain_id: self.chain_id, + access_list: self.access_list, + gas_priority_fee: self.gas_priority_fee, + blob_hashes: self.blob_hashes, + max_fee_per_blob_gas: self.max_fee_per_blob_gas, + authorization_list: self.authorization_list, + }; + + // Derive tx type from fields, if some fields are wrongly set it will return an error. + if self.tx_type.is_none() { + tx.derive_tx_type()?; + } + + Ok(tx) + } +} + +/// Error type for building [`TxEnv`] +#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub enum TxEnvBuildError { + /// Derive tx type error + DeriveErr(DeriveTxTypeError), + /// Missing priority fee for EIP-1559 + MissingGasPriorityFeeForEip1559, + /// Missing blob hashes for EIP-4844 + MissingBlobHashesForEip4844, + /// Missing authorization list for EIP-7702 + MissingAuthorizationListForEip7702, + /// Missing target for EIP-4844 + MissingTargetForEip4844, +} + +impl From for TxEnvBuildError { + fn from(error: DeriveTxTypeError) -> Self { + TxEnvBuildError::DeriveErr(error) + } +} + +impl TxEnv { + /// Create a new builder for constructing a [`TxEnv`] + pub fn builder() -> TxEnvBuilder { + TxEnvBuilder::new() + } + + /// Create a new builder for constructing a [`TxEnv`] with benchmark-specific values. + pub fn builder_for_bench() -> TxEnvBuilder { + TxEnv::new_bench().modify() + } + + /// Modify the [`TxEnv`] by using builder pattern. + pub fn modify(self) -> TxEnvBuilder { + let TxEnv { + tx_type, + caller, + gas_limit, + gas_price, + kind, + value, + data, + nonce, + chain_id, + access_list, + gas_priority_fee, + blob_hashes, + max_fee_per_blob_gas, + authorization_list, + } = self; + + TxEnvBuilder::new() + .tx_type(Some(tx_type)) + .caller(caller) + .gas_limit(gas_limit) + .gas_price(gas_price) + .kind(kind) + .value(value) + .data(data) + .nonce(nonce) + .chain_id(chain_id) + .access_list(access_list) + .gas_priority_fee(gas_priority_fee) + .blob_hashes(blob_hashes) + .max_fee_per_blob_gas(max_fee_per_blob_gas) + .authorization_list(authorization_list) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + fn effective_gas_setup( + tx_type: TransactionType, + gas_price: u128, + gas_priority_fee: Option, + ) -> u128 { + let tx = TxEnv { + tx_type: tx_type as u8, + gas_price, + gas_priority_fee, + ..Default::default() + }; + let base_fee = 100; + tx.effective_gas_price(base_fee) + } + + #[test] + fn test_tx_env_builder_build_valid_legacy() { + // Legacy transaction + let tx = TxEnvBuilder::new() + .tx_type(Some(0)) + .caller(Address::from([1u8; 20])) + .gas_limit(21000) + .gas_price(20) + .kind(TxKind::Call(Address::from([2u8; 20]))) + .value(U256::from(100)) + .data(Bytes::from(vec![0x01, 0x02])) + .nonce(5) + .chain_id(Some(1)) + .build() + .unwrap(); + + assert_eq!(tx.kind, TxKind::Call(Address::from([2u8; 20]))); + assert_eq!(tx.caller, Address::from([1u8; 20])); + assert_eq!(tx.gas_limit, 21000); + assert_eq!(tx.gas_price, 20); + assert_eq!(tx.value, U256::from(100)); + assert_eq!(tx.data, Bytes::from(vec![0x01, 0x02])); + assert_eq!(tx.nonce, 5); + assert_eq!(tx.chain_id, Some(1)); + assert_eq!(tx.tx_type, TransactionType::Legacy); + } + + #[test] + fn test_tx_env_builder_build_valid_eip2930() { + // EIP-2930 transaction with access list + let access_list = AccessList(vec![AccessListItem { + address: Address::from([3u8; 20]), + storage_keys: vec![B256::from([4u8; 32])], + }]); + let tx = TxEnvBuilder::new() + .tx_type(Some(1)) + .caller(Address::from([1u8; 20])) + .gas_limit(50000) + .gas_price(25) + .kind(TxKind::Call(Address::from([2u8; 20]))) + .access_list(access_list.clone()) + .build() + .unwrap(); + + assert_eq!(tx.tx_type, TransactionType::Eip2930); + assert_eq!(tx.access_list, access_list); + } + + #[test] + fn test_tx_env_builder_build_valid_eip1559() { + // EIP-1559 transaction + let tx = TxEnvBuilder::new() + .tx_type(Some(2)) + .caller(Address::from([1u8; 20])) + .gas_limit(50000) + .gas_price(30) + .gas_priority_fee(Some(10)) + .kind(TxKind::Call(Address::from([2u8; 20]))) + .build() + .unwrap(); + + assert_eq!(tx.tx_type, TransactionType::Eip1559); + assert_eq!(tx.gas_priority_fee, Some(10)); + } + + #[test] + fn test_tx_env_builder_build_valid_eip4844() { + // EIP-4844 blob transaction + let blob_hashes = vec![B256::from([5u8; 32]), B256::from([6u8; 32])]; + let tx = TxEnvBuilder::new() + .tx_type(Some(3)) + .caller(Address::from([1u8; 20])) + .gas_limit(50000) + .gas_price(30) + .gas_priority_fee(Some(10)) + .kind(TxKind::Call(Address::from([2u8; 20]))) + .blob_hashes(blob_hashes.clone()) + .max_fee_per_blob_gas(100) + .build() + .unwrap(); + + assert_eq!(tx.tx_type, TransactionType::Eip4844); + assert_eq!(tx.blob_hashes, blob_hashes); + assert_eq!(tx.max_fee_per_blob_gas, 100); + } + + #[test] + fn test_tx_env_builder_build_valid_eip7702() { + // EIP-7702 EOA code transaction + let auth = RecoveredAuthorization::new_unchecked( + Authorization { + chain_id: U256::from(1), + nonce: 0, + address: Address::default(), + }, + RecoveredAuthority::Valid(Address::default()), + ); + let auth_list = vec![Either::Right(auth)]; + + let tx = TxEnvBuilder::new() + .tx_type(Some(4)) + .caller(Address::from([1u8; 20])) + .gas_limit(50000) + .gas_price(30) + .gas_priority_fee(Some(10)) + .kind(TxKind::Call(Address::from([2u8; 20]))) + .authorization_list(auth_list.clone()) + .build() + .unwrap(); + + assert_eq!(tx.tx_type, TransactionType::Eip7702); + assert_eq!(tx.authorization_list.len(), 1); + } + + #[test] + fn test_tx_env_builder_build_create_transaction() { + // Contract creation transaction + let bytecode = Bytes::from(vec![0x60, 0x80, 0x60, 0x40]); + let tx = TxEnvBuilder::new() + .kind(TxKind::Create) + .data(bytecode.clone()) + .gas_limit(100000) + .gas_price(20) + .build() + .unwrap(); + + assert_eq!(tx.kind, TxKind::Create); + assert_eq!(tx.data, bytecode); + } + + #[test] + fn test_tx_env_builder_build_errors_eip1559_missing_priority_fee() { + // EIP-1559 without gas_priority_fee should fail + let result = TxEnvBuilder::new() + .tx_type(Some(2)) + .caller(Address::from([1u8; 20])) + .gas_limit(50000) + .gas_price(30) + .kind(TxKind::Call(Address::from([2u8; 20]))) + .build(); + + assert!(matches!( + result, + Err(TxEnvBuildError::MissingGasPriorityFeeForEip1559) + )); + } + + #[test] + fn test_tx_env_builder_build_errors_eip4844_missing_blob_hashes() { + // EIP-4844 without blob hashes should fail + let result = TxEnvBuilder::new() + .tx_type(Some(3)) + .gas_priority_fee(Some(10)) + .kind(TxKind::Call(Address::from([2u8; 20]))) + .build(); + + assert!(matches!( + result, + Err(TxEnvBuildError::MissingBlobHashesForEip4844) + )); + } + + #[test] + fn test_tx_env_builder_build_errors_eip4844_not_call() { + // EIP-4844 with Create should fail + let result = TxEnvBuilder::new() + .tx_type(Some(3)) + .gas_priority_fee(Some(10)) + .blob_hashes(vec![B256::from([5u8; 32])]) + .kind(TxKind::Create) + .build(); + + assert!(matches!( + result, + Err(TxEnvBuildError::MissingTargetForEip4844) + )); + } + + #[test] + fn test_tx_env_builder_build_errors_eip7702_missing_auth_list() { + // EIP-7702 without authorization list should fail + let result = TxEnvBuilder::new() + .tx_type(Some(4)) + .gas_priority_fee(Some(10)) + .kind(TxKind::Call(Address::from([2u8; 20]))) + .build(); + + assert!(matches!( + result, + Err(TxEnvBuildError::MissingAuthorizationListForEip7702) + )); + } + + #[test] + fn test_tx_env_builder_build_errors_eip7702_not_call() { + // EIP-7702 with Create should fail + let auth = RecoveredAuthorization::new_unchecked( + Authorization { + chain_id: U256::from(1), + nonce: 0, + address: Address::default(), + }, + RecoveredAuthority::Valid(Address::default()), + ); + let result = TxEnvBuilder::new() + .tx_type(Some(4)) + .gas_priority_fee(Some(10)) + .authorization_list(vec![Either::Right(auth)]) + .kind(TxKind::Create) + .build(); + + assert!(matches!(result, Err(TxEnvBuildError::DeriveErr(_)))); + } + + #[test] + fn test_tx_env_builder_build_fill_legacy() { + // Legacy transaction with build_fill + let tx = TxEnvBuilder::new() + .caller(Address::from([1u8; 20])) + .gas_limit(21000) + .gas_price(20) + .kind(TxKind::Call(Address::from([2u8; 20]))) + .build_fill(); + + assert_eq!(tx.tx_type, TransactionType::Legacy); + assert_eq!(tx.gas_priority_fee, None); + } + + #[test] + fn test_tx_env_builder_build_fill_eip1559_missing_priority_fee() { + // EIP-1559 without gas_priority_fee should be filled with 0 + let tx = TxEnvBuilder::new() + .tx_type(Some(2)) + .caller(Address::from([1u8; 20])) + .gas_limit(50000) + .gas_price(30) + .kind(TxKind::Call(Address::from([2u8; 20]))) + .build_fill(); + + assert_eq!(tx.tx_type, TransactionType::Eip1559); + assert_eq!(tx.gas_priority_fee, Some(0)); + } + + #[test] + fn test_tx_env_builder_build_fill_eip4844_missing_blob_hashes() { + // EIP-4844 without blob hashes should add default blob hash + let tx = TxEnvBuilder::new() + .tx_type(Some(3)) + .gas_priority_fee(Some(10)) + .kind(TxKind::Call(Address::from([2u8; 20]))) + .build_fill(); + + assert_eq!(tx.tx_type, TransactionType::Eip4844); + assert_eq!(tx.blob_hashes.len(), 1); + assert_eq!(tx.blob_hashes[0], B256::default()); + } + + #[test] + fn test_tx_env_builder_build_fill_eip4844_create_to_call() { + // EIP-4844 with Create should be converted to Call + let tx = TxEnvBuilder::new() + .tx_type(Some(3)) + .gas_priority_fee(Some(10)) + .blob_hashes(vec![B256::from([5u8; 32])]) + .kind(TxKind::Create) + .build_fill(); + + assert_eq!(tx.tx_type, TransactionType::Eip4844); + assert_eq!(tx.kind, TxKind::Call(Address::default())); + } + + #[test] + fn test_tx_env_builder_build_fill_eip7702_missing_auth_list() { + // EIP-7702 without authorization list should add dummy auth + let tx = TxEnvBuilder::new() + .tx_type(Some(4)) + .gas_priority_fee(Some(10)) + .kind(TxKind::Call(Address::from([2u8; 20]))) + .build_fill(); + + assert_eq!(tx.tx_type, TransactionType::Eip7702); + assert_eq!(tx.authorization_list.len(), 1); + } + + #[test] + fn test_tx_env_builder_build_fill_eip7702_create_to_call() { + // EIP-7702 with Create should be converted to Call + let auth = RecoveredAuthorization::new_unchecked( + Authorization { + chain_id: U256::from(1), + nonce: 0, + address: Address::default(), + }, + RecoveredAuthority::Valid(Address::default()), + ); + let tx = TxEnvBuilder::new() + .tx_type(Some(4)) + .gas_priority_fee(Some(10)) + .authorization_list(vec![Either::Right(auth)]) + .kind(TxKind::Create) + .build_fill(); + + assert_eq!(tx.tx_type, TransactionType::Eip7702); + assert_eq!(tx.kind, TxKind::Call(Address::default())); + } + + #[test] + fn test_tx_env_builder_derive_tx_type_legacy() { + // No special fields, should derive Legacy + let tx = TxEnvBuilder::new() + .caller(Address::from([1u8; 20])) + .gas_limit(21000) + .gas_price(20) + .build() + .unwrap(); + + assert_eq!(tx.tx_type, TransactionType::Legacy); + } + + #[test] + fn test_tx_env_builder_derive_tx_type_eip2930() { + // Access list present, should derive EIP-2930 + let access_list = AccessList(vec![AccessListItem { + address: Address::from([3u8; 20]), + storage_keys: vec![B256::from([4u8; 32])], + }]); + let tx = TxEnvBuilder::new() + .caller(Address::from([1u8; 20])) + .access_list(access_list) + .build() + .unwrap(); + + assert_eq!(tx.tx_type, TransactionType::Eip2930); + } + + #[test] + fn test_tx_env_builder_derive_tx_type_eip1559() { + // Gas priority fee present, should derive EIP-1559 + let tx = TxEnvBuilder::new() + .caller(Address::from([1u8; 20])) + .gas_priority_fee(Some(10)) + .build() + .unwrap(); + + assert_eq!(tx.tx_type, TransactionType::Eip1559); + } + + #[test] + fn test_tx_env_builder_derive_tx_type_eip4844() { + // Blob hashes present, should derive EIP-4844 + let tx = TxEnvBuilder::new() + .caller(Address::from([1u8; 20])) + .gas_priority_fee(Some(10)) + .blob_hashes(vec![B256::from([5u8; 32])]) + .kind(TxKind::Call(Address::from([2u8; 20]))) + .build() + .unwrap(); + + assert_eq!(tx.tx_type, TransactionType::Eip4844); + } + + #[test] + fn test_tx_env_builder_derive_tx_type_eip7702() { + // Authorization list present, should derive EIP-7702 + let auth = RecoveredAuthorization::new_unchecked( + Authorization { + chain_id: U256::from(1), + nonce: 0, + address: Address::default(), + }, + RecoveredAuthority::Valid(Address::default()), + ); + let tx = TxEnvBuilder::new() + .caller(Address::from([1u8; 20])) + .gas_priority_fee(Some(10)) + .authorization_list(vec![Either::Right(auth)]) + .kind(TxKind::Call(Address::from([2u8; 20]))) + .build() + .unwrap(); + + assert_eq!(tx.tx_type, TransactionType::Eip7702); + } + + #[test] + fn test_tx_env_builder_custom_tx_type() { + // Custom transaction type (0xFF) + let tx = TxEnvBuilder::new() + .tx_type(Some(0xFF)) + .caller(Address::from([1u8; 20])) + .build() + .unwrap(); + + assert_eq!(tx.tx_type, TransactionType::Custom); + } + + #[test] + fn test_tx_env_builder_chain_methods() { + // Test method chaining + let tx = TxEnvBuilder::new() + .caller(Address::from([1u8; 20])) + .gas_limit(50000) + .gas_price(25) + .kind(TxKind::Call(Address::from([2u8; 20]))) + .value(U256::from(1000)) + .data(Bytes::from(vec![0x12, 0x34])) + .nonce(10) + .chain_id(Some(5)) + .access_list(AccessList(vec![AccessListItem { + address: Address::from([3u8; 20]), + storage_keys: vec![], + }])) + .gas_priority_fee(Some(5)) + .blob_hashes(vec![B256::from([7u8; 32])]) + .max_fee_per_blob_gas(200) + .build_fill(); + + assert_eq!(tx.caller, Address::from([1u8; 20])); + assert_eq!(tx.gas_limit, 50000); + assert_eq!(tx.gas_price, 25); + assert_eq!(tx.kind, TxKind::Call(Address::from([2u8; 20]))); + assert_eq!(tx.value, U256::from(1000)); + assert_eq!(tx.data, Bytes::from(vec![0x12, 0x34])); + assert_eq!(tx.nonce, 10); + assert_eq!(tx.chain_id, Some(5)); + assert_eq!(tx.access_list.len(), 1); + assert_eq!(tx.gas_priority_fee, Some(5)); + assert_eq!(tx.blob_hashes.len(), 1); + assert_eq!(tx.max_fee_per_blob_gas, 200); + } + + #[test] + fn test_effective_gas_price() { + assert_eq!(90, effective_gas_setup(TransactionType::Legacy, 90, None)); + assert_eq!( + 90, + effective_gas_setup(TransactionType::Legacy, 90, Some(0)) + ); + assert_eq!( + 90, + effective_gas_setup(TransactionType::Legacy, 90, Some(10)) + ); + assert_eq!( + 120, + effective_gas_setup(TransactionType::Legacy, 120, Some(10)) + ); + assert_eq!(90, effective_gas_setup(TransactionType::Eip2930, 90, None)); + assert_eq!( + 90, + effective_gas_setup(TransactionType::Eip2930, 90, Some(0)) + ); + assert_eq!( + 90, + effective_gas_setup(TransactionType::Eip2930, 90, Some(10)) + ); + assert_eq!( + 120, + effective_gas_setup(TransactionType::Eip2930, 120, Some(10)) + ); + assert_eq!(90, effective_gas_setup(TransactionType::Eip1559, 90, None)); + assert_eq!( + 90, + effective_gas_setup(TransactionType::Eip1559, 90, Some(0)) + ); + assert_eq!( + 90, + effective_gas_setup(TransactionType::Eip1559, 90, Some(10)) + ); + assert_eq!( + 110, + effective_gas_setup(TransactionType::Eip1559, 120, Some(10)) + ); + assert_eq!(90, effective_gas_setup(TransactionType::Eip4844, 90, None)); + assert_eq!( + 90, + effective_gas_setup(TransactionType::Eip4844, 90, Some(0)) + ); + assert_eq!( + 90, + effective_gas_setup(TransactionType::Eip4844, 90, Some(10)) + ); + assert_eq!( + 110, + effective_gas_setup(TransactionType::Eip4844, 120, Some(10)) + ); + assert_eq!(90, effective_gas_setup(TransactionType::Eip7702, 90, None)); + assert_eq!( + 90, + effective_gas_setup(TransactionType::Eip7702, 90, Some(0)) + ); + assert_eq!( + 90, + effective_gas_setup(TransactionType::Eip7702, 90, Some(10)) + ); + assert_eq!( + 110, + effective_gas_setup(TransactionType::Eip7702, 120, Some(10)) + ); + } +} diff --git a/crates/database/CHANGELOG.md b/crates/database/CHANGELOG.md new file mode 100644 index 0000000000..1cfa90d7b8 --- /dev/null +++ b/crates/database/CHANGELOG.md @@ -0,0 +1,223 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [7.0.2](https://github.com/bluealloy/revm/compare/revm-database-v7.0.1...revm-database-v7.0.2) - 2025-07-23 + +### Other + +- updated the following local packages: revm-primitives, revm-bytecode, revm-database-interface, revm-state + +## [7.0.1](https://github.com/bluealloy/revm/compare/revm-database-v7.0.0...revm-database-v7.0.1) - 2025-07-03 + +### Other + +- updated the following local packages: revm-bytecode, revm-state, revm-database-interface + +## [7.0.0](https://github.com/bluealloy/revm/compare/revm-database-v6.0.0...revm-database-v7.0.0) - 2025-06-30 + +### Other + +- updated the following local packages: revm-bytecode, revm-state, revm-database-interface + +## [6.0.0](https://github.com/bluealloy/revm/compare/revm-database-v5.0.0...revm-database-v6.0.0) - 2025-06-19 + +### Added + +- *(precompile)* rug/gmp-based modexp ([#2596](https://github.com/bluealloy/revm/pull/2596)) + +### Fixed + +- change account state to None if NotExisting on insert_account_info ([#2630](https://github.com/bluealloy/revm/pull/2630)) + +### Other + +- lints for revm-database ([#2639](https://github.com/bluealloy/revm/pull/2639)) +- bump alloydb test ([#2640](https://github.com/bluealloy/revm/pull/2640)) + +## [5.0.0](https://github.com/bluealloy/revm/compare/revm-database-v4.0.1...revm-database-v5.0.0) - 2025-06-06 + +### Added + +- *(database)* Implement DatabaseRef for State ([#2570](https://github.com/bluealloy/revm/pull/2570)) +- added TxEnv::new_bench() add util function ([#2556](https://github.com/bluealloy/revm/pull/2556)) +- transact multi tx ([#2517](https://github.com/bluealloy/revm/pull/2517)) + +### Other + +- Avoid clone before converting ref BundleAccount to CacheAccount ([#2574](https://github.com/bluealloy/revm/pull/2574)) +- *(docs)* add lints to database-interface and op-revm crates ([#2568](https://github.com/bluealloy/revm/pull/2568)) + +## [4.0.1](https://github.com/bluealloy/revm/compare/revm-database-v4.0.0...revm-database-v4.0.1) - 2025-05-22 + +### Other + +- bump alloy libs ([#2533](https://github.com/bluealloy/revm/pull/2533)) +- make crates.io version badge clickable ([#2526](https://github.com/bluealloy/revm/pull/2526)) +- Storage Types Alias ([#2461](https://github.com/bluealloy/revm/pull/2461)) + + +## [4.0.0](https://github.com/bluealloy/revm/compare/revm-database-v3.1.0...revm-database-v4.0.0) - 2025-05-07 + +Dependency bump + +## [3.1.0](https://github.com/bluealloy/revm/compare/revm-database-v3.0.0...revm-database-v3.1.0) - 2025-05-07 + +### Added + +- *(database)* re-export all public items from alloydb when feature … ([#2443](https://github.com/bluealloy/revm/pull/2443)) + +### Other + +- copy edit The Book ([#2463](https://github.com/bluealloy/revm/pull/2463)) +- bump dependency version ([#2431](https://github.com/bluealloy/revm/pull/2431)) +- fixed broken link ([#2421](https://github.com/bluealloy/revm/pull/2421)) +- remove alloy-sol-types deps ([#2411](https://github.com/bluealloy/revm/pull/2411)) + +## [3.0.0](https://github.com/bluealloy/revm/compare/revm-database-v2.0.0...revm-database-v3.0.0) - 2025-04-09 + +### Other + +- clean unsed indicatif ([#2379](https://github.com/bluealloy/revm/pull/2379)) +- add 0x prefix to b256! and address! calls ([#2345](https://github.com/bluealloy/revm/pull/2345)) +- *(database)* remove auto_impl dependency ([#2344](https://github.com/bluealloy/revm/pull/2344)) + +## [2.0.0](https://github.com/bluealloy/revm/compare/revm-database-v1.0.0...revm-database-v2.0.0) - 2025-03-28 + +### Other + +- make number more readable ([#2300](https://github.com/bluealloy/revm/pull/2300)) + +## [1.0.0](https://github.com/bluealloy/revm/compare/revm-database-v1.0.0-alpha.5...revm-database-v1.0.0) - 2025-03-24 + +### Other + +- docs nits ([#2292](https://github.com/bluealloy/revm/pull/2292)) + +## [1.0.0-alpha.5](https://github.com/bluealloy/revm/compare/revm-database-v1.0.0-alpha.4...revm-database-v1.0.0-alpha.5) - 2025-03-21 + +### Other + +- make clippy happy ([#2274](https://github.com/bluealloy/revm/pull/2274)) +- simplify single UT for OpSpecId compatibility. ([#2216](https://github.com/bluealloy/revm/pull/2216)) + +## [1.0.0-alpha.4](https://github.com/bluealloy/revm/compare/revm-database-v1.0.0-alpha.3...revm-database-v1.0.0-alpha.4) - 2025-03-16 + +### Other + +- updated the following local packages: revm-primitives, revm-bytecode + +## [1.0.0-alpha.3](https://github.com/bluealloy/revm/compare/revm-database-v1.0.0-alpha.2...revm-database-v1.0.0-alpha.3) - 2025-03-11 + +### Fixed + +- correct propagate features ([#2177](https://github.com/bluealloy/revm/pull/2177)) + +### Other + +- bump alloy ([#2183](https://github.com/bluealloy/revm/pull/2183)) + +## [1.0.0-alpha.2](https://github.com/bluealloy/revm/compare/revm-database-v1.0.0-alpha.1...revm-database-v1.0.0-alpha.2) - 2025-03-10 + +### Fixed + +- use correct HashMap import ([#2148](https://github.com/bluealloy/revm/pull/2148)) +- *(op)* Handler deposit tx halt, catch_error handle ([#2144](https://github.com/bluealloy/revm/pull/2144)) + +### Other + +- *(db)* separate fields from `CacheDB` into `Cache` ([#2131](https://github.com/bluealloy/revm/pull/2131)) +- PrecompileErrors to PrecompileError ([#2103](https://github.com/bluealloy/revm/pull/2103)) +- *(deps)* bump breaking deps ([#2093](https://github.com/bluealloy/revm/pull/2093)) +- move all dependencies to workspace ([#2092](https://github.com/bluealloy/revm/pull/2092)) +- re-export all crates from `revm` ([#2088](https://github.com/bluealloy/revm/pull/2088)) + +## [1.0.0-alpha.1](https://github.com/bluealloy/revm/releases/tag/revm-database-v1.0.0-alpha.1) - 2025-02-16 + +### Added + +- Context execution (#2013) +- EthHandler trait (#2001) +- expose precompile address in Journal, DB::Error: StdError (#1956) +- integrate codspeed (#1935) +- *(database)* implement order-independent equality for Reverts (#1827) +- couple convenience functions for nested cache dbs (#1852) +- Restucturing Part7 Handler and Context rework (#1865) +- add support for async database (#1809) +- restructure Part2 database crate (#1784) +- *(examples)* generate block traces (#895) +- implement EIP-4844 (#668) +- *(Shanghai)* All EIPs: push0, warm coinbase, limit/measure initcode (#376) +- Migrate `primitive_types::U256` to `ruint::Uint<256, 4>` (#239) +- Introduce ByteCode format, Update Readme (#156) + +### Fixed + +- no_std for revm-database (#2077) +- fix typos ([#620](https://github.com/bluealloy/revm/pull/620)) + +### Other + +- set alpha.1 version +- Bump licence year to 2025 (#2058) +- add comment for pub function and fix typo (#2015) +- bump alloy versions to match latest (#2007) +- fix comments and docs into more sensible (#1920) +- bumps select alloy crates to 0.6 (#1854) +- *(TransitionAccount)* remove unneeded clone (#1860) +- *(CacheAccount)* remove unneeded clone (#1859) +- bump alloy to 0.4.2 (#1817) +- *(primitives)* replace HashMap re-exports with alloy_primitives::map (#1805) +- Bump new logo (#1735) +- *(README)* add rbuilder to used-by (#1585) +- added simular to used-by (#1521) +- add Trin to used by list (#1393) +- Fix typo in readme ([#1185](https://github.com/bluealloy/revm/pull/1185)) +- Add Hardhat to the "Used by" list ([#1164](https://github.com/bluealloy/revm/pull/1164)) +- Add VERBS to used by list ([#1141](https://github.com/bluealloy/revm/pull/1141)) +- license date and revm docs (#1080) +- *(docs)* Update the benchmark docs to point to revm package (#906) +- *(docs)* Update top-level benchmark docs (#894) +- clang requirement (#784) +- Readme Updates (#756) +- Logo (#743) +- book workflow ([#537](https://github.com/bluealloy/revm/pull/537)) +- add example to revm crate ([#468](https://github.com/bluealloy/revm/pull/468)) +- Update README.md ([#424](https://github.com/bluealloy/revm/pull/424)) +- add no_std to primitives ([#366](https://github.com/bluealloy/revm/pull/366)) +- revm-precompiles to revm-precompile +- Bump v20, changelog ([#350](https://github.com/bluealloy/revm/pull/350)) +- typos (#232) +- Add support for old forks. ([#191](https://github.com/bluealloy/revm/pull/191)) +- revm bump 1.8. update libs. snailtracer rename ([#159](https://github.com/bluealloy/revm/pull/159)) +- typo fixes +- fix readme typo +- Big Refactor. Machine to Interpreter. refactor instructions. call/create struct ([#52](https://github.com/bluealloy/revm/pull/52)) +- readme. debuger update +- Bump revm v0.3.0. README updated +- readme +- Add time elapsed for tests +- readme updated +- Include Basefee into cost calc. readme change +- Initialize precompile accounts +- Status update. Taking a break +- Merkle calc. Tweaks and debugging for eip158 +- Replace aurora bn lib with parity's. All Bn128Add/Mul/Pair tests passes +- TEMP +- one tab removed +- readme +- README Example simplified +- Gas calculation for Call/Create. Example Added +- readme usage +- README changes +- Static gas cost added +- Subroutine changelogs and reverts +- Readme postulates +- Spelling +- Restructure project +- First iteration. Machine is looking okay diff --git a/crates/database/Cargo.toml b/crates/database/Cargo.toml new file mode 100644 index 0000000000..071a38a396 --- /dev/null +++ b/crates/database/Cargo.toml @@ -0,0 +1,68 @@ +[package] +name = "revm-database" +description = "Revm Database implementations" +version = "7.1.0" +authors.workspace = true +edition.workspace = true +keywords.workspace = true +license.workspace = true +repository.workspace = true +readme.workspace = true + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] + +[lints] +workspace = true + +[dependencies] +state.workspace = true +primitives.workspace = true +database-interface.workspace = true +bytecode.workspace = true + +# Optional +serde = { workspace = true, features = ["derive", "rc"], optional = true } + +# alloydb +tokio = { workspace = true, features = [ + "rt-multi-thread", + "macros", +], optional = true } +alloy-provider = { workspace = true, optional = true } +alloy-eips = { workspace = true, optional = true } +alloy-transport = { workspace = true, optional = true } + +[dev-dependencies] +serde_json = { workspace = true, features = ["alloc"] } +anyhow.workspace = true +rstest.workspace = true + +[features] +default = ["std"] +std = [ + "serde?/std", + "alloy-eips?/std", + "bytecode/std", + "database-interface/std", + "primitives/std", + "state/std", + "serde_json/std" +] +serde = [ + "dep:serde", + "alloy-eips?/serde", + "bytecode/serde", + "database-interface/serde", + "primitives/serde", + "state/serde" +] +alloydb = [ + "std", + "database-interface/asyncdb", + "dep:tokio", + "dep:alloy-provider", + "dep:alloy-eips", + "dep:alloy-transport", +] diff --git a/crates/database/LICENSE b/crates/database/LICENSE new file mode 100644 index 0000000000..be6d350ebe --- /dev/null +++ b/crates/database/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021-2025 draganrakita + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/crates/database/interface/CHANGELOG.md b/crates/database/interface/CHANGELOG.md new file mode 100644 index 0000000000..1e2d3eb839 --- /dev/null +++ b/crates/database/interface/CHANGELOG.md @@ -0,0 +1,189 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [7.0.2](https://github.com/bluealloy/revm/compare/revm-database-interface-v7.0.1...revm-database-interface-v7.0.2) - 2025-07-23 + +### Other + +- impl DatabaseRef for WrapDatabaseRef ([#2726](https://github.com/bluealloy/revm/pull/2726)) + +## [7.0.1](https://github.com/bluealloy/revm/compare/revm-database-interface-v7.0.0...revm-database-interface-v7.0.1) - 2025-07-03 + +### Other + +- updated the following local packages: revm-state + +## [7.0.0](https://github.com/bluealloy/revm/compare/revm-database-interface-v6.0.0...revm-database-interface-v7.0.0) - 2025-06-30 + +### Added + +- implement Database traits for either::Either ([#2673](https://github.com/bluealloy/revm/pull/2673)) + +### Other + +- fix copy-pasted inner doc comments ([#2663](https://github.com/bluealloy/revm/pull/2663)) + +## [6.0.0](https://github.com/bluealloy/revm/compare/revm-database-interface-v5.0.0...revm-database-interface-v6.0.0) - 2025-06-19 + +### Added + +- *(precompile)* rug/gmp-based modexp ([#2596](https://github.com/bluealloy/revm/pull/2596)) + +## [5.0.0](https://github.com/bluealloy/revm/compare/revm-database-interface-v4.0.1...revm-database-interface-v5.0.0) - 2025-06-06 + +### Added + +- added TxEnv::new_bench() add util function ([#2556](https://github.com/bluealloy/revm/pull/2556)) +- transact multi tx ([#2517](https://github.com/bluealloy/revm/pull/2517)) + +### Other + +- *(docs)* add lints to database-interface and op-revm crates ([#2568](https://github.com/bluealloy/revm/pull/2568)) + +## [4.0.1](https://github.com/bluealloy/revm/compare/revm-database-interface-v4.0.0...revm-database-interface-v4.0.1) - 2025-05-22 + +### Other + +- make crates.io version badge clickable ([#2526](https://github.com/bluealloy/revm/pull/2526)) +- Storage Types Alias ([#2461](https://github.com/bluealloy/revm/pull/2461)) + +## [4.0.0](https://github.com/bluealloy/revm/compare/revm-database-interface-v3.0.1...revm-database-interface-v4.0.0) - 2025-05-07 + +Dependency bump + +## [3.0.1](https://github.com/bluealloy/revm/compare/revm-database-interface-v3.0.0...revm-database-interface-v3.0.1) - 2025-05-07 + +### Other + +- copy edit The Book ([#2463](https://github.com/bluealloy/revm/pull/2463)) +- bump dependency version ([#2431](https://github.com/bluealloy/revm/pull/2431)) +- fixed broken link ([#2421](https://github.com/bluealloy/revm/pull/2421)) +- remove alloy-sol-types deps ([#2411](https://github.com/bluealloy/revm/pull/2411)) + +## [3.0.0](https://github.com/bluealloy/revm/compare/revm-database-interface-v2.0.0...revm-database-interface-v3.0.0) - 2025-04-09 + +### Other + +- clean unsed indicatif ([#2379](https://github.com/bluealloy/revm/pull/2379)) +- add 0x prefix to b256! and address! calls ([#2345](https://github.com/bluealloy/revm/pull/2345)) + +## [2.0.0](https://github.com/bluealloy/revm/compare/revm-database-interface-v1.0.0...revm-database-interface-v2.0.0) - 2025-03-28 + +### Other + +- Propagate asyncdb feature flag from database-interface to revm ([#2310](https://github.com/bluealloy/revm/pull/2310)) + +## [1.0.0](https://github.com/bluealloy/revm/compare/revm-database-interface-v1.0.0-alpha.54...revm-database-interface-v1.0.0) - 2025-03-24 + +Stable version + +## [1.0.0-alpha.5](https://github.com/bluealloy/revm/compare/revm-database-interface-v1.0.0-alpha.4...revm-database-interface-v1.0.0-alpha.5) - 2025-03-21 + +### Other + +- updated the following local packages: revm-primitives + +## [1.0.0-alpha.4](https://github.com/bluealloy/revm/compare/revm-database-interface-v1.0.0-alpha.3...revm-database-interface-v1.0.0-alpha.4) - 2025-03-16 + +### Other + +- updated the following local packages: revm-primitives + +## [1.0.0-alpha.3](https://github.com/bluealloy/revm/compare/revm-database-interface-v1.0.0-alpha.2...revm-database-interface-v1.0.0-alpha.3) - 2025-03-11 + +### Fixed + +- remove wrong Clone Macro in WrapDatabaseRef ([#2181](https://github.com/bluealloy/revm/pull/2181)) +- correct propagate features ([#2177](https://github.com/bluealloy/revm/pull/2177)) + +## [1.0.0-alpha.2](https://github.com/bluealloy/revm/compare/revm-database-interface-v1.0.0-alpha.1...revm-database-interface-v1.0.0-alpha.2) - 2025-03-10 + +### Added + +- TryDatabaseCommit ([#2121](https://github.com/bluealloy/revm/pull/2121)) + +### Other + +- move all dependencies to workspace ([#2092](https://github.com/bluealloy/revm/pull/2092)) + +## [1.0.0-alpha.1](https://github.com/bluealloy/revm/releases/tag/revm-database-interface-v1.0.0-alpha.1) - 2025-02-16 + +### Added + +- Evm structure (Cached Instructions and Precompiles) (#2049) +- expose precompile address in Journal, DB::Error: StdError (#1956) +- integrate codspeed (#1935) +- Restucturing Part7 Handler and Context rework (#1865) +- add support for async database (#1809) +- restructure Part2 database crate (#1784) +- project restructuring Part1 (#1776) +- *(examples)* generate block traces (#895) +- implement EIP-4844 (#668) +- *(Shanghai)* All EIPs: push0, warm coinbase, limit/measure initcode (#376) +- Migrate `primitive_types::U256` to `ruint::Uint<256, 4>` (#239) +- Introduce ByteCode format, Update Readme (#156) + +### Fixed + +- fix typos ([#620](https://github.com/bluealloy/revm/pull/620)) + +### Other + +- set alpha.1 version +- Bump licence year to 2025 (#2058) +- Make inspector use generics, rm associated types (#1934) +- fix comments and docs into more sensible (#1920) +- Bump new logo (#1735) +- *(README)* add rbuilder to used-by (#1585) +- added simular to used-by (#1521) +- add Trin to used by list (#1393) +- Fix typo in readme ([#1185](https://github.com/bluealloy/revm/pull/1185)) +- Add Hardhat to the "Used by" list ([#1164](https://github.com/bluealloy/revm/pull/1164)) +- Add VERBS to used by list ([#1141](https://github.com/bluealloy/revm/pull/1141)) +- license date and revm docs (#1080) +- *(docs)* Update the benchmark docs to point to revm package (#906) +- *(docs)* Update top-level benchmark docs (#894) +- clang requirement (#784) +- Readme Updates (#756) +- Logo (#743) +- book workflow ([#537](https://github.com/bluealloy/revm/pull/537)) +- add example to revm crate ([#468](https://github.com/bluealloy/revm/pull/468)) +- Update README.md ([#424](https://github.com/bluealloy/revm/pull/424)) +- add no_std to primitives ([#366](https://github.com/bluealloy/revm/pull/366)) +- revm-precompiles to revm-precompile +- Bump v20, changelog ([#350](https://github.com/bluealloy/revm/pull/350)) +- typos (#232) +- Add support for old forks. ([#191](https://github.com/bluealloy/revm/pull/191)) +- revm bump 1.8. update libs. snailtracer rename ([#159](https://github.com/bluealloy/revm/pull/159)) +- typo fixes +- fix readme typo +- Big Refactor. Machine to Interpreter. refactor instructions. call/create struct ([#52](https://github.com/bluealloy/revm/pull/52)) +- readme. debuger update +- Bump revm v0.3.0. README updated +- readme +- Add time elapsed for tests +- readme updated +- Include Basefee into cost calc. readme change +- Initialize precompile accounts +- Status update. Taking a break +- Merkle calc. Tweaks and debugging for eip158 +- Replace aurora bn lib with parity's. All Bn128Add/Mul/Pair tests passes +- TEMP +- one tab removed +- readme +- README Example simplified +- Gas calculation for Call/Create. Example Added +- readme usage +- README changes +- Static gas cost added +- Subroutine changelogs and reverts +- Readme postulates +- Spelling +- Restructure project +- First iteration. Machine is looking okay diff --git a/crates/database/interface/Cargo.toml b/crates/database/interface/Cargo.toml new file mode 100644 index 0000000000..66c147d5b4 --- /dev/null +++ b/crates/database/interface/Cargo.toml @@ -0,0 +1,52 @@ +[package] +name = "revm-database-interface" +description = "Revm Database interface" +version = "7.1.0" +authors.workspace = true +edition.workspace = true +keywords.workspace = true +license.workspace = true +repository.workspace = true +readme.workspace = true + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] + +[lints] +workspace = true + +[dependencies] +# revm +state.workspace = true +primitives.workspace = true + +# misc +auto_impl.workspace = true +either.workspace = true + +# Optional +serde = { workspace = true, features = ["derive", "rc"], optional = true } + +# asyncdb +tokio = { workspace = true, optional = true } + +[dev-dependencies] +anyhow.workspace = true +rstest.workspace = true + +[features] +default = ["std"] +std = [ + "serde?/std", + "primitives/std", + "state/std", + "either/std" +] +serde = [ + "dep:serde", + "primitives/serde", + "state/serde", + "either/serde" +] +asyncdb = ["dep:tokio", "tokio/rt-multi-thread"] diff --git a/crates/database/interface/LICENSE b/crates/database/interface/LICENSE new file mode 100644 index 0000000000..be6d350ebe --- /dev/null +++ b/crates/database/interface/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021-2025 draganrakita + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/crates/database/interface/src/async_db.rs b/crates/database/interface/src/async_db.rs new file mode 100644 index 0000000000..5966905214 --- /dev/null +++ b/crates/database/interface/src/async_db.rs @@ -0,0 +1,237 @@ +//! Async database interface. +use crate::{DBErrorMarker, Database, DatabaseRef}; +use core::{error::Error, future::Future}; +use primitives::{Address, StorageKey, StorageValue, B256}; +use state::{AccountInfo, Bytecode}; +use tokio::runtime::{Handle, Runtime}; + +/// The async EVM database interface +/// +/// Contains the same methods as [Database], but it returns [Future] type instead. +/// +/// Use [WrapDatabaseAsync] to provide [Database] implementation for a type that only implements this trait. +pub trait DatabaseAsync { + /// The database error type + type Error: Send + DBErrorMarker + Error; + + /// Gets basic account information. + fn basic_async( + &mut self, + address: Address, + ) -> impl Future, Self::Error>> + Send; + + /// Gets account code by its hash. + fn code_by_hash_async( + &mut self, + code_hash: B256, + ) -> impl Future> + Send; + + /// Gets storage value of address at index. + fn storage_async( + &mut self, + address: Address, + index: StorageKey, + ) -> impl Future> + Send; + + /// Gets block hash by block number. + fn block_hash_async( + &mut self, + number: u64, + ) -> impl Future> + Send; + + /// Returns the salt bucket capacity for the given address and optional storage key. + fn salt_bucket_capacity_async( + &self, + _address: Address, + _index: Option, + ) -> impl Future> + Send { + async { unimplemented!("salt bucket capacity is not implemented for this database") } + } +} + +/// The async EVM database interface +/// +/// Contains the same methods as [DatabaseRef], but it returns [Future] type instead. +/// +/// Use [WrapDatabaseAsync] to provide [DatabaseRef] implementation for a type that only implements this trait. +pub trait DatabaseAsyncRef { + /// The database error type + type Error: Send + DBErrorMarker + Error; + + /// Gets basic account information. + fn basic_async_ref( + &self, + address: Address, + ) -> impl Future, Self::Error>> + Send; + + /// Gets account code by its hash. + fn code_by_hash_async_ref( + &self, + code_hash: B256, + ) -> impl Future> + Send; + + /// Gets storage value of address at index. + fn storage_async_ref( + &self, + address: Address, + index: StorageKey, + ) -> impl Future> + Send; + + /// Gets block hash by block number. + fn block_hash_async_ref( + &self, + number: u64, + ) -> impl Future> + Send; + + /// Returns the salt bucket capacity for the given address and optional storage key. + fn salt_bucket_capacity_async_ref( + &self, + _address: Address, + _index: Option, + ) -> impl Future> + Send { + async { + unimplemented!("salt bucket capacity is not implemented for this database reference") + } + } +} + +/// Wraps a [DatabaseAsync] or [DatabaseAsyncRef] to provide a [`Database`] implementation. +#[derive(Debug)] +pub struct WrapDatabaseAsync { + db: T, + rt: HandleOrRuntime, +} + +impl WrapDatabaseAsync { + /// Wraps a [DatabaseAsync] or [DatabaseAsyncRef] instance. + /// + /// Returns `None` if no tokio runtime is available or if the current runtime is a current-thread runtime. + pub fn new(db: T) -> Option { + let rt = match Handle::try_current() { + Ok(handle) => match handle.runtime_flavor() { + tokio::runtime::RuntimeFlavor::CurrentThread => return None, + _ => HandleOrRuntime::Handle(handle), + }, + Err(_) => return None, + }; + Some(Self { db, rt }) + } + + /// Wraps a [DatabaseAsync] or [DatabaseAsyncRef] instance, with a runtime. + /// + /// Refer to [tokio::runtime::Builder] on how to create a runtime if you are in synchronous world. + /// + /// If you are already using something like [tokio::main], call [`WrapDatabaseAsync::new`] instead. + pub fn with_runtime(db: T, runtime: Runtime) -> Self { + let rt = HandleOrRuntime::Runtime(runtime); + Self { db, rt } + } + + /// Wraps a [DatabaseAsync] or [DatabaseAsyncRef] instance, with a runtime handle. + /// + /// This generally allows you to pass any valid runtime handle, refer to [tokio::runtime::Handle] on how + /// to obtain a handle. + /// + /// If you are already in asynchronous world, like [tokio::main], use [`WrapDatabaseAsync::new`] instead. + pub fn with_handle(db: T, handle: Handle) -> Self { + let rt = HandleOrRuntime::Handle(handle); + Self { db, rt } + } +} + +impl Database for WrapDatabaseAsync { + type Error = T::Error; + + #[inline] + fn basic(&mut self, address: Address) -> Result, Self::Error> { + self.rt.block_on(self.db.basic_async(address)) + } + + #[inline] + fn code_by_hash(&mut self, code_hash: B256) -> Result { + self.rt.block_on(self.db.code_by_hash_async(code_hash)) + } + + #[inline] + fn storage( + &mut self, + address: Address, + index: StorageKey, + ) -> Result { + self.rt.block_on(self.db.storage_async(address, index)) + } + + #[inline] + fn block_hash(&mut self, number: u64) -> Result { + self.rt.block_on(self.db.block_hash_async(number)) + } + + #[inline] + fn salt_bucket_capacity( + &self, + address: Address, + index: Option, + ) -> Result<(usize, u64), Self::Error> { + self.rt + .block_on(self.db.salt_bucket_capacity_async(address, index)) + } +} + +impl DatabaseRef for WrapDatabaseAsync { + type Error = T::Error; + + #[inline] + fn basic_ref(&self, address: Address) -> Result, Self::Error> { + self.rt.block_on(self.db.basic_async_ref(address)) + } + + #[inline] + fn code_by_hash_ref(&self, code_hash: B256) -> Result { + self.rt.block_on(self.db.code_by_hash_async_ref(code_hash)) + } + + #[inline] + fn storage_ref( + &self, + address: Address, + index: StorageKey, + ) -> Result { + self.rt.block_on(self.db.storage_async_ref(address, index)) + } + + #[inline] + fn block_hash_ref(&self, number: u64) -> Result { + self.rt.block_on(self.db.block_hash_async_ref(number)) + } + + #[inline] + fn salt_bucket_capacity_ref( + &self, + address: Address, + index: Option, + ) -> Result<(usize, u64), Self::Error> { + self.rt + .block_on(self.db.salt_bucket_capacity_async_ref(address, index)) + } +} + +// Hold a tokio runtime handle or full runtime +#[derive(Debug)] +enum HandleOrRuntime { + Handle(Handle), + Runtime(Runtime), +} + +impl HandleOrRuntime { + #[inline] + fn block_on(&self, f: F) -> F::Output + where + F: Future + Send, + F::Output: Send, + { + match self { + Self::Handle(handle) => tokio::task::block_in_place(move || handle.block_on(f)), + Self::Runtime(rt) => rt.block_on(f), + } + } +} diff --git a/crates/database/interface/src/either.rs b/crates/database/interface/src/either.rs new file mode 100644 index 0000000000..38499bbe93 --- /dev/null +++ b/crates/database/interface/src/either.rs @@ -0,0 +1,121 @@ +//! Database implementations for `either::Either` type. + +use crate::{Database, DatabaseCommit, DatabaseRef}; +use either::Either; +use primitives::{Address, HashMap, StorageKey, StorageValue, B256}; +use state::{Account, AccountInfo, Bytecode}; + +impl Database for Either +where + L: Database, + R: Database, +{ + type Error = L::Error; + + fn basic(&mut self, address: Address) -> Result, Self::Error> { + match self { + Self::Left(db) => db.basic(address), + Self::Right(db) => db.basic(address), + } + } + + fn code_by_hash(&mut self, code_hash: B256) -> Result { + match self { + Self::Left(db) => db.code_by_hash(code_hash), + Self::Right(db) => db.code_by_hash(code_hash), + } + } + + fn storage( + &mut self, + address: Address, + index: StorageKey, + ) -> Result { + match self { + Self::Left(db) => db.storage(address, index), + Self::Right(db) => db.storage(address, index), + } + } + + fn block_hash(&mut self, number: u64) -> Result { + match self { + Self::Left(db) => db.block_hash(number), + Self::Right(db) => db.block_hash(number), + } + } + + fn salt_bucket_capacity( + &self, + _address: Address, + _index: Option, + ) -> Result<(usize, u64), Self::Error> { + match self { + Self::Left(db) => db.salt_bucket_capacity(_address, _index), + Self::Right(db) => db.salt_bucket_capacity(_address, _index), + } + } +} + +impl DatabaseCommit for Either +where + L: DatabaseCommit, + R: DatabaseCommit, +{ + fn commit(&mut self, changes: HashMap) { + match self { + Self::Left(db) => db.commit(changes), + Self::Right(db) => db.commit(changes), + } + } +} + +impl DatabaseRef for Either +where + L: DatabaseRef, + R: DatabaseRef, +{ + type Error = L::Error; + + fn basic_ref(&self, address: Address) -> Result, Self::Error> { + match self { + Self::Left(db) => db.basic_ref(address), + Self::Right(db) => db.basic_ref(address), + } + } + + fn code_by_hash_ref(&self, code_hash: B256) -> Result { + match self { + Self::Left(db) => db.code_by_hash_ref(code_hash), + Self::Right(db) => db.code_by_hash_ref(code_hash), + } + } + + fn storage_ref( + &self, + address: Address, + index: StorageKey, + ) -> Result { + match self { + Self::Left(db) => db.storage_ref(address, index), + Self::Right(db) => db.storage_ref(address, index), + } + } + + fn block_hash_ref(&self, number: u64) -> Result { + match self { + Self::Left(db) => db.block_hash_ref(number), + Self::Right(db) => db.block_hash_ref(number), + } + } + + fn salt_bucket_capacity_ref( + &self, + address: Address, + index: Option, + ) -> Result<(usize, u64), Self::Error> { + match self { + Self::Left(db) => db.salt_bucket_capacity_ref(address, index), + Self::Right(db) => db.salt_bucket_capacity_ref(address, index), + } + } +} diff --git a/crates/revm/src/db/emptydb.rs b/crates/database/interface/src/empty_db.rs similarity index 59% rename from crates/revm/src/db/emptydb.rs rename to crates/database/interface/src/empty_db.rs index 9911612837..19a1393197 100644 --- a/crates/revm/src/db/emptydb.rs +++ b/crates/database/interface/src/empty_db.rs @@ -1,14 +1,15 @@ +//! Empty database implementation. +use crate::{DBErrorMarker, Database, DatabaseRef}; +use core::error::Error; use core::{convert::Infallible, fmt, marker::PhantomData}; -use revm_interpreter::primitives::{ - db::{Database, DatabaseRef}, - keccak256, AccountInfo, Address, Bytecode, B256, U256, -}; +use primitives::{keccak256, Address, StorageKey, StorageValue, B256}; +use state::{AccountInfo, Bytecode}; use std::string::ToString; -/// An empty database that always returns default values when queried. +/// An empty database that always returns default values when queried pub type EmptyDB = EmptyDBTyped; -/// An empty database that always returns default values when queried. +/// An empty database that always returns default values when queried /// /// This is generic over a type which is used as the database error type. #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] @@ -46,20 +47,15 @@ impl PartialEq for EmptyDBTyped { impl Eq for EmptyDBTyped {} impl EmptyDBTyped { + /// Create a new empty database. pub fn new() -> Self { Self { _phantom: PhantomData, } } - - #[doc(hidden)] - #[deprecated = "use `new` instead"] - pub fn new_keccak_block_hash() -> Self { - Self::new() - } } -impl Database for EmptyDBTyped { +impl Database for EmptyDBTyped { type Error = E; #[inline] @@ -73,17 +69,30 @@ impl Database for EmptyDBTyped { } #[inline] - fn storage(&mut self, address: Address, index: U256) -> Result { + fn storage( + &mut self, + address: Address, + index: StorageKey, + ) -> Result { ::storage_ref(self, address, index) } #[inline] - fn block_hash(&mut self, number: U256) -> Result { + fn block_hash(&mut self, number: u64) -> Result { ::block_hash_ref(self, number) } + + #[inline] + fn salt_bucket_capacity( + &self, + address: Address, + index: Option, + ) -> Result<(usize, u64), Self::Error> { + ::salt_bucket_capacity_ref(self, address, index) + } } -impl DatabaseRef for EmptyDBTyped { +impl DatabaseRef for EmptyDBTyped { type Error = E; #[inline] @@ -97,42 +106,55 @@ impl DatabaseRef for EmptyDBTyped { } #[inline] - fn storage_ref(&self, _address: Address, _index: U256) -> Result { - Ok(U256::default()) + fn storage_ref( + &self, + _address: Address, + _index: StorageKey, + ) -> Result { + Ok(StorageValue::default()) } #[inline] - fn block_hash_ref(&self, number: U256) -> Result { + fn block_hash_ref(&self, number: u64) -> Result { Ok(keccak256(number.to_string().as_bytes())) } + + #[inline] + fn salt_bucket_capacity_ref( + &self, + _address: Address, + _index: Option, + ) -> Result<(usize, u64), Self::Error> { + Ok((0, 0)) + } } #[cfg(test)] mod tests { use super::*; - use crate::primitives::b256; + use primitives::b256; #[test] fn conform_block_hash_calculation() { let db = EmptyDB::new(); assert_eq!( - db.block_hash_ref(U256::from(0)), + db.block_hash_ref(0u64), Ok(b256!( - "044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d" + "0x044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d" )) ); assert_eq!( - db.block_hash_ref(U256::from(1)), + db.block_hash_ref(1u64), Ok(b256!( - "c89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6" + "0xc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6" )) ); assert_eq!( - db.block_hash_ref(U256::from(100)), + db.block_hash_ref(100u64), Ok(b256!( - "8c18210df0d9514f2d2e5d8ca7c100978219ee80d3968ad850ab5ead208287b3" + "0x8c18210df0d9514f2d2e5d8ca7c100978219ee80d3968ad850ab5ead208287b3" )) ); } diff --git a/crates/database/interface/src/lib.rs b/crates/database/interface/src/lib.rs new file mode 100644 index 0000000000..806e3052c9 --- /dev/null +++ b/crates/database/interface/src/lib.rs @@ -0,0 +1,208 @@ +//! Database interface. +#![cfg_attr(not(test), warn(unused_crate_dependencies))] +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(not(feature = "std"))] +extern crate alloc as std; + +use core::convert::Infallible; + +use auto_impl::auto_impl; +use core::error::Error; +use primitives::{address, Address, HashMap, StorageKey, StorageValue, B256, U256}; +use state::{Account, AccountInfo, Bytecode}; +use std::string::String; + +/// Address with all `0xff..ff` in it. Used for testing. +pub const FFADDRESS: Address = address!("0xffffffffffffffffffffffffffffffffffffffff"); +/// BENCH_TARGET address +pub const BENCH_TARGET: Address = FFADDRESS; +/// BENCH_TARGET_BALANCE balance +pub const BENCH_TARGET_BALANCE: U256 = U256::from_limbs([10_000_000_000_000_000, 0, 0, 0]); +/// Address with all `0xee..ee` in it. Used for testing. +pub const EEADDRESS: Address = address!("0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"); +/// BENCH_CALLER address +pub const BENCH_CALLER: Address = EEADDRESS; +/// BENCH_CALLER_BALANCE balance +pub const BENCH_CALLER_BALANCE: U256 = U256::from_limbs([10_000_000_000_000_000, 0, 0, 0]); + +#[cfg(feature = "asyncdb")] +pub mod async_db; +pub mod either; +pub mod empty_db; +pub mod try_commit; + +#[cfg(feature = "asyncdb")] +pub use async_db::{DatabaseAsync, WrapDatabaseAsync}; +pub use empty_db::{EmptyDB, EmptyDBTyped}; +pub use try_commit::{ArcUpgradeError, TryDatabaseCommit}; + +/// Database error marker is needed to implement From conversion for Error type. +pub trait DBErrorMarker {} + +/// Implement marker for `()`. +impl DBErrorMarker for () {} +impl DBErrorMarker for Infallible {} +impl DBErrorMarker for String {} + +/// EVM database interface. +#[auto_impl(&mut, Box)] +pub trait Database { + /// The database error type. + type Error: DBErrorMarker + Error; + + /// Gets basic account information. + fn basic(&mut self, address: Address) -> Result, Self::Error>; + + /// Gets account code by its hash. + fn code_by_hash(&mut self, code_hash: B256) -> Result; + + /// Gets storage value of address at index. + fn storage(&mut self, address: Address, index: StorageKey) + -> Result; + + /// Gets block hash by block number. + fn block_hash(&mut self, number: u64) -> Result; + + /// Returns the salt bucket capacity for the given address and optional storage key. + fn salt_bucket_capacity( + &self, + _address: Address, + _index: Option, + ) -> Result<(usize, u64), Self::Error> { + unimplemented!("salt bucket capacity is not implemented for this database") + } +} + +/// EVM database commit interface. +#[auto_impl(&mut, Box)] +pub trait DatabaseCommit { + /// Commit changes to the database. + fn commit(&mut self, changes: HashMap); +} + +/// EVM database interface. +/// +/// Contains the same methods as [`Database`], but with `&self` receivers instead of `&mut self`. +/// +/// Use [`WrapDatabaseRef`] to provide [`Database`] implementation for a type +/// that only implements this trait. +#[auto_impl(&, &mut, Box, Rc, Arc)] +pub trait DatabaseRef { + /// The database error type. + type Error: DBErrorMarker + Error; + + /// Gets basic account information. + fn basic_ref(&self, address: Address) -> Result, Self::Error>; + + /// Gets account code by its hash. + fn code_by_hash_ref(&self, code_hash: B256) -> Result; + + /// Gets storage value of address at index. + fn storage_ref(&self, address: Address, index: StorageKey) + -> Result; + + /// Gets block hash by block number. + fn block_hash_ref(&self, number: u64) -> Result; + + /// Returns the salt bucket capacity for the given address and optional storage key. + fn salt_bucket_capacity_ref( + &self, + _address: Address, + _index: Option, + ) -> Result<(usize, u64), Self::Error> { + unimplemented!("salt bucket capacity is not implemented for this database reference") + } +} + +/// Wraps a [`DatabaseRef`] to provide a [`Database`] implementation. +#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct WrapDatabaseRef(pub T); + +impl From for WrapDatabaseRef { + #[inline] + fn from(f: F) -> Self { + WrapDatabaseRef(f) + } +} + +impl Database for WrapDatabaseRef { + type Error = T::Error; + + #[inline] + fn basic(&mut self, address: Address) -> Result, Self::Error> { + self.0.basic_ref(address) + } + + #[inline] + fn code_by_hash(&mut self, code_hash: B256) -> Result { + self.0.code_by_hash_ref(code_hash) + } + + #[inline] + fn storage( + &mut self, + address: Address, + index: StorageKey, + ) -> Result { + self.0.storage_ref(address, index) + } + + #[inline] + fn block_hash(&mut self, number: u64) -> Result { + self.0.block_hash_ref(number) + } + + #[inline] + fn salt_bucket_capacity( + &self, + address: Address, + index: Option, + ) -> Result<(usize, u64), Self::Error> { + self.0.salt_bucket_capacity_ref(address, index) + } +} + +impl DatabaseCommit for WrapDatabaseRef { + #[inline] + fn commit(&mut self, changes: HashMap) { + self.0.commit(changes) + } +} + +impl DatabaseRef for WrapDatabaseRef { + type Error = T::Error; + + #[inline] + fn basic_ref(&self, address: Address) -> Result, Self::Error> { + self.0.basic_ref(address) + } + + #[inline] + fn code_by_hash_ref(&self, code_hash: B256) -> Result { + self.0.code_by_hash_ref(code_hash) + } + + #[inline] + fn storage_ref( + &self, + address: Address, + index: StorageKey, + ) -> Result { + self.0.storage_ref(address, index) + } + + #[inline] + fn block_hash_ref(&self, number: u64) -> Result { + self.0.block_hash_ref(number) + } + + #[inline] + fn salt_bucket_capacity_ref( + &self, + address: Address, + index: Option, + ) -> Result<(usize, u64), Self::Error> { + self.0.salt_bucket_capacity_ref(address, index) + } +} diff --git a/crates/database/interface/src/try_commit.rs b/crates/database/interface/src/try_commit.rs new file mode 100644 index 0000000000..9a7595adcf --- /dev/null +++ b/crates/database/interface/src/try_commit.rs @@ -0,0 +1,85 @@ +//! Try database commit interface. +use crate::DatabaseCommit; +use core::{convert::Infallible, error::Error, fmt}; +use primitives::{Address, HashMap}; +use state::Account; +use std::sync::Arc; + +/// EVM database commit interface that can fail. +/// +/// This is intended for use with types that may fail to commit changes, e.g. +/// because they are directly interacting with the filesystem, or must arrange +/// access to a shared resource. +pub trait TryDatabaseCommit { + /// Error type for when [`TryDatabaseCommit::try_commit`] fails. + type Error: Error; + + /// Attempt to commit changes to the database. + fn try_commit(&mut self, changes: HashMap) -> Result<(), Self::Error>; +} + +impl TryDatabaseCommit for Db +where + Db: DatabaseCommit, +{ + type Error = Infallible; + + #[inline] + fn try_commit(&mut self, changes: HashMap) -> Result<(), Self::Error> { + self.commit(changes); + Ok(()) + } +} + +/// Error type for implementation of [`TryDatabaseCommit`] on +/// [`Arc`]. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct ArcUpgradeError; + +impl fmt::Display for ArcUpgradeError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "Arc reference is not unique, cannot mutate") + } +} + +impl Error for ArcUpgradeError {} + +impl TryDatabaseCommit for Arc +where + Db: DatabaseCommit + Send + Sync, +{ + type Error = ArcUpgradeError; + + #[inline] + fn try_commit(&mut self, changes: HashMap) -> Result<(), Self::Error> { + Arc::get_mut(self) + .map(|db| db.commit(changes)) + .ok_or(ArcUpgradeError) + } +} + +#[cfg(test)] +mod test { + use super::*; + use crate::DatabaseCommit; + use std::sync::Arc; + + struct MockDb; + + impl DatabaseCommit for MockDb { + fn commit(&mut self, _changes: HashMap) {} + } + + #[test] + fn arc_try_commit() { + let mut db = Arc::new(MockDb); + let db_2 = Arc::clone(&db); + + assert_eq!( + db.try_commit(Default::default()).unwrap_err(), + ArcUpgradeError + ); + drop(db_2); + db.try_commit(Default::default()).unwrap(); + } +} diff --git a/crates/database/src/alloydb.rs b/crates/database/src/alloydb.rs new file mode 100644 index 0000000000..5a0234ba72 --- /dev/null +++ b/crates/database/src/alloydb.rs @@ -0,0 +1,143 @@ +//! Alloy provider database implementation. + +pub use alloy_eips::BlockId; +use alloy_provider::{ + network::{primitives::HeaderResponse, BlockResponse}, + Network, Provider, +}; +use alloy_transport::TransportError; +use core::error::Error; +use database_interface::{async_db::DatabaseAsyncRef, DBErrorMarker}; +use primitives::{Address, StorageKey, StorageValue, B256}; +use state::{AccountInfo, Bytecode}; +use std::fmt::Display; + +/// Error type for transport-related database operations. +#[derive(Debug)] +pub struct DBTransportError(pub TransportError); + +impl DBErrorMarker for DBTransportError {} + +impl Display for DBTransportError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "Transport error: {}", self.0) + } +} + +impl Error for DBTransportError {} + +impl From for DBTransportError { + fn from(e: TransportError) -> Self { + Self(e) + } +} + +/// An alloy-powered REVM [Database][database_interface::Database]. +/// +/// When accessing the database, it'll use the given provider to fetch the corresponding account's data. +#[derive(Debug)] +pub struct AlloyDB> { + /// The provider to fetch the data from. + provider: P, + /// The block number on which the queries will be based on. + block_number: BlockId, + _marker: core::marker::PhantomData N>, +} + +impl> AlloyDB { + /// Creates a new AlloyDB instance, with a [Provider] and a block. + pub fn new(provider: P, block_number: BlockId) -> Self { + Self { + provider, + block_number, + _marker: core::marker::PhantomData, + } + } + + /// Sets the block number on which the queries will be based on. + pub fn set_block_number(&mut self, block_number: BlockId) { + self.block_number = block_number; + } +} + +impl> DatabaseAsyncRef for AlloyDB { + type Error = DBTransportError; + + async fn basic_async_ref(&self, address: Address) -> Result, Self::Error> { + let nonce = self + .provider + .get_transaction_count(address) + .block_id(self.block_number); + let balance = self + .provider + .get_balance(address) + .block_id(self.block_number); + let code = self + .provider + .get_code_at(address) + .block_id(self.block_number); + + let (nonce, balance, code) = tokio::join!(nonce, balance, code,); + + let balance = balance?; + let code = Bytecode::new_raw(code?.0.into()); + let code_hash = code.hash_slow(); + let nonce = nonce?; + + Ok(Some(AccountInfo::new(balance, nonce, code_hash, code))) + } + + async fn block_hash_async_ref(&self, number: u64) -> Result { + let block = self + .provider + // SAFETY: We know number <= u64::MAX, so we can safely convert it to u64 + .get_block_by_number(number.into()) + .await?; + // SAFETY: If the number is given, the block is supposed to be finalized, so unwrapping is safe. + Ok(B256::new(*block.unwrap().header().hash())) + } + + async fn code_by_hash_async_ref(&self, _code_hash: B256) -> Result { + panic!("This should not be called, as the code is already loaded"); + // This is not needed, as the code is already loaded with basic_ref + } + + async fn storage_async_ref( + &self, + address: Address, + index: StorageKey, + ) -> Result { + Ok(self + .provider + .get_storage_at(address, index) + .block_id(self.block_number) + .await?) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use alloy_provider::ProviderBuilder; + use database_interface::{DatabaseRef, WrapDatabaseAsync}; + + #[tokio::test] + #[ignore = "flaky RPC"] + async fn can_get_basic() { + let client = ProviderBuilder::new() + .connect("https://mainnet.infura.io/v3/c60b0bb42f8a4c6481ecd229eddaca27") + .await + .unwrap() + .erased(); + let alloydb = AlloyDB::new(client, BlockId::from(16148323)); + let wrapped_alloydb = WrapDatabaseAsync::new(alloydb).unwrap(); + + // ETH/USDT pair on Uniswap V2 + let address: Address = "0x0d4a11d5EEaaC28EC3F61d100daF4d40471f1852" + .parse() + .unwrap(); + + let acc_info = wrapped_alloydb.basic_ref(address).unwrap().unwrap(); + assert!(acc_info.exists()); + } +} diff --git a/crates/revm/src/db/in_memory_db.rs b/crates/database/src/in_memory_db.rs similarity index 67% rename from crates/revm/src/db/in_memory_db.rs rename to crates/database/src/in_memory_db.rs index a46e6be9cf..306b48565b 100644 --- a/crates/revm/src/db/in_memory_db.rs +++ b/crates/database/src/in_memory_db.rs @@ -1,25 +1,25 @@ -use super::{DatabaseCommit, DatabaseRef, EmptyDB}; -use crate::primitives::{ - hash_map::Entry, Account, AccountInfo, Address, Bytecode, HashMap, Log, B256, KECCAK_EMPTY, - U256, -}; -use crate::Database; use core::convert::Infallible; +use database_interface::{ + Database, DatabaseCommit, DatabaseRef, EmptyDB, BENCH_CALLER, BENCH_CALLER_BALANCE, + BENCH_TARGET, BENCH_TARGET_BALANCE, +}; +use primitives::{ + hash_map::Entry, Address, HashMap, Log, StorageKey, StorageValue, B256, KECCAK_EMPTY, U256, +}; +use state::{Account, AccountInfo, Bytecode}; use std::vec::Vec; /// A [Database] implementation that stores all state changes in memory. pub type InMemoryDB = CacheDB; -/// A [Database] implementation that stores all state changes in memory. -/// -/// This implementation wraps a [DatabaseRef] that is used to load data ([AccountInfo]). +/// A cache used in [CacheDB]. Its kept separate so it can be used independently. /// /// Accounts and code are stored in two separate maps, the `accounts` map maps addresses to [DbAccount], /// whereas contracts are identified by their code hash, and are stored in the `contracts` map. /// The [DbAccount] holds the code hash of the contract, which is used to look up the contract in the `contracts` map. #[derive(Debug, Clone)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct CacheDB { +pub struct Cache { /// Account info where None means it is not existing. Not existing state is needed for Pre TANGERINE forks. /// `code` is always `None`, and bytecode can be found in `contracts`. pub accounts: HashMap, @@ -29,9 +29,34 @@ pub struct CacheDB { pub logs: Vec, /// All cached block hashes from the [DatabaseRef]. pub block_hashes: HashMap, +} + +impl Default for Cache { + fn default() -> Self { + let mut contracts = HashMap::default(); + contracts.insert(KECCAK_EMPTY, Bytecode::default()); + contracts.insert(B256::ZERO, Bytecode::default()); + + Cache { + accounts: HashMap::default(), + contracts, + logs: Vec::default(), + block_hashes: HashMap::default(), + } + } +} + +/// A [Database] implementation that stores all state changes in memory. +/// +/// This implementation wraps a [DatabaseRef] that is used to load data ([AccountInfo]). +#[derive(Debug, Clone)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct CacheDB { + /// The cache that stores all state changes. + pub cache: Cache, /// The underlying database ([DatabaseRef]) that is used to load data. /// - /// Note: this is read-only, data is never written to this database. + /// Note: This is read-only, data is never written to this database. pub db: ExtDB, } @@ -41,16 +66,44 @@ impl Default for CacheDB { } } +impl CacheDB> { + /// Flattens a nested cache by applying the outer cache to the inner cache. + /// + /// The behavior is as follows: + /// - Accounts are overridden with outer accounts + /// - Contracts are overridden with outer contracts + /// - Logs are appended + /// - Block hashes are overridden with outer block hashes + pub fn flatten(self) -> CacheDB { + let CacheDB { + cache: + Cache { + accounts, + contracts, + logs, + block_hashes, + }, + db: mut inner, + } = self; + + inner.cache.accounts.extend(accounts); + inner.cache.contracts.extend(contracts); + inner.cache.logs.extend(logs); + inner.cache.block_hashes.extend(block_hashes); + inner + } + + /// Discards the outer cache and return the inner cache. + pub fn discard_outer(self) -> CacheDB { + self.db + } +} + impl CacheDB { + /// Creates a new cache with the given external database. pub fn new(db: ExtDB) -> Self { - let mut contracts = HashMap::new(); - contracts.insert(KECCAK_EMPTY, Bytecode::default()); - contracts.insert(B256::ZERO, Bytecode::default()); Self { - accounts: HashMap::new(), - contracts, - logs: Vec::default(), - block_hashes: HashMap::new(), + cache: Cache::default(), db, } } @@ -66,20 +119,30 @@ impl CacheDB { if account.code_hash == KECCAK_EMPTY { account.code_hash = code.hash_slow(); } - self.contracts + self.cache + .contracts .entry(account.code_hash) .or_insert_with(|| code.clone()); } } - if account.code_hash == B256::ZERO { + if account.code_hash.is_zero() { account.code_hash = KECCAK_EMPTY; } } - /// Insert account info but not override storage + /// Inserts account info but not override storage pub fn insert_account_info(&mut self, address: Address, mut info: AccountInfo) { self.insert_contract(&mut info); - self.accounts.entry(address).or_default().info = info; + let account_entry = self.cache.accounts.entry(address).or_default(); + account_entry.update_info(info); + if account_entry.account_state == AccountState::NotExisting { + account_entry.update_account_state(AccountState::None); + } + } + + /// Wraps the cache in a [CacheDB], creating a nested cache. + pub fn nest(self) -> CacheDB { + CacheDB::new(self) } } @@ -89,7 +152,7 @@ impl CacheDB { /// If the account was not found in the cache, it will be loaded from the underlying database. pub fn load_account(&mut self, address: Address) -> Result<&mut DbAccount, ExtDB::Error> { let db = &self.db; - match self.accounts.entry(address) { + match self.cache.accounts.entry(address) { Entry::Occupied(entry) => Ok(entry.into_mut()), Entry::Vacant(entry) => Ok(entry.insert( db.basic_ref(address)? @@ -102,23 +165,23 @@ impl CacheDB { } } - /// insert account storage without overriding account info + /// Inserts account storage without overriding account info pub fn insert_account_storage( &mut self, address: Address, - slot: U256, - value: U256, + slot: StorageKey, + value: StorageValue, ) -> Result<(), ExtDB::Error> { let account = self.load_account(address)?; account.storage.insert(slot, value); Ok(()) } - /// replace account storage without overriding account info + /// Replaces account storage without overriding account info pub fn replace_account_storage( &mut self, address: Address, - storage: HashMap, + storage: HashMap, ) -> Result<(), ExtDB::Error> { let account = self.load_account(address)?; account.account_state = AccountState::StorageCleared; @@ -134,7 +197,7 @@ impl DatabaseCommit for CacheDB { continue; } if account.is_selfdestructed() { - let db_account = self.accounts.entry(address).or_default(); + let db_account = self.cache.accounts.entry(address).or_default(); db_account.storage.clear(); db_account.account_state = AccountState::NotExisting; db_account.info = AccountInfo::default(); @@ -143,7 +206,7 @@ impl DatabaseCommit for CacheDB { let is_newly_created = account.is_created(); self.insert_contract(&mut account.info); - let db_account = self.accounts.entry(address).or_default(); + let db_account = self.cache.accounts.entry(address).or_default(); db_account.info = account.info; db_account.account_state = if is_newly_created { @@ -169,7 +232,7 @@ impl Database for CacheDB { type Error = ExtDB::Error; fn basic(&mut self, address: Address) -> Result, Self::Error> { - let basic = match self.accounts.entry(address) { + let basic = match self.cache.accounts.entry(address) { Entry::Occupied(entry) => entry.into_mut(), Entry::Vacant(entry) => entry.insert( self.db @@ -185,10 +248,10 @@ impl Database for CacheDB { } fn code_by_hash(&mut self, code_hash: B256) -> Result { - match self.contracts.entry(code_hash) { + match self.cache.contracts.entry(code_hash) { Entry::Occupied(entry) => Ok(entry.get().clone()), Entry::Vacant(entry) => { - // if you return code bytes when basic fn is called this function is not needed. + // If you return code bytes when basic fn is called this function is not needed. Ok(entry.insert(self.db.code_by_hash_ref(code_hash)?).clone()) } } @@ -197,8 +260,12 @@ impl Database for CacheDB { /// Get the value in an account's storage slot. /// /// It is assumed that account is already loaded. - fn storage(&mut self, address: Address, index: U256) -> Result { - match self.accounts.entry(address) { + fn storage( + &mut self, + address: Address, + index: StorageKey, + ) -> Result { + match self.cache.accounts.entry(address) { Entry::Occupied(mut acc_entry) => { let acc_entry = acc_entry.get_mut(); match acc_entry.storage.entry(index) { @@ -208,7 +275,7 @@ impl Database for CacheDB { acc_entry.account_state, AccountState::StorageCleared | AccountState::NotExisting ) { - Ok(U256::ZERO) + Ok(StorageValue::ZERO) } else { let slot = self.db.storage_ref(address, index)?; entry.insert(slot); @@ -218,7 +285,7 @@ impl Database for CacheDB { } } Entry::Vacant(acc_entry) => { - // acc needs to be loaded for us to access slots. + // Acc needs to be loaded for us to access slots. let info = self.db.basic_ref(address)?; let (account, value) = if info.is_some() { let value = self.db.storage_ref(address, index)?; @@ -226,7 +293,7 @@ impl Database for CacheDB { account.storage.insert(index, value); (account, value) } else { - (info.into(), U256::ZERO) + (info.into(), StorageValue::ZERO) }; acc_entry.insert(account); Ok(value) @@ -234,8 +301,8 @@ impl Database for CacheDB { } } - fn block_hash(&mut self, number: U256) -> Result { - match self.block_hashes.entry(number) { + fn block_hash(&mut self, number: u64) -> Result { + match self.cache.block_hashes.entry(U256::from(number)) { Entry::Occupied(entry) => Ok(*entry.get()), Entry::Vacant(entry) => { let hash = self.db.block_hash_ref(number)?; @@ -244,27 +311,40 @@ impl Database for CacheDB { } } } + + fn salt_bucket_capacity( + &self, + address: Address, + index: Option, + ) -> Result<(usize, u64), Self::Error> { + // we don't cache salt bucket capacity, so we directly call the underlying database + self.db.salt_bucket_capacity_ref(address, index) + } } impl DatabaseRef for CacheDB { type Error = ExtDB::Error; fn basic_ref(&self, address: Address) -> Result, Self::Error> { - match self.accounts.get(&address) { + match self.cache.accounts.get(&address) { Some(acc) => Ok(acc.info()), None => self.db.basic_ref(address), } } fn code_by_hash_ref(&self, code_hash: B256) -> Result { - match self.contracts.get(&code_hash) { + match self.cache.contracts.get(&code_hash) { Some(entry) => Ok(entry.clone()), None => self.db.code_by_hash_ref(code_hash), } } - fn storage_ref(&self, address: Address, index: U256) -> Result { - match self.accounts.get(&address) { + fn storage_ref( + &self, + address: Address, + index: StorageKey, + ) -> Result { + match self.cache.accounts.get(&address) { Some(acc_entry) => match acc_entry.storage.get(&index) { Some(entry) => Ok(*entry), None => { @@ -272,7 +352,7 @@ impl DatabaseRef for CacheDB { acc_entry.account_state, AccountState::StorageCleared | AccountState::NotExisting ) { - Ok(U256::ZERO) + Ok(StorageValue::ZERO) } else { self.db.storage_ref(address, index) } @@ -282,25 +362,37 @@ impl DatabaseRef for CacheDB { } } - fn block_hash_ref(&self, number: U256) -> Result { - match self.block_hashes.get(&number) { + fn block_hash_ref(&self, number: u64) -> Result { + match self.cache.block_hashes.get(&U256::from(number)) { Some(entry) => Ok(*entry), None => self.db.block_hash_ref(number), } } + + fn salt_bucket_capacity_ref( + &self, + address: Address, + index: Option, + ) -> Result<(usize, u64), Self::Error> { + // we don't cache salt bucket capacity, so we directly call the underlying database + self.db.salt_bucket_capacity_ref(address, index) + } } +/// Database account representation. #[derive(Debug, Clone, Default)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct DbAccount { + /// Basic account information. pub info: AccountInfo, /// If account is selfdestructed or newly created, storage will be cleared. pub account_state: AccountState, - /// storage slots - pub storage: HashMap, + /// Storage slots + pub storage: HashMap, } impl DbAccount { + /// Creates a new non-existing account. pub fn new_not_existing() -> Self { Self { account_state: AccountState::NotExisting, @@ -308,6 +400,7 @@ impl DbAccount { } } + /// Returns account info if the account exists. pub fn info(&self) -> Option { if matches!(self.account_state, AccountState::NotExisting) { None @@ -315,6 +408,18 @@ impl DbAccount { Some(self.info.clone()) } } + + /// Updates the account information. + #[inline(always)] + pub fn update_info(&mut self, info: AccountInfo) { + self.info = info; + } + + /// Updates the account state. + #[inline(always)] + pub fn update_account_state(&mut self, account_state: AccountState) { + self.account_state = account_state; + } } impl From> for DbAccount { @@ -333,6 +438,7 @@ impl From for DbAccount { } } +/// State of an account in the database. #[derive(Debug, Clone, Default, PartialEq, Eq, Hash)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum AccountState { @@ -342,7 +448,7 @@ pub enum AccountState { /// EVM touched this account. For newer hardfork this means it can be cleared/removed from state. Touched, /// EVM cleared storage of this account, mostly by selfdestruct, we don't ask database for storage slots - /// and assume they are U256::ZERO + /// and assume they are StorageValue::ZERO StorageCleared, /// EVM didn't interacted with this account #[default] @@ -363,6 +469,7 @@ impl AccountState { pub struct BenchmarkDB(pub Bytecode, B256); impl BenchmarkDB { + /// Creates a new benchmark database with the given bytecode. pub fn new_bytecode(bytecode: Bytecode) -> Self { let hash = bytecode.hash_slow(); Self(bytecode, hash) @@ -373,18 +480,18 @@ impl Database for BenchmarkDB { type Error = Infallible; /// Get basic account information. fn basic(&mut self, address: Address) -> Result, Self::Error> { - if address == Address::ZERO { + if address == BENCH_TARGET { return Ok(Some(AccountInfo { nonce: 1, - balance: U256::from(10000000), + balance: BENCH_TARGET_BALANCE, code: Some(self.0.clone()), code_hash: self.1, })); } - if address == Address::with_last_byte(1) { + if address == BENCH_CALLER { return Ok(Some(AccountInfo { nonce: 0, - balance: U256::from(10000000), + balance: BENCH_CALLER_BALANCE, code: None, code_hash: KECCAK_EMPTY, })); @@ -398,20 +505,34 @@ impl Database for BenchmarkDB { } /// Get storage value of address at index. - fn storage(&mut self, _address: Address, _index: U256) -> Result { - Ok(U256::default()) + fn storage( + &mut self, + _address: Address, + _index: StorageKey, + ) -> Result { + Ok(StorageValue::default()) } // History related - fn block_hash(&mut self, _number: U256) -> Result { + fn block_hash(&mut self, _number: u64) -> Result { Ok(B256::default()) } + + fn salt_bucket_capacity( + &self, + _address: Address, + _index: Option, + ) -> Result<(usize, u64), Self::Error> { + Ok((0, 0)) + } } #[cfg(test)] mod tests { use super::{CacheDB, EmptyDB}; - use crate::primitives::{db::Database, AccountInfo, Address, U256}; + use database_interface::Database; + use primitives::{Address, HashMap, StorageKey, StorageValue}; + use state::AccountInfo; #[test] fn test_insert_account_storage() { @@ -426,7 +547,7 @@ mod tests { }, ); - let (key, value) = (U256::from(123), U256::from(456)); + let (key, value) = (StorageKey::from(123), StorageValue::from(456)); let mut new_state = CacheDB::new(init_state); new_state .insert_account_storage(account, key, value) @@ -449,23 +570,23 @@ mod tests { }, ); - let (key0, value0) = (U256::from(123), U256::from(456)); - let (key1, value1) = (U256::from(789), U256::from(999)); + let (key0, value0) = (StorageKey::from(123), StorageValue::from(456)); + let (key1, value1) = (StorageKey::from(789), StorageValue::from(999)); init_state .insert_account_storage(account, key0, value0) .unwrap(); let mut new_state = CacheDB::new(init_state); new_state - .replace_account_storage(account, [(key1, value1)].into()) + .replace_account_storage(account, HashMap::from_iter([(key1, value1)])) .unwrap(); assert_eq!(new_state.basic(account).unwrap().unwrap().nonce, nonce); - assert_eq!(new_state.storage(account, key0), Ok(U256::ZERO)); + assert_eq!(new_state.storage(account, key0), Ok(StorageValue::ZERO)); assert_eq!(new_state.storage(account, key1), Ok(value1)); } - #[cfg(feature = "serde-json")] + #[cfg(feature = "serde")] #[test] fn test_serialize_deserialize_cachedb() { let account = Address::with_last_byte(69); @@ -482,9 +603,15 @@ mod tests { let serialized = serde_json::to_string(&init_state).unwrap(); let deserialized: CacheDB = serde_json::from_str(&serialized).unwrap(); - assert!(deserialized.accounts.contains_key(&account)); + assert!(deserialized.cache.accounts.contains_key(&account)); assert_eq!( - deserialized.accounts.get(&account).unwrap().info.nonce, + deserialized + .cache + .accounts + .get(&account) + .unwrap() + .info + .nonce, nonce ); } diff --git a/crates/database/src/lib.rs b/crates/database/src/lib.rs new file mode 100644 index 0000000000..a1f6f5c543 --- /dev/null +++ b/crates/database/src/lib.rs @@ -0,0 +1,25 @@ +//! Database implementations. +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(not(feature = "std"))] +extern crate alloc as std; + +#[cfg(feature = "alloydb")] +mod alloydb; + +pub use database_interface::*; + +/// In-memory database implementations. +pub mod in_memory_db; +/// State management and tracking. +pub mod states; + +#[cfg(feature = "alloydb")] +pub use alloydb::{AlloyDB, BlockId, DBTransportError}; + +pub use in_memory_db::*; +pub use states::{ + AccountRevert, AccountStatus, BundleAccount, BundleState, CacheState, DBBox, + OriginalValuesKnown, PlainAccount, RevertToSlot, State, StateBuilder, StateDBBox, + StorageWithOriginalValues, TransitionAccount, TransitionState, +}; diff --git a/crates/revm/src/db/states.rs b/crates/database/src/states.rs similarity index 68% rename from crates/revm/src/db/states.rs rename to crates/database/src/states.rs index 2fa08b2a52..49adc0e773 100644 --- a/crates/revm/src/db/states.rs +++ b/crates/database/src/states.rs @@ -1,14 +1,28 @@ +//! State management and tracking for the EVM. + +/// Account status tracking. pub mod account_status; +/// Bundle account representation. pub mod bundle_account; +/// Bundle state management. pub mod bundle_state; +/// Cache state implementation. pub mod cache; +/// Cache account representation. pub mod cache_account; +/// State changeset tracking. pub mod changes; +/// Plain account representation. pub mod plain_account; +/// State revert tracking. pub mod reverts; +/// Main state implementation. pub mod state; +/// State builder utilities. pub mod state_builder; +/// Transition account representation. pub mod transition_account; +/// Transition state management. pub mod transition_state; /// Account status for Block and Bundle states. diff --git a/crates/revm/src/db/states/account_status.rs b/crates/database/src/states/account_status.rs similarity index 84% rename from crates/revm/src/db/states/account_status.rs rename to crates/database/src/states/account_status.rs index aaf0b5b48e..ac443fb280 100644 --- a/crates/revm/src/db/states/account_status.rs +++ b/crates/database/src/states/account_status.rs @@ -1,16 +1,38 @@ +/// AccountStatus represents the various states an account can be in after being loaded from the database. +/// /// After account get loaded from database it can be in a lot of different states /// while we execute multiple transaction and even blocks over account that is in memory. /// This structure models all possible states that account can be in. -#[derive(Clone, Copy, Default, Debug, PartialEq, Eq, Hash)] +/// +/// # Variants +/// +/// - `LoadedNotExisting`: the account has been loaded but does not exist. +/// - `Loaded`: the account has been loaded and exists. +/// - `LoadedEmptyEIP161`: the account is loaded and empty, as per EIP-161. +/// - `InMemoryChange`: there are changes in the account that exist only in memory. +/// - `Changed`: the account has been modified. +/// - `Destroyed`: the account has been destroyed. +/// - `DestroyedChanged`: the account has been destroyed and then modified. +/// - `DestroyedAgain`: the account has been destroyed again. +#[derive(Clone, Copy, Default, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum AccountStatus { + /// The account has been loaded but does not exist. #[default] LoadedNotExisting, + /// The account has been loaded and exists. Loaded, + /// The account is loaded and empty, as per EIP-161. LoadedEmptyEIP161, + /// There are changes in the account that exist only in memory. InMemoryChange, + /// The account has been modified. Changed, + /// The account has been destroyed. Destroyed, + /// The account has been destroyed and then modified. DestroyedChanged, + /// The account has been destroyed again. DestroyedAgain, } @@ -58,11 +80,11 @@ impl AccountStatus { /// Returns the next account status on creation. pub fn on_created(&self) -> AccountStatus { match self { - // if account was destroyed previously just copy new info to it. + // If account was destroyed previously just copy new info to it. AccountStatus::DestroyedAgain | AccountStatus::Destroyed | AccountStatus::DestroyedChanged => AccountStatus::DestroyedChanged, - // if account is loaded from db. + // If account is loaded from db. AccountStatus::LoadedNotExisting // Loaded empty eip161 to creates is not possible as CREATE2 was added after EIP-161 | AccountStatus::LoadedEmptyEIP161 @@ -142,10 +164,10 @@ impl AccountStatus { // The account was loaded as existing. AccountStatus::Loaded => { if had_no_nonce_and_code { - // account is fully in memory + // Account is fully in memory AccountStatus::InMemoryChange } else { - // can be contract and some of storage slots can be present inside db. + // Can be contract and some of storage slots can be present inside db. AccountStatus::Changed } } @@ -170,7 +192,7 @@ impl AccountStatus { // Non existing account can't be destroyed. AccountStatus::LoadedNotExisting => AccountStatus::LoadedNotExisting, // If account is created and selfdestructed in the same block, mark it as destroyed again. - // Note: there is no big difference between Destroyed and DestroyedAgain in this case, + // Note: There is no big difference between Destroyed and DestroyedAgain in this case, // but was added for clarity. AccountStatus::DestroyedChanged | AccountStatus::DestroyedAgain @@ -184,15 +206,15 @@ impl AccountStatus { /// Transition to other state while preserving invariance of this state. /// /// It this account was Destroyed and other account is not: - /// we should mark extended account as destroyed too. - /// and as other account had some changes, extended account - /// should be marked as DestroyedChanged. + /// - We should mark extended account as destroyed too. + /// - And as other account had some changes, extended account + /// should be marked as DestroyedChanged. /// /// If both account are not destroyed and if this account is in memory: - /// this means that extended account is in memory too. + /// - This means that extended account is in memory too. /// /// Otherwise, if both are destroyed or other is destroyed: - /// set other status to extended account. + /// - Sets other status to extended account. pub fn transition(&mut self, other: Self) { *self = match (self.was_destroyed(), other.was_destroyed()) { (true, false) => Self::DestroyedChanged, @@ -209,7 +231,7 @@ mod test { #[test] fn test_account_status() { - // account not modified + // Account not modified assert!(AccountStatus::Loaded.is_not_modified()); assert!(AccountStatus::LoadedEmptyEIP161.is_not_modified()); assert!(AccountStatus::LoadedNotExisting.is_not_modified()); @@ -219,7 +241,7 @@ mod test { assert!(!AccountStatus::DestroyedChanged.is_not_modified()); assert!(!AccountStatus::DestroyedAgain.is_not_modified()); - // we know full storage + // We know full storage assert!(!AccountStatus::LoadedEmptyEIP161.is_storage_known()); assert!(AccountStatus::LoadedNotExisting.is_storage_known()); assert!(AccountStatus::InMemoryChange.is_storage_known()); @@ -229,7 +251,7 @@ mod test { assert!(!AccountStatus::Loaded.is_storage_known()); assert!(!AccountStatus::Changed.is_storage_known()); - // account was destroyed + // Account was destroyed assert!(!AccountStatus::LoadedEmptyEIP161.was_destroyed()); assert!(!AccountStatus::LoadedNotExisting.was_destroyed()); assert!(!AccountStatus::InMemoryChange.was_destroyed()); @@ -239,7 +261,7 @@ mod test { assert!(!AccountStatus::Loaded.was_destroyed()); assert!(!AccountStatus::Changed.was_destroyed()); - // account modified but not destroyed + // Account modified but not destroyed assert!(AccountStatus::Changed.is_modified_and_not_destroyed()); assert!(AccountStatus::InMemoryChange.is_modified_and_not_destroyed()); assert!(!AccountStatus::Loaded.is_modified_and_not_destroyed()); diff --git a/crates/revm/src/db/states/bundle_account.rs b/crates/database/src/states/bundle_account.rs similarity index 88% rename from crates/revm/src/db/states/bundle_account.rs rename to crates/database/src/states/bundle_account.rs index 9916139d12..ffa4b20b4f 100644 --- a/crates/revm/src/db/states/bundle_account.rs +++ b/crates/database/src/states/bundle_account.rs @@ -2,8 +2,8 @@ use super::{ reverts::AccountInfoRevert, AccountRevert, AccountStatus, RevertToSlot, StorageSlot, StorageWithOriginalValues, TransitionAccount, }; -use revm_interpreter::primitives::{AccountInfo, U256}; -use revm_precompile::HashMap; +use primitives::{HashMap, StorageKey, StorageValue}; +use state::AccountInfo; /// Account information focused on creating of database changesets /// and Reverts. @@ -11,18 +11,22 @@ use revm_precompile::HashMap; /// Status is needed as to know from what state we are applying the TransitionAccount. /// /// Original account info is needed to know if there was a change. +/// /// Same thing for storage with original value. /// /// On selfdestruct storage original value is ignored. #[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct BundleAccount { + /// Current account information. pub info: Option, + /// Original account information before modifications. pub original_info: Option, /// Contains both original and present state. /// When extracting changeset we compare if original value is different from present value. /// If it is different we add it to changeset. /// - /// If Account was destroyed we ignore original value and compare present state with U256::ZERO. + /// If Account was destroyed we ignore original value and compare present state with StorageValue::ZERO. pub storage: StorageWithOriginalValues, /// Account status. pub status: AccountStatus, @@ -45,6 +49,7 @@ impl BundleAccount { } /// The approximate size of changes needed to store this account. + /// /// `1 + storage_len` pub fn size_hint(&self) -> usize { 1 + self.storage.len() @@ -52,19 +57,19 @@ impl BundleAccount { /// Return storage slot if it exists. /// - /// In case we know that account is newly created or destroyed, return `Some(U256::ZERO)` - pub fn storage_slot(&self, slot: U256) -> Option { + /// In case we know that account is newly created or destroyed, return `Some(StorageValue::ZERO)` + pub fn storage_slot(&self, slot: StorageKey) -> Option { let slot = self.storage.get(&slot).map(|s| s.present_value); if slot.is_some() { slot } else if self.status.is_storage_known() { - Some(U256::ZERO) + Some(StorageValue::ZERO) } else { None } } - /// Fetch account info if it exist. + /// Fetch account info if it exists. pub fn account_info(&self) -> Option { self.info.clone() } @@ -93,19 +98,19 @@ impl BundleAccount { AccountInfoRevert::DeleteIt => { self.info = None; if self.original_info.is_none() { - self.storage = HashMap::new(); + self.storage = HashMap::default(); return true; } else { - // set all storage to zero but preserve original values. + // Set all storage to zero but preserve original values. self.storage.iter_mut().for_each(|(_, v)| { - v.present_value = U256::ZERO; + v.present_value = StorageValue::ZERO; }); return false; } } AccountInfoRevert::RevertTo(info) => self.info = Some(info), }; - // revert storage + // Revert storage for (key, slot) in revert.storage { match slot { RevertToSlot::Some(value) => { @@ -117,7 +122,7 @@ impl BundleAccount { .present_value = value; } RevertToSlot::Destroyed => { - // if it was destroyed this means that storage was created and we need to remove it. + // If it was destroyed this means that storage was created and we need to remove it. self.storage.remove(&key); } } @@ -126,7 +131,9 @@ impl BundleAccount { } /// Update to new state and generate AccountRevert that if applied to new state will - /// revert it to previous state. If no revert is present, update is noop. + /// revert it to previous state. + /// + /// If no revert is present, update is noop. pub fn update_and_create_revert( &mut self, transition: TransitionAccount, @@ -135,7 +142,7 @@ impl BundleAccount { let updated_storage = transition.storage; let updated_status = transition.status; - // the helper that extends this storage but preserves original value. + // The helper that extends this storage but preserves original value. let extend_storage = |this_storage: &mut StorageWithOriginalValues, storage_update: StorageWithOriginalValues| { @@ -145,7 +152,7 @@ impl BundleAccount { }; let previous_storage_from_update = - |updated_storage: &StorageWithOriginalValues| -> HashMap { + |updated_storage: &StorageWithOriginalValues| -> HashMap { updated_storage .iter() .filter(|s| s.1.is_changed()) @@ -167,7 +174,7 @@ impl BundleAccount { let previous_storage = previous_storage_from_update(&updated_storage); match self.status { AccountStatus::Changed | AccountStatus::Loaded => { - // extend the storage. original values is not used inside bundle. + // Extend the storage. original values is not used inside bundle. extend_storage(&mut self.storage, updated_storage); } AccountStatus::LoadedEmptyEIP161 => { @@ -191,7 +198,7 @@ impl BundleAccount { let previous_storage = previous_storage_from_update(&updated_storage); let in_memory_info_revert = match self.status { AccountStatus::Loaded | AccountStatus::InMemoryChange => { - // from loaded (Or LoadedEmpty) to InMemoryChange can happen if there is balance change + // From loaded (Or LoadedEmpty) to InMemoryChange can happen if there is balance change // or new created account but Loaded didn't have contract. extend_storage(&mut self.storage, updated_storage); info_revert @@ -224,7 +231,7 @@ impl BundleAccount { None } AccountStatus::Destroyed => { - // clear this storage and move it to the Revert. + // Clear this storage and move it to the Revert. let this_storage = self.storage.drain().collect(); let ret = match self.status { AccountStatus::InMemoryChange | AccountStatus::Changed | AccountStatus::Loaded | AccountStatus::LoadedEmptyEIP161 => { @@ -242,21 +249,21 @@ impl BundleAccount { self.info = None; } - // set present to destroyed. + // Set present to destroyed. ret } AccountStatus::DestroyedChanged => { // Previous block created account or changed. // (It was destroyed on previous block or one before). - // check common pre destroy paths. + // Check common pre destroy paths. // If common path is there it will drain the storage. if let Some(revert_state) = AccountRevert::new_selfdestructed_from_bundle( info_revert.clone(), self, &updated_storage, ) { - // set to destroyed and revert state. + // Set to destroyed and revert state. self.status = AccountStatus::DestroyedChanged; self.info = updated_info; self.storage = updated_storage; @@ -265,7 +272,7 @@ impl BundleAccount { } else { let ret = match self.status { AccountStatus::Destroyed | AccountStatus::LoadedNotExisting => { - // from destroyed state new account is made + // From destroyed state new account is made Some(AccountRevert { account: AccountInfoRevert::DeleteIt, storage: previous_storage_from_update(&updated_storage), @@ -283,7 +290,7 @@ impl BundleAccount { .map(|t| (t.0, RevertToSlot::Some(t.1.present_value))) .collect::>(); for key in updated_storage.keys() { - // as it is not existing inside Destroyed storage this means + // As it is not existing inside Destroyed storage this means // that previous values must be zero storage.entry(*key).or_insert(RevertToSlot::Destroyed); } @@ -301,7 +308,7 @@ impl BundleAccount { } AccountStatus::DestroyedAgain => { Some(AccountRevert::new_selfdestructed_again( - // destroyed again will set empty account. + // Destroyed again will set empty account. AccountStatus::DestroyedAgain, AccountInfoRevert::DeleteIt, HashMap::default(), @@ -312,7 +319,7 @@ impl BundleAccount { }; self.status = AccountStatus::DestroyedChanged; self.info = updated_info; - // extends current storage. + // Extends current storage. extend_storage(&mut self.storage, updated_storage); ret @@ -322,7 +329,7 @@ impl BundleAccount { // Previous block created account // (It was destroyed on previous block or one before). - // check common pre destroy paths. + // Check common pre destroy paths. // This will drain the storage if it is common transition. let ret = if let Some(revert_state) = AccountRevert::new_selfdestructed_from_bundle( info_revert, @@ -335,18 +342,18 @@ impl BundleAccount { AccountStatus::Destroyed | AccountStatus::DestroyedAgain | AccountStatus::LoadedNotExisting => { - // From destroyed to destroyed again. is noop + // From destroyed to destroyed again is noop // - // DestroyedAgain to DestroyedAgain is noop + // From DestroyedAgain to DestroyedAgain is noop // - // From LoadedNotExisting to DestroyedAgain - // is noop as account is destroyed again + // From LoadedNotExisting to DestroyedAgain is noop + // as account is destroyed again None } AccountStatus::DestroyedChanged => { // From destroyed changed to destroyed again. Some(AccountRevert::new_selfdestructed_again( - // destroyed again will set empty account. + // Destroyed again will set empty account. AccountStatus::DestroyedChanged, AccountInfoRevert::RevertTo(self.info.clone().unwrap_or_default()), self.storage.drain().collect(), @@ -356,7 +363,7 @@ impl BundleAccount { _ => unreachable!("Invalid state to DestroyedAgain from {self:?}"), } }; - // set to destroyed and revert state. + // Set to destroyed and revert state. self.status = AccountStatus::DestroyedAgain; self.info = None; self.storage.clear(); diff --git a/crates/revm/src/db/states/bundle_state.rs b/crates/database/src/states/bundle_state.rs similarity index 67% rename from crates/revm/src/db/states/bundle_state.rs rename to crates/database/src/states/bundle_state.rs index 8dd4edfe26..7b24298e04 100644 --- a/crates/revm/src/db/states/bundle_state.rs +++ b/crates/database/src/states/bundle_state.rs @@ -4,11 +4,12 @@ use super::{ AccountRevert, AccountStatus, BundleAccount, PlainStateReverts, RevertToSlot, StorageSlot, TransitionState, }; +use bytecode::Bytecode; use core::{mem, ops::RangeInclusive}; -use revm_interpreter::primitives::{ - hash_map::{self, Entry}, - AccountInfo, Address, Bytecode, HashMap, HashSet, B256, KECCAK_EMPTY, U256, +use primitives::{ + hash_map::Entry, Address, HashMap, HashSet, StorageKey, StorageValue, B256, KECCAK_EMPTY, }; +use state::AccountInfo; use std::{ collections::{BTreeMap, BTreeSet}, vec::Vec, @@ -20,12 +21,12 @@ pub struct BundleBuilder { states: HashSet
, state_original: HashMap, state_present: HashMap, - state_storage: HashMap>, + state_storage: HashMap>, reverts: BTreeSet<(u64, Address)>, revert_range: RangeInclusive, revert_account: HashMap<(u64, Address), Option>>, - revert_storage: HashMap<(u64, Address), Vec<(U256, U256)>>, + revert_storage: HashMap<(u64, Address), Vec<(StorageKey, StorageValue)>>, contracts: HashMap, } @@ -33,12 +34,12 @@ pub struct BundleBuilder { /// Option for [`BundleState`] when converting it to the plain state. #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum OriginalValuesKnown { - /// Check changed with original values that [BundleState] has. + /// Checks changed with original values that [BundleState] has. /// /// If we don't expect parent blocks to be committed or unwinded from database, this option /// should be used. Yes, - /// Don't check original values, see the implementation of [BundleState::into_plain_state] for + /// Doesn't check original values, see the implementation of [BundleState::to_plain_state] for /// more info. /// /// If the Bundle can be split or extended, we would not be sure about original values, in that @@ -55,23 +56,23 @@ impl OriginalValuesKnown { impl Default for BundleBuilder { fn default() -> Self { BundleBuilder { - states: HashSet::new(), - state_original: HashMap::new(), - state_present: HashMap::new(), - state_storage: HashMap::new(), + states: HashSet::default(), + state_original: HashMap::default(), + state_present: HashMap::default(), + state_storage: HashMap::default(), reverts: BTreeSet::new(), revert_range: 0..=0, - revert_account: HashMap::new(), - revert_storage: HashMap::new(), - contracts: HashMap::new(), + revert_account: HashMap::default(), + revert_storage: HashMap::default(), + contracts: HashMap::default(), } } } impl BundleBuilder { - /// Create builder instance + /// Creates builder instance. /// - /// `revert_range` indicates the size of BundleState `reverts` field + /// `revert_range` indicates the size of BundleState `reverts` field. pub fn new(revert_range: RangeInclusive) -> Self { BundleBuilder { revert_range, @@ -79,79 +80,170 @@ impl BundleBuilder { } } - /// Collect address info of BundleState state + /// Applies a transformation to the builder. + pub fn apply(self, f: F) -> Self + where + F: FnOnce(Self) -> Self, + { + f(self) + } + + /// Applies a mutable transformation to the builder. + pub fn apply_mut(&mut self, f: F) -> &mut Self + where + F: FnOnce(&mut Self), + { + f(self); + self + } + + /// Collects address info of BundleState state. pub fn state_address(mut self, address: Address) -> Self { - self.states.insert(address); + self.set_state_address(address); self } - /// Collect account info of BundleState state + /// Collects account info of BundleState state. pub fn state_original_account_info(mut self, address: Address, original: AccountInfo) -> Self { - self.states.insert(address); - self.state_original.insert(address, original); + self.set_state_original_account_info(address, original); self } - /// Collect account info of BundleState state + /// Collects account info of BundleState state. pub fn state_present_account_info(mut self, address: Address, present: AccountInfo) -> Self { - self.states.insert(address); - self.state_present.insert(address, present); + self.set_state_present_account_info(address, present); self } - /// Collect storage info of BundleState state - pub fn state_storage(mut self, address: Address, storage: HashMap) -> Self { - self.states.insert(address); - self.state_storage.insert(address, storage); + /// Collects storage info of BundleState state. + pub fn state_storage( + mut self, + address: Address, + storage: HashMap, + ) -> Self { + self.set_state_storage(address, storage); self } - /// Collect address info of BundleState reverts + /// Collects address info of BundleState reverts. /// /// `block_number` must respect `revert_range`, or the input - /// will be ignored during the final build process + /// will be ignored during the final build process. pub fn revert_address(mut self, block_number: u64, address: Address) -> Self { - self.reverts.insert((block_number, address)); + self.set_revert_address(block_number, address); self } - /// Collect account info of BundleState reverts + /// Collects account info of BundleState reverts. /// /// `block_number` must respect `revert_range`, or the input - /// will be ignored during the final build process + /// will be ignored during the final build process. pub fn revert_account_info( mut self, block_number: u64, address: Address, account: Option>, ) -> Self { - self.reverts.insert((block_number, address)); - self.revert_account.insert((block_number, address), account); + self.set_revert_account_info(block_number, address, account); self } - /// Collect storage info of BundleState reverts + /// Collects storage info of BundleState reverts. /// /// `block_number` must respect `revert_range`, or the input - /// will be ignored during the final build process + /// will be ignored during the final build process. pub fn revert_storage( mut self, block_number: u64, address: Address, - storage: Vec<(U256, U256)>, + storage: Vec<(StorageKey, StorageValue)>, ) -> Self { + self.set_revert_storage(block_number, address, storage); + self + } + + /// Collects contracts info. + pub fn contract(mut self, address: B256, bytecode: Bytecode) -> Self { + self.set_contract(address, bytecode); + self + } + + /// Sets address info of BundleState state. + pub fn set_state_address(&mut self, address: Address) -> &mut Self { + self.states.insert(address); + self + } + + /// Sets original account info of BundleState state. + pub fn set_state_original_account_info( + &mut self, + address: Address, + original: AccountInfo, + ) -> &mut Self { + self.states.insert(address); + self.state_original.insert(address, original); + self + } + + /// Sets present account info of BundleState state. + pub fn set_state_present_account_info( + &mut self, + address: Address, + present: AccountInfo, + ) -> &mut Self { + self.states.insert(address); + self.state_present.insert(address, present); + self + } + + /// Sets storage info of BundleState state. + pub fn set_state_storage( + &mut self, + address: Address, + storage: HashMap, + ) -> &mut Self { + self.states.insert(address); + self.state_storage.insert(address, storage); + self + } + + /// Sets address info of BundleState reverts. + pub fn set_revert_address(&mut self, block_number: u64, address: Address) -> &mut Self { + self.reverts.insert((block_number, address)); + self + } + + /// Sets account info of BundleState reverts. + pub fn set_revert_account_info( + &mut self, + block_number: u64, + address: Address, + account: Option>, + ) -> &mut Self { + self.reverts.insert((block_number, address)); + self.revert_account.insert((block_number, address), account); + self + } + + /// Sets storage info of BundleState reverts. + pub fn set_revert_storage( + &mut self, + block_number: u64, + address: Address, + storage: Vec<(StorageKey, StorageValue)>, + ) -> &mut Self { self.reverts.insert((block_number, address)); self.revert_storage.insert((block_number, address), storage); self } - /// Collect contracts info - pub fn contract(mut self, address: B256, bytecode: Bytecode) -> Self { + /// Sets contracts info. + pub fn set_contract(&mut self, address: B256, bytecode: Bytecode) -> &mut Self { self.contracts.insert(address, bytecode); self } - /// Create `BundleState` instance based on collected information + /// Creates `BundleState` instance based on collected information. pub fn build(mut self) -> BundleState { let mut state_size = 0; let state = self @@ -233,6 +325,57 @@ impl BundleBuilder { pub fn get_states(&self) -> &HashSet
{ &self.states } + + /// Mutable getter for `states` field + pub fn get_states_mut(&mut self) -> &mut HashSet
{ + &mut self.states + } + + /// Mutable getter for `state_original` field + pub fn get_state_original_mut(&mut self) -> &mut HashMap { + &mut self.state_original + } + + /// Mutable getter for `state_present` field + pub fn get_state_present_mut(&mut self) -> &mut HashMap { + &mut self.state_present + } + + /// Mutable getter for `state_storage` field + pub fn get_state_storage_mut( + &mut self, + ) -> &mut HashMap> { + &mut self.state_storage + } + + /// Mutable getter for `reverts` field + pub fn get_reverts_mut(&mut self) -> &mut BTreeSet<(u64, Address)> { + &mut self.reverts + } + + /// Mutable getter for `revert_range` field + pub fn get_revert_range_mut(&mut self) -> &mut RangeInclusive { + &mut self.revert_range + } + + /// Mutable getter for `revert_account` field + pub fn get_revert_account_mut( + &mut self, + ) -> &mut HashMap<(u64, Address), Option>> { + &mut self.revert_account + } + + /// Mutable getter for `revert_storage` field + pub fn get_revert_storage_mut( + &mut self, + ) -> &mut HashMap<(u64, Address), Vec<(StorageKey, StorageValue)>> { + &mut self.revert_storage + } + + /// Mutable getter for `contracts` field + pub fn get_contracts_mut(&mut self) -> &mut HashMap { + &mut self.contracts + } } /// Bundle retention policy for applying substate to the bundle. @@ -254,41 +397,45 @@ impl BundleRetention { /// Bundle state contain only values that got changed /// /// For every account it contains both original and present state. +/// /// This is needed to decide if there were any changes to the account. /// /// Reverts and created when TransitionState is applied to BundleState. +/// /// And can be used to revert BundleState to the state before transition. #[derive(Default, Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct BundleState { - /// Account state. + /// Account state pub state: HashMap, /// All created contracts in this block. pub contracts: HashMap, - /// Changes to revert. + /// Changes to revert + /// + /// **Note**: Inside vector is *not* sorted by address. /// - /// Note: Inside vector is *not* sorted by address. /// But it is unique by address. pub reverts: Reverts, - /// The size of the plain state in the bundle state. + /// The size of the plain state in the bundle state pub state_size: usize, - /// The size of reverts in the bundle state. + /// The size of reverts in the bundle state pub reverts_size: usize, } impl BundleState { - /// Return builder instance for further manipulation + /// Returns builder instance for further manipulation. pub fn builder(revert_range: RangeInclusive) -> BundleBuilder { BundleBuilder::new(revert_range) } - /// Create it with new and old values of both Storage and AccountInfo. + /// Creates it with new and old values of both Storage and AccountInfo. pub fn new( state: impl IntoIterator< Item = ( Address, Option, Option, - HashMap, + HashMap, ), >, reverts: impl IntoIterator< @@ -296,7 +443,7 @@ impl BundleState { Item = ( Address, Option>, - impl IntoIterator, + impl IntoIterator, ), >, >, @@ -360,18 +507,19 @@ impl BundleState { } /// Returns the approximate size of changes in the bundle state. + /// /// The estimation is not precise, because the information about the number of /// destroyed entries that need to be removed is not accessible to the bundle state. pub fn size_hint(&self) -> usize { self.state_size + self.reverts_size + self.contracts.len() } - /// Return reference to the state. + /// Returns reference to the state. pub fn state(&self) -> &HashMap { &self.state } - /// Is bundle state empty. + /// Checks whether bundle state is empty. pub fn is_empty(&self) -> bool { self.len() == 0 } @@ -381,26 +529,28 @@ impl BundleState { self.state.len() } - /// Get account from state + /// Gets account from state. pub fn account(&self, address: &Address) -> Option<&BundleAccount> { self.state.get(address) } - /// Get bytecode from state + /// Gets bytecode from state. pub fn bytecode(&self, hash: &B256) -> Option { self.contracts.get(hash).cloned() } - /// Consume `TransitionState` by applying the changes and creating the reverts + /// Consumes [`TransitionState`] by applying the changes and creating the + /// reverts. /// - /// If [BundleRetention::includes_reverts] is `true`, then the reverts will be retained. + /// If [BundleRetention::includes_reverts] is `true`, then the reverts will + /// be retained. pub fn apply_transitions_and_create_reverts( &mut self, transitions: TransitionState, retention: BundleRetention, ) { let include_reverts = retention.includes_reverts(); - // pessimistically pre-allocate assuming _all_ accounts changed. + // Pessimistically pre-allocate assuming _all_ accounts changed. let reverts_capacity = if include_reverts { transitions.transitions.len() } else { @@ -409,23 +559,23 @@ impl BundleState { let mut reverts = Vec::with_capacity(reverts_capacity); for (address, transition) in transitions.transitions.into_iter() { - // add new contract if it was created/changed. + // Add new contract if it was created/changed. if let Some((hash, new_bytecode)) = transition.has_new_contract() { self.contracts.insert(hash, new_bytecode.clone()); } - // update state and create revert. + // Update state and create revert. let revert = match self.state.entry(address) { - hash_map::Entry::Occupied(mut entry) => { + Entry::Occupied(mut entry) => { let entry = entry.get_mut(); self.state_size -= entry.size_hint(); - // update and create revert if it is present + // Update and create revert if it is present let revert = entry.update_and_create_revert(transition); - // update the state size + // Update the state size self.state_size += entry.size_hint(); revert } - hash_map::Entry::Vacant(entry) => { - // make revert from transition account + Entry::Vacant(entry) => { + // Make revert from transition account let present_bundle = transition.present_bundle_account(); let revert = transition.create_revert(); if revert.is_some() { @@ -436,7 +586,7 @@ impl BundleState { } }; - // append revert if present. + // Append revert if present. if let Some(revert) = revert.filter(|_| include_reverts) { self.reverts_size += revert.size_hint(); reverts.push((address, revert)); @@ -446,31 +596,32 @@ impl BundleState { self.reverts.push(reverts); } - /// Consume the bundle state and return plain state. - pub fn into_plain_state(self, is_value_known: OriginalValuesKnown) -> StateChangeset { - // pessimistically pre-allocate assuming _all_ accounts changed. + /// Generate a [`StateChangeset`] from the bundle state without consuming + /// it. + pub fn to_plain_state(&self, is_value_known: OriginalValuesKnown) -> StateChangeset { + // Pessimistically pre-allocate assuming _all_ accounts changed. let state_len = self.state.len(); let mut accounts = Vec::with_capacity(state_len); let mut storage = Vec::with_capacity(state_len); - for (address, account) in self.state { - // append account info if it is changed. + for (address, account) in &self.state { + // Append account info if it is changed. let was_destroyed = account.was_destroyed(); if is_value_known.is_not_known() || account.is_info_changed() { - let info = account.info.map(AccountInfo::without_code); - accounts.push((address, info)); + let info = account.info.as_ref().map(AccountInfo::copy_without_code); + accounts.push((*address, info)); } - // append storage changes + // Append storage changes - // NOTE: Assumption is that revert is going to remove whole plain storage from + // Note: Assumption is that revert is going to remove whole plain storage from // database so we can check if plain state was wiped or not. let mut account_storage_changed = Vec::with_capacity(account.storage.len()); - for (key, slot) in account.storage { + for (key, slot) in account.storage.iter().map(|(k, v)| (*k, *v)) { // If storage was destroyed that means that storage was wiped. // In that case we need to check if present storage value is different then ZERO. - let destroyed_and_not_zero = was_destroyed && slot.present_value != U256::ZERO; + let destroyed_and_not_zero = was_destroyed && !slot.present_value.is_zero(); // If account is not destroyed check if original values was changed, // so we can update it. @@ -485,19 +636,21 @@ impl BundleState { } if !account_storage_changed.is_empty() || was_destroyed { - // append storage changes to account. + // Append storage changes to account. storage.push(PlainStorageChangeset { - address, + address: *address, wipe_storage: was_destroyed, storage: account_storage_changed, }); } } + let contracts = self .contracts - .into_iter() - // remove empty bytecodes - .filter(|(b, _)| *b != KECCAK_EMPTY) + .iter() + // Remove empty bytecodes + .filter(|(b, _)| **b != KECCAK_EMPTY) + .map(|(b, code)| (*b, code.clone())) .collect::>(); StateChangeset { accounts, @@ -506,34 +659,52 @@ impl BundleState { } } - /// Consume the bundle state and split it into reverts and plain state. + /// Converts the bundle state into a [`StateChangeset`]. + #[deprecated = "Use `to_plain_state` instead"] + pub fn into_plain_state(self, is_value_known: OriginalValuesKnown) -> StateChangeset { + self.to_plain_state(is_value_known) + } + + /// Generates a [`StateChangeset`] and [`PlainStateReverts`] from the bundle + /// state. + pub fn to_plain_state_and_reverts( + &self, + is_value_known: OriginalValuesKnown, + ) -> (StateChangeset, PlainStateReverts) { + ( + self.to_plain_state(is_value_known), + self.reverts.to_plain_state_reverts(), + ) + } + + /// Consumes the bundle state and split it into a [`StateChangeset`] and a + /// [`PlainStateReverts`]. + #[deprecated = "Use `to_plain_state_and_reverts` instead"] pub fn into_plain_state_and_reverts( - mut self, + self, is_value_known: OriginalValuesKnown, ) -> (StateChangeset, PlainStateReverts) { - let reverts = self.take_all_reverts(); - let plain_state = self.into_plain_state(is_value_known); - (plain_state, reverts.into_plain_state_reverts()) + self.to_plain_state_and_reverts(is_value_known) } - /// Extend the bundle with other state + /// Extends the bundle with other state. /// - /// Update the `other` state only if `other` is not flagged as destroyed. + /// Updates the `other` state only if `other` is not flagged as destroyed. pub fn extend_state(&mut self, other_state: HashMap) { for (address, other_account) in other_state { match self.state.entry(address) { - hash_map::Entry::Occupied(mut entry) => { + Entry::Occupied(mut entry) => { let this = entry.get_mut(); self.state_size -= this.size_hint(); - // if other was destroyed. replace `this` storage with + // If other was destroyed. replace `this` storage with // the `other one. if other_account.was_destroyed() { this.storage = other_account.storage; } else { - // otherwise extend this storage with other + // Otherwise extend this storage with other for (key, storage_slot) in other_account.storage { - // update present value or insert storage slot. + // Update present value or insert storage slot. this.storage .entry(key) .or_insert(storage_slot) @@ -546,24 +717,26 @@ impl BundleState { // Update the state size self.state_size += this.size_hint(); } - hash_map::Entry::Vacant(entry) => { - // just insert if empty + Entry::Vacant(entry) => { + // Just insert if empty self.state_size += other_account.size_hint(); entry.insert(other_account); } } } } - /// Extend the state with state that is build on top of it. + /// Extends the state with state that is build on top of it. /// /// If storage was wiped in `other` state, copy `this` plain state /// and put it inside `other` revert (if there is no duplicates of course). /// /// If `this` and `other` accounts were both destroyed invalidate second - /// wipe flag (from `other`). As wiping from database should be done only once + /// wipe flag (from `other`). + /// + /// As wiping from database should be done only once /// and we already transferred all potentially missing storages to the `other` revert. pub fn extend(&mut self, mut other: Self) { - // iterate over reverts and if its storage is wiped try to add previous bundle + // Iterate over reverts and if its storage is wiped try to add previous bundle // state as there is potential missing slots. for (address, revert) in other.reverts.iter_mut().flatten() { if revert.wipe_storage { @@ -571,7 +744,7 @@ impl BundleState { // we need to move storage from present state. if let Some(this_account) = self.state.get_mut(address) { // As this account was destroyed inside `other` bundle. - // we are fine to wipe/drain this storage and put it inside revert. + // We are fine to wipe/drain this storage and put it inside revert. for (key, value) in this_account.storage.drain() { revert .storage @@ -579,7 +752,7 @@ impl BundleState { .or_insert(RevertToSlot::Some(value.present_value)); } - // nullify `other` wipe as primary database wipe is done in `this`. + // Nullify `other` wipe as primary database wipe is done in `this`. if this_account.was_destroyed() { revert.wipe_storage = false; } @@ -597,9 +770,9 @@ impl BundleState { self.reverts.extend(other.reverts); } - /// Take first N raw reverts from the [BundleState]. + /// Takes first N raw reverts from the [BundleState]. pub fn take_n_reverts(&mut self, reverts_to_take: usize) -> Reverts { - // split is done as [0, num) and [num, len]. + // Split is done as [0, num) and [num, len]. if reverts_to_take > self.reverts.len() { return self.take_all_reverts(); } @@ -613,19 +786,19 @@ impl BundleState { detached_reverts } - /// Return and clear all reverts from [BundleState] + /// Returns and clears all reverts from [BundleState]. pub fn take_all_reverts(&mut self) -> Reverts { self.reverts_size = 0; - core::mem::take(&mut self.reverts) + mem::take(&mut self.reverts) } - /// Reverts the state changes of the latest transition + /// Reverts the state changes of the latest transition. /// - /// Note: This is the same as `BundleState::revert(1)` + /// **Note**: This is the same as `BundleState::revert(1)` /// /// Returns true if the state was reverted. pub fn revert_latest(&mut self) -> bool { - // revert the latest recorded state + // Revert the latest recorded state if let Some(reverts) = self.reverts.pop() { for (address, revert_account) in reverts.into_iter() { self.reverts_size -= revert_account.size_hint(); @@ -640,12 +813,12 @@ impl BundleState { } } Entry::Vacant(entry) => { - // create empty account that we will revert on. + // Create empty account that we will revert on. // Only place where this account is not existing is if revert is DeleteIt. let mut account = BundleAccount::new( None, None, - HashMap::new(), + HashMap::default(), AccountStatus::LoadedNotExisting, ); if !account.revert(revert_account) { @@ -672,24 +845,25 @@ impl BundleState { while self.revert_latest() { num_transitions -= 1; if num_transitions == 0 { - // break the loop. + // Break the loop. break; } } } - /// Prepends present the state with the given BundleState. + /// Prepends present the state with the given [BundleState]. + /// /// It adds changes from the given state but does not override any existing changes. /// /// Reverts are not updated. pub fn prepend_state(&mut self, mut other: BundleState) { - // take this bundle + // Take this bundle let this_bundle = mem::take(self); - // extend other bundle state with this + // Extend other bundle state with this other.extend_state(this_bundle.state); - // extend other contracts + // Extend other contracts other.contracts.extend(this_bundle.contracts); - // swap bundles + // Swap bundles mem::swap(self, &mut other) } } @@ -697,11 +871,12 @@ impl BundleState { #[cfg(test)] mod tests { use super::*; - use crate::{db::StorageWithOriginalValues, TransitionAccount}; + use crate::{StorageWithOriginalValues, TransitionAccount}; + use primitives::U256; #[test] fn transition_states() { - // dummy data + // Dummy data let address = Address::new([0x01; 20]); let acc1 = AccountInfo { balance: U256::from(10), @@ -712,7 +887,7 @@ mod tests { let mut bundle_state = BundleState::default(); - // have transition from loaded to all other states + // Have transition from loaded to all other states let transition = TransitionAccount { info: Some(acc1), @@ -723,7 +898,7 @@ mod tests { storage_was_destroyed: false, }; - // apply first transition + // Apply first transition bundle_state.apply_transitions_and_create_reverts( TransitionState::single(address, transition.clone()), BundleRetention::Reverts, @@ -738,17 +913,17 @@ mod tests { Address::new([0x61; 20]) } - fn slot1() -> U256 { - U256::from(5) + fn slot1() -> StorageKey { + StorageKey::from(5) } - fn slot2() -> U256 { - U256::from(7) + fn slot2() -> StorageKey { + StorageKey::from(7) } - /// Test bundle one + /// Tests bundle one. fn test_bundle1() -> BundleState { - // block changes + // Block changes BundleState::new( vec![ ( @@ -760,9 +935,9 @@ mod tests { code_hash: KECCAK_EMPTY, code: None, }), - HashMap::from([ - (slot1(), (U256::from(0), U256::from(10))), - (slot2(), (U256::from(0), U256::from(15))), + HashMap::from_iter([ + (slot1(), (StorageValue::from(0), StorageValue::from(10))), + (slot2(), (StorageValue::from(0), StorageValue::from(15))), ]), ), ( @@ -774,14 +949,17 @@ mod tests { code_hash: KECCAK_EMPTY, code: None, }), - HashMap::from([]), + HashMap::default(), ), ], vec![vec![ ( account1(), Some(None), - vec![(slot1(), U256::from(0)), (slot2(), U256::from(0))], + vec![ + (slot1(), StorageValue::from(0)), + (slot2(), StorageValue::from(0)), + ], ), (account2(), Some(None), vec![]), ]], @@ -789,9 +967,9 @@ mod tests { ) } - /// Test bundle two + /// Tests bundle two. fn test_bundle2() -> BundleState { - // block changes + // Block changes BundleState::new( vec![( account1(), @@ -802,7 +980,7 @@ mod tests { code_hash: KECCAK_EMPTY, code: None, }), - HashMap::from([(slot1(), (U256::from(0), U256::from(15)))]), + HashMap::from_iter([(slot1(), (StorageValue::from(0), StorageValue::from(15)))]), )], vec![vec![( account1(), @@ -812,13 +990,13 @@ mod tests { code_hash: KECCAK_EMPTY, code: None, })), - vec![(slot1(), U256::from(10))], + vec![(slot1(), StorageValue::from(10))], )]], vec![], ) } - /// Test bundle three + /// Tests bundle three. fn test_bundle3() -> BundleState { BundleState::builder(0..=0) .state_present_account_info( @@ -832,7 +1010,7 @@ mod tests { ) .state_storage( account1(), - HashMap::from([(slot1(), (U256::from(0), U256::from(10)))]), + HashMap::from_iter([(slot1(), (StorageValue::from(0), StorageValue::from(10)))]), ) .state_address(account2()) .state_present_account_info( @@ -846,12 +1024,12 @@ mod tests { ) .revert_address(0, account1()) .revert_account_info(0, account1(), Some(None)) - .revert_storage(0, account1(), vec![(slot1(), U256::from(0))]) + .revert_storage(0, account1(), vec![(slot1(), StorageValue::from(0))]) .revert_account_info(0, account2(), Some(None)) .build() } - /// Test bundle four + /// Tests bundle four. fn test_bundle4() -> BundleState { BundleState::builder(0..=0) .state_present_account_info( @@ -865,7 +1043,7 @@ mod tests { ) .state_storage( account1(), - HashMap::from([(slot1(), (U256::from(0), U256::from(15)))]), + HashMap::from_iter([(slot1(), (StorageValue::from(0), StorageValue::from(15)))]), ) .revert_address(0, account1()) .revert_account_info( @@ -878,7 +1056,7 @@ mod tests { code: None, })), ) - .revert_storage(0, account1(), vec![(slot1(), U256::from(10))]) + .revert_storage(0, account1(), vec![(slot1(), StorageValue::from(10))]) .build() } @@ -887,21 +1065,21 @@ mod tests { extended.extend(bundle2.clone()); let mut reverted = extended.clone(); - // revert zero does nothing. + // Revert zero does nothing. reverted.revert(0); assert_eq!(reverted, extended); - // revert by one gives us bundle one. + // Revert by one gives us bundle one. reverted.revert(1); assert_eq!(reverted, bundle1); - // reverted by additional one gives us empty bundle. + // Reverted by additional one gives us empty bundle. reverted.revert(1); assert_eq!(reverted, BundleState::default()); let mut reverted = extended.clone(); - // reverted by bigger number gives us empty bundle + // Reverted by bigger number gives us empty bundle reverted.revert(10); assert_eq!(reverted, BundleState::default()); } @@ -947,7 +1125,7 @@ mod tests { revert1 .1 .storage - .insert(slot2(), RevertToSlot::Some(U256::from(15))); + .insert(slot2(), RevertToSlot::Some(StorageValue::from(15))); assert_eq!( b1.reverts.as_ref(), @@ -985,17 +1163,17 @@ mod tests { .build(); state.revert_latest(); - // state for account one was deleted + // State for account one was deleted assert_eq!(state.state.get(&account1()), None); state.revert_latest(); - // state is set to + // State is set to assert_eq!( state.state.get(&account1()), Some(&BundleAccount::new( None, Some(AccountInfo::default()), - HashMap::new(), + HashMap::default(), AccountStatus::Changed )) ); @@ -1008,7 +1186,7 @@ mod tests { .revert_address(2, account2()) .revert_account_info(0, account1(), Some(None)) .revert_account_info(2, account2(), None) - .revert_storage(0, account1(), vec![(slot1(), U256::from(10))]) + .revert_storage(0, account1(), vec![(slot1(), StorageValue::from(10))]) .build(); assert_eq!(state.reverts.len(), 4); @@ -1034,27 +1212,27 @@ mod tests { let mut extended = bundle1.clone(); extended.extend(bundle2.clone()); - // check that we have two reverts + // Check that we have two reverts assert_eq!(extended.reverts.len(), 2); - // take all by big N + // Take all by big N let mut extended2 = extended.clone(); assert_eq!(extended2.take_n_reverts(100), extended.reverts); - // take all reverts + // Take all reverts let mut extended2 = extended.clone(); assert_eq!(extended2.take_all_reverts(), extended.reverts); - // take zero revert + // Take zero revert let taken_reverts = extended.take_n_reverts(0); assert_eq!(taken_reverts, Reverts::default()); assert_eq!(extended.reverts.len(), 2); - // take one revert + // Take one revert let taken_reverts = extended.take_n_reverts(1); assert_eq!(taken_reverts, bundle1.reverts); - // take last revert + // Take last revert let taken_reverts = extended.take_n_reverts(1); assert_eq!(taken_reverts, bundle2.reverts); } @@ -1092,14 +1270,78 @@ mod tests { test.prepend_state(previous_state); assert_eq!(test.state.len(), 2); - // reverts num should stay the same. + // Reverts num should stay the same. assert_eq!(test.reverts.len(), 1); - // account1 is not overwritten. + // Account1 is not overwritten. assert_eq!( test.state.get(&address1).unwrap().info, Some(account1_changed) ); - // account2 got inserted + // Account2 got inserted assert_eq!(test.state.get(&address2).unwrap().info, Some(account2)); } + + #[test] + fn test_getters() { + let mut builder = BundleBuilder::new(0..=3); + + // Test get_states and get_states_mut + assert!(builder.get_states().is_empty()); + builder.get_states_mut().insert(account1()); + assert!(builder.get_states().contains(&account1())); + + // Test get_state_original_mut + assert!(builder.get_state_original_mut().is_empty()); + builder + .get_state_original_mut() + .insert(account1(), AccountInfo::default()); + assert!(builder.get_state_original_mut().contains_key(&account1())); + + // Test get_state_present_mut + assert!(builder.get_state_present_mut().is_empty()); + builder + .get_state_present_mut() + .insert(account1(), AccountInfo::default()); + assert!(builder.get_state_present_mut().contains_key(&account1())); + + // Test get_state_storage_mut + assert!(builder.get_state_storage_mut().is_empty()); + builder + .get_state_storage_mut() + .insert(account1(), HashMap::default()); + assert!(builder.get_state_storage_mut().contains_key(&account1())); + + // Test get_reverts_mut + assert!(builder.get_reverts_mut().is_empty()); + builder.get_reverts_mut().insert((0, account1())); + assert!(builder.get_reverts_mut().contains(&(0, account1()))); + + // Test get_revert_range_mut + assert_eq!(builder.get_revert_range_mut().clone(), 0..=3); + + // Test get_revert_account_mut + assert!(builder.get_revert_account_mut().is_empty()); + builder + .get_revert_account_mut() + .insert((0, account1()), Some(None)); + assert!(builder + .get_revert_account_mut() + .contains_key(&(0, account1()))); + + // Test get_revert_storage_mut + assert!(builder.get_revert_storage_mut().is_empty()); + builder + .get_revert_storage_mut() + .insert((0, account1()), vec![(slot1(), StorageValue::from(0))]); + assert!(builder + .get_revert_storage_mut() + .contains_key(&(0, account1()))); + + // Test get_contracts_mut + assert!(builder.get_contracts_mut().is_empty()); + builder + .get_contracts_mut() + .insert(B256::default(), Bytecode::default()); + assert!(builder.get_contracts_mut().contains_key(&B256::default())); + } } diff --git a/crates/revm/src/db/states/cache.rs b/crates/database/src/states/cache.rs similarity index 84% rename from crates/revm/src/db/states/cache.rs rename to crates/database/src/states/cache.rs index 63c0160bab..9105f974cd 100644 --- a/crates/revm/src/db/states/cache.rs +++ b/crates/database/src/states/cache.rs @@ -1,14 +1,16 @@ use super::{ plain_account::PlainStorage, transition_account::TransitionAccount, CacheAccount, PlainAccount, }; -use revm_interpreter::primitives::{ - Account, AccountInfo, Address, Bytecode, EvmState, HashMap, B256, -}; +use bytecode::Bytecode; +use primitives::{Address, HashMap, B256}; +use state::{Account, AccountInfo, EvmState}; use std::vec::Vec; -/// Cache state contains both modified and original values. +/// Cache state contains both modified and original values /// +/// # Note /// Cache state is main state that revm uses to access state. +/// /// It loads all accounts from database and applies revm output to it. /// /// It generates transitions that is used to build BundleState. @@ -16,10 +18,9 @@ use std::vec::Vec; pub struct CacheState { /// Block state account with account state pub accounts: HashMap, - /// created contracts - /// TODO add bytecode counter for number of bytecodes added/removed. + /// Created contracts pub contracts: HashMap, - /// Has EIP-161 state clear enabled (Spurious Dragon hardfork). + /// Has EIP-161 state clear enabled (Spurious Dragon hardfork) pub has_state_clear: bool, } @@ -30,7 +31,7 @@ impl Default for CacheState { } impl CacheState { - /// New default state. + /// Creates a new default state. pub fn new(has_state_clear: bool) -> Self { Self { accounts: HashMap::default(), @@ -39,7 +40,7 @@ impl CacheState { } } - /// Set state clear flag. EIP-161. + /// Sets state clear flag. EIP-161. pub fn set_state_clear_flag(&mut self, has_state_clear: bool) { self.has_state_clear = has_state_clear; } @@ -56,13 +57,13 @@ impl CacheState { }) } - /// Insert not existing account. + /// Inserts not existing account. pub fn insert_not_existing(&mut self, address: Address) { self.accounts .insert(address, CacheAccount::new_loaded_not_existing()); } - /// Insert Loaded (Or LoadedEmptyEip161 if account is empty) account. + /// Inserts Loaded (Or LoadedEmptyEip161 if account is empty) account. pub fn insert_account(&mut self, address: Address, info: AccountInfo) { let account = if !info.is_empty() { CacheAccount::new_loaded(info, HashMap::default()) @@ -87,7 +88,7 @@ impl CacheState { self.accounts.insert(address, account); } - /// Apply output of revm execution and create account transitions that are used to build BundleState. + /// Applies output of revm execution and create account transitions that are used to build BundleState. pub fn apply_evm_state(&mut self, evm_state: EvmState) -> Vec<(Address, TransitionAccount)> { let mut transitions = Vec::with_capacity(evm_state.len()); for (address, account) in evm_state { @@ -98,14 +99,15 @@ impl CacheState { transitions } - /// Apply updated account state to the cached account. + /// Applies updated account state to the cached account. + /// /// Returns account transition if applicable. fn apply_account_state( &mut self, address: Address, account: Account, ) -> Option { - // not touched account are never changed. + // Not touched account are never changed. if !account.is_touched() { return None; } @@ -124,7 +126,7 @@ impl CacheState { let is_created = account.is_created(); let is_empty = account.is_empty(); - // transform evm storage to storage with previous value. + // Transform evm storage to storage with previous value. let changed_storage = account .storage .into_iter() @@ -132,7 +134,7 @@ impl CacheState { .map(|(key, slot)| (key, slot.into())) .collect(); - // Note: it can happen that created contract get selfdestructed in same block + // Note: It can happen that created contract get selfdestructed in same block // that is why is_created is checked after selfdestructed // // Note: Create2 opcode (Petersburg) was after state clear EIP (Spurious Dragon) @@ -150,10 +152,10 @@ impl CacheState { // EIP-161 state clear if is_empty { if self.has_state_clear { - // touch empty account. + // Touch empty account. this_account.touch_empty_eip161() } else { - // if account is empty and state clear is not enabled we should save + // If account is empty and state clear is not enabled we should save // empty account. this_account.touch_create_pre_eip161(changed_storage) } diff --git a/crates/revm/src/db/states/cache_account.rs b/crates/database/src/states/cache_account.rs similarity index 85% rename from crates/revm/src/db/states/cache_account.rs rename to crates/database/src/states/cache_account.rs index 126ce2ffe7..159eb1ad13 100644 --- a/crates/revm/src/db/states/cache_account.rs +++ b/crates/database/src/states/cache_account.rs @@ -2,19 +2,27 @@ use super::{ plain_account::PlainStorage, AccountStatus, BundleAccount, PlainAccount, StorageWithOriginalValues, TransitionAccount, }; -use revm_interpreter::primitives::{AccountInfo, U256}; -use revm_precompile::HashMap; +use primitives::{HashMap, StorageKey, StorageValue, U256}; +use state::AccountInfo; /// Cache account contains plain state that gets updated /// at every transaction when evm output is applied to CacheState. #[derive(Clone, Debug, PartialEq, Eq)] pub struct CacheAccount { + /// Account information and storage, if account exists. pub account: Option, + /// Account status flags. pub status: AccountStatus, } impl From for CacheAccount { fn from(account: BundleAccount) -> Self { + CacheAccount::from(&account) + } +} + +impl From<&BundleAccount> for CacheAccount { + fn from(account: &BundleAccount) -> Self { let storage = account .storage .iter() @@ -31,7 +39,7 @@ impl From for CacheAccount { } impl CacheAccount { - /// Create new account that is loaded from database. + /// Creates new account that is loaded from database. pub fn new_loaded(info: AccountInfo, storage: PlainStorage) -> Self { Self { account: Some(PlainAccount { info, storage }), @@ -39,7 +47,7 @@ impl CacheAccount { } } - /// Create new account that is loaded empty from database. + /// Creates new account that is loaded empty from database. pub fn new_loaded_empty_eip161(storage: PlainStorage) -> Self { Self { account: Some(PlainAccount::new_empty_with_storage(storage)), @@ -55,7 +63,7 @@ impl CacheAccount { } } - /// Create new account that is newly created + /// Creates new account that is newly created. pub fn new_newly_created(info: AccountInfo, storage: PlainStorage) -> Self { Self { account: Some(PlainAccount { info, storage }), @@ -63,7 +71,7 @@ impl CacheAccount { } } - /// Create account that is destroyed. + /// Creates account that is destroyed. pub fn new_destroyed() -> Self { Self { account: None, @@ -71,7 +79,7 @@ impl CacheAccount { } } - /// Create changed account + /// Creates changed account. pub fn new_changed(info: AccountInfo, storage: PlainStorage) -> Self { Self { account: Some(PlainAccount { info, storage }), @@ -79,7 +87,7 @@ impl CacheAccount { } } - /// Return true if account is some + /// Returns true if account is some. pub fn is_some(&self) -> bool { matches!( self.status, @@ -91,19 +99,19 @@ impl CacheAccount { ) } - /// Return storage slot if it exist. - pub fn storage_slot(&self, slot: U256) -> Option { + /// Returns storage slot if it exists. + pub fn storage_slot(&self, slot: StorageKey) -> Option { self.account .as_ref() .and_then(|a| a.storage.get(&slot).cloned()) } - /// Fetch account info if it exist. + /// Fetches account info if it exists. pub fn account_info(&self) -> Option { self.account.as_ref().map(|a| a.info.clone()) } - /// Dissolve account into components. + /// Dissolves account into components. pub fn into_components(self) -> (Option<(AccountInfo, PlainStorage)>, AccountStatus) { (self.account.map(|a| a.into_components()), self.status) } @@ -168,11 +176,11 @@ impl CacheAccount { } } - /// Consume self and make account as destroyed. + /// Consumes self and make account as destroyed. /// - /// Set account as None and set status to Destroyer or DestroyedAgain. + /// Sets account as None and set status to Destroyer or DestroyedAgain. pub fn selfdestruct(&mut self) -> Option { - // account should be None after selfdestruct so we can take it. + // Account should be None after selfdestruct so we can take it. let previous_info = self.account.take().map(|a| a.info); let previous_status = self.status; @@ -186,7 +194,7 @@ impl CacheAccount { status: self.status, previous_info, previous_status, - storage: HashMap::new(), + storage: HashMap::default(), storage_was_destroyed: true, }) } @@ -225,7 +233,7 @@ impl CacheAccount { /// Increment balance by `balance` amount. Assume that balance will not /// overflow or be zero. /// - /// Note: only if balance is zero we would return None as no transition would be made. + /// Note: Only if balance is zero we would return None as no transition would be made. pub fn increment_balance(&mut self, balance: u128) -> Option { if balance == 0 { return None; @@ -259,7 +267,7 @@ impl CacheAccount { status: self.status, previous_info, previous_status, - storage: HashMap::new(), + storage: HashMap::default(), storage_was_destroyed: false, }, ) @@ -276,18 +284,20 @@ impl CacheAccount { }) } + /// Updates the account with new information and storage changes. + /// + /// Merges the provided storage values with the existing storage and updates the account status. pub fn change( &mut self, new: AccountInfo, storage: StorageWithOriginalValues, ) -> TransitionAccount { let previous_status = self.status; - let previous_info = self.account.as_ref().map(|a| a.info.clone()); - let mut this_storage = self - .account - .take() - .map(|acc| acc.storage) - .unwrap_or_default(); + let (previous_info, mut this_storage) = if let Some(account) = self.account.take() { + (Some(account.info), account.storage) + } else { + (None, Default::default()) + }; this_storage.extend(storage.iter().map(|(k, s)| (*k, s.present_value))); let changed_account = PlainAccount { diff --git a/crates/revm/src/db/states/changes.rs b/crates/database/src/states/changes.rs similarity index 54% rename from crates/revm/src/db/states/changes.rs rename to crates/database/src/states/changes.rs index 555ba1e015..860ebb9a26 100644 --- a/crates/revm/src/db/states/changes.rs +++ b/crates/database/src/states/changes.rs @@ -1,12 +1,15 @@ use super::RevertToSlot; -use revm_interpreter::primitives::{AccountInfo, Address, Bytecode, B256, U256}; +use bytecode::Bytecode; +use primitives::{Address, StorageKey, StorageValue, B256}; +use state::AccountInfo; use std::vec::Vec; -/// accounts/storages/contracts for inclusion into database. +/// `accounts`/`storages`/`contracts` for inclusion into database. +/// /// Structure is made so it is easier to apply directly to database -/// that mostly have separate tables to store account/storage/contract data. +/// that mostly have separate tables to store `accounts`/`storages`/`contracts` data. /// -/// Note: that data is **not** sorted. Some database benefit of faster inclusion +/// **Note**: That data is **not** sorted. Some database benefit of faster inclusion /// and smaller footprint if data is inserted in sorted order. #[derive(Clone, Debug, Default)] pub struct StateChangeset { @@ -18,30 +21,35 @@ pub struct StateChangeset { pub contracts: Vec<(B256, Bytecode)>, } -/// Plain storage changeset. Used to apply storage changes of plain state to -/// the database. +/// Plain storage changeset. +/// +/// Used to apply storage changes of plain state to the database. #[derive(Clone, Debug, PartialEq, Eq, Default)] pub struct PlainStorageChangeset { /// Address of account pub address: Address, - /// Wipe storage, + /// Wipe storage pub wipe_storage: bool, - /// Storage key value pairs. - pub storage: Vec<(U256, U256)>, + /// Storage key value pairs + pub storage: Vec<(StorageKey, StorageValue)>, } -/// Plain Storage Revert. Containing old values of changed storage. +/// Plain Storage Revert. +/// +/// [`PlainStorageRevert`] contains old values of changed storage. #[derive(Clone, Debug, PartialEq, Eq, Default)] pub struct PlainStorageRevert { /// Address of account pub address: Address, - /// Is storage wiped in this revert. Wiped flag is set on - /// first known selfdestruct and would require clearing the + /// Whether storage is wiped in this revert + /// + /// **Note**: Wiped flag is set on first known selfdestruct and would require clearing the /// state of this storage from database (And moving it to revert). pub wiped: bool, - /// Contains the storage key and old values of that storage. - /// Reverts are **not** sorted. - pub storage_revert: Vec<(U256, RevertToSlot)>, + /// Contains the storage key and old values of that storage + /// + /// **Note**: Reverts are **not** sorted. + pub storage_revert: Vec<(StorageKey, RevertToSlot)>, } /// Plain state reverts are used to easily store reverts into database. @@ -49,16 +57,16 @@ pub struct PlainStorageRevert { /// Note that accounts are assumed **not** sorted. #[derive(Clone, Debug, Default)] pub struct PlainStateReverts { - /// Vector of account with removed contracts bytecode + /// Vector of account with removed contracts bytecode. /// - /// Note: If AccountInfo is None means that account needs to be removed. + /// **Note**: If AccountInfo is None means that account needs to be removed. pub accounts: Vec)>>, /// Vector of storage with its address. pub storage: Vec>, } impl PlainStateReverts { - /// Constructs new [PlainStateReverts] with pre-allocated capacity. + /// Constructs new [`PlainStateReverts`] with pre-allocated capacity. pub fn with_capacity(capacity: usize) -> Self { Self { accounts: Vec::with_capacity(capacity), @@ -68,4 +76,4 @@ impl PlainStateReverts { } /// Storage reverts -pub type StorageRevert = Vec)>>; +pub type StorageRevert = Vec)>>; diff --git a/crates/revm/src/db/states/plain_account.rs b/crates/database/src/states/plain_account.rs similarity index 71% rename from crates/revm/src/db/states/plain_account.rs rename to crates/database/src/states/plain_account.rs index 5aadfcc073..1dfa8aa5ba 100644 --- a/crates/revm/src/db/states/plain_account.rs +++ b/crates/database/src/states/plain_account.rs @@ -1,13 +1,17 @@ -use crate::primitives::{AccountInfo, EvmStorageSlot, HashMap, U256}; +use primitives::{HashMap, StorageKey, StorageValue}; +use state::{AccountInfo, EvmStorageSlot}; -// TODO rename this to BundleAccount. As for the block level we have original state. +/// Plain account of StateDatabase. #[derive(Clone, Debug, Default, PartialEq, Eq)] pub struct PlainAccount { + /// Account information. pub info: AccountInfo, + /// Account storage. pub storage: PlainStorage, } impl PlainAccount { + /// Creates a new empty account with the given storage. pub fn new_empty_with_storage(storage: PlainStorage) -> Self { Self { info: AccountInfo::default(), @@ -15,13 +19,14 @@ impl PlainAccount { } } + /// Consumes the account and returns its components. pub fn into_components(self) -> (AccountInfo, PlainStorage) { (self.info, self.storage) } } /// This type keeps track of the current value of a storage slot. -#[derive(Debug, Clone, Default, PartialEq, Eq, Hash)] +#[derive(Debug, Copy, Clone, Default, PartialEq, Eq, Hash)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct StorageSlot { /// The value of the storage slot before it was changed. @@ -29,9 +34,9 @@ pub struct StorageSlot { /// When the slot is first loaded, this is the original value. /// /// If the slot was not changed, this is equal to the present value. - pub previous_or_original_value: U256, + pub previous_or_original_value: StorageValue, /// When loaded with sload present value is set to original value - pub present_value: U256, + pub present_value: StorageValue, } impl From for StorageSlot { @@ -42,7 +47,7 @@ impl From for StorageSlot { impl StorageSlot { /// Creates a new _unchanged_ `StorageSlot` for the given value. - pub fn new(original: U256) -> Self { + pub fn new(original: StorageValue) -> Self { Self { previous_or_original_value: original, present_value: original, @@ -50,7 +55,10 @@ impl StorageSlot { } /// Creates a new _changed_ `StorageSlot`. - pub fn new_changed(previous_or_original_value: U256, present_value: U256) -> Self { + pub fn new_changed( + previous_or_original_value: StorageValue, + present_value: StorageValue, + ) -> Self { Self { previous_or_original_value, present_value, @@ -63,12 +71,12 @@ impl StorageSlot { } /// Returns the original value of the storage slot. - pub fn original_value(&self) -> U256 { + pub fn original_value(&self) -> StorageValue { self.previous_or_original_value } /// Returns the current value of the storage slot. - pub fn present_value(&self) -> U256 { + pub fn present_value(&self) -> StorageValue { self.present_value } } @@ -76,17 +84,17 @@ impl StorageSlot { /// This storage represent values that are before block changed. /// /// Note: Storage that we get EVM contains original values before block changed. -pub type StorageWithOriginalValues = HashMap; +pub type StorageWithOriginalValues = HashMap; /// Simple plain storage that does not have previous value. /// This is used for loading from database, cache and for bundle state. -pub type PlainStorage = HashMap; +pub type PlainStorage = HashMap; impl From for PlainAccount { fn from(info: AccountInfo) -> Self { Self { info, - storage: HashMap::new(), + storage: HashMap::default(), } } } diff --git a/crates/revm/src/db/states/reverts.rs b/crates/database/src/states/reverts.rs similarity index 50% rename from crates/revm/src/db/states/reverts.rs rename to crates/database/src/states/reverts.rs index 5be2c932fd..4b8d989d3f 100644 --- a/crates/revm/src/db/states/reverts.rs +++ b/crates/database/src/states/reverts.rs @@ -2,12 +2,17 @@ use super::{ changes::PlainStorageRevert, AccountStatus, BundleAccount, PlainStateReverts, StorageWithOriginalValues, }; -use core::ops::{Deref, DerefMut}; -use revm_interpreter::primitives::{AccountInfo, Address, HashMap, U256}; +use core::{ + cmp::Ordering, + ops::{Deref, DerefMut}, +}; +use primitives::{Address, HashMap, StorageKey, StorageValue}; +use state::AccountInfo; use std::vec::Vec; /// Contains reverts of multiple account in multiple transitions (Transitions as a block). -#[derive(Clone, Debug, Default, PartialEq, Eq)] +#[derive(Clone, Debug, Default, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Reverts(Vec>); impl Deref for Reverts { @@ -25,43 +30,51 @@ impl DerefMut for Reverts { } impl Reverts { - /// Create new reverts + /// Creates new reverts. pub fn new(reverts: Vec>) -> Self { Self(reverts) } - /// Sort account inside transition by their address. + /// Sorts account inside transition by their address. pub fn sort(&mut self) { for revert in &mut self.0 { revert.sort_by_key(|(address, _)| *address); } } - /// Extend reverts with other reverts. + /// Extends reverts with other reverts. pub fn extend(&mut self, other: Reverts) { self.0.extend(other.0); } - /// Consume reverts and create plain state reverts. + /// Generates a [`PlainStateReverts`]. /// /// Note that account are sorted by address. - pub fn into_plain_state_reverts(mut self) -> PlainStateReverts { + pub fn to_plain_state_reverts(&self) -> PlainStateReverts { let mut state_reverts = PlainStateReverts::with_capacity(self.0.len()); - for reverts in self.0.drain(..) { - // pessimistically pre-allocate assuming _all_ accounts changed. + for reverts in &self.0 { + // Pessimistically pre-allocate assuming _all_ accounts changed. let mut accounts = Vec::with_capacity(reverts.len()); let mut storage = Vec::with_capacity(reverts.len()); - for (address, revert_account) in reverts.into_iter() { - match revert_account.account { - AccountInfoRevert::RevertTo(acc) => accounts.push((address, Some(acc))), - AccountInfoRevert::DeleteIt => accounts.push((address, None)), + for (address, revert_account) in reverts { + match &revert_account.account { + AccountInfoRevert::RevertTo(acc) => { + // Cloning is cheap, because account info has 3 small + // fields and a Bytes + accounts.push((*address, Some(acc.clone()))) + } + AccountInfoRevert::DeleteIt => accounts.push((*address, None)), AccountInfoRevert::DoNothing => (), } if revert_account.wipe_storage || !revert_account.storage.is_empty() { storage.push(PlainStorageRevert { - address, + address: *address, wiped: revert_account.wipe_storage, - storage_revert: revert_account.storage.into_iter().collect::>(), + storage_revert: revert_account + .storage + .iter() + .map(|(k, v)| (*k, *v)) + .collect::>(), }); } } @@ -70,31 +83,84 @@ impl Reverts { } state_reverts } + + /// Compare two Reverts instances, ignoring the order of elements + pub fn content_eq(&self, other: &Self) -> bool { + if self.0.len() != other.0.len() { + return false; + } + + for (self_transition, other_transition) in self.0.iter().zip(other.0.iter()) { + if self_transition.len() != other_transition.len() { + return false; + } + + let mut self_transition = self_transition.clone(); + let mut other_transition = other_transition.clone(); + // Sort both transitions + self_transition.sort_by(|(addr1, revert1), (addr2, revert2)| { + addr1.cmp(addr2).then_with(|| revert1.cmp(revert2)) + }); + other_transition.sort_by(|(addr1, revert1), (addr2, revert2)| { + addr1.cmp(addr2).then_with(|| revert1.cmp(revert2)) + }); + + // Compare sorted transitions + if self_transition != other_transition { + return false; + } + } + + true + } + + /// Consume reverts and create [`PlainStateReverts`]. + /// + /// Note that account are sorted by address. + #[deprecated = "Use `to_plain_state_reverts` instead"] + pub fn into_plain_state_reverts(self) -> PlainStateReverts { + self.to_plain_state_reverts() + } +} + +impl PartialEq for Reverts { + fn eq(&self, other: &Self) -> bool { + self.content_eq(other) + } } /// Assumption is that Revert can return full state from any future state to any past state. /// +/// # Note /// It is created when new account state is applied to old account state. +/// /// And it is used to revert new account state to the old account state. /// -/// AccountRevert is structured in this way as we need to save it inside database. +/// [AccountRevert] is structured in this way as we need to save it inside database. +/// /// And we need to be able to read it from database. #[derive(Clone, Default, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct AccountRevert { + /// Account information revert. pub account: AccountInfoRevert, - pub storage: HashMap, + /// Storage slots to revert. + pub storage: HashMap, + /// Previous account status before the change. pub previous_status: AccountStatus, + /// Whether to wipe the storage. pub wipe_storage: bool, } impl AccountRevert { /// The approximate size of changes needed to store this account revert. + /// /// `1 + storage_reverts_len` pub fn size_hint(&self) -> usize { 1 + self.storage.len() } - /// Very similar to new_selfdestructed but it will add additional zeros (RevertToSlot::Destroyed) + /// Very similar to new_selfdestructed but it will add additional zeros ([RevertToSlot::Destroyed]) /// for the storage that are set if account is again created. pub fn new_selfdestructed_again( status: AccountStatus, @@ -104,7 +170,7 @@ impl AccountRevert { ) -> Self { // Take present storage values as the storages that we are going to revert to. // As those values got destroyed. - let mut previous_storage: HashMap = previous_storage + let mut previous_storage: HashMap = previous_storage .drain() .map(|(key, value)| (key, RevertToSlot::Some(value.present_value))) .collect(); @@ -121,7 +187,7 @@ impl AccountRevert { } } - /// Create revert for states that were before selfdestruct. + /// Creates revert for states that were before selfdestruct. pub fn new_selfdestructed_from_bundle( account_info_revert: AccountInfoRevert, bundle_account: &mut BundleAccount, @@ -155,7 +221,7 @@ impl AccountRevert { let previous_storage = storage .iter_mut() .map(|(key, value)| { - // take previous value and set ZERO as storage got destroyed. + // Take previous value and set ZERO as storage got destroyed. (*key, RevertToSlot::Some(value.present_value)) }) .collect(); @@ -179,9 +245,56 @@ impl AccountRevert { } } +/// Implements partial ordering for AccountRevert +impl PartialOrd for AccountRevert { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +/// Implements total ordering for AccountRevert +impl Ord for AccountRevert { + fn cmp(&self, other: &Self) -> Ordering { + // First compare accounts + if let Some(ord) = self.account.partial_cmp(&other.account) { + if ord != Ordering::Equal { + return ord; + } + } + + // Convert HashMaps to sorted vectors for comparison + let mut self_storage: Vec<_> = self.storage.iter().collect(); + let mut other_storage: Vec<_> = other.storage.iter().collect(); + + // Sort by key and then by value + self_storage.sort_by(|(k1, v1), (k2, v2)| k1.cmp(k2).then_with(|| v1.cmp(v2))); + other_storage.sort_by(|(k1, v1), (k2, v2)| k1.cmp(k2).then_with(|| v1.cmp(v2))); + + // Compare each element + for (self_entry, other_entry) in self_storage.iter().zip(other_storage.iter()) { + let key_ord = self_entry.0.cmp(other_entry.0); + if key_ord != Ordering::Equal { + return key_ord; + } + let value_ord = self_entry.1.cmp(other_entry.1); + if value_ord != Ordering::Equal { + return value_ord; + } + } + + // If one vector is longer than the other, or if all elements are equal + self_storage + .len() + .cmp(&other_storage.len()) + .then_with(|| self.previous_status.cmp(&other.previous_status)) + .then_with(|| self.wipe_storage.cmp(&other.wipe_storage)) + } +} + /// Depending on previous state of account info this /// will tell us what to do on revert. -#[derive(Clone, Default, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Default, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum AccountInfoRevert { #[default] /// Nothing changed @@ -197,19 +310,25 @@ pub enum AccountInfoRevert { /// * Value, on revert set this value /// * Destroyed, should be removed on revert but on Revert set it as zero. /// -/// Note: It is completely different state if Storage is Zero or Some or if Storage was -/// Destroyed. Because if it is destroyed, previous values can be found in database or it can be zero. -#[derive(Clone, Debug, Copy, PartialEq, Eq, Hash)] +/// **Note**: It is completely different state if Storage is Zero or Some or if Storage was +/// Destroyed. +/// +/// Because if it is destroyed, previous values can be found in database or it can be zero. +#[derive(Clone, Debug, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum RevertToSlot { - Some(U256), + /// Revert to this value. + Some(StorageValue), + /// Storage was destroyed. Destroyed, } impl RevertToSlot { - pub fn to_previous_value(self) -> U256 { + /// Returns the previous value to set on revert. + pub fn to_previous_value(self) -> StorageValue { match self { RevertToSlot::Some(value) => value, - RevertToSlot::Destroyed => U256::ZERO, + RevertToSlot::Destroyed => StorageValue::ZERO, } } } diff --git a/crates/revm/src/db/states/state.rs b/crates/database/src/states/state.rs similarity index 72% rename from crates/revm/src/db/states/state.rs rename to crates/database/src/states/state.rs index 2b63b7abd4..fa623cc014 100644 --- a/crates/revm/src/db/states/state.rs +++ b/crates/database/src/states/state.rs @@ -2,58 +2,65 @@ use super::{ bundle_state::BundleRetention, cache::CacheState, plain_account::PlainStorage, BundleState, CacheAccount, StateBuilder, TransitionAccount, TransitionState, }; -use crate::db::EmptyDB; -use revm_interpreter::primitives::{ - db::{Database, DatabaseCommit}, - hash_map, Account, AccountInfo, Address, Bytecode, HashMap, B256, BLOCK_HASH_HISTORY, U256, -}; +use bytecode::Bytecode; +use database_interface::{Database, DatabaseCommit, DatabaseRef, EmptyDB}; +use primitives::{hash_map, Address, HashMap, StorageKey, StorageValue, B256, BLOCK_HASH_HISTORY}; +use state::{Account, AccountInfo}; use std::{ boxed::Box, collections::{btree_map, BTreeMap}, vec::Vec, }; -/// Database boxed with a lifetime and Send. +/// Database boxed with a lifetime and Send pub type DBBox<'a, E> = Box + Send + 'a>; -/// More constrained version of State that uses Boxed database with a lifetime. +/// More constrained version of State that uses Boxed database with a lifetime /// /// This is used to make it easier to use State. pub type StateDBBox<'a, E> = State>; -/// State of blockchain. +/// State of blockchain /// /// State clear flag is set inside CacheState and by default it is enabled. +/// /// If you want to disable it use `set_state_clear_flag` function. #[derive(Debug)] pub struct State { /// Cached state contains both changed from evm execution and cached/loaded account/storages - /// from database. This allows us to have only one layer of cache where we can fetch data. - /// Additionally we can introduce some preloading of data from database. + /// from database + /// + /// This allows us to have only one layer of cache where we can fetch data. + /// + /// Additionally, we can introduce some preloading of data from database. pub cache: CacheState, - /// Optional database that we use to fetch data from. If database is not present, we will - /// return not existing account and storage. + /// Optional database that we use to fetch data from /// - /// Note: It is marked as Send so database can be shared between threads. + /// If database is not present, we will return not existing account and storage. + /// + /// **Note**: It is marked as Send so database can be shared between threads. pub database: DB, - /// Block state, it aggregates transactions transitions into one state. + /// Block state, it aggregates transactions transitions into one state /// /// Build reverts and state that gets applied to the state. pub transition_state: Option, - /// After block is finishes we merge those changes inside bundle. + /// After block is finishes we merge those changes inside bundle + /// /// Bundle is used to update database and create changesets. + /// /// Bundle state can be set on initialization if we want to use preloaded bundle. pub bundle_state: BundleState, /// Addition layer that is going to be used to fetched values before fetching values - /// from database. + /// from database /// /// Bundle is the main output of the state execution and this allows setting previous bundle /// and using its values for execution. pub use_preloaded_bundle: bool, - /// If EVM asks for block hash we will first check if they are found here. - /// and then ask the database. + /// If EVM asks for block hash, we will first check if they are found here, + /// then ask the database + /// + /// This map can be used to give different values for block hashes if in case. /// - /// This map can be used to give different values for block hashes if in case /// The fork block is different or some blocks are not saved inside database. pub block_hashes: BTreeMap, } @@ -68,24 +75,24 @@ impl State { impl State { /// Returns the size hint for the inner bundle state. + /// /// See [BundleState::size_hint] for more info. pub fn bundle_size_hint(&self) -> usize { self.bundle_state.size_hint() } - /// Iterate over received balances and increment all account balances. - /// If account is not found inside cache state it will be loaded from database. + /// Iterates over received balances and increment all account balances. + /// + /// **Note**: If account is not found inside cache state it will be loaded from database. /// /// Update will create transitions for all accounts that are updated. /// - /// Like [CacheAccount::increment_balance], this assumes that incremented balances are not - /// zero, and will not overflow once incremented. If using this to implement withdrawals, zero - /// balances must be filtered out before calling this function. + /// If using this to implement withdrawals, zero balances must be filtered out before calling this function. pub fn increment_balances( &mut self, balances: impl IntoIterator, ) -> Result<(), DB::Error> { - // make transition and update cache state + // Make transition and update cache state let mut transitions = Vec::new(); for (address, balance) in balances { if balance == 0 { @@ -99,21 +106,21 @@ impl State { .expect("Balance is not zero"), )) } - // append transition + // Append transition if let Some(s) = self.transition_state.as_mut() { s.add_transitions(transitions) } Ok(()) } - /// Drain balances from given account and return those values. + /// Drains balances from given account and return those values. /// /// It is used for DAO hardfork state change to move values from given accounts. pub fn drain_balances( &mut self, addresses: impl IntoIterator, ) -> Result, DB::Error> { - // make transition and update cache state + // Make transition and update cache state let mut transitions = Vec::new(); let mut balances = Vec::new(); for address in addresses { @@ -122,7 +129,7 @@ impl State { balances.push(balance); transitions.push((address, transition)) } - // append transition + // Append transition if let Some(s) = self.transition_state.as_mut() { s.add_transitions(transitions) } @@ -134,14 +141,17 @@ impl State { self.cache.set_state_clear_flag(has_state_clear); } + /// Inserts a non-existing account into the state. pub fn insert_not_existing(&mut self, address: Address) { self.cache.insert_not_existing(address) } + /// Inserts an account into the state. pub fn insert_account(&mut self, address: Address, info: AccountInfo) { self.cache.insert_account(address, info) } + /// Inserts an account with storage into the state. pub fn insert_account_with_storage( &mut self, address: Address, @@ -152,15 +162,16 @@ impl State { .insert_account_with_storage(address, info, storage) } - /// Apply evm transitions to transition state. + /// Applies evm transitions to transition state. pub fn apply_transition(&mut self, transitions: Vec<(Address, TransitionAccount)>) { - // add transition to transition state. + // Add transition to transition state. if let Some(s) = self.transition_state.as_mut() { s.add_transitions(transitions) } } /// Take all transitions and merge them inside bundle state. + /// /// This action will create final post state and all reverts so that /// we at any time revert state of bundle to the state before transition /// is applied. @@ -171,25 +182,27 @@ impl State { } } + /// Get a mutable reference to the [`CacheAccount`] for the given address. + /// + /// If the account is not found in the cache, it will be loaded from the + /// database and inserted into the cache. pub fn load_cache_account(&mut self, address: Address) -> Result<&mut CacheAccount, DB::Error> { match self.cache.accounts.entry(address) { hash_map::Entry::Vacant(entry) => { if self.use_preloaded_bundle { - // load account from bundle state - if let Some(account) = - self.bundle_state.account(&address).cloned().map(Into::into) - { + // Load account from bundle state + if let Some(account) = self.bundle_state.account(&address).map(Into::into) { return Ok(entry.insert(account)); } } - // if not found in bundle, load it from database + // If not found in bundle, load it from database let info = self.database.basic(address)?; let account = match info { None => CacheAccount::new_loaded_not_existing(), Some(acc) if acc.is_empty() => { - CacheAccount::new_loaded_empty_eip161(HashMap::new()) + CacheAccount::new_loaded_empty_eip161(HashMap::default()) } - Some(acc) => CacheAccount::new_loaded(acc, HashMap::new()), + Some(acc) => CacheAccount::new_loaded(acc, HashMap::default()), }; Ok(entry.insert(account)) } @@ -197,16 +210,17 @@ impl State { } } - // TODO make cache aware of transitions dropping by having global transition counter. - /// Takes changeset and reverts from state and replaces it with empty one. - /// This will trop pending Transition and any transitions would be lost. + // TODO : Make cache aware of transitions dropping by having global transition counter. + /// Takess the [`BundleState`] changeset from the [`State`], replacing it + /// with an empty one. + /// + /// This will not apply any pending [`TransitionState`]. /// - /// NOTE: If either: - /// * The [State] has not been built with [StateBuilder::with_bundle_update], or - /// * The [State] has a [TransitionState] set to `None` when - /// [State::merge_transitions] is called, + /// It is recommended to call [`State::merge_transitions`] before taking the bundle. /// - /// this will panic. + /// If the `State` has been built with the + /// [`StateBuilder::with_bundle_prestate`] option, the pre-state will be + /// taken along with any changes made by [`State::merge_transitions`]. pub fn take_bundle(&mut self) -> BundleState { core::mem::take(&mut self.bundle_state) } @@ -229,7 +243,7 @@ impl Database for State { return Ok(code.clone()); } } - // if not found in bundle ask database + // If not found in bundle ask database let code = self.database.code_by_hash(code_hash)?; entry.insert(code.clone()); Ok(code) @@ -238,11 +252,15 @@ impl Database for State { res } - fn storage(&mut self, address: Address, index: U256) -> Result { + fn storage( + &mut self, + address: Address, + index: StorageKey, + ) -> Result { // Account is guaranteed to be loaded. // Note that storage from bundle is already loaded with account. if let Some(account) = self.cache.accounts.get_mut(&address) { - // account will always be some, but if it is not, U256::ZERO will be returned. + // Account will always be some, but if it is not, StorageValue::ZERO will be returned. let is_storage_known = account.status.is_storage_known(); Ok(account .account @@ -250,10 +268,10 @@ impl Database for State { .map(|account| match account.storage.entry(index) { hash_map::Entry::Occupied(entry) => Ok(*entry.get()), hash_map::Entry::Vacant(entry) => { - // if account was destroyed or account is newly built + // If account was destroyed or account is newly built // we return zero and don't ask database. let value = if is_storage_known { - U256::ZERO + StorageValue::ZERO } else { self.database.storage(address, index)? }; @@ -268,16 +286,14 @@ impl Database for State { } } - fn block_hash(&mut self, number: U256) -> Result { - // block number is never bigger then u64::MAX. - let u64num: u64 = number.to(); - match self.block_hashes.entry(u64num) { + fn block_hash(&mut self, number: u64) -> Result { + match self.block_hashes.entry(number) { btree_map::Entry::Occupied(entry) => Ok(*entry.get()), btree_map::Entry::Vacant(entry) => { let ret = *entry.insert(self.database.block_hash(number)?); - // prune all hashes that are older then BLOCK_HASH_HISTORY - let last_block = u64num.saturating_sub(BLOCK_HASH_HISTORY as u64); + // Prune all hashes that are older than BLOCK_HASH_HISTORY + let last_block = number.saturating_sub(BLOCK_HASH_HISTORY); while let Some(entry) = self.block_hashes.first_entry() { if *entry.key() < last_block { entry.remove(); @@ -290,6 +306,15 @@ impl Database for State { } } } + + fn salt_bucket_capacity( + &self, + address: Address, + index: Option, + ) -> Result<(usize, u64), Self::Error> { + // For salt storage, we don't have it in cache, so we directly get it from database. + self.database.salt_bucket_capacity(address, index) + } } impl DatabaseCommit for State { @@ -299,22 +324,96 @@ impl DatabaseCommit for State { } } +impl DatabaseRef for State { + type Error = DB::Error; + + fn basic_ref(&self, address: Address) -> Result, Self::Error> { + // Account is already in cache + if let Some(account) = self.cache.accounts.get(&address) { + return Ok(account.account_info()); + } + // If bundle state is used, check if account is in bundle state + if self.use_preloaded_bundle { + if let Some(account) = self.bundle_state.account(&address) { + return Ok(account.account_info()); + } + } + // If not found, load it from database + self.database.basic_ref(address) + } + + fn code_by_hash_ref(&self, code_hash: B256) -> Result { + // Check if code is in cache + if let Some(code) = self.cache.contracts.get(&code_hash) { + return Ok(code.clone()); + } + // If bundle state is used, check if code is in bundle state + if self.use_preloaded_bundle { + if let Some(code) = self.bundle_state.contracts.get(&code_hash) { + return Ok(code.clone()); + } + } + // If not found, load it from database + self.database.code_by_hash_ref(code_hash) + } + + fn storage_ref( + &self, + address: Address, + index: StorageKey, + ) -> Result { + // Check if account is in cache, the account is not guaranteed to be loaded + if let Some(account) = self.cache.accounts.get(&address) { + if let Some(plain_account) = &account.account { + // If storage is known, we can return it + if let Some(storage_value) = plain_account.storage.get(&index) { + return Ok(*storage_value); + } + // If account was destroyed or account is newly built + // we return zero and don't ask database. + if account.status.is_storage_known() { + return Ok(StorageValue::ZERO); + } + } + } + // If not found, load it from database + self.database.storage_ref(address, index) + } + + fn block_hash_ref(&self, number: u64) -> Result { + if let Some(entry) = self.block_hashes.get(&number) { + return Ok(*entry); + } + // If not found, load it from database + self.database.block_hash_ref(number) + } + + fn salt_bucket_capacity_ref( + &self, + address: Address, + index: Option, + ) -> Result<(usize, u64), Self::Error> { + // For salt storage, we don't have it in cache, so we directly get it from database. + self.database.salt_bucket_capacity_ref(address, index) + } +} + #[cfg(test)] mod tests { use super::*; - use crate::db::{ + use crate::{ states::{reverts::AccountInfoRevert, StorageSlot}, AccountRevert, AccountStatus, BundleAccount, RevertToSlot, }; - use revm_interpreter::primitives::keccak256; + use primitives::{keccak256, U256}; #[test] fn block_hash_cache() { let mut state = State::builder().build(); - state.block_hash(U256::from(1)).unwrap(); - state.block_hash(U256::from(2)).unwrap(); + state.block_hash(1u64).unwrap(); + state.block_hash(2u64).unwrap(); - let test_number = BLOCK_HASH_HISTORY as u64 + 2; + let test_number = BLOCK_HASH_HISTORY + 2; let block1_hash = keccak256(U256::from(1).to_string().as_bytes()); let block2_hash = keccak256(U256::from(2).to_string().as_bytes()); @@ -325,7 +424,7 @@ mod tests { BTreeMap::from([(1, block1_hash), (2, block2_hash)]) ); - state.block_hash(U256::from(test_number)).unwrap(); + state.block_hash(test_number).unwrap(); assert_eq!( state.block_hashes, BTreeMap::from([(test_number, block_test_hash), (2, block2_hash)]) @@ -342,7 +441,11 @@ mod tests { fn reverts_preserve_old_values() { let mut state = State::builder().with_bundle_update().build(); - let (slot1, slot2, slot3) = (U256::from(1), U256::from(2), U256::from(3)); + let (slot1, slot2, slot3) = ( + StorageKey::from(1), + StorageKey::from(2), + StorageKey::from(3), + ); // Non-existing account for testing account state transitions. // [LoadedNotExisting] -> [Changed] (nonce: 1, balance: 1) -> [Changed] (nonce: 2) -> [Changed] (nonce: 3) @@ -367,9 +470,9 @@ mod tests { nonce: 1, ..Default::default() }; - let existing_account_initial_storage = HashMap::::from([ - (slot1, U256::from(100)), // 0x01 => 100 - (slot2, U256::from(200)), // 0x02 => 200 + let existing_account_initial_storage = HashMap::::from_iter([ + (slot1, StorageValue::from(100)), // 0x01 => 100 + (slot2, StorageValue::from(200)), // 0x02 => 200 ]); let existing_account_changed_info = AccountInfo { nonce: 2, @@ -395,11 +498,11 @@ mod tests { info: Some(existing_account_changed_info.clone()), previous_status: AccountStatus::Loaded, previous_info: Some(existing_account_initial_info.clone()), - storage: HashMap::from([( + storage: HashMap::from_iter([( slot1, StorageSlot::new_changed( *existing_account_initial_storage.get(&slot1).unwrap(), - U256::from(1000), + StorageValue::from(1000), ), )]), storage_was_destroyed: false, @@ -428,9 +531,9 @@ mod tests { info: Some(new_account_changed_info2.clone()), previous_status: AccountStatus::InMemoryChange, previous_info: Some(new_account_changed_info), - storage: HashMap::from([( + storage: HashMap::from_iter([( slot1, - StorageSlot::new_changed(U256::ZERO, U256::from(1)), + StorageSlot::new_changed(StorageValue::ZERO, StorageValue::from(1)), )]), storage_was_destroyed: false, }, @@ -442,22 +545,25 @@ mod tests { info: Some(existing_account_changed_info.clone()), previous_status: AccountStatus::InMemoryChange, previous_info: Some(existing_account_changed_info.clone()), - storage: HashMap::from([ + storage: HashMap::from_iter([ ( slot1, - StorageSlot::new_changed(U256::from(100), U256::from(1_000)), + StorageSlot::new_changed( + StorageValue::from(100), + StorageValue::from(1_000), + ), ), ( slot2, StorageSlot::new_changed( *existing_account_initial_storage.get(&slot2).unwrap(), - U256::from(2_000), + StorageValue::from(2_000), ), ), // Create new slot ( slot3, - StorageSlot::new_changed(U256::ZERO, U256::from(3_000)), + StorageSlot::new_changed(StorageValue::ZERO, StorageValue::from(3_000)), ), ]), storage_was_destroyed: false, @@ -479,7 +585,10 @@ mod tests { AccountRevert { account: AccountInfoRevert::DeleteIt, previous_status: AccountStatus::LoadedNotExisting, - storage: HashMap::from([(slot1, RevertToSlot::Some(U256::ZERO))]), + storage: HashMap::from_iter([( + slot1, + RevertToSlot::Some(StorageValue::ZERO) + )]), wipe_storage: false, } ), @@ -488,7 +597,7 @@ mod tests { AccountRevert { account: AccountInfoRevert::RevertTo(existing_account_initial_info.clone()), previous_status: AccountStatus::Loaded, - storage: HashMap::from([ + storage: HashMap::from_iter([ ( slot1, RevertToSlot::Some( @@ -501,7 +610,7 @@ mod tests { *existing_account_initial_storage.get(&slot2).unwrap() ) ), - (slot3, RevertToSlot::Some(U256::ZERO)) + (slot3, RevertToSlot::Some(StorageValue::ZERO)) ]), wipe_storage: false, } @@ -518,9 +627,9 @@ mod tests { info: Some(new_account_changed_info2), original_info: None, status: AccountStatus::InMemoryChange, - storage: HashMap::from([( + storage: HashMap::from_iter([( slot1, - StorageSlot::new_changed(U256::ZERO, U256::from(1)) + StorageSlot::new_changed(StorageValue::ZERO, StorageValue::from(1)) )]), }), "The latest state of the new account is incorrect" @@ -534,25 +643,25 @@ mod tests { info: Some(existing_account_changed_info), original_info: Some(existing_account_initial_info), status: AccountStatus::InMemoryChange, - storage: HashMap::from([ + storage: HashMap::from_iter([ ( slot1, StorageSlot::new_changed( *existing_account_initial_storage.get(&slot1).unwrap(), - U256::from(1_000) + StorageValue::from(1_000) ) ), ( slot2, StorageSlot::new_changed( *existing_account_initial_storage.get(&slot2).unwrap(), - U256::from(2_000) + StorageValue::from(2_000) ) ), // Create new slot ( slot3, - StorageSlot::new_changed(U256::ZERO, U256::from(3_000)) + StorageSlot::new_changed(StorageValue::ZERO, StorageValue::from(3_000)) ), ]), }), @@ -587,7 +696,7 @@ mod tests { }; // Existing account with storage. - let (slot1, slot2) = (U256::from(1), U256::from(2)); + let (slot1, slot2) = (StorageKey::from(1), StorageKey::from(2)); let existing_account_with_storage_address = Address::from_slice(&[0x3; 20]); let existing_account_with_storage_info = AccountInfo { nonce: 1, @@ -622,12 +731,15 @@ mod tests { info: Some(existing_account_with_storage_info.clone()), previous_status: AccountStatus::Loaded, previous_info: Some(existing_account_with_storage_info.clone()), - storage: HashMap::from([ + storage: HashMap::from_iter([ ( slot1, - StorageSlot::new_changed(U256::from(1), U256::from(10)), + StorageSlot::new_changed(StorageValue::from(1), StorageValue::from(10)), + ), + ( + slot2, + StorageSlot::new_changed(StorageValue::ZERO, StorageValue::from(20)), ), - (slot2, StorageSlot::new_changed(U256::ZERO, U256::from(20))), ]), storage_was_destroyed: false, }, @@ -663,12 +775,15 @@ mod tests { info: Some(existing_account_with_storage_info.clone()), previous_status: AccountStatus::Changed, previous_info: Some(existing_account_with_storage_info.clone()), - storage: HashMap::from([ + storage: HashMap::from_iter([ ( slot1, - StorageSlot::new_changed(U256::from(10), U256::from(1)), + StorageSlot::new_changed(StorageValue::from(10), StorageValue::from(1)), + ), + ( + slot2, + StorageSlot::new_changed(StorageValue::from(20), StorageValue::ZERO), ), - (slot2, StorageSlot::new_changed(U256::from(20), U256::ZERO)), ]), storage_was_destroyed: false, }, @@ -697,7 +812,7 @@ mod tests { ..Default::default() }; - let (slot1, slot2) = (U256::from(1), U256::from(2)); + let (slot1, slot2) = (StorageKey::from(1), StorageKey::from(2)); // Existing account is destroyed. state.apply_transition(Vec::from([( @@ -720,9 +835,9 @@ mod tests { info: Some(existing_account_info.clone()), previous_status: AccountStatus::Destroyed, previous_info: None, - storage: HashMap::from([( + storage: HashMap::from_iter([( slot1, - StorageSlot::new_changed(U256::ZERO, U256::from(1)), + StorageSlot::new_changed(StorageValue::ZERO, StorageValue::from(1)), )]), storage_was_destroyed: false, }, @@ -750,9 +865,9 @@ mod tests { info: Some(existing_account_info.clone()), previous_status: AccountStatus::DestroyedAgain, previous_info: None, - storage: HashMap::from([( + storage: HashMap::from_iter([( slot2, - StorageSlot::new_changed(U256::ZERO, U256::from(2)), + StorageSlot::new_changed(StorageValue::ZERO, StorageValue::from(2)), )]), storage_was_destroyed: false, }, @@ -764,14 +879,14 @@ mod tests { assert_eq!( bundle_state.state, - HashMap::from([( + HashMap::from_iter([( existing_account_address, BundleAccount { info: Some(existing_account_info.clone()), original_info: Some(existing_account_info.clone()), - storage: HashMap::from([( + storage: HashMap::from_iter([( slot2, - StorageSlot::new_changed(U256::ZERO, U256::from(2)) + StorageSlot::new_changed(StorageValue::ZERO, StorageValue::from(2)) )]), status: AccountStatus::DestroyedChanged, } @@ -785,7 +900,7 @@ mod tests { AccountRevert { account: AccountInfoRevert::DoNothing, previous_status: AccountStatus::Loaded, - storage: HashMap::from([(slot2, RevertToSlot::Destroyed)]), + storage: HashMap::from_iter([(slot2, RevertToSlot::Destroyed)]), wipe_storage: true, } )])]) diff --git a/crates/revm/src/db/states/state_builder.rs b/crates/database/src/states/state_builder.rs similarity index 80% rename from crates/revm/src/db/states/state_builder.rs rename to crates/database/src/states/state_builder.rs index f029ae13d4..c2047d490c 100644 --- a/crates/revm/src/db/states/state_builder.rs +++ b/crates/database/src/states/state_builder.rs @@ -1,37 +1,38 @@ use super::{cache::CacheState, state::DBBox, BundleState, State, TransitionState}; -use crate::db::EmptyDB; -use revm_interpreter::primitives::{ - db::{Database, DatabaseRef, WrapDatabaseRef}, - B256, -}; +use database_interface::{DBErrorMarker, Database, DatabaseRef, EmptyDB, WrapDatabaseRef}; +use primitives::B256; use std::collections::BTreeMap; /// Allows building of State and initializing it with different options. #[derive(Clone, Debug, PartialEq, Eq)] pub struct StateBuilder { - /// Database that we use to fetch data from. + /// Database that we use to fetch data from database: DB, - /// Enabled state clear flag that is introduced in Spurious Dragon hardfork. + /// Enabled state clear flag that is introduced in Spurious Dragon hardfork + /// /// Default is true as spurious dragon happened long time ago. with_state_clear: bool, - /// if there is prestate that we want to use. - /// This would mean that we have additional state layer between evm and disk/database. + /// If there is prestate that we want to use, + /// this would mean that we have additional state layer between evm and disk/database. with_bundle_prestate: Option, /// This will initialize cache to this state. with_cache_prestate: Option, - /// Do we want to create reverts and update bundle state. + /// Do we want to create reverts and update bundle state? + /// /// Default is false. with_bundle_update: bool, - /// Do we want to merge transitions in background. - /// This will allows evm to continue executing. + /// Do we want to merge transitions in background? + /// + /// This will allow evm to continue executing. + /// /// Default is false. with_background_transition_merge: bool, - /// If we want to set different block hashes + /// If we want to set different block hashes, with_block_hashes: BTreeMap, } impl StateBuilder { - /// Create a new builder with an empty database. + /// Creates a new builder with an empty database. /// /// If you want to instantiate it with a specific database, use /// [`new_with_database`](Self::new_with_database). @@ -62,8 +63,8 @@ impl StateBuilder { /// Set the database. pub fn with_database(self, database: ODB) -> StateBuilder { - // cast to the different database, - // Note that we return different type depending of the database NewDBError. + // Cast to the different database. + // Note that we return different type depending on the database NewDBError. StateBuilder { with_state_clear: self.with_state_clear, database, @@ -84,7 +85,7 @@ impl StateBuilder { } /// With boxed version of database. - pub fn with_database_boxed( + pub fn with_database_boxed( self, database: DBBox<'_, Error>, ) -> StateBuilder> { @@ -101,8 +102,11 @@ impl StateBuilder { } /// Allows setting prestate that is going to be used for execution. + /// + /// # Note /// This bundle state will act as additional layer of cache. - /// and State after not finding data inside StateCache will try to find it inside BundleState. + /// + /// And State after not finding data inside StateCache will try to find it inside BundleState. /// /// On update Bundle state will be changed and updated. pub fn with_bundle_prestate(self, bundle: BundleState) -> Self { @@ -112,7 +116,7 @@ impl StateBuilder { } } - /// Make transitions and update bundle state. + /// Makes transitions and update bundle state. /// /// This is needed option if we want to create reverts /// and getting output of changed states. @@ -123,8 +127,11 @@ impl StateBuilder { } } - /// It will use different cache for the state. If set, it will ignore bundle prestate. - /// and will ignore `without_state_clear` flag as cache contains its own state_clear flag. + /// It will use different cache for the state. + /// + /// **Note**: If set, it will ignore bundle prestate. + /// + /// And will ignore `without_state_clear` flag as cache contains its own state_clear flag. /// /// This is useful for testing. pub fn with_cached_prestate(self, cache: CacheState) -> Self { @@ -143,6 +150,7 @@ impl StateBuilder { } } + /// Sets the block hashes for the state. pub fn with_block_hashes(self, block_hashes: BTreeMap) -> Self { Self { with_block_hashes: block_hashes, @@ -150,6 +158,7 @@ impl StateBuilder { } } + /// Builds the State with the configured settings. pub fn build(mut self) -> State { let use_preloaded_bundle = if self.with_cache_prestate.is_some() { self.with_bundle_prestate = None; diff --git a/crates/revm/src/db/states/transition_account.rs b/crates/database/src/states/transition_account.rs similarity index 81% rename from crates/revm/src/db/states/transition_account.rs rename to crates/database/src/states/transition_account.rs index 599bc290b0..0ab8389b24 100644 --- a/crates/revm/src/db/states/transition_account.rs +++ b/crates/database/src/states/transition_account.rs @@ -1,6 +1,7 @@ -use super::{AccountRevert, BundleAccount, StorageWithOriginalValues}; -use crate::db::AccountStatus; -use revm_interpreter::primitives::{hash_map, AccountInfo, Bytecode, B256, I256, U256}; +use super::{AccountRevert, AccountStatus, BundleAccount, StorageWithOriginalValues}; +use bytecode::Bytecode; +use primitives::{hash_map, B256, U256}; +use state::AccountInfo; /// Account Created when EVM state is merged to cache state. /// And it is sent to Block state. @@ -9,7 +10,9 @@ use revm_interpreter::primitives::{hash_map, AccountInfo, Bytecode, B256, I256, /// create needed Reverts. #[derive(Clone, Debug, PartialEq, Eq, Default)] pub struct TransitionAccount { + /// Account information, if account exists. pub info: Option, + /// Current account status. pub status: AccountStatus, /// Previous account info is needed for account that got initially loaded. /// Initially loaded account are not present inside bundle and are needed @@ -69,26 +72,13 @@ impl TransitionAccount { .unwrap_or_default() } - /// Calculate the change in account's balance for this transition. - /// Returns `None` if delta does not fit in [I256]. - pub fn balance_delta(&self) -> Option { - let previous_balance = self.previous_balance(); - let current_balance = self.current_balance(); - let delta = I256::try_from(previous_balance.abs_diff(current_balance)).ok()?; - if current_balance >= previous_balance { - Some(delta) - } else { - delta.checked_neg() - } - } - /// Update new values of transition. Don't override old values. /// Both account info and old storages need to be left intact. pub fn update(&mut self, other: Self) { - self.info.clone_from(&other.info); + self.info = other.info; self.status = other.status; - // if transition is from some to destroyed drop the storage. + // If transition is from some to destroyed drop the storage. // This need to be done here as it is one increment of the state. if matches!( other.status, @@ -97,7 +87,7 @@ impl TransitionAccount { self.storage = other.storage; self.storage_was_destroyed = true; } else { - // update changed values to this transition. + // Update changed values to this transition. for (key, slot) in other.storage.into_iter() { match self.storage.entry(key) { hash_map::Entry::Vacant(entry) => { @@ -105,11 +95,11 @@ impl TransitionAccount { } hash_map::Entry::Occupied(mut entry) => { let value = entry.get_mut(); - // if new value is same as original value. Remove storage entry. + // If new value is same as original value. Remove storage entry. if value.original_value() == slot.present_value() { entry.remove(); } else { - // if value is different, update transition present value; + // If value is different, update transition present value; value.present_value = slot.present_value; } } @@ -139,7 +129,7 @@ impl TransitionAccount { BundleAccount { info: self.previous_info.clone(), original_info: self.previous_info.clone(), - storage: StorageWithOriginalValues::new(), + storage: StorageWithOriginalValues::default(), status: self.previous_status, } } diff --git a/crates/revm/src/db/states/transition_state.rs b/crates/database/src/states/transition_state.rs similarity index 63% rename from crates/revm/src/db/states/transition_state.rs rename to crates/database/src/states/transition_state.rs index 4e3ba16847..a021f34534 100644 --- a/crates/revm/src/db/states/transition_state.rs +++ b/crates/database/src/states/transition_state.rs @@ -1,7 +1,8 @@ use super::TransitionAccount; -use revm_interpreter::primitives::{hash_map::Entry, Address, HashMap}; +use primitives::{hash_map::Entry, Address, HashMap}; use std::vec::Vec; +/// State of accounts in transition between transaction executions. #[derive(Clone, Default, Debug, PartialEq, Eq)] pub struct TransitionState { /// Block state account with account state @@ -9,18 +10,25 @@ pub struct TransitionState { } impl TransitionState { - /// Create new transition state with one transition. + /// Create new transition state containing one [`TransitionAccount`]. pub fn single(address: Address, transition: TransitionAccount) -> Self { - let mut transitions = HashMap::new(); + let mut transitions = HashMap::default(); transitions.insert(address, transition); TransitionState { transitions } } - /// Return transition id and all account transitions. Leave empty transition map. + /// Take the contents of this [`TransitionState`] and replace it with an + /// empty one. + /// + /// See [core::mem::take]. pub fn take(&mut self) -> TransitionState { core::mem::take(self) } + /// Add transitions to the transition state. + /// + /// This will insert new [`TransitionAccount`]s, or update existing ones via + /// [`update`][TransitionAccount::update]. pub fn add_transitions(&mut self, transitions: Vec<(Address, TransitionAccount)>) { for (address, account) in transitions { match self.transitions.entry(address) { diff --git a/crates/handler/CHANGELOG.md b/crates/handler/CHANGELOG.md new file mode 100644 index 0000000000..19ce478016 --- /dev/null +++ b/crates/handler/CHANGELOG.md @@ -0,0 +1,351 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + + +## [8.1.0](https://github.com/bluealloy/revm/compare/revm-handler-v8.0.3...revm-handler-v8.1.0) - 2025-07-23 + +### Added + +- add a way for precompiles to revert ([#2711](https://github.com/bluealloy/revm/pull/2711)) + +### Fixed + +- fully deprecate serde-json ([#2767](https://github.com/bluealloy/revm/pull/2767)) +- system call should have 30M gas limit ([#2755](https://github.com/bluealloy/revm/pull/2755)) +- gas deduction with `disable_balance_check` ([#2699](https://github.com/bluealloy/revm/pull/2699)) + +### Other + +- change gas parameter to immutable reference ([#2702](https://github.com/bluealloy/revm/pull/2702)) +- remove State bound from JournalTr in Handler::Evm ([#2715](https://github.com/bluealloy/revm/pull/2715)) + +## [8.0.3](https://github.com/bluealloy/revm/compare/revm-handler-v8.0.2...revm-handler-v8.0.3) - 2025-07-14 + +### Other + +- simplify gas calculations by introducing a used() method ([#2703](https://github.com/bluealloy/revm/pull/2703)) + +## [8.0.2](https://github.com/bluealloy/revm/compare/revm-handler-v8.0.1...revm-handler-v8.0.2) - 2025-07-03 + +### Other + +- document external state transitions for EIP-4788 and EIP-2935 ([#2678](https://github.com/bluealloy/revm/pull/2678)) +- minor fixes ([#2686](https://github.com/bluealloy/revm/pull/2686)) +- fix in pre_execution.rs about nonce bump for CREATE ([#2684](https://github.com/bluealloy/revm/pull/2684)) + +## [8.0.1](https://github.com/bluealloy/revm/compare/revm-handler-v7.0.1...revm-handler-v8.0.1) - 2025-06-30 + +### Added + +- optional_eip3541 ([#2661](https://github.com/bluealloy/revm/pull/2661)) + +### Other + +- cargo clippy --fix --all ([#2671](https://github.com/bluealloy/revm/pull/2671)) +- use TxEnv::builder ([#2652](https://github.com/bluealloy/revm/pull/2652)) +- fix copy-pasted inner doc comments ([#2663](https://github.com/bluealloy/revm/pull/2663)) + +## [7.0.1](https://github.com/bluealloy/revm/compare/revm-handler-v7.0.0...revm-handler-v7.0.1) - 2025-06-20 + +### Fixed + +- call stack_frame.clear() at end ([#2656](https://github.com/bluealloy/revm/pull/2656)) + +## [7.0.0](https://github.com/bluealloy/revm/compare/revm-handler-v6.0.0...revm-handler-v7.0.0) - 2025-06-19 + +### Added + +- remove EOF ([#2644](https://github.com/bluealloy/revm/pull/2644)) +- configurable contract size limit ([#2611](https://github.com/bluealloy/revm/pull/2611)) ([#2642](https://github.com/bluealloy/revm/pull/2642)) +- *(precompile)* rug/gmp-based modexp ([#2596](https://github.com/bluealloy/revm/pull/2596)) +- change blob_max_count to max_blobs_per_tx ([#2608](https://github.com/bluealloy/revm/pull/2608)) +- add optional priority fee check configuration ([#2588](https://github.com/bluealloy/revm/pull/2588)) + +### Other + +- lints handler inspector interpreter ([#2646](https://github.com/bluealloy/revm/pull/2646)) +- bump all deps ([#2647](https://github.com/bluealloy/revm/pull/2647)) +- re-use frame allocation ([#2636](https://github.com/bluealloy/revm/pull/2636)) +- store coinbase address separately to avoid cloning warm addresses in the common case ([#2634](https://github.com/bluealloy/revm/pull/2634)) +- rename `transact` methods ([#2616](https://github.com/bluealloy/revm/pull/2616)) + +## [6.0.0](https://github.com/bluealloy/revm/compare/revm-handler-v5.0.1...revm-handler-v6.0.0) - 2025-06-06 + +### Added + +- add with_caller for system_transact ([#2587](https://github.com/bluealloy/revm/pull/2587)) +- *(Osaka)* EIP-7825 tx limit cap ([#2575](https://github.com/bluealloy/revm/pull/2575)) +- expand timestamp/block_number to u256 ([#2546](https://github.com/bluealloy/revm/pull/2546)) +- transact multi tx ([#2517](https://github.com/bluealloy/revm/pull/2517)) + +### Other + +- tag v75 revm v24.0.1 ([#2563](https://github.com/bluealloy/revm/pull/2563)) ([#2589](https://github.com/bluealloy/revm/pull/2589)) +- *(docs)* add lints to database-interface and op-revm crates ([#2568](https://github.com/bluealloy/revm/pull/2568)) +- unify calling of journal account loading ([#2561](https://github.com/bluealloy/revm/pull/2561)) +- ContextTr rm *_ref, and add *_mut fn ([#2560](https://github.com/bluealloy/revm/pull/2560)) +- *(cfg)* add tx_chain_id_check fields. Optimize effective gas cost calc ([#2557](https://github.com/bluealloy/revm/pull/2557)) +- simplify Interpreter loop ([#2544](https://github.com/bluealloy/revm/pull/2544)) + +## [5.0.1](https://github.com/bluealloy/revm/compare/revm-handler-v5.0.0...revm-handler-v5.0.1) - 2025-05-31 + +### Other + +- unify calling of journal account loading + +## [5.0.0](https://github.com/bluealloy/revm/compare/revm-handler-v4.1.0...revm-handler-v5.0.0) - 2025-05-22 + +### Added + +- make blob max number optional ([#2532](https://github.com/bluealloy/revm/pull/2532)) + +### Other + +- add TxEnvBuilder::build_fill ([#2536](https://github.com/bluealloy/revm/pull/2536)) +- make crates.io version badge clickable ([#2526](https://github.com/bluealloy/revm/pull/2526)) +- fix clippy ([#2523](https://github.com/bluealloy/revm/pull/2523)) +- Storage Types Alias ([#2461](https://github.com/bluealloy/revm/pull/2461)) + + +## [4.1.0](https://github.com/bluealloy/revm/compare/revm-handler-v4.0.0...revm-handler-v4.1.0) - 2025-05-07 + +Dependency bump + +## [4.0.0](https://github.com/bluealloy/revm/compare/revm-handler-v3.0.1...revm-handler-v4.0.0) - 2025-05-07 + +### Added + +- system_call switch order of inputs, address than bytes ([#2485](https://github.com/bluealloy/revm/pull/2485)) +- *(Osaka)* disable EOF ([#2480](https://github.com/bluealloy/revm/pull/2480)) +- skip cloning of call input from shared memory ([#2462](https://github.com/bluealloy/revm/pull/2462)) +- Add a custom address to the CreateScheme. ([#2464](https://github.com/bluealloy/revm/pull/2464)) +- remove spec id verification on `apply_eip7702_auth_list` ([#2466](https://github.com/bluealloy/revm/pull/2466)) +- *(Handler)* merge state validation with deduct_caller ([#2460](https://github.com/bluealloy/revm/pull/2460)) +- replace input Bytes and refactored code where required ([#2453](https://github.com/bluealloy/revm/pull/2453)) +- *(tx)* Add Either RecoveredAuthorization ([#2448](https://github.com/bluealloy/revm/pull/2448)) +- *(EOF)* Changes needed for devnet-1 ([#2377](https://github.com/bluealloy/revm/pull/2377)) +- Move SharedMemory buffer to context ([#2382](https://github.com/bluealloy/revm/pull/2382)) + +### Fixed + +- *(eof)* extdelegate bytecode check after eip7702 load ([#2417](https://github.com/bluealloy/revm/pull/2417)) +- skip account list for legacy ([#2400](https://github.com/bluealloy/revm/pull/2400)) + +### Other + +- Add clones to FrameData ([#2482](https://github.com/bluealloy/revm/pull/2482)) +- Add Bytecode address to Interpreter ([#2479](https://github.com/bluealloy/revm/pull/2479)) +- copy edit The Book ([#2463](https://github.com/bluealloy/revm/pull/2463)) +- bump dependency version ([#2431](https://github.com/bluealloy/revm/pull/2431)) +- fixed broken link ([#2421](https://github.com/bluealloy/revm/pull/2421)) +- backport from release branch ([#2415](https://github.com/bluealloy/revm/pull/2415)) ([#2416](https://github.com/bluealloy/revm/pull/2416)) +- *(lints)* revm-context lints ([#2404](https://github.com/bluealloy/revm/pull/2404)) + +## [3.0.0](https://github.com/bluealloy/revm/compare/revm-handler-v2.0.0...revm-handler-v3.0.0) - 2025-04-09 + +### Added + +- support for system calls ([#2350](https://github.com/bluealloy/revm/pull/2350)) + +### Other + +- make blob params u64 ([#2385](https://github.com/bluealloy/revm/pull/2385)) +- add 0x prefix to b256! and address! calls ([#2345](https://github.com/bluealloy/revm/pull/2345)) + +## [2.0.0](https://github.com/bluealloy/revm/compare/revm-handler-v1.0.0...revm-handler-v2.0.0) - 2025-03-28 + +### Added + +- cache precompile warming ([#2317](https://github.com/bluealloy/revm/pull/2317)) +- provide more context to precompiles ([#2318](https://github.com/bluealloy/revm/pull/2318)) +- Add JournalInner ([#2311](https://github.com/bluealloy/revm/pull/2311)) + +### Fixed + +- broken disable balance check ([#2286](https://github.com/bluealloy/revm/pull/2286)) + +### Other + +- remove outdated TODO comments ([#2325](https://github.com/bluealloy/revm/pull/2325)) +- add EIP-170 contract code size limit tests ([#2312](https://github.com/bluealloy/revm/pull/2312)) +- Remove LATEST variant from SpecId enum ([#2299](https://github.com/bluealloy/revm/pull/2299)) +- add unit test for EIP-3860 initcode size limit ([#2302](https://github.com/bluealloy/revm/pull/2302)) + +## [1.0.0](https://github.com/bluealloy/revm/compare/revm-handler-v1.0.0-alpha.7...revm-handler-v1.0.0) - 2025-03-24 + +### Other + +- updated the following local packages: revm-database, revm-precompile + +## [1.0.0-alpha.7](https://github.com/bluealloy/revm/compare/revm-handler-v1.0.0-alpha.6...revm-handler-v1.0.0-alpha.7) - 2025-03-21 + +### Added + +- Remove PrecompileError from PrecompileProvider ([#2233](https://github.com/bluealloy/revm/pull/2233)) +- allow reuse of API for calculating initial tx gas for tx ([#2215](https://github.com/bluealloy/revm/pull/2215)) + +### Other + +- remove wrong `&mut` and duplicated spec ([#2276](https://github.com/bluealloy/revm/pull/2276)) +- Add custom instruction example ([#2261](https://github.com/bluealloy/revm/pull/2261)) +- use AccessListItem associated type instead of AccessList ([#2214](https://github.com/bluealloy/revm/pull/2214)) + +## [1.0.0-alpha.6](https://github.com/bluealloy/revm/compare/revm-handler-v1.0.0-alpha.5...revm-handler-v1.0.0-alpha.6) - 2025-03-16 + +### Added + +- *(docs)* MyEvm example and book cleanup ([#2218](https://github.com/bluealloy/revm/pull/2218)) + +## [1.0.0-alpha.5](https://github.com/bluealloy/revm/compare/revm-handler-v1.0.0-alpha.4...revm-handler-v1.0.0-alpha.5) - 2025-03-12 + +### Added + +- add custom error to context ([#2197](https://github.com/bluealloy/revm/pull/2197)) +- Add tx/block to EvmExecution trait ([#2195](https://github.com/bluealloy/revm/pull/2195)) + +### Other + +- add debug to precompiles type ([#2193](https://github.com/bluealloy/revm/pull/2193)) + +## [1.0.0-alpha.4](https://github.com/bluealloy/revm/compare/revm-handler-v1.0.0-alpha.3...revm-handler-v1.0.0-alpha.4) - 2025-03-11 + +### Added + +- decouple first_frame_input from inspector ([#2180](https://github.com/bluealloy/revm/pull/2180)) + +### Fixed + +- *(op)* fix inspection call ([#2184](https://github.com/bluealloy/revm/pull/2184)) +- correct propagate features ([#2177](https://github.com/bluealloy/revm/pull/2177)) + +### Other + +- Add comments to handler methods ([#2188](https://github.com/bluealloy/revm/pull/2188)) +- remove CTX phantomdata from precompile providers ([#2178](https://github.com/bluealloy/revm/pull/2178)) + +## [1.0.0-alpha.3](https://github.com/bluealloy/revm/compare/revm-handler-v1.0.0-alpha.2...revm-handler-v1.0.0-alpha.3) - 2025-03-10 + +### Other + +- updated the following local packages: revm-interpreter, revm-precompile + +## [1.0.0-alpha.2](https://github.com/bluealloy/revm/compare/revm-handler-v1.0.0-alpha.1...revm-handler-v1.0.0-alpha.2) - 2025-03-10 + +### Added + +- *(handler)* add MainnetContext alias generic over Database ([#2166](https://github.com/bluealloy/revm/pull/2166)) +- remove specification crate ([#2165](https://github.com/bluealloy/revm/pull/2165)) + +### Fixed + +- *(op)* Handler deposit tx halt, catch_error handle ([#2144](https://github.com/bluealloy/revm/pull/2144)) +- call clear ([#2091](https://github.com/bluealloy/revm/pull/2091)) + +### Other + +- op-revm cleanup and few docs ([#2156](https://github.com/bluealloy/revm/pull/2156)) +- JournalTr, JournalOutput, op only using revm crate ([#2155](https://github.com/bluealloy/revm/pull/2155)) +- rename transact_previous to replay, move EvmTr traits ([#2153](https://github.com/bluealloy/revm/pull/2153)) +- docs and cleanup (rm Custom Inst) ([#2151](https://github.com/bluealloy/revm/pull/2151)) +- move mainnet builder to handler crate ([#2138](https://github.com/bluealloy/revm/pull/2138)) +- add immutable gas API to LoopControl ([#2134](https://github.com/bluealloy/revm/pull/2134)) +- PrecompileErrors to PrecompileError ([#2103](https://github.com/bluealloy/revm/pull/2103)) +- re-export all crates from `revm` ([#2088](https://github.com/bluealloy/revm/pull/2088)) + +## [1.0.0-alpha.1](https://github.com/bluealloy/revm/releases/tag/revm-handler-v1.0.0-alpha.1) - 2025-02-16 + +### Added + +- Split Inspector trait from EthHandler into standalone crate (#2075) +- Introduce Auth and AccessList traits (#2079) +- Evm structure (Cached Instructions and Precompiles) (#2049) +- Add essential EIP-7756 tracing fields (#2023) +- Context execution (#2013) +- EthHandler trait (#2001) +- *(EIP-7623)* adjuct floor gas check order (main) (#1991) +- *(EIP-7840)* Add blob schedule to execution client cfg (#1980) +- *(eip7702)* apply latest EIP-7702 changes, backport from v52 (#1969) +- *(EIP-7623)* Increase calldata cost. backport from rel/v51 (#1965) +- simplify Transaction trait (#1959) +- align Block trait (#1957) +- expose precompile address in Journal, DB::Error: StdError (#1956) +- Make Ctx journal generic (#1933) +- removed create address collision check (#1928) +- Restucturing Part7 Handler and Context rework (#1865) +- *(examples)* generate block traces (#895) +- implement EIP-4844 (#668) +- *(Shanghai)* All EIPs: push0, warm coinbase, limit/measure initcode (#376) +- Migrate `primitive_types::U256` to `ruint::Uint<256, 4>` (#239) +- Introduce ByteCode format, Update Readme (#156) + +### Fixed + +- *(Inspector)* call handler functions (#2026) +- deduplicate validate_initial_tx_gas API (#2006) +- *(eof)* dont run precompile on ext delegate call (#1964) +- fix typos ([#620](https://github.com/bluealloy/revm/pull/620)) + +### Other + +- set alpha.1 version +- backport op l1 fetch perf (#2076) +- relax trait req in EthPrecompiles::default (#2071) +- add default generics for InterpreterTypes (#2070) +- API cleanup (#2067) +- Add helpers with_inspector with_precompile (#2063) +- Add bytecode hash in interpreter [#1888](https://github.com/bluealloy/revm/pull/1888) ([#1952](https://github.com/bluealloy/revm/pull/1952)) +- Make inspector use generics, rm associated types (#1934) +- fix comments and docs into more sensible (#1920) +- Rename PRAGUE_EOF to OSAKA (#1903) +- Bump new logo (#1735) +- *(README)* add rbuilder to used-by (#1585) +- added simular to used-by (#1521) +- add Trin to used by list (#1393) +- Fix typo in readme ([#1185](https://github.com/bluealloy/revm/pull/1185)) +- Add Hardhat to the "Used by" list ([#1164](https://github.com/bluealloy/revm/pull/1164)) +- Add VERBS to used by list ([#1141](https://github.com/bluealloy/revm/pull/1141)) +- license date and revm docs (#1080) +- *(docs)* Update the benchmark docs to point to revm package (#906) +- *(docs)* Update top-level benchmark docs (#894) +- clang requirement (#784) +- Readme Updates (#756) +- Logo (#743) +- book workflow ([#537](https://github.com/bluealloy/revm/pull/537)) +- add example to revm crate ([#468](https://github.com/bluealloy/revm/pull/468)) +- Update README.md ([#424](https://github.com/bluealloy/revm/pull/424)) +- add no_std to primitives ([#366](https://github.com/bluealloy/revm/pull/366)) +- revm-precompiles to revm-precompile +- Bump v20, changelog ([#350](https://github.com/bluealloy/revm/pull/350)) +- typos (#232) +- Add support for old forks. ([#191](https://github.com/bluealloy/revm/pull/191)) +- revm bump 1.8. update libs. snailtracer rename ([#159](https://github.com/bluealloy/revm/pull/159)) +- typo fixes +- fix readme typo +- Big Refactor. Machine to Interpreter. refactor instructions. call/create struct ([#52](https://github.com/bluealloy/revm/pull/52)) +- readme. debuger update +- Bump revm v0.3.0. README updated +- readme +- Add time elapsed for tests +- readme updated +- Include Basefee into cost calc. readme change +- Initialize precompile accounts +- Status update. Taking a break +- Merkle calc. Tweaks and debugging for eip158 +- Replace aurora bn lib with parity's. All Bn128Add/Mul/Pair tests passes +- TEMP +- one tab removed +- readme +- README Example simplified +- Gas calculation for Call/Create. Example Added +- readme usage +- README changes +- Static gas cost added +- Subroutine changelogs and reverts +- Readme postulates +- Spelling +- Restructure project +- First iteration. Machine is looking okay diff --git a/crates/handler/Cargo.toml b/crates/handler/Cargo.toml new file mode 100644 index 0000000000..eb5a2a201f --- /dev/null +++ b/crates/handler/Cargo.toml @@ -0,0 +1,76 @@ +[package] +name = "revm-handler" +description = "Revm handler crates" +version = "8.1.0" +authors.workspace = true +edition.workspace = true +keywords.workspace = true +license.workspace = true +repository.workspace = true +readme.workspace = true + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] + +[lints] +workspace = true + +[dependencies] +# revm +database-interface.workspace = true +interpreter.workspace = true +precompile.workspace = true +context-interface.workspace = true +context.workspace = true +primitives.workspace = true +state.workspace = true +bytecode.workspace = true + +auto_impl.workspace = true +derive-where.workspace = true + +# Optional +serde = { version = "1.0", default-features = false, features = [ + "derive", + "rc", +], optional = true } + +[dev-dependencies] +database.workspace = true +alloy-eip7702.workspace = true +alloy-provider.workspace = true +alloy-signer.workspace = true +alloy-signer-local.workspace = true + +[features] +default = ["std"] +std = [ + "serde?/std", + "alloy-eip7702/std", + "bytecode/std", + "context/std", + "context-interface/std", + "database/std", + "database-interface/std", + "interpreter/std", + "precompile/std", + "primitives/std", + "state/std", +] +serde = [ + "dep:serde", + "primitives/serde", + "state/serde", + "context-interface/serde", + "alloy-eip7702/serde", + "bytecode/serde", + "context/serde", + "database/serde", + "database-interface/serde", + "interpreter/serde", + "derive-where/serde", +] + +# Deprecated, please use `serde` feature instead. +serde-json = ["serde"] diff --git a/crates/handler/LICENSE b/crates/handler/LICENSE new file mode 100644 index 0000000000..be6d350ebe --- /dev/null +++ b/crates/handler/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021-2025 draganrakita + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/crates/handler/src/api.rs b/crates/handler/src/api.rs new file mode 100644 index 0000000000..020d03e4df --- /dev/null +++ b/crates/handler/src/api.rs @@ -0,0 +1,214 @@ +use crate::{ + frame::EthFrame, instructions::InstructionProvider, Handler, MainnetHandler, PrecompileProvider, +}; +use context::{ + result::{ + EVMError, ExecResultAndState, ExecutionResult, HaltReason, InvalidTransaction, + ResultAndState, ResultVecAndState, + }, + Block, ContextSetters, ContextTr, Database, Evm, JournalTr, Transaction, +}; +use database_interface::DatabaseCommit; +use interpreter::{interpreter::EthInterpreter, InterpreterResult}; +use state::EvmState; +use std::vec::Vec; + +/// Execute EVM transactions. Main trait for transaction execution. +pub trait ExecuteEvm { + /// Output of transaction execution. + type ExecutionResult; + /// Output state type representing changes after execution. + type State; + /// Error type + type Error; + /// Transaction type. + type Tx: Transaction; + /// Block type. + type Block: Block; + + /// Set the block. + fn set_block(&mut self, block: Self::Block); + + /// Execute transaction and store state inside journal. Returns output of transaction execution. + /// + /// # Return Value + /// Returns only the execution result + /// + /// # Error Handling + /// If the transaction fails, the journal will revert all changes of given transaction. + /// For quicker error handling, use [`ExecuteEvm::transact`] that will drop the journal. + /// + /// # State Management + /// State changes are stored in the internal journal. + /// To retrieve the state, call [`ExecuteEvm::finalize`] after transaction execution. + /// + /// # History Note + /// Previously this function returned both output and state. + /// Now it follows a two-step process: execute then finalize. + fn transact_one(&mut self, tx: Self::Tx) -> Result; + + /// Finalize execution, clearing the journal and returning the accumulated state changes. + /// + /// # State Management + /// Journal is cleared and can be used for next transaction. + fn finalize(&mut self) -> Self::State; + + /// Transact the given transaction and finalize in a single operation. + /// + /// Internally calls [`ExecuteEvm::transact_one`] followed by [`ExecuteEvm::finalize`]. + /// + /// # Outcome of Error + /// + /// If the transaction fails, the journal is considered broken. + #[inline] + fn transact( + &mut self, + tx: Self::Tx, + ) -> Result, Self::Error> { + let output_or_error = self.transact_one(tx); + // finalize will clear the journal + let state = self.finalize(); + let output = output_or_error?; + Ok(ExecResultAndState::new(output, state)) + } + + /// Execute multiple transactions without finalizing the state. + /// + /// Returns a vector of execution results. State changes are accumulated in the journal + /// but not finalized. Call [`ExecuteEvm::finalize`] after execution to retrieve state changes. + /// + /// # Outcome of Error + /// + /// If any transaction fails, the journal is finalized and the last error is returned. + /// + /// TODO add tx index to the error. + #[inline] + fn transact_many( + &mut self, + txs: impl Iterator, + ) -> Result, Self::Error> { + let mut outputs = Vec::new(); + for tx in txs { + outputs.push(self.transact_one(tx).inspect_err(|_| { + let _ = self.finalize(); + })?); + } + Ok(outputs) + } + + /// Execute multiple transactions and finalize the state in a single operation. + /// + /// Internally calls [`ExecuteEvm::transact_many`] followed by [`ExecuteEvm::finalize`]. + #[inline] + fn transact_many_finalize( + &mut self, + txs: impl Iterator, + ) -> Result, Self::Error> { + // on error transact_multi will clear the journal + let result = self.transact_many(txs)?; + let state = self.finalize(); + Ok(ExecResultAndState::new(result, state)) + } + + /// Execute previous transaction and finalize it. + fn replay( + &mut self, + ) -> Result, Self::Error>; +} + +/// Extension of the [`ExecuteEvm`] trait that adds a method that commits the state after execution. +pub trait ExecuteCommitEvm: ExecuteEvm { + /// Commit the state. + fn commit(&mut self, state: Self::State); + + /// Finalize the state and commit it to the database. + /// + /// Internally calls `finalize` and `commit` functions. + #[inline] + fn commit_inner(&mut self) { + let state = self.finalize(); + self.commit(state); + } + + /// Transact the transaction and commit to the state. + #[inline] + fn transact_commit(&mut self, tx: Self::Tx) -> Result { + let output = self.transact_one(tx)?; + self.commit_inner(); + Ok(output) + } + + /// Transact multiple transactions and commit to the state. + /// + /// Internally calls `transact_many` and `commit_inner` functions. + #[inline] + fn transact_many_commit( + &mut self, + txs: impl Iterator, + ) -> Result, Self::Error> { + let outputs = self.transact_many(txs)?; + self.commit_inner(); + Ok(outputs) + } + + /// Replay the transaction and commit to the state. + /// + /// Internally calls `replay` and `commit` functions. + #[inline] + fn replay_commit(&mut self) -> Result { + let result = self.replay()?; + self.commit(result.state); + Ok(result.result) + } +} + +impl ExecuteEvm + for Evm> +where + CTX: ContextTr> + ContextSetters, + INST: InstructionProvider, + PRECOMPILES: PrecompileProvider, +{ + type ExecutionResult = ExecutionResult; + type State = EvmState; + type Error = EVMError<::Error, InvalidTransaction>; + type Tx = ::Tx; + type Block = ::Block; + + #[inline] + fn transact_one(&mut self, tx: Self::Tx) -> Result { + self.ctx.set_tx(tx); + MainnetHandler::default().run(self) + } + + #[inline] + fn finalize(&mut self) -> Self::State { + self.journal_mut().finalize() + } + + #[inline] + fn set_block(&mut self, block: Self::Block) { + self.ctx.set_block(block); + } + + #[inline] + fn replay(&mut self) -> Result, Self::Error> { + MainnetHandler::default().run(self).map(|result| { + let state = self.finalize(); + ResultAndState::new(result, state) + }) + } +} + +impl ExecuteCommitEvm + for Evm> +where + CTX: ContextTr, Db: DatabaseCommit> + ContextSetters, + INST: InstructionProvider, + PRECOMPILES: PrecompileProvider, +{ + #[inline] + fn commit(&mut self, state: Self::State) { + self.db_mut().commit(state); + } +} diff --git a/crates/handler/src/evm.rs b/crates/handler/src/evm.rs new file mode 100644 index 0000000000..72a11e984e --- /dev/null +++ b/crates/handler/src/evm.rs @@ -0,0 +1,183 @@ +use crate::{ + instructions::InstructionProvider, item_or_result::FrameInitOrResult, EthFrame, FrameResult, + ItemOrResult, PrecompileProvider, +}; +use auto_impl::auto_impl; +use context::{ContextTr, Database, Evm, FrameStack}; +use context_interface::context::ContextError; +use interpreter::{interpreter::EthInterpreter, interpreter_action::FrameInit, InterpreterResult}; + +/// Type alias for database error within a context +pub type ContextDbError = ContextError>; + +/// Type alias for frame error within a context +pub type ContextTrDbError = <::Db as Database>::Error; + +/// Type alias for frame init result +pub type FrameInitResult<'a, F> = ItemOrResult<&'a mut F, ::FrameResult>; + +/// Trait for defining a frame type used in EVM execution. +#[auto_impl(&mut, Box)] +pub trait FrameTr { + /// The result type returned when a frame completes execution. + type FrameResult: Into; + /// The initialization type used to create a new frame. + type FrameInit: Into; +} + +/// A trait that integrates context, instruction set, and precompiles to create an EVM struct. +/// +/// In addition to execution capabilities, this trait provides getter methods for its component fields. +#[auto_impl(&mut, Box)] +pub trait EvmTr { + /// The context type that implements ContextTr to provide access to execution state + type Context: ContextTr; + /// The instruction set type that implements InstructionProvider to define available operations + type Instructions: InstructionProvider; + /// The type containing the available precompiled contracts + type Precompiles: PrecompileProvider; + /// The type containing the frame + type Frame: FrameTr; + + /// Returns a mutable reference to the execution context + fn ctx(&mut self) -> &mut Self::Context; + + /// Returns a mutable reference to the execution context + fn ctx_mut(&mut self) -> &mut Self::Context { + self.ctx() + } + + /// Returns an immutable reference to the execution context + fn ctx_ref(&self) -> &Self::Context; + + /// Returns mutable references to both the context and instruction set. + /// This enables atomic access to both components when needed. + fn ctx_instructions(&mut self) -> (&mut Self::Context, &mut Self::Instructions); + + /// Returns mutable references to both the context and precompiles. + /// This enables atomic access to both components when needed. + fn ctx_precompiles(&mut self) -> (&mut Self::Context, &mut Self::Precompiles); + + /// Returns a mutable reference to the frame stack. + fn frame_stack(&mut self) -> &mut FrameStack; + + /// Initializes the frame for the given frame input. Frame is pushed to the frame stack. + fn frame_init( + &mut self, + frame_input: ::FrameInit, + ) -> Result, ContextDbError>; + + /// Run the frame from the top of the stack. Returns the frame init or result. + /// + /// If frame has returned result it would mark it as finished. + fn frame_run( + &mut self, + ) -> Result, ContextDbError>; + + /// Returns the result of the frame to the caller. Frame is popped from the frame stack. + /// Consumes the frame result or returns it if there is more frames to run. + fn frame_return_result( + &mut self, + result: ::FrameResult, + ) -> Result::FrameResult>, ContextDbError>; +} + +impl EvmTr for Evm> +where + CTX: ContextTr, + I: InstructionProvider, + P: PrecompileProvider, +{ + type Context = CTX; + type Instructions = I; + type Precompiles = P; + type Frame = EthFrame; + + #[inline] + fn ctx(&mut self) -> &mut Self::Context { + &mut self.ctx + } + + #[inline] + fn ctx_ref(&self) -> &Self::Context { + &self.ctx + } + + #[inline] + fn frame_stack(&mut self) -> &mut FrameStack { + &mut self.frame_stack + } + + /// Initializes the frame for the given frame input. Frame is pushed to the frame stack. + #[inline] + fn frame_init( + &mut self, + frame_input: ::FrameInit, + ) -> Result, ContextDbError> { + let is_first_init = self.frame_stack.index().is_none(); + let new_frame = if is_first_init { + self.frame_stack.start_init() + } else { + self.frame_stack.get_next() + }; + + let ctx = &mut self.ctx; + let precompiles = &mut self.precompiles; + let res = Self::Frame::init_with_context(new_frame, ctx, precompiles, frame_input)?; + + Ok(res.map_frame(|token| { + if is_first_init { + self.frame_stack.end_init(token); + } else { + self.frame_stack.push(token); + } + self.frame_stack.get() + })) + } + + /// Run the frame from the top of the stack. Returns the frame init or result. + #[inline] + fn frame_run(&mut self) -> Result, ContextDbError> { + let frame = self.frame_stack.get(); + let context = &mut self.ctx; + let instructions = &mut self.instruction; + + let action = frame + .interpreter + .run_plain(instructions.instruction_table(), context); + + frame.process_next_action(context, action).inspect(|i| { + if i.is_result() { + frame.set_finished(true); + } + }) + } + + /// Returns the result of the frame to the caller. Frame is popped from the frame stack. + #[inline] + fn frame_return_result( + &mut self, + result: ::FrameResult, + ) -> Result::FrameResult>, ContextDbError> { + if self.frame_stack.get().is_finished() { + self.frame_stack.pop(); + } + if self.frame_stack.index().is_none() { + return Ok(Some(result)); + } + self.frame_stack + .get() + .return_result::<_, ContextDbError>(&mut self.ctx, result)?; + Ok(None) + } + + #[inline] + fn ctx_instructions(&mut self) -> (&mut Self::Context, &mut Self::Instructions) { + (&mut self.ctx, &mut self.instruction) + } + + #[inline] + fn ctx_precompiles(&mut self) -> (&mut Self::Context, &mut Self::Precompiles) { + (&mut self.ctx, &mut self.precompiles) + } +} diff --git a/crates/handler/src/execution.rs b/crates/handler/src/execution.rs new file mode 100644 index 0000000000..14cc194a2f --- /dev/null +++ b/crates/handler/src/execution.rs @@ -0,0 +1,32 @@ +use context_interface::Transaction; +use interpreter::{ + CallInput, CallInputs, CallScheme, CallValue, CreateInputs, CreateScheme, FrameInput, +}; +use primitives::TxKind; +use std::boxed::Box; + +/// Creates the first [`FrameInput`] from the transaction, spec and gas limit. +pub fn create_init_frame(tx: &impl Transaction, gas_limit: u64) -> FrameInput { + let input = tx.input().clone(); + + match tx.kind() { + TxKind::Call(target_address) => FrameInput::Call(Box::new(CallInputs { + input: CallInput::Bytes(input), + gas_limit, + target_address, + bytecode_address: target_address, + caller: tx.caller(), + value: CallValue::Transfer(tx.value()), + scheme: CallScheme::Call, + is_static: false, + return_memory_offset: 0..0, + })), + TxKind::Create => FrameInput::Create(Box::new(CreateInputs { + caller: tx.caller(), + scheme: CreateScheme::Create, + value: tx.value(), + init_code: input, + gas_limit, + })), + } +} diff --git a/crates/handler/src/frame.rs b/crates/handler/src/frame.rs new file mode 100644 index 0000000000..c645811dbc --- /dev/null +++ b/crates/handler/src/frame.rs @@ -0,0 +1,773 @@ +use crate::evm::FrameTr; +use crate::item_or_result::FrameInitOrResult; +use crate::{precompile_provider::PrecompileProvider, ItemOrResult}; +use crate::{CallFrame, CreateFrame, FrameData, FrameResult}; +use context::result::FromStringError; +use context_interface::context::ContextError; +use context_interface::local::{FrameToken, OutFrame}; +use context_interface::ContextTr; +use context_interface::{ + journaled_state::{JournalCheckpoint, JournalTr}, + Cfg, Database, +}; +use core::cmp::min; +use derive_where::derive_where; +use interpreter::interpreter_action::FrameInit; +use interpreter::{ + gas, + interpreter::{EthInterpreter, ExtBytecode}, + interpreter_types::ReturnData, + CallInput, CallInputs, CallOutcome, CallValue, CreateInputs, CreateOutcome, CreateScheme, + FrameInput, Gas, InputsImpl, InstructionResult, Interpreter, InterpreterAction, + InterpreterResult, InterpreterTypes, SharedMemory, +}; +use primitives::{ + constants::CALL_STACK_LIMIT, + hardfork::SpecId::{self, HOMESTEAD, LONDON, SPURIOUS_DRAGON}, +}; +use primitives::{keccak256, Address, Bytes, B256, U256}; +use state::Bytecode; +use std::borrow::ToOwned; +use std::boxed::Box; + +/// Frame implementation for Ethereum. +#[derive_where(Clone, Debug; IW, + ::Stack, + ::Memory, + ::Bytecode, + ::ReturnData, + ::Input, + ::RuntimeFlag, + ::Extend, +)] +pub struct EthFrame { + /// Frame-specific data (Call, Create, or EOFCreate). + pub data: FrameData, + /// Input data for the frame. + pub input: FrameInput, + /// Current call depth in the execution stack. + pub depth: usize, + /// Journal checkpoint for state reversion. + pub checkpoint: JournalCheckpoint, + /// Interpreter instance for executing bytecode. + pub interpreter: Interpreter, + /// Whether the frame has been finished its execution. + /// Frame is considered finished if it has been called and returned a result. + pub is_finished: bool, +} + +impl FrameTr for EthFrame { + type FrameResult = FrameResult; + type FrameInit = FrameInit; +} + +impl Default for EthFrame { + fn default() -> Self { + Self::do_default(Interpreter::default()) + } +} + +impl EthFrame { + fn invalid() -> Self { + Self::do_default(Interpreter::invalid()) + } + + fn do_default(interpreter: Interpreter) -> Self { + Self { + data: FrameData::Call(CallFrame { + return_memory_range: 0..0, + }), + input: FrameInput::Empty, + depth: 0, + checkpoint: JournalCheckpoint::default(), + interpreter, + is_finished: false, + } + } + + /// Returns true if the frame has finished execution. + pub fn is_finished(&self) -> bool { + self.is_finished + } + + /// Sets the finished state of the frame. + pub fn set_finished(&mut self, finished: bool) { + self.is_finished = finished; + } +} + +/// Type alias for database errors from a context. +pub type ContextTrDbError = <::Db as Database>::Error; + +impl EthFrame { + /// Clear and initialize a frame. + #[allow(clippy::too_many_arguments)] + pub fn clear( + &mut self, + data: FrameData, + input: FrameInput, + depth: usize, + memory: SharedMemory, + bytecode: ExtBytecode, + inputs: InputsImpl, + is_static: bool, + spec_id: SpecId, + gas_limit: u64, + checkpoint: JournalCheckpoint, + ) { + let Self { + data: data_ref, + input: input_ref, + depth: depth_ref, + interpreter, + checkpoint: checkpoint_ref, + is_finished: is_finished_ref, + } = self; + *data_ref = data; + *input_ref = input; + *depth_ref = depth; + *is_finished_ref = false; + interpreter.clear(memory, bytecode, inputs, is_static, spec_id, gas_limit); + *checkpoint_ref = checkpoint; + } + + /// Make call frame + #[inline] + pub fn make_call_frame< + CTX: ContextTr, + PRECOMPILES: PrecompileProvider, + ERROR: From> + FromStringError, + >( + mut this: OutFrame<'_, Self>, + ctx: &mut CTX, + precompiles: &mut PRECOMPILES, + depth: usize, + memory: SharedMemory, + inputs: Box, + ) -> Result, ERROR> { + let gas = Gas::new(inputs.gas_limit); + let return_result = |instruction_result: InstructionResult| { + Ok(ItemOrResult::Result(FrameResult::Call(CallOutcome { + result: InterpreterResult { + result: instruction_result, + gas, + output: Bytes::new(), + }, + memory_offset: inputs.return_memory_offset.clone(), + }))) + }; + + // Check depth + if depth > CALL_STACK_LIMIT as usize { + return return_result(InstructionResult::CallTooDeep); + } + + // Make account warm and loaded. + let _ = ctx + .journal_mut() + .load_account_delegated(inputs.bytecode_address)?; + + // Create subroutine checkpoint + let checkpoint = ctx.journal_mut().checkpoint(); + + // Touch address. For "EIP-158 State Clear", this will erase empty accounts. + if let CallValue::Transfer(value) = inputs.value { + // Transfer value from caller to called account + // Target will get touched even if balance transferred is zero. + if let Some(i) = + ctx.journal_mut() + .transfer(inputs.caller, inputs.target_address, value)? + { + ctx.journal_mut().checkpoint_revert(checkpoint); + return return_result(i.into()); + } + } + + let interpreter_input = InputsImpl { + target_address: inputs.target_address, + caller_address: inputs.caller, + bytecode_address: Some(inputs.bytecode_address), + input: inputs.input.clone(), + call_value: inputs.value.get(), + }; + let is_static = inputs.is_static; + let gas_limit = inputs.gas_limit; + + if let Some(result) = precompiles + .run( + ctx, + &inputs.bytecode_address, + &interpreter_input, + is_static, + gas_limit, + ) + .map_err(ERROR::from_string)? + { + if result.result.is_ok() { + ctx.journal_mut().checkpoint_commit(); + } else { + ctx.journal_mut().checkpoint_revert(checkpoint); + } + return Ok(ItemOrResult::Result(FrameResult::Call(CallOutcome { + result, + memory_offset: inputs.return_memory_offset.clone(), + }))); + } + + let account = ctx + .journal_mut() + .load_account_code(inputs.bytecode_address)?; + + let mut code_hash = account.info.code_hash(); + let mut bytecode = account.info.code.clone().unwrap_or_default(); + + if let Bytecode::Eip7702(eip7702_bytecode) = bytecode { + let account = &ctx + .journal_mut() + .load_account_code(eip7702_bytecode.delegated_address)? + .info; + bytecode = account.code.clone().unwrap_or_default(); + code_hash = account.code_hash(); + } + + // Returns success if bytecode is empty. + if bytecode.is_empty() { + ctx.journal_mut().checkpoint_commit(); + return return_result(InstructionResult::Stop); + } + + // Create interpreter and executes call and push new CallStackFrame. + this.get(EthFrame::invalid).clear( + FrameData::Call(CallFrame { + return_memory_range: inputs.return_memory_offset.clone(), + }), + FrameInput::Call(inputs), + depth, + memory, + ExtBytecode::new_with_hash(bytecode, code_hash), + interpreter_input, + is_static, + ctx.cfg().spec().into(), + gas_limit, + checkpoint, + ); + Ok(ItemOrResult::Item(this.consume())) + } + + /// Make create frame. + #[inline] + pub fn make_create_frame< + CTX: ContextTr, + ERROR: From> + FromStringError, + >( + mut this: OutFrame<'_, Self>, + context: &mut CTX, + depth: usize, + memory: SharedMemory, + inputs: Box, + ) -> Result, ERROR> { + let spec = context.cfg().spec().into(); + let return_error = |e| { + Ok(ItemOrResult::Result(FrameResult::Create(CreateOutcome { + result: InterpreterResult { + result: e, + gas: Gas::new(inputs.gas_limit), + output: Bytes::new(), + }, + address: None, + }))) + }; + + // Check depth + if depth > CALL_STACK_LIMIT as usize { + return return_error(InstructionResult::CallTooDeep); + } + + // Prague EOF + // TODO(EOF) + // if spec.is_enabled_in(OSAKA) && inputs.init_code.starts_with(&EOF_MAGIC_BYTES) { + // return return_error(InstructionResult::CreateInitCodeStartingEF00); + // } + + // Fetch balance of caller. + let caller_info = &mut context.journal_mut().load_account(inputs.caller)?.data.info; + + // Check if caller has enough balance to send to the created contract. + if caller_info.balance < inputs.value { + return return_error(InstructionResult::OutOfFunds); + } + + // Increase nonce of caller and check if it overflows + let old_nonce = caller_info.nonce; + let Some(new_nonce) = old_nonce.checked_add(1) else { + return return_error(InstructionResult::Return); + }; + caller_info.nonce = new_nonce; + context + .journal_mut() + .nonce_bump_journal_entry(inputs.caller); + + // Create address + let mut init_code_hash = B256::ZERO; + let created_address = match inputs.scheme { + CreateScheme::Create => inputs.caller.create(old_nonce), + CreateScheme::Create2 { salt } => { + init_code_hash = keccak256(&inputs.init_code); + inputs.caller.create2(salt.to_be_bytes(), init_code_hash) + } + CreateScheme::Custom { address } => address, + }; + + // warm load account. + context.journal_mut().load_account(created_address)?; + + // Create account, transfer funds and make the journal checkpoint. + let checkpoint = match context.journal_mut().create_account_checkpoint( + inputs.caller, + created_address, + inputs.value, + spec, + ) { + Ok(checkpoint) => checkpoint, + Err(e) => return return_error(e.into()), + }; + + let bytecode = ExtBytecode::new_with_hash( + Bytecode::new_legacy(inputs.init_code.clone()), + init_code_hash, + ); + + let interpreter_input = InputsImpl { + target_address: created_address, + caller_address: inputs.caller, + bytecode_address: None, + input: CallInput::Bytes(Bytes::new()), + call_value: inputs.value, + }; + let gas_limit = inputs.gas_limit; + + this.get(EthFrame::invalid).clear( + FrameData::Create(CreateFrame { created_address }), + FrameInput::Create(inputs), + depth, + memory, + bytecode, + interpreter_input, + false, + spec, + gas_limit, + checkpoint, + ); + Ok(ItemOrResult::Item(this.consume())) + } + + /* + /// Make create frame. + #[inline] + pub fn make_eofcreate_frame( + mut this: OutFrame<'_, Self>, + evm: &mut EVM, + depth: usize, + memory: SharedMemory, + inputs: Box, + ) -> Result, ERROR> { + let context = evm.ctx(); + let spec = context.cfg().spec().into(); + let return_error = |e| { + Ok(ItemOrResult::Result(FrameResult::EOFCreate( + CreateOutcome { + result: InterpreterResult { + result: e, + gas: Gas::new(inputs.gas_limit), + output: Bytes::new(), + }, + address: None, + }, + ))) + }; + + let (input, initcode, created_address) = match &inputs.kind { + EOFCreateKind::Opcode { + initcode, + input, + created_address, + } => (input.clone(), initcode.clone(), Some(*created_address)), + EOFCreateKind::Tx { .. } => { + // Decode eof and init code. + // TODO : Handle inc_nonce handling more gracefully. + // let Ok((eof, input)) = Eof::decode_dangling(initdata.clone()) else { + // context.journal_mut().inc_account_nonce(inputs.caller)?; + // return return_error(InstructionResult::InvalidEOFInitCode); + // }; + + // if eof.validate().is_err() { + // // TODO : (EOF) New error type. + // context.journal_mut().inc_account_nonce(inputs.caller)?; + // return return_error(InstructionResult::InvalidEOFInitCode); + // } + + // // Use nonce from tx to calculate address. + // let tx = context.tx(); + // let create_address = tx.caller().create(tx.nonce()); + unreachable!("EOF is disabled"); + //(CallInput::Bytes(input), eof, Some(create_address)) + } + }; + + // Check depth + if depth > CALL_STACK_LIMIT as usize { + return return_error(InstructionResult::CallTooDeep); + } + + // Fetch balance of caller. + let caller = context.journal_mut().load_account(inputs.caller)?.data; + + // Check if caller has enough balance to send to the created contract. + if caller.info.balance < inputs.value { + return return_error(InstructionResult::OutOfFunds); + } + + // Increase nonce of caller and check if it overflows + let Some(new_nonce) = caller.info.nonce.checked_add(1) else { + // Can't happen on mainnet. + return return_error(InstructionResult::Return); + }; + caller.info.nonce = new_nonce; + context + .journal_mut() + .nonce_bump_journal_entry(inputs.caller); + + let old_nonce = new_nonce - 1; + + let created_address = created_address.unwrap_or_else(|| inputs.caller.create(old_nonce)); + + // Load account so it needs to be marked as warm for access list. + context.journal_mut().load_account(created_address)?; + + // Create account, transfer funds and make the journal checkpoint. + let checkpoint = match context.journal_mut().create_account_checkpoint( + inputs.caller, + created_address, + inputs.value, + spec, + ) { + Ok(checkpoint) => checkpoint, + Err(e) => return return_error(e.into()), + }; + + let interpreter_input = InputsImpl { + target_address: created_address, + caller_address: inputs.caller, + bytecode_address: None, + input, + call_value: inputs.value, + }; + + let gas_limit = inputs.gas_limit; + this.get(EthFrame::invalid).clear( + FrameData::EOFCreate(EOFCreateFrame { created_address }), + FrameInput::EOFCreate(inputs), + depth, + memory, + ExtBytecode::new(Bytecode::Eof(initcode)), + interpreter_input, + false, + true, + spec, + gas_limit, + checkpoint, + ); + Ok(ItemOrResult::Item(this.consume())) + } + */ + + /// Initializes a frame with the given context and precompiles. + pub fn init_with_context< + CTX: ContextTr, + PRECOMPILES: PrecompileProvider, + >( + this: OutFrame<'_, Self>, + ctx: &mut CTX, + precompiles: &mut PRECOMPILES, + frame_init: FrameInit, + ) -> Result< + ItemOrResult, + ContextError<<::Db as Database>::Error>, + > { + // TODO cleanup inner make functions + let FrameInit { + depth, + memory, + frame_input, + } = frame_init; + + match frame_input { + FrameInput::Call(inputs) => { + Self::make_call_frame(this, ctx, precompiles, depth, memory, inputs) + } + FrameInput::Create(inputs) => Self::make_create_frame(this, ctx, depth, memory, inputs), + FrameInput::Empty => unreachable!(), + } + } +} + +impl EthFrame { + /// Processes the next interpreter action, either creating a new frame or returning a result. + pub fn process_next_action< + CTX: ContextTr, + ERROR: From> + FromStringError, + >( + &mut self, + context: &mut CTX, + next_action: InterpreterAction, + ) -> Result, ERROR> { + let spec = context.cfg().spec().into(); + + // Run interpreter + + let mut interpreter_result = match next_action { + InterpreterAction::NewFrame(frame_input) => { + let depth = self.depth + 1; + return Ok(ItemOrResult::Item(FrameInit { + frame_input, + depth, + memory: self.interpreter.memory.new_child_context(), + })); + } + InterpreterAction::Return(result) => result, + }; + + // Handle return from frame + let result = match &self.data { + FrameData::Call(frame) => { + // return_call + // Revert changes or not. + if interpreter_result.result.is_ok() { + context.journal_mut().checkpoint_commit(); + } else { + context.journal_mut().checkpoint_revert(self.checkpoint); + } + ItemOrResult::Result(FrameResult::Call(CallOutcome::new( + interpreter_result, + frame.return_memory_range.clone(), + ))) + } + FrameData::Create(frame) => { + let max_code_size = context.cfg().max_code_size(); + let is_eip3541_disabled = context.cfg().is_eip3541_disabled(); + return_create( + context.journal_mut(), + self.checkpoint, + &mut interpreter_result, + frame.created_address, + max_code_size, + is_eip3541_disabled, + spec, + ); + + ItemOrResult::Result(FrameResult::Create(CreateOutcome::new( + interpreter_result, + Some(frame.created_address), + ))) + } + }; + + Ok(result) + } + + /// Processes a frame result and updates the interpreter state accordingly. + pub fn return_result> + FromStringError>( + &mut self, + ctx: &mut CTX, + result: FrameResult, + ) -> Result<(), ERROR> { + self.interpreter.memory.free_child_context(); + match core::mem::replace(ctx.error(), Ok(())) { + Err(ContextError::Db(e)) => return Err(e.into()), + Err(ContextError::Custom(e)) => return Err(ERROR::from_string(e)), + Ok(_) => (), + } + + // Insert result to the top frame. + match result { + FrameResult::Call(outcome) => { + let out_gas = outcome.gas(); + let ins_result = *outcome.instruction_result(); + let returned_len = outcome.result.output.len(); + + let interpreter = &mut self.interpreter; + let mem_length = outcome.memory_length(); + let mem_start = outcome.memory_start(); + interpreter.return_data.set_buffer(outcome.result.output); + + let target_len = min(mem_length, returned_len); + + if ins_result == InstructionResult::FatalExternalError { + panic!("Fatal external error in insert_call_outcome"); + } + + let item = if ins_result.is_ok() { + U256::from(1) + } else { + U256::ZERO + }; + // Safe to push without stack limit check + let _ = interpreter.stack.push(item); + + // Return unspend gas. + if ins_result.is_ok_or_revert() { + interpreter.gas.erase_cost(out_gas.remaining()); + interpreter + .memory + .set(mem_start, &interpreter.return_data.buffer()[..target_len]); + } + + if ins_result.is_ok() { + interpreter.gas.record_refund(out_gas.refunded()); + } + } + FrameResult::Create(outcome) => { + let instruction_result = *outcome.instruction_result(); + let interpreter = &mut self.interpreter; + + if instruction_result == InstructionResult::Revert { + // Save data to return data buffer if the create reverted + interpreter + .return_data + .set_buffer(outcome.output().to_owned()); + } else { + // Otherwise clear it. Note that RETURN opcode should abort. + interpreter.return_data.clear(); + }; + + assert_ne!( + instruction_result, + InstructionResult::FatalExternalError, + "Fatal external error in insert_eofcreate_outcome" + ); + + let this_gas = &mut interpreter.gas; + if instruction_result.is_ok_or_revert() { + this_gas.erase_cost(outcome.gas().remaining()); + } + + let stack_item = if instruction_result.is_ok() { + this_gas.record_refund(outcome.gas().refunded()); + outcome.address.unwrap_or_default().into_word().into() + } else { + U256::ZERO + }; + + // Safe to push without stack limit check + let _ = interpreter.stack.push(stack_item); + } + } + + Ok(()) + } +} + +/// Handles the result of a CREATE operation, including validation and state updates. +pub fn return_create( + journal: &mut JOURNAL, + checkpoint: JournalCheckpoint, + interpreter_result: &mut InterpreterResult, + address: Address, + max_code_size: usize, + is_eip3541_disabled: bool, + spec_id: SpecId, +) { + // If return is not ok revert and return. + if !interpreter_result.result.is_ok() { + journal.checkpoint_revert(checkpoint); + return; + } + // Host error if present on execution + // If ok, check contract creation limit and calculate gas deduction on output len. + // + // EIP-3541: Reject new contract code starting with the 0xEF byte + if !is_eip3541_disabled + && spec_id.is_enabled_in(LONDON) + && interpreter_result.output.first() == Some(&0xEF) + { + journal.checkpoint_revert(checkpoint); + interpreter_result.result = InstructionResult::CreateContractStartingWithEF; + return; + } + + // EIP-170: Contract code size limit to 0x6000 (~25kb) + // EIP-7907 increased this limit to 0xc000 (~49kb). + if spec_id.is_enabled_in(SPURIOUS_DRAGON) && interpreter_result.output.len() > max_code_size { + journal.checkpoint_revert(checkpoint); + interpreter_result.result = InstructionResult::CreateContractSizeLimit; + return; + } + let gas_for_code = interpreter_result.output.len() as u64 * gas::CODEDEPOSIT; + if !interpreter_result.gas.record_cost(gas_for_code) { + // Record code deposit gas cost and check if we are out of gas. + // EIP-2 point 3: If contract creation does not have enough gas to pay for the + // final gas fee for adding the contract code to the state, the contract + // creation fails (i.e. goes out-of-gas) rather than leaving an empty contract. + if spec_id.is_enabled_in(HOMESTEAD) { + journal.checkpoint_revert(checkpoint); + interpreter_result.result = InstructionResult::OutOfGas; + return; + } else { + interpreter_result.output = Bytes::new(); + } + } + // If we have enough gas we can commit changes. + journal.checkpoint_commit(); + + // Do analysis of bytecode straight away. + let bytecode = Bytecode::new_legacy(interpreter_result.output.clone()); + + // Set code + journal.set_code(address, bytecode); + + interpreter_result.result = InstructionResult::Return; +} + +/* +pub fn return_eofcreate( + journal: &mut JOURNAL, + checkpoint: JournalCheckpoint, + interpreter_result: &mut InterpreterResult, + address: Address, + max_code_size: usize, +) { + // Note we still execute RETURN opcode and return the bytes. + // In EOF those opcodes should abort execution. + // + // In RETURN gas is still protecting us from ddos and in oog, + // behaviour will be same as if it failed on return. + // + // Bytes of RETURN will drained in `insert_eofcreate_outcome`. + if interpreter_result.result != InstructionResult::ReturnContract { + journal.checkpoint_revert(checkpoint); + return; + } + + if interpreter_result.output.len() > max_code_size { + journal.checkpoint_revert(checkpoint); + interpreter_result.result = InstructionResult::CreateContractSizeLimit; + return; + } + + // Deduct gas for code deployment. + let gas_for_code = interpreter_result.output.len() as u64 * gas::CODEDEPOSIT; + if !interpreter_result.gas.record_cost(gas_for_code) { + journal.checkpoint_revert(checkpoint); + interpreter_result.result = InstructionResult::OutOfGas; + return; + } + + journal.checkpoint_commit(); + + // Decode bytecode has a performance hit, but it has reasonable restrains. + let bytecode = Eof::decode(interpreter_result.output.clone()).expect("Eof is already verified"); + + // Eof bytecode is going to be hashed. + journal.set_code(address, Bytecode::Eof(Arc::new(bytecode))); +} + */ diff --git a/crates/handler/src/frame_data.rs b/crates/handler/src/frame_data.rs new file mode 100644 index 0000000000..2c1d6b5243 --- /dev/null +++ b/crates/handler/src/frame_data.rs @@ -0,0 +1,138 @@ +use context_interface::result::Output; +use core::ops::Range; +use interpreter::{CallOutcome, CreateOutcome, Gas, InstructionResult, InterpreterResult}; +use primitives::Address; + +/// Call Frame +#[derive(Debug, Clone)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct CallFrame { + /// Call frame has return memory range where output will be stored. + pub return_memory_range: Range, +} + +/// Create Frame +#[derive(Debug, Clone)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct CreateFrame { + /// Create frame has a created address. + pub created_address: Address, +} + +/// Frame Data +/// +/// [`FrameData`] bundles different types of frames. +#[derive(Debug, Clone)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub enum FrameData { + /// Call frame data. + Call(CallFrame), + /// Create frame data. + Create(CreateFrame), +} + +/// Frame Result +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[derive(Debug, Clone)] +pub enum FrameResult { + /// Call frame result. + Call(CallOutcome), + /// Create frame result. + Create(CreateOutcome), +} + +impl FrameResult { + /// Casts frame result to interpreter result. + #[inline] + pub fn into_interpreter_result(self) -> InterpreterResult { + match self { + FrameResult::Call(outcome) => outcome.result, + FrameResult::Create(outcome) => outcome.result, + } + } + + /// Returns execution output. + #[inline] + pub fn output(&self) -> Output { + match self { + FrameResult::Call(outcome) => Output::Call(outcome.result.output.clone()), + FrameResult::Create(outcome) => { + Output::Create(outcome.result.output.clone(), outcome.address) + } + } + } + + /// Returns reference to gas. + #[inline] + pub fn gas(&self) -> &Gas { + match self { + FrameResult::Call(outcome) => &outcome.result.gas, + FrameResult::Create(outcome) => &outcome.result.gas, + } + } + + /// Returns mutable reference to interpreter result. + #[inline] + pub fn gas_mut(&mut self) -> &mut Gas { + match self { + FrameResult::Call(outcome) => &mut outcome.result.gas, + FrameResult::Create(outcome) => &mut outcome.result.gas, + } + } + + /// Returns reference to interpreter result. + #[inline] + pub fn interpreter_result(&self) -> &InterpreterResult { + match self { + FrameResult::Call(outcome) => &outcome.result, + FrameResult::Create(outcome) => &outcome.result, + } + } + + /// Returns mutable reference to interpreter result. + #[inline] + pub fn interpreter_result_mut(&mut self) -> &InterpreterResult { + match self { + FrameResult::Call(outcome) => &mut outcome.result, + FrameResult::Create(outcome) => &mut outcome.result, + } + } + + /// Return Instruction result. + #[inline] + pub fn instruction_result(&self) -> InstructionResult { + self.interpreter_result().result + } +} + +impl FrameData { + /// Creates a new create frame data. + pub fn new_create(created_address: Address) -> Self { + Self::Create(CreateFrame { created_address }) + } + + /// Creates a new call frame data. + pub fn new_call(return_memory_range: Range) -> Self { + Self::Call(CallFrame { + return_memory_range, + }) + } + + /// Returns true if frame is call frame. + pub fn is_call(&self) -> bool { + matches!(self, Self::Call { .. }) + } + + /// Returns true if frame is create frame. + pub fn is_create(&self) -> bool { + matches!(self, Self::Create { .. }) + } + + /// Returns created address if frame is create otherwise returns None. + pub fn created_address(&self) -> Option
{ + match self { + Self::Create(create_frame) => Some(create_frame.created_address), + _ => None, + } + } +} diff --git a/crates/handler/src/handler.rs b/crates/handler/src/handler.rs new file mode 100644 index 0000000000..ad0c73ba96 --- /dev/null +++ b/crates/handler/src/handler.rs @@ -0,0 +1,461 @@ +use crate::{ + evm::FrameTr, execution, post_execution, pre_execution, validation, EvmTr, FrameResult, + ItemOrResult, +}; +use context::result::{ExecutionResult, FromStringError}; +use context::LocalContextTr; +use context_interface::context::ContextError; +use context_interface::ContextTr; +use context_interface::{ + result::{HaltReasonTr, InvalidHeader, InvalidTransaction}, + Cfg, Database, JournalTr, Transaction, +}; +use interpreter::interpreter_action::FrameInit; +use interpreter::{Gas, InitialAndFloorGas, SharedMemory}; +use primitives::U256; + +/// Trait for errors that can occur during EVM execution. +/// +/// This trait represents the minimal error requirements for EVM execution, +/// ensuring that all necessary error types can be converted into the handler's error type. +pub trait EvmTrError: + From + + From + + From<<::Db as Database>::Error> + + From::Db as Database>::Error>> + + FromStringError +{ +} + +impl< + EVM: EvmTr, + T: From + + From + + From<<::Db as Database>::Error> + + From::Db as Database>::Error>> + + FromStringError, + > EvmTrError for T +{ +} + +/// The main implementation of Ethereum Mainnet transaction execution. +/// +/// The [`Handler::run`] method serves as the entry point for execution and provides +/// out-of-the-box support for executing Ethereum mainnet transactions. +/// +/// This trait allows EVM variants to customize execution logic by implementing +/// their own method implementations. +/// +/// The handler logic consists of four phases: +/// * Validation - Validates tx/block/config fields and loads caller account and validates initial gas requirements and +/// balance checks. +/// * Pre-execution - Loads and warms accounts, deducts initial gas +/// * Execution - Executes the main frame loop, delegating to [`EvmTr`] for creating and running call frames. +/// * Post-execution - Calculates final refunds, validates gas floor, reimburses caller, +/// and rewards beneficiary +/// +/// +/// The [`Handler::catch_error`] method handles cleanup of intermediate state if an error +/// occurs during execution. +/// +/// # Returns +/// +/// Returns execution status, error, gas spend and logs. State change is not returned and it is +/// contained inside Context Journal. This setup allows multiple transactions to be chain executed. +/// +/// To finalize the execution and obtain changed state, call [`JournalTr::finalize`] function. +pub trait Handler { + /// The EVM type containing Context, Instruction, and Precompiles implementations. + type Evm: EvmTr< + Context: ContextTr, + Frame: FrameTr, + >; + /// The error type returned by this handler. + type Error: EvmTrError; + /// The halt reason type included in the output + type HaltReason: HaltReasonTr; + + /// The main entry point for transaction execution. + /// + /// This method calls [`Handler::run_without_catch_error`] and if it returns an error, + /// calls [`Handler::catch_error`] to handle the error and cleanup. + /// + /// The [`Handler::catch_error`] method ensures intermediate state is properly cleared. + /// + /// # Error handling + /// + /// In case of error, the journal can be in an inconsistent state and should be cleared by calling + /// [`JournalTr::discard_tx`] method or dropped. + /// + /// # Returns + /// + /// Returns execution result, error, gas spend and logs. + #[inline] + fn run( + &mut self, + evm: &mut Self::Evm, + ) -> Result, Self::Error> { + // Run inner handler and catch all errors to handle cleanup. + match self.run_without_catch_error(evm) { + Ok(output) => Ok(output), + Err(e) => self.catch_error(evm, e), + } + } + + /// Runs the system call. + /// + /// System call is a special transaction where caller is a [`crate::SYSTEM_ADDRESS`] + /// + /// It is used to call a system contracts and it skips all the `validation` and `pre-execution` and most of `post-execution` phases. + /// For example it will not deduct the caller or reward the beneficiary. + /// + /// State changs can be obtained by calling [`JournalTr::finalize`] method from the [`EvmTr::Context`]. + /// + /// # Error handling + /// + /// By design system call should not fail and should always succeed. + /// In case of an error (If fetching account/storage on rpc fails), the journal can be in an inconsistent + /// state and should be cleared by calling [`JournalTr::discard_tx`] method or dropped. + #[inline] + fn run_system_call( + &mut self, + evm: &mut Self::Evm, + ) -> Result, Self::Error> { + // dummy values that are not used. + let init_and_floor_gas = InitialAndFloorGas::new(0, 0); + // call execution and than output. + match self + .execution(evm, &init_and_floor_gas) + .and_then(|exec_result| self.execution_result(evm, exec_result)) + { + out @ Ok(_) => out, + Err(e) => self.catch_error(evm, e), + } + } + + /// Called by [`Handler::run`] to execute the core handler logic. + /// + /// Executes the four phases in sequence: [Handler::validate], + /// [Handler::pre_execution], [Handler::execution], [Handler::post_execution]. + /// + /// Returns any errors without catching them or calling [`Handler::catch_error`]. + #[inline] + fn run_without_catch_error( + &mut self, + evm: &mut Self::Evm, + ) -> Result, Self::Error> { + let init_and_floor_gas = self.validate(evm)?; + let eip7702_refund = self.pre_execution(evm)? as i64; + let mut exec_result = self.execution(evm, &init_and_floor_gas)?; + self.post_execution(evm, &mut exec_result, init_and_floor_gas, eip7702_refund)?; + + // Prepare the output + self.execution_result(evm, exec_result) + } + + /// Validates the execution environment and transaction parameters. + /// + /// Calculates initial and floor gas requirements and verifies they are covered by the gas limit. + /// + /// Validation against state is done later in pre-execution phase in deduct_caller function. + #[inline] + fn validate(&self, evm: &mut Self::Evm) -> Result { + self.validate_env(evm)?; + self.validate_initial_tx_gas(evm) + } + + /// Prepares the EVM state for execution. + /// + /// Loads the beneficiary account (EIP-3651: Warm COINBASE) and all accounts/storage from the access list (EIP-2929). + /// + /// Deducts the maximum possible fee from the caller's balance. + /// + /// For EIP-7702 transactions, applies the authorization list and delegates successful authorizations. + /// Returns the gas refund amount from EIP-7702. Authorizations are applied before execution begins. + #[inline] + fn pre_execution(&self, evm: &mut Self::Evm) -> Result { + self.validate_against_state_and_deduct_caller(evm)?; + self.load_accounts(evm)?; + + let gas = self.apply_eip7702_auth_list(evm)?; + Ok(gas) + } + + /// Creates and executes the initial frame, then processes the execution loop. + /// + /// Always calls [Handler::last_frame_result] to handle returned gas from the call. + #[inline] + fn execution( + &mut self, + evm: &mut Self::Evm, + init_and_floor_gas: &InitialAndFloorGas, + ) -> Result { + let gas_limit = evm.ctx().tx().gas_limit() - init_and_floor_gas.initial_gas; + // Create first frame action + let first_frame_input = self.first_frame_input(evm, gas_limit)?; + + // Run execution loop + let mut frame_result = self.run_exec_loop(evm, first_frame_input)?; + + // Handle last frame result + self.last_frame_result(evm, &mut frame_result)?; + Ok(frame_result) + } + + /// Handles the final steps of transaction execution. + /// + /// Calculates final refunds and validates the gas floor (EIP-7623) to ensure minimum gas is spent. + /// After EIP-7623, at least floor gas must be consumed. + /// + /// Reimburses unused gas to the caller and rewards the beneficiary with transaction fees. + /// The effective gas price determines rewards, with the base fee being burned. + /// + /// Finally, finalizes output by returning the journal state and clearing internal state + /// for the next execution. + #[inline] + fn post_execution( + &self, + evm: &mut Self::Evm, + exec_result: &mut FrameResult, + init_and_floor_gas: InitialAndFloorGas, + eip7702_gas_refund: i64, + ) -> Result<(), Self::Error> { + // Calculate final refund and add EIP-7702 refund to gas. + self.refund(evm, exec_result, eip7702_gas_refund); + // Ensure gas floor is met and minimum floor gas is spent. + self.eip7623_check_gas_floor(evm, exec_result, init_and_floor_gas); + // Return unused gas to caller + self.reimburse_caller(evm, exec_result)?; + // Pay transaction fees to beneficiary + self.reward_beneficiary(evm, exec_result)?; + Ok(()) + } + + /* VALIDATION */ + + /// Validates block, transaction and configuration fields. + /// + /// Performs all validation checks that can be done without loading state. + /// For example, verifies transaction gas limit is below block gas limit. + #[inline] + fn validate_env(&self, evm: &mut Self::Evm) -> Result<(), Self::Error> { + validation::validate_env(evm.ctx()) + } + + /// Calculates initial gas costs based on transaction type and input data. + /// + /// Includes additional costs for access list and authorization list. + /// + /// Verifies the initial cost does not exceed the transaction gas limit. + #[inline] + fn validate_initial_tx_gas(&self, evm: &Self::Evm) -> Result { + let ctx = evm.ctx_ref(); + validation::validate_initial_tx_gas(ctx.tx(), ctx.cfg().spec().into()).map_err(From::from) + } + + /* PRE EXECUTION */ + + /// Loads access list and beneficiary account, marking them as warm in the [`context::Journal`]. + #[inline] + fn load_accounts(&self, evm: &mut Self::Evm) -> Result<(), Self::Error> { + pre_execution::load_accounts(evm) + } + + /// Processes the authorization list, validating authority signatures, nonces and chain IDs. + /// Applies valid authorizations to accounts. + /// + /// Returns the gas refund amount specified by EIP-7702. + #[inline] + fn apply_eip7702_auth_list(&self, evm: &mut Self::Evm) -> Result { + pre_execution::apply_eip7702_auth_list(evm.ctx()) + } + + /// Deducts maximum possible fee and transfer value from caller's balance. + /// + /// Unused fees are returned to caller after execution completes. + #[inline] + fn validate_against_state_and_deduct_caller( + &self, + evm: &mut Self::Evm, + ) -> Result<(), Self::Error> { + pre_execution::validate_against_state_and_deduct_caller(evm.ctx()) + } + + /* EXECUTION */ + + /// Creates initial frame input using transaction parameters, gas limit and configuration. + #[inline] + fn first_frame_input( + &mut self, + evm: &mut Self::Evm, + gas_limit: u64, + ) -> Result { + let memory = + SharedMemory::new_with_buffer(evm.ctx().local().shared_memory_buffer().clone()); + let ctx = evm.ctx_ref(); + Ok(FrameInit { + depth: 0, + memory, + frame_input: execution::create_init_frame(ctx.tx(), gas_limit), + }) + } + + /// Processes the result of the initial call and handles returned gas. + #[inline] + fn last_frame_result( + &mut self, + evm: &mut Self::Evm, + frame_result: &mut <::Frame as FrameTr>::FrameResult, + ) -> Result<(), Self::Error> { + let instruction_result = frame_result.interpreter_result().result; + let gas = frame_result.gas_mut(); + let remaining = gas.remaining(); + let refunded = gas.refunded(); + + // Spend the gas limit. Gas is reimbursed when the tx returns successfully. + *gas = Gas::new_spent(evm.ctx().tx().gas_limit()); + + if instruction_result.is_ok_or_revert() { + gas.erase_cost(remaining); + } + + if instruction_result.is_ok() { + gas.record_refund(refunded); + } + Ok(()) + } + + /* FRAMES */ + + /// Executes the main frame processing loop. + /// + /// This loop manages the frame stack, processing each frame until execution completes. + /// For each iteration: + /// 1. Calls the current frame + /// 2. Handles the returned frame input or result + /// 3. Creates new frames or propagates results as needed + #[inline] + fn run_exec_loop( + &mut self, + evm: &mut Self::Evm, + first_frame_input: <::Frame as FrameTr>::FrameInit, + ) -> Result { + let res = evm.frame_init(first_frame_input)?; + + if let ItemOrResult::Result(frame_result) = res { + return Ok(frame_result); + } + + loop { + let call_or_result = evm.frame_run()?; + + let result = match call_or_result { + ItemOrResult::Item(init) => { + match evm.frame_init(init)? { + ItemOrResult::Item(_) => { + continue; + } + // Do not pop the frame since no new frame was created + ItemOrResult::Result(result) => result, + } + } + ItemOrResult::Result(result) => result, + }; + + if let Some(result) = evm.frame_return_result(result)? { + return Ok(result); + } + } + } + + /* POST EXECUTION */ + + /// Validates that the minimum gas floor requirements are satisfied. + /// + /// Ensures that at least the floor gas amount has been consumed during execution. + #[inline] + fn eip7623_check_gas_floor( + &self, + _evm: &mut Self::Evm, + exec_result: &mut <::Frame as FrameTr>::FrameResult, + init_and_floor_gas: InitialAndFloorGas, + ) { + post_execution::eip7623_check_gas_floor(exec_result.gas_mut(), init_and_floor_gas) + } + + /// Calculates the final gas refund amount, including any EIP-7702 refunds. + #[inline] + fn refund( + &self, + evm: &mut Self::Evm, + exec_result: &mut <::Frame as FrameTr>::FrameResult, + eip7702_refund: i64, + ) { + let spec = evm.ctx().cfg().spec().into(); + post_execution::refund(spec, exec_result.gas_mut(), eip7702_refund) + } + + /// Returns unused gas costs to the transaction sender's account. + #[inline] + fn reimburse_caller( + &self, + evm: &mut Self::Evm, + exec_result: &mut <::Frame as FrameTr>::FrameResult, + ) -> Result<(), Self::Error> { + post_execution::reimburse_caller(evm.ctx(), exec_result.gas(), U256::ZERO) + .map_err(From::from) + } + + /// Transfers transaction fees to the block beneficiary's account. + #[inline] + fn reward_beneficiary( + &self, + evm: &mut Self::Evm, + exec_result: &mut <::Frame as FrameTr>::FrameResult, + ) -> Result<(), Self::Error> { + post_execution::reward_beneficiary(evm.ctx(), exec_result.gas()).map_err(From::from) + } + + /// Processes the final execution output. + /// + /// This method, retrieves the final state from the journal, converts internal results to the external output format. + /// Internal state is cleared and EVM is prepared for the next transaction. + #[inline] + fn execution_result( + &mut self, + evm: &mut Self::Evm, + result: <::Frame as FrameTr>::FrameResult, + ) -> Result, Self::Error> { + match core::mem::replace(evm.ctx().error(), Ok(())) { + Err(ContextError::Db(e)) => return Err(e.into()), + Err(ContextError::Custom(e)) => return Err(Self::Error::from_string(e)), + Ok(_) => (), + } + + let exec_result = post_execution::output(evm.ctx(), result); + + // commit transaction + evm.ctx().journal_mut().commit_tx(); + evm.ctx().local_mut().clear(); + evm.frame_stack().clear(); + + Ok(exec_result) + } + + /// Handles cleanup when an error occurs during execution. + /// + /// Ensures the journal state is properly cleared before propagating the error. + /// On happy path journal is cleared in [`Handler::execution_result`] method. + #[inline] + fn catch_error( + &self, + evm: &mut Self::Evm, + error: Self::Error, + ) -> Result, Self::Error> { + // clean up local context. Initcode cache needs to be discarded. + evm.ctx().local_mut().clear(); + evm.ctx().journal_mut().discard_tx(); + evm.frame_stack().clear(); + Err(error) + } +} diff --git a/crates/handler/src/instructions.rs b/crates/handler/src/instructions.rs new file mode 100644 index 0000000000..a7006be15f --- /dev/null +++ b/crates/handler/src/instructions.rs @@ -0,0 +1,82 @@ +use auto_impl::auto_impl; +use interpreter::{ + instructions::{instruction_table, InstructionTable}, + Host, Instruction, InterpreterTypes, +}; +use std::boxed::Box; + +/// Stores instructions for EVM. +#[auto_impl(&, Arc, Rc)] +pub trait InstructionProvider { + /// Context type. + type Context; + /// Interpreter types. + type InterpreterTypes: InterpreterTypes; + + /// Returns the instruction table that is used by EvmTr to execute instructions. + fn instruction_table(&self) -> &InstructionTable; +} + +/// Ethereum instruction contains list of mainnet instructions that is used for Interpreter execution. +#[derive(Debug)] +pub struct EthInstructions { + /// Table containing instruction implementations indexed by opcode. + pub instruction_table: Box>, +} + +impl Clone for EthInstructions +where + WIRE: InterpreterTypes, +{ + fn clone(&self) -> Self { + Self { + instruction_table: self.instruction_table.clone(), + } + } +} + +impl EthInstructions +where + WIRE: InterpreterTypes, + HOST: Host, +{ + /// Returns `EthInstructions` with mainnet spec. + pub fn new_mainnet() -> Self { + Self::new(instruction_table::()) + } + + /// Rerurns new `EthInstructions` with custom instruction table. + pub fn new(base_table: InstructionTable) -> Self { + Self { + instruction_table: Box::new(base_table), + } + } + + /// Inserts a new instruction into the instruction table.s + pub fn insert_instruction(&mut self, opcode: u8, instruction: Instruction) { + self.instruction_table[opcode as usize] = instruction; + } +} + +impl InstructionProvider for EthInstructions +where + IT: InterpreterTypes, + CTX: Host, +{ + type InterpreterTypes = IT; + type Context = CTX; + + fn instruction_table(&self) -> &InstructionTable { + &self.instruction_table + } +} + +impl Default for EthInstructions +where + WIRE: InterpreterTypes, + HOST: Host, +{ + fn default() -> Self { + Self::new_mainnet() + } +} diff --git a/crates/handler/src/item_or_result.rs b/crates/handler/src/item_or_result.rs new file mode 100644 index 0000000000..6eecb55b4f --- /dev/null +++ b/crates/handler/src/item_or_result.rs @@ -0,0 +1,44 @@ +use crate::evm::FrameTr; + +/// Represents either an item or a result. +#[derive(Clone, Debug)] +pub enum ItemOrResult { + /// Contains an item that needs further processing. + Item(ITEM), + /// Contains a final result. + Result(RES), +} + +impl ItemOrResult { + /// Maps the item variant using the provided function, leaving results unchanged. + pub fn map_frame(self, f: impl FnOnce(ITEM) -> OITEM) -> ItemOrResult { + match self { + ItemOrResult::Item(item) => ItemOrResult::Item(f(item)), + ItemOrResult::Result(result) => ItemOrResult::Result(result), + } + } + + /// Maps the result variant using the provided function, leaving items unchanged. + pub fn map_result(self, f: impl FnOnce(RES) -> ORES) -> ItemOrResult { + match self { + ItemOrResult::Item(item) => ItemOrResult::Item(item), + ItemOrResult::Result(result) => ItemOrResult::Result(f(result)), + } + } +} + +impl ItemOrResult { + /// Returns true if this is a result variant. + pub fn is_result(&self) -> bool { + matches!(self, ItemOrResult::Result(_)) + } + + /// Returns true if this is an item variant. + pub fn is_item(&self) -> bool { + matches!(self, ItemOrResult::Item(_)) + } +} + +/// Type alias for frame initialization or result. +pub type FrameInitOrResult = + ItemOrResult<::FrameInit, ::FrameResult>; diff --git a/crates/handler/src/lib.rs b/crates/handler/src/lib.rs new file mode 100644 index 0000000000..a220439545 --- /dev/null +++ b/crates/handler/src/lib.rs @@ -0,0 +1,44 @@ +//! EVM execution handling. +#![cfg_attr(not(test), warn(unused_crate_dependencies))] +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(not(feature = "std"))] +extern crate alloc as std; + +// Mainnet related handlers. + +/// EVM execution API traits and implementations. +pub mod api; +/// Core EVM traits for execution and frame management. +pub mod evm; +/// EVM execution logic and utilities. +pub mod execution; +mod frame; +mod frame_data; +/// Handler implementation for orchestrating EVM execution. +pub mod handler; +/// EVM instruction set implementations and tables. +pub mod instructions; +mod item_or_result; +mod mainnet_builder; +mod mainnet_handler; +/// Post-execution operations including gas refunds and state finalization. +pub mod post_execution; +pub mod pre_execution; +mod precompile_provider; +/// System call implementations for special EVM operations. +pub mod system_call; +/// Transaction and environment validation utilities. +pub mod validation; + +// Public exports +pub use api::{ExecuteCommitEvm, ExecuteEvm}; +pub use evm::{EvmTr, FrameTr}; +pub use frame::{return_create, ContextTrDbError, EthFrame}; +pub use frame_data::{CallFrame, CreateFrame, FrameData, FrameResult}; +pub use handler::{EvmTrError, Handler}; +pub use item_or_result::{FrameInitOrResult, ItemOrResult}; +pub use mainnet_builder::{MainBuilder, MainContext, MainnetContext, MainnetEvm}; +pub use mainnet_handler::MainnetHandler; +pub use precompile_provider::{EthPrecompiles, PrecompileProvider}; +pub use system_call::{SystemCallCommitEvm, SystemCallEvm, SystemCallTx, SYSTEM_ADDRESS}; diff --git a/crates/handler/src/mainnet_builder.rs b/crates/handler/src/mainnet_builder.rs new file mode 100644 index 0000000000..4e53287c93 --- /dev/null +++ b/crates/handler/src/mainnet_builder.rs @@ -0,0 +1,134 @@ +use crate::{frame::EthFrame, instructions::EthInstructions, EthPrecompiles}; +use context::{BlockEnv, Cfg, CfgEnv, Context, Evm, FrameStack, Journal, TxEnv}; +use context_interface::{Block, Database, JournalTr, Transaction}; +use database_interface::EmptyDB; +use interpreter::interpreter::EthInterpreter; +use primitives::hardfork::SpecId; + +/// Type alias for a mainnet EVM instance with standard Ethereum components. +pub type MainnetEvm = + Evm, EthPrecompiles, EthFrame>; + +/// Type alias for a mainnet context with standard Ethereum environment types. +pub type MainnetContext = Context, ()>; + +/// Trait for building mainnet EVM instances from contexts. +pub trait MainBuilder: Sized { + /// The context type that will be used in the EVM. + type Context; + + /// Builds a mainnet EVM instance without an inspector. + fn build_mainnet(self) -> MainnetEvm; + + /// Builds a mainnet EVM instance with the provided inspector. + fn build_mainnet_with_inspector(self, inspector: INSP) + -> MainnetEvm; +} + +impl MainBuilder for Context +where + BLOCK: Block, + TX: Transaction, + CFG: Cfg, + DB: Database, + JOURNAL: JournalTr, +{ + type Context = Self; + + fn build_mainnet(self) -> MainnetEvm { + Evm { + ctx: self, + inspector: (), + instruction: EthInstructions::default(), + precompiles: EthPrecompiles::default(), + frame_stack: FrameStack::new(), + } + } + + fn build_mainnet_with_inspector( + self, + inspector: INSP, + ) -> MainnetEvm { + Evm { + ctx: self, + inspector, + instruction: EthInstructions::default(), + precompiles: EthPrecompiles::default(), + frame_stack: FrameStack::new(), + } + } +} + +/// Trait used to initialize Context with default mainnet types. +pub trait MainContext { + /// Creates a new mainnet context with default configuration. + fn mainnet() -> Self; +} + +impl MainContext for Context, ()> { + fn mainnet() -> Self { + Context::new(EmptyDB::new(), SpecId::default()) + } +} + +#[cfg(test)] +mod test { + use crate::ExecuteEvm; + use crate::{MainBuilder, MainContext}; + use alloy_signer::{Either, SignerSync}; + use alloy_signer_local::PrivateKeySigner; + use bytecode::{ + opcode::{PUSH1, SSTORE}, + Bytecode, + }; + use context::{Context, TxEnv}; + use context_interface::transaction::Authorization; + use database::{BenchmarkDB, EEADDRESS, FFADDRESS}; + use primitives::{hardfork::SpecId, TxKind, U256}; + use primitives::{StorageKey, StorageValue}; + + #[test] + fn sanity_eip7702_tx() { + let signer = PrivateKeySigner::random(); + let auth = Authorization { + chain_id: U256::ZERO, + nonce: 0, + address: FFADDRESS, + }; + let signature = signer.sign_hash_sync(&auth.signature_hash()).unwrap(); + let auth = auth.into_signed(signature); + + let bytecode = Bytecode::new_legacy([PUSH1, 0x01, PUSH1, 0x01, SSTORE].into()); + + let ctx = Context::mainnet() + .modify_cfg_chained(|cfg| cfg.spec = SpecId::PRAGUE) + .with_db(BenchmarkDB::new_bytecode(bytecode)); + + let mut evm = ctx.build_mainnet(); + + let state = evm + .transact( + TxEnv::builder() + .gas_limit(100_000) + .authorization_list(vec![Either::Left(auth)]) + .caller(EEADDRESS) + .kind(TxKind::Call(signer.address())) + .build() + .unwrap(), + ) + .unwrap() + .state; + + let auth_acc = state.get(&signer.address()).unwrap(); + assert_eq!(auth_acc.info.code, Some(Bytecode::new_eip7702(FFADDRESS))); + assert_eq!(auth_acc.info.nonce, 1); + assert_eq!( + auth_acc + .storage + .get(&StorageKey::from(1)) + .unwrap() + .present_value, + StorageValue::from(1) + ); + } +} diff --git a/crates/handler/src/mainnet_handler.rs b/crates/handler/src/mainnet_handler.rs new file mode 100644 index 0000000000..f78b10424a --- /dev/null +++ b/crates/handler/src/mainnet_handler.rs @@ -0,0 +1,33 @@ +use super::{EvmTrError, Handler}; +use crate::{evm::FrameTr, EvmTr, FrameResult}; +use context_interface::{result::HaltReason, ContextTr, JournalTr}; +use interpreter::interpreter_action::FrameInit; +use state::EvmState; + +/// Mainnet handler that implements the default [`Handler`] trait for the Evm. +#[derive(Debug, Clone)] +pub struct MainnetHandler { + /// Phantom data to hold the generic type parameters. + pub _phantom: core::marker::PhantomData<(CTX, ERROR, FRAME)>, +} + +impl Handler for MainnetHandler +where + EVM: EvmTr>, Frame = FRAME>, + ERROR: EvmTrError, + // TODO `FrameResult` should be a generic trait. + // TODO `FrameInit` should be a generic. + FRAME: FrameTr, +{ + type Evm = EVM; + type Error = ERROR; + type HaltReason = HaltReason; +} + +impl Default for MainnetHandler { + fn default() -> Self { + Self { + _phantom: core::marker::PhantomData, + } + } +} diff --git a/crates/handler/src/post_execution.rs b/crates/handler/src/post_execution.rs new file mode 100644 index 0000000000..69f5d453f3 --- /dev/null +++ b/crates/handler/src/post_execution.rs @@ -0,0 +1,117 @@ +use crate::FrameResult; +use context_interface::{ + journaled_state::JournalTr, + result::{ExecutionResult, HaltReasonTr}, + Block, Cfg, ContextTr, Database, Transaction, +}; +use interpreter::{Gas, InitialAndFloorGas, SuccessOrHalt}; +use primitives::{hardfork::SpecId, U256}; + +/// Ensures minimum gas floor is spent according to EIP-7623. +pub fn eip7623_check_gas_floor(gas: &mut Gas, init_and_floor_gas: InitialAndFloorGas) { + // EIP-7623: Increase calldata cost + // spend at least a gas_floor amount of gas. + if gas.spent_sub_refunded() < init_and_floor_gas.floor_gas { + gas.set_spent(init_and_floor_gas.floor_gas); + // clear refund + gas.set_refund(0); + } +} + +/// Calculates and applies gas refunds based on the specification. +pub fn refund(spec: SpecId, gas: &mut Gas, eip7702_refund: i64) { + gas.record_refund(eip7702_refund); + // Calculate gas refund for transaction. + // If spec is set to london, it will decrease the maximum refund amount to 5th part of + // gas spend. (Before london it was 2th part of gas spend) + gas.set_final_refund(spec.is_enabled_in(SpecId::LONDON)); +} + +/// Reimburses the caller for unused gas. +#[inline] +pub fn reimburse_caller( + context: &mut CTX, + gas: &Gas, + additional_refund: U256, +) -> Result<(), ::Error> { + let basefee = context.block().basefee() as u128; + let caller = context.tx().caller(); + let effective_gas_price = context.tx().effective_gas_price(basefee); + + // Return balance of not spend gas. + context.journal_mut().balance_incr( + caller, + U256::from( + effective_gas_price.saturating_mul((gas.remaining() + gas.refunded() as u64) as u128), + ) + additional_refund, + )?; + + Ok(()) +} + +/// Rewards the beneficiary with transaction fees. +#[inline] +pub fn reward_beneficiary( + context: &mut CTX, + gas: &Gas, +) -> Result<(), ::Error> { + let beneficiary = context.block().beneficiary(); + let basefee = context.block().basefee() as u128; + let effective_gas_price = context.tx().effective_gas_price(basefee); + + // Transfer fee to coinbase/beneficiary. + // EIP-1559 discard basefee for coinbase transfer. Basefee amount of gas is discarded. + let coinbase_gas_price = if context.cfg().spec().into().is_enabled_in(SpecId::LONDON) { + effective_gas_price.saturating_sub(basefee) + } else { + effective_gas_price + }; + + // reward beneficiary + context.journal_mut().balance_incr( + beneficiary, + U256::from(coinbase_gas_price * gas.used() as u128), + )?; + + Ok(()) +} + +/// Calculate last gas spent and transform internal reason to external. +/// +/// TODO make Journal FinalOutput more generic. +pub fn output, HALTREASON: HaltReasonTr>( + context: &mut CTX, + // TODO, make this more generic and nice. + // FrameResult should be a generic that returns gas and interpreter result. + result: FrameResult, +) -> ExecutionResult { + // Used gas with refund calculated. + let gas_refunded = result.gas().refunded() as u64; + let gas_used = result.gas().used(); + let output = result.output(); + let instruction_result = result.into_interpreter_result(); + + // take logs from journal. + let logs = context.journal_mut().take_logs(); + + match SuccessOrHalt::::from(instruction_result.result) { + SuccessOrHalt::Success(reason) => ExecutionResult::Success { + reason, + gas_used, + gas_refunded, + logs, + output, + }, + SuccessOrHalt::Revert => ExecutionResult::Revert { + gas_used, + output: output.into_data(), + }, + SuccessOrHalt::Halt(reason) => ExecutionResult::Halt { reason, gas_used }, + // Only two internal return flags. + flag @ (SuccessOrHalt::FatalExternalError | SuccessOrHalt::Internal(_)) => { + panic!( + "Encountered unexpected internal return flag: {flag:?} with instruction result: {instruction_result:?}" + ) + } + } +} diff --git a/crates/handler/src/pre_execution.rs b/crates/handler/src/pre_execution.rs new file mode 100644 index 0000000000..c1a9aa3816 --- /dev/null +++ b/crates/handler/src/pre_execution.rs @@ -0,0 +1,266 @@ +//! Handles related to the main function of the EVM. +//! +//! They handle initial setup of the EVM, call loop and the final return of the EVM + +use crate::{EvmTr, PrecompileProvider}; +use bytecode::Bytecode; +use context_interface::transaction::{AccessListItemTr, AuthorizationTr}; +use context_interface::ContextTr; +use context_interface::{ + journaled_state::JournalTr, + result::InvalidTransaction, + transaction::{Transaction, TransactionType}, + Block, Cfg, Database, +}; +use core::cmp::Ordering; +use primitives::StorageKey; +use primitives::{eip7702, hardfork::SpecId, KECCAK_EMPTY, U256}; +use state::AccountInfo; +use std::boxed::Box; + +/// Loads and warms accounts for execution, including precompiles and access list. +pub fn load_accounts< + EVM: EvmTr>, + ERROR: From<<::Db as Database>::Error>, +>( + evm: &mut EVM, +) -> Result<(), ERROR> { + let (context, precompiles) = evm.ctx_precompiles(); + + let gen_spec = context.cfg().spec(); + let spec = gen_spec.clone().into(); + // sets eth spec id in journal + context.journal_mut().set_spec_id(spec); + let precompiles_changed = precompiles.set_spec(gen_spec); + let empty_warmed_precompiles = context.journal_mut().precompile_addresses().is_empty(); + + if precompiles_changed || empty_warmed_precompiles { + // load new precompile addresses into journal. + // When precompiles addresses are changed we reset the warmed hashmap to those new addresses. + context + .journal_mut() + .warm_precompiles(precompiles.warm_addresses().collect()); + } + + // Load coinbase + // EIP-3651: Warm COINBASE. Starts the `COINBASE` address warm + if spec.is_enabled_in(SpecId::SHANGHAI) { + let coinbase = context.block().beneficiary(); + context.journal_mut().warm_coinbase_account(coinbase); + } + + // Load access list + let (tx, journal) = context.tx_journal_mut(); + // legacy is only tx type that does not have access list. + if tx.tx_type() != TransactionType::Legacy { + if let Some(access_list) = tx.access_list() { + for item in access_list { + let address = item.address(); + let mut storage = item.storage_slots().peekable(); + if storage.peek().is_none() { + journal.warm_account(*address); + } else { + journal.warm_account_and_storage( + *address, + storage.map(|i| StorageKey::from_be_bytes(i.0)), + )?; + } + } + } + } + + Ok(()) +} + +/// Validates caller account nonce and code according to EIP-3607. +#[inline] +pub fn validate_account_nonce_and_code( + caller_info: &mut AccountInfo, + tx_nonce: u64, + is_eip3607_disabled: bool, + is_nonce_check_disabled: bool, +) -> Result<(), InvalidTransaction> { + // EIP-3607: Reject transactions from senders with deployed code + // This EIP is introduced after london but there was no collision in past + // so we can leave it enabled always + if !is_eip3607_disabled { + let bytecode = match caller_info.code.as_ref() { + Some(code) => code, + None => &Bytecode::default(), + }; + // Allow EOAs whose code is a valid delegation designation, + // i.e. 0xef0100 || address, to continue to originate transactions. + if !bytecode.is_empty() && !bytecode.is_eip7702() { + return Err(InvalidTransaction::RejectCallerWithCode); + } + } + + // Check that the transaction's nonce is correct + if !is_nonce_check_disabled { + let tx = tx_nonce; + let state = caller_info.nonce; + match tx.cmp(&state) { + Ordering::Greater => { + return Err(InvalidTransaction::NonceTooHigh { tx, state }); + } + Ordering::Less => { + return Err(InvalidTransaction::NonceTooLow { tx, state }); + } + _ => {} + } + } + Ok(()) +} + +/// Validates caller state and deducts transaction costs from the caller's balance. +#[inline] +pub fn validate_against_state_and_deduct_caller< + CTX: ContextTr, + ERROR: From + From<::Error>, +>( + context: &mut CTX, +) -> Result<(), ERROR> { + let basefee = context.block().basefee() as u128; + let blob_price = context.block().blob_gasprice().unwrap_or_default(); + let is_balance_check_disabled = context.cfg().is_balance_check_disabled(); + let is_eip3607_disabled = context.cfg().is_eip3607_disabled(); + let is_nonce_check_disabled = context.cfg().is_nonce_check_disabled(); + + let (tx, journal) = context.tx_journal_mut(); + + // Load caller's account. + let caller_account = journal.load_account_code(tx.caller())?.data; + + validate_account_nonce_and_code( + &mut caller_account.info, + tx.nonce(), + is_eip3607_disabled, + is_nonce_check_disabled, + )?; + + // Bump the nonce for calls. Nonce for CREATE will be bumped in `make_create_frame`. + if tx.kind().is_call() { + // Nonce is already checked + caller_account.info.nonce = caller_account.info.nonce.saturating_add(1); + } + + let max_balance_spending = tx.max_balance_spending()?; + + // Check if account has enough balance for `gas_limit * max_fee`` and value transfer. + // Transfer will be done inside `*_inner` functions. + if max_balance_spending > caller_account.info.balance && !is_balance_check_disabled { + return Err(InvalidTransaction::LackOfFundForMaxFee { + fee: Box::new(max_balance_spending), + balance: Box::new(caller_account.info.balance), + } + .into()); + } + + let effective_balance_spending = tx + .effective_balance_spending(basefee, blob_price) + .expect("effective balance is always smaller than max balance so it can't overflow"); + + // subtracting max balance spending with value that is going to be deducted later in the call. + let gas_balance_spending = effective_balance_spending - tx.value(); + + let mut new_balance = caller_account + .info + .balance + .saturating_sub(gas_balance_spending); + + if is_balance_check_disabled { + // Make sure the caller's balance is at least the value of the transaction. + new_balance = new_balance.max(tx.value()); + } + + let old_balance = caller_account.info.balance; + // Touch account so we know it is changed. + caller_account.mark_touch(); + caller_account.info.balance = new_balance; + + journal.caller_accounting_journal_entry(tx.caller(), old_balance, tx.kind().is_call()); + Ok(()) +} + +/// Apply EIP-7702 auth list and return number gas refund on already created accounts. +#[inline] +pub fn apply_eip7702_auth_list< + CTX: ContextTr, + ERROR: From + From<::Error>, +>( + context: &mut CTX, +) -> Result { + let tx = context.tx(); + // Return if there is no auth list. + if tx.tx_type() != TransactionType::Eip7702 { + return Ok(0); + } + + let chain_id = context.cfg().chain_id(); + let (tx, journal) = context.tx_journal_mut(); + + let mut refunded_accounts = 0; + for authorization in tx.authorization_list() { + // 1. Verify the chain id is either 0 or the chain's current ID. + let auth_chain_id = authorization.chain_id(); + if !auth_chain_id.is_zero() && auth_chain_id != U256::from(chain_id) { + continue; + } + + // 2. Verify the `nonce` is less than `2**64 - 1`. + if authorization.nonce() == u64::MAX { + continue; + } + + // recover authority and authorized addresses. + // 3. `authority = ecrecover(keccak(MAGIC || rlp([chain_id, address, nonce])), y_parity, r, s]` + let Some(authority) = authorization.authority() else { + continue; + }; + + // warm authority account and check nonce. + // 4. Add `authority` to `accessed_addresses` (as defined in [EIP-2929](./eip-2929.md).) + let mut authority_acc = journal.load_account_code(authority)?; + + // 5. Verify the code of `authority` is either empty or already delegated. + if let Some(bytecode) = &authority_acc.info.code { + // if it is not empty and it is not eip7702 + if !bytecode.is_empty() && !bytecode.is_eip7702() { + continue; + } + } + + // 6. Verify the nonce of `authority` is equal to `nonce`. In case `authority` does not exist in the trie, verify that `nonce` is equal to `0`. + if authorization.nonce() != authority_acc.info.nonce { + continue; + } + + // 7. Add `PER_EMPTY_ACCOUNT_COST - PER_AUTH_BASE_COST` gas to the global refund counter if `authority` exists in the trie. + if !(authority_acc.is_empty() && authority_acc.is_loaded_as_not_existing_not_touched()) { + refunded_accounts += 1; + } + + // 8. Set the code of `authority` to be `0xef0100 || address`. This is a delegation designation. + // * As a special case, if `address` is `0x0000000000000000000000000000000000000000` do not write the designation. + // Clear the accounts code and reset the account's code hash to the empty hash `0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470`. + let address = authorization.address(); + let (bytecode, hash) = if address.is_zero() { + (Bytecode::default(), KECCAK_EMPTY) + } else { + let bytecode = Bytecode::new_eip7702(address); + let hash = bytecode.hash_slow(); + (bytecode, hash) + }; + authority_acc.info.code_hash = hash; + authority_acc.info.code = Some(bytecode); + + // 9. Increase the nonce of `authority` by one. + authority_acc.info.nonce = authority_acc.info.nonce.saturating_add(1); + authority_acc.mark_touch(); + } + + let refunded_gas = + refunded_accounts * (eip7702::PER_EMPTY_ACCOUNT_COST - eip7702::PER_AUTH_BASE_COST); + + Ok(refunded_gas) +} diff --git a/crates/handler/src/precompile_provider.rs b/crates/handler/src/precompile_provider.rs new file mode 100644 index 0000000000..bf960a1e51 --- /dev/null +++ b/crates/handler/src/precompile_provider.rs @@ -0,0 +1,153 @@ +use auto_impl::auto_impl; +use context::{Cfg, LocalContextTr}; +use context_interface::ContextTr; +use interpreter::{CallInput, Gas, InputsImpl, InstructionResult, InterpreterResult}; +use precompile::PrecompileError; +use precompile::{PrecompileSpecId, Precompiles}; +use primitives::{hardfork::SpecId, Address, Bytes}; +use std::boxed::Box; +use std::string::String; + +/// Provider for precompiled contracts in the EVM. +#[auto_impl(&mut, Box)] +pub trait PrecompileProvider { + /// The output type returned by precompile execution. + type Output; + + /// Sets the spec id and returns true if the spec id was changed. Initial call to set_spec will always return true. + /// + /// Returned booling will determine if precompile addresses should be injected into the journal. + fn set_spec(&mut self, spec: ::Spec) -> bool; + + /// Run the precompile. + fn run( + &mut self, + context: &mut CTX, + address: &Address, + inputs: &InputsImpl, + is_static: bool, + gas_limit: u64, + ) -> Result, String>; + + /// Get the warm addresses. + fn warm_addresses(&self) -> Box>; + + /// Check if the address is a precompile. + fn contains(&self, address: &Address) -> bool; +} + +/// The [`PrecompileProvider`] for ethereum precompiles. +#[derive(Debug)] +pub struct EthPrecompiles { + /// Contains precompiles for the current spec. + pub precompiles: &'static Precompiles, + /// Current spec. None means that spec was not set yet. + pub spec: SpecId, +} + +impl EthPrecompiles { + /// Returns addresses of the precompiles. + pub fn warm_addresses(&self) -> Box> { + Box::new(self.precompiles.addresses().cloned()) + } + + /// Returns whether the address is a precompile. + pub fn contains(&self, address: &Address) -> bool { + self.precompiles.contains(address) + } +} + +impl Clone for EthPrecompiles { + fn clone(&self) -> Self { + Self { + precompiles: self.precompiles, + spec: self.spec, + } + } +} + +impl Default for EthPrecompiles { + fn default() -> Self { + let spec = SpecId::default(); + Self { + precompiles: Precompiles::new(PrecompileSpecId::from_spec_id(spec)), + spec, + } + } +} + +impl PrecompileProvider for EthPrecompiles { + type Output = InterpreterResult; + + fn set_spec(&mut self, spec: ::Spec) -> bool { + let spec = spec.into(); + // generate new precompiles only on new spec + if spec == self.spec { + return false; + } + self.precompiles = Precompiles::new(PrecompileSpecId::from_spec_id(spec)); + self.spec = spec; + true + } + + fn run( + &mut self, + context: &mut CTX, + address: &Address, + inputs: &InputsImpl, + _is_static: bool, + gas_limit: u64, + ) -> Result, String> { + let Some(precompile) = self.precompiles.get(address) else { + return Ok(None); + }; + let mut result = InterpreterResult { + result: InstructionResult::Return, + gas: Gas::new(gas_limit), + output: Bytes::new(), + }; + + let r; + let input_bytes = match &inputs.input { + CallInput::SharedBuffer(range) => { + if let Some(slice) = context.local().shared_memory_buffer_slice(range.clone()) { + r = slice; + r.as_ref() + } else { + &[] + } + } + CallInput::Bytes(bytes) => bytes.0.iter().as_slice(), + }; + + match (*precompile)(input_bytes, gas_limit) { + Ok(output) => { + let underflow = result.gas.record_cost(output.gas_used); + assert!(underflow, "Gas underflow is not possible"); + result.result = if output.reverted { + InstructionResult::Revert + } else { + InstructionResult::Return + }; + result.output = output.bytes; + } + Err(PrecompileError::Fatal(e)) => return Err(e), + Err(e) => { + result.result = if e.is_oog() { + InstructionResult::PrecompileOOG + } else { + InstructionResult::PrecompileError + }; + } + } + Ok(Some(result)) + } + + fn warm_addresses(&self) -> Box> { + self.warm_addresses() + } + + fn contains(&self, address: &Address) -> bool { + self.contains(address) + } +} diff --git a/crates/handler/src/system_call.rs b/crates/handler/src/system_call.rs new file mode 100644 index 0000000000..5f27a9fb85 --- /dev/null +++ b/crates/handler/src/system_call.rs @@ -0,0 +1,255 @@ +//! System call logic for external state transitions required by certain EIPs (notably [EIP-2935](https://eips.ethereum.org/EIPS/eip-2935) and [EIP-4788](https://eips.ethereum.org/EIPS/eip-4788)). +//! +//! These EIPs require the client to perform special system calls to update state (such as block hashes or beacon roots) at block boundaries, outside of normal EVM transaction execution. REVM provides the system call mechanism, but the actual state transitions must be performed by the client or test harness, not by the EVM itself. +//! +//! # Example: Using `transact_system_call` for pre/post block hooks +//! +//! The client should use [`SystemCallEvm::transact_system_call`] method to perform required state updates before or after block execution, as specified by the EIP: +//! +//! ```rust,ignore +//! // Example: update beacon root (EIP-4788) at the start of a block +//! let beacon_root: Bytes = ...; // obtained from consensus layer +//! let beacon_contract: Address = "0x000F3df6D732807Ef1319fB7B8bB8522d0Beac02".parse().unwrap(); +//! evm.transact_system_call(beacon_contract, beacon_root)?; +//! +//! // Example: update block hash (EIP-2935) at the end of a block +//! let block_hash: Bytes = ...; // new block hash +//! let history_contract: Address = "0x0000F90827F1C53a10cb7A02335B175320002935".parse().unwrap(); +//! evm.transact_system_call(history_contract, block_hash)?; +//! ``` +//! +//! See the book section on [External State Transitions](../../book/src/external_state_transitions.md) for more details. +use crate::{ + frame::EthFrame, instructions::InstructionProvider, ExecuteCommitEvm, ExecuteEvm, Handler, + MainnetHandler, PrecompileProvider, +}; +use context::{result::ExecResultAndState, ContextSetters, ContextTr, Evm, JournalTr, TxEnv}; +use database_interface::DatabaseCommit; +use interpreter::{interpreter::EthInterpreter, InterpreterResult}; +use primitives::{address, Address, Bytes, TxKind}; +use state::EvmState; + +/// The system address used for system calls. +pub const SYSTEM_ADDRESS: Address = address!("0xfffffffffffffffffffffffffffffffffffffffe"); + +/// Creates the system transaction with default values and set data and tx call target to system contract address +/// that is going to be called. +/// +/// The caller is set to be [`SYSTEM_ADDRESS`]. +/// +/// It is used inside [`SystemCallEvm`] and [`SystemCallCommitEvm`] traits to prepare EVM for system call execution. +pub trait SystemCallTx: Sized { + /// Creates new transaction for system call. + fn new_system_tx(system_contract_address: Address, data: Bytes) -> Self { + Self::new_system_tx_with_caller(SYSTEM_ADDRESS, system_contract_address, data) + } + + /// Creates a new system transaction with a custom caller address. + fn new_system_tx_with_caller( + caller: Address, + system_contract_address: Address, + data: Bytes, + ) -> Self; +} + +impl SystemCallTx for TxEnv { + fn new_system_tx_with_caller( + caller: Address, + system_contract_address: Address, + data: Bytes, + ) -> Self { + TxEnv::builder() + .caller(caller) + .data(data) + .kind(TxKind::Call(system_contract_address)) + .gas_limit(30_000_000) + .build() + .unwrap() + } +} + +/// API for executing the system calls. System calls dont deduct the caller or reward the +/// beneficiary. They are used before and after block execution to insert or obtain blockchain state. +/// +/// It act similar to `transact` function and sets default Tx with data and system contract as a target. +pub trait SystemCallEvm: ExecuteEvm { + /// System call is a special transaction call that is used to call a system contract. + /// + /// Transaction fields are reset and set in [`SystemCallTx`] and data and target are set to + /// given values. + /// + /// Block values are taken into account and will determent how system call will be executed. + fn transact_system_call_with_caller( + &mut self, + caller: Address, + system_contract_address: Address, + data: Bytes, + ) -> Result; + + /// Calls [`SystemCallEvm::transact_system_call_with_caller`] with [`SYSTEM_ADDRESS`] as a caller. + fn transact_system_call( + &mut self, + system_contract_address: Address, + data: Bytes, + ) -> Result { + self.transact_system_call_with_caller(SYSTEM_ADDRESS, system_contract_address, data) + } + + /// Transact the system call and finalize. + /// + /// Internally calls combo of `transact_system_call` and `finalize` functions. + fn transact_system_call_finalize( + &mut self, + system_contract_address: Address, + data: Bytes, + ) -> Result, Self::Error> { + self.transact_system_call_with_caller_finalize( + SYSTEM_ADDRESS, + system_contract_address, + data, + ) + } + + /// Calls [`SystemCallEvm::transact_system_call_with_caller`] and `finalize` functions. + fn transact_system_call_with_caller_finalize( + &mut self, + caller: Address, + system_contract_address: Address, + data: Bytes, + ) -> Result, Self::Error> { + let result = + self.transact_system_call_with_caller(caller, system_contract_address, data)?; + let state = self.finalize(); + Ok(ExecResultAndState::new(result, state)) + } +} + +/// Extension of the [`SystemCallEvm`] trait that adds a method that commits the state after execution. +pub trait SystemCallCommitEvm: SystemCallEvm + ExecuteCommitEvm { + /// Transact the system call and commit to the state. + fn transact_system_call_commit( + &mut self, + system_contract_address: Address, + data: Bytes, + ) -> Result { + self.transact_system_call_with_caller_commit(SYSTEM_ADDRESS, system_contract_address, data) + } + + /// Calls [`SystemCallCommitEvm::transact_system_call_commit`] with [`SYSTEM_ADDRESS`] as a caller. + fn transact_system_call_with_caller_commit( + &mut self, + caller: Address, + system_contract_address: Address, + data: Bytes, + ) -> Result; +} + +impl SystemCallEvm + for Evm> +where + CTX: ContextTr, Tx: SystemCallTx> + ContextSetters, + INST: InstructionProvider, + PRECOMPILES: PrecompileProvider, +{ + fn transact_system_call_with_caller( + &mut self, + caller: Address, + system_contract_address: Address, + data: Bytes, + ) -> Result { + // set tx fields. + self.set_tx(CTX::Tx::new_system_tx_with_caller( + caller, + system_contract_address, + data, + )); + // create handler + MainnetHandler::default().run_system_call(self) + } +} + +impl SystemCallCommitEvm + for Evm> +where + CTX: ContextTr, Db: DatabaseCommit, Tx: SystemCallTx> + + ContextSetters, + INST: InstructionProvider, + PRECOMPILES: PrecompileProvider, +{ + fn transact_system_call_with_caller_commit( + &mut self, + caller: Address, + system_contract_address: Address, + data: Bytes, + ) -> Result { + self.transact_system_call_with_caller_finalize(caller, system_contract_address, data) + .map(|output| { + self.db_mut().commit(output.state); + output.result + }) + } +} + +#[cfg(test)] +mod tests { + use crate::{MainBuilder, MainContext}; + + use super::*; + use context::{ + result::{ExecutionResult, Output, SuccessReason}, + Context, Transaction, + }; + use database::InMemoryDB; + use primitives::{b256, bytes, StorageKey, U256}; + use state::{AccountInfo, Bytecode}; + + const HISTORY_STORAGE_ADDRESS: Address = address!("0x0000F90827F1C53a10cb7A02335B175320002935"); + static HISTORY_STORAGE_CODE: Bytes = bytes!("0x3373fffffffffffffffffffffffffffffffffffffffe14604657602036036042575f35600143038111604257611fff81430311604257611fff9006545f5260205ff35b5f5ffd5b5f35611fff60014303065500"); + + #[test] + fn test_system_call() { + let mut db = InMemoryDB::default(); + db.insert_account_info( + HISTORY_STORAGE_ADDRESS, + AccountInfo::default().with_code(Bytecode::new_legacy(HISTORY_STORAGE_CODE.clone())), + ); + + let block_hash = + b256!("0x1111111111111111111111111111111111111111111111111111111111111111"); + + let mut evm = Context::mainnet() + .with_db(db) + // block with number 1 will set storage at slot 0. + .modify_block_chained(|b| b.number = U256::ONE) + .build_mainnet(); + let output = evm + .transact_system_call_finalize(HISTORY_STORAGE_ADDRESS, block_hash.0.into()) + .unwrap(); + + // system call gas limit is 30M + assert_eq!(evm.ctx.tx().gas_limit(), 30_000_000); + + assert_eq!( + output.result, + ExecutionResult::Success { + reason: SuccessReason::Stop, + gas_used: 22143, + gas_refunded: 0, + logs: vec![], + output: Output::Call(Bytes::default()) + } + ); + // only system contract is updated and present + assert_eq!(output.state.len(), 1); + assert_eq!( + output.state[&HISTORY_STORAGE_ADDRESS] + .storage + .get(&StorageKey::from(0)) + .map(|slot| slot.present_value) + .unwrap_or_default(), + U256::from_be_bytes(block_hash.0), + "State is not updated {:?}", + output.state + ); + } +} diff --git a/crates/handler/src/validation.rs b/crates/handler/src/validation.rs new file mode 100644 index 0000000000..73fccedcf8 --- /dev/null +++ b/crates/handler/src/validation.rs @@ -0,0 +1,607 @@ +use context_interface::{ + result::{InvalidHeader, InvalidTransaction}, + transaction::{Transaction, TransactionType}, + Block, Cfg, ContextTr, +}; +use core::cmp; +use interpreter::gas::{self, InitialAndFloorGas}; +use primitives::{eip4844, hardfork::SpecId, B256}; + +/// Validates the execution environment including block and transaction parameters. +pub fn validate_env + From>( + context: CTX, +) -> Result<(), ERROR> { + let spec = context.cfg().spec().into(); + // `prevrandao` is required for the merge + if spec.is_enabled_in(SpecId::MERGE) && context.block().prevrandao().is_none() { + return Err(InvalidHeader::PrevrandaoNotSet.into()); + } + // `excess_blob_gas` is required for Cancun + if spec.is_enabled_in(SpecId::CANCUN) && context.block().blob_excess_gas_and_price().is_none() { + return Err(InvalidHeader::ExcessBlobGasNotSet.into()); + } + validate_tx_env::(context, spec).map_err(Into::into) +} + +/// Validate transaction that has EIP-1559 priority fee +pub fn validate_priority_fee_tx( + max_fee: u128, + max_priority_fee: u128, + base_fee: Option, + disable_priority_fee_check: bool, +) -> Result<(), InvalidTransaction> { + if !disable_priority_fee_check && max_priority_fee > max_fee { + // Or gas_max_fee for eip1559 + return Err(InvalidTransaction::PriorityFeeGreaterThanMaxFee); + } + + // Check minimal cost against basefee + if let Some(base_fee) = base_fee { + let effective_gas_price = cmp::min(max_fee, base_fee.saturating_add(max_priority_fee)); + if effective_gas_price < base_fee { + return Err(InvalidTransaction::GasPriceLessThanBasefee); + } + } + + Ok(()) +} + +/// Validate EIP-4844 transaction. +pub fn validate_eip4844_tx( + blobs: &[B256], + max_blob_fee: u128, + block_blob_gas_price: u128, + max_blobs: Option, +) -> Result<(), InvalidTransaction> { + // Ensure that the user was willing to at least pay the current blob gasprice + if block_blob_gas_price > max_blob_fee { + return Err(InvalidTransaction::BlobGasPriceGreaterThanMax); + } + + // There must be at least one blob + if blobs.is_empty() { + return Err(InvalidTransaction::EmptyBlobs); + } + + // All versioned blob hashes must start with VERSIONED_HASH_VERSION_KZG + for blob in blobs { + if blob[0] != eip4844::VERSIONED_HASH_VERSION_KZG { + return Err(InvalidTransaction::BlobVersionNotSupported); + } + } + + // Ensure the total blob gas spent is at most equal to the limit + // assert blob_gas_used <= MAX_BLOB_GAS_PER_BLOCK + if let Some(max_blobs) = max_blobs { + if blobs.len() > max_blobs as usize { + return Err(InvalidTransaction::TooManyBlobs { + have: blobs.len(), + max: max_blobs as usize, + }); + } + } + Ok(()) +} + +/// Validate transaction against block and configuration for mainnet. +pub fn validate_tx_env( + context: CTX, + spec_id: SpecId, +) -> Result<(), InvalidTransaction> { + // Check if the transaction's chain id is correct + let tx_type = context.tx().tx_type(); + let tx = context.tx(); + + let base_fee = if context.cfg().is_base_fee_check_disabled() { + None + } else { + Some(context.block().basefee() as u128) + }; + + let tx_type = TransactionType::from(tx_type); + + // Check chain_id if config is enabled. + // EIP-155: Simple replay attack protection + if context.cfg().tx_chain_id_check() { + if let Some(chain_id) = tx.chain_id() { + if chain_id != context.cfg().chain_id() { + return Err(InvalidTransaction::InvalidChainId); + } + } else if !tx_type.is_legacy() && !tx_type.is_custom() { + // Legacy transaction are the only one that can omit chain_id. + return Err(InvalidTransaction::MissingChainId); + } + } + + // EIP-7825: Transaction Gas Limit Cap + let cap = context.cfg().tx_gas_limit_cap(); + if tx.gas_limit() > cap { + return Err(InvalidTransaction::TxGasLimitGreaterThanCap { + gas_limit: tx.gas_limit(), + cap, + }); + } + + let disable_priority_fee_check = context.cfg().is_priority_fee_check_disabled(); + + match tx_type { + TransactionType::Legacy => { + // Gas price must be at least the basefee. + if let Some(base_fee) = base_fee { + if tx.gas_price() < base_fee { + return Err(InvalidTransaction::GasPriceLessThanBasefee); + } + } + } + TransactionType::Eip2930 => { + // Enabled in BERLIN hardfork + if !spec_id.is_enabled_in(SpecId::BERLIN) { + return Err(InvalidTransaction::Eip2930NotSupported); + } + + // Gas price must be at least the basefee. + if let Some(base_fee) = base_fee { + if tx.gas_price() < base_fee { + return Err(InvalidTransaction::GasPriceLessThanBasefee); + } + } + } + TransactionType::Eip1559 => { + if !spec_id.is_enabled_in(SpecId::LONDON) { + return Err(InvalidTransaction::Eip1559NotSupported); + } + validate_priority_fee_tx( + tx.max_fee_per_gas(), + tx.max_priority_fee_per_gas().unwrap_or_default(), + base_fee, + disable_priority_fee_check, + )?; + } + TransactionType::Eip4844 => { + if !spec_id.is_enabled_in(SpecId::CANCUN) { + return Err(InvalidTransaction::Eip4844NotSupported); + } + + validate_priority_fee_tx( + tx.max_fee_per_gas(), + tx.max_priority_fee_per_gas().unwrap_or_default(), + base_fee, + disable_priority_fee_check, + )?; + + validate_eip4844_tx( + tx.blob_versioned_hashes(), + tx.max_fee_per_blob_gas(), + context.block().blob_gasprice().unwrap_or_default(), + context.cfg().max_blobs_per_tx(), + )?; + } + TransactionType::Eip7702 => { + // Check if EIP-7702 transaction is enabled. + if !spec_id.is_enabled_in(SpecId::PRAGUE) { + return Err(InvalidTransaction::Eip7702NotSupported); + } + + validate_priority_fee_tx( + tx.max_fee_per_gas(), + tx.max_priority_fee_per_gas().unwrap_or_default(), + base_fee, + disable_priority_fee_check, + )?; + + let auth_list_len = tx.authorization_list_len(); + // The transaction is considered invalid if the length of authorization_list is zero. + if auth_list_len == 0 { + return Err(InvalidTransaction::EmptyAuthorizationList); + } + } + /* // TODO(EOF) EOF removed from spec. + TransactionType::Eip7873 => { + // Check if EIP-7873 transaction is enabled. + if !spec_id.is_enabled_in(SpecId::OSAKA) { + return Err(InvalidTransaction::Eip7873NotSupported); + } + // validate chain id + if Some(context.cfg().chain_id()) != tx.chain_id() { + return Err(InvalidTransaction::InvalidChainId); + } + + // validate initcodes. + validate_eip7873_initcodes(tx.initcodes())?; + + // InitcodeTransaction is invalid if the to is nil. + if tx.kind().is_create() { + return Err(InvalidTransaction::Eip7873MissingTarget); + } + + validate_priority_fee_tx( + tx.max_fee_per_gas(), + tx.max_priority_fee_per_gas().unwrap_or_default(), + base_fee, + )?; + } + */ + TransactionType::Custom => { + // Custom transaction type check is not done here. + } + }; + + // Check if gas_limit is more than block_gas_limit + if !context.cfg().is_block_gas_limit_disabled() && tx.gas_limit() > context.block().gas_limit() + { + return Err(InvalidTransaction::CallerGasLimitMoreThanBlock); + } + + // EIP-3860: Limit and meter initcode. Still valid with EIP-7907 and increase of initcode size. + if spec_id.is_enabled_in(SpecId::SHANGHAI) + && tx.kind().is_create() + && context.tx().input().len() > context.cfg().max_initcode_size() + { + return Err(InvalidTransaction::CreateInitCodeSizeLimit); + } + + Ok(()) +} + +/* TODO(EOF) +/// Validate Initcode Transaction initcode list, return error if any of the following conditions are met: +/// * there are zero entries in initcodes, or if there are more than MAX_INITCODE_COUNT entries. +/// * any entry in initcodes is zero length, or if any entry exceeds MAX_INITCODE_SIZE. +/// * the to is nil. +pub fn validate_eip7873_initcodes(initcodes: &[Bytes]) -> Result<(), InvalidTransaction> { + let mut i = 0; + for initcode in initcodes { + // InitcodeTransaction is invalid if any entry in initcodes is zero length + if initcode.is_empty() { + return Err(InvalidTransaction::Eip7873EmptyInitcode { i }); + } + + // or if any entry exceeds MAX_INITCODE_SIZE. + if initcode.len() > MAX_INITCODE_SIZE { + return Err(InvalidTransaction::Eip7873InitcodeTooLarge { + i, + size: initcode.len(), + }); + } + + i += 1; + } + + // InitcodeTransaction is invalid if there are zero entries in initcodes, + if i == 0 { + return Err(InvalidTransaction::Eip7873EmptyInitcodeList); + } + + // or if there are more than MAX_INITCODE_COUNT entries. + if i > MAX_INITCODE_COUNT { + return Err(InvalidTransaction::Eip7873TooManyInitcodes { size: i }); + } + + Ok(()) +} +*/ + +/// Validate initial transaction gas. +pub fn validate_initial_tx_gas( + tx: impl Transaction, + spec: SpecId, +) -> Result { + let gas = gas::calculate_initial_tx_gas_for_tx(&tx, spec); + + // Additional check to see if limit is big enough to cover initial gas. + if gas.initial_gas > tx.gas_limit() { + return Err(InvalidTransaction::CallGasCostMoreThanGasLimit { + gas_limit: tx.gas_limit(), + initial_gas: gas.initial_gas, + }); + } + + // EIP-7623: Increase calldata cost + // floor gas should be less than gas limit. + if spec.is_enabled_in(SpecId::PRAGUE) && gas.floor_gas > tx.gas_limit() { + return Err(InvalidTransaction::GasFloorMoreThanGasLimit { + gas_floor: gas.floor_gas, + gas_limit: tx.gas_limit(), + }); + }; + + Ok(gas) +} + +#[cfg(test)] +mod tests { + use crate::{ExecuteCommitEvm, MainBuilder, MainContext}; + use bytecode::opcode; + use context::{ + result::{EVMError, ExecutionResult, HaltReason, InvalidTransaction, Output}, + Context, TxEnv, + }; + use database::{CacheDB, EmptyDB}; + use primitives::{address, eip3860, eip7907, hardfork::SpecId, Bytes, TxKind}; + + fn deploy_contract( + bytecode: Bytes, + spec_id: Option, + ) -> Result> { + let ctx = Context::mainnet() + .modify_cfg_chained(|c| { + if let Some(spec_id) = spec_id { + c.spec = spec_id; + } + }) + .with_db(CacheDB::::default()); + + let mut evm = ctx.build_mainnet(); + evm.transact_commit( + TxEnv::builder() + .kind(TxKind::Create) + .data(bytecode.clone()) + .build() + .unwrap(), + ) + } + + #[test] + fn test_eip3860_initcode_size_limit_failure() { + let large_bytecode = vec![opcode::STOP; eip3860::MAX_INITCODE_SIZE + 1]; + let bytecode: Bytes = large_bytecode.into(); + let result = deploy_contract(bytecode, Some(SpecId::PRAGUE)); + assert!(matches!( + result, + Err(EVMError::Transaction( + InvalidTransaction::CreateInitCodeSizeLimit + )) + )); + } + + #[test] + fn test_eip3860_initcode_size_limit_success_prague() { + let large_bytecode = vec![opcode::STOP; eip3860::MAX_INITCODE_SIZE]; + let bytecode: Bytes = large_bytecode.into(); + let result = deploy_contract(bytecode, Some(SpecId::PRAGUE)); + assert!(matches!(result, Ok(ExecutionResult::Success { .. }))); + } + + #[test] + fn test_eip7907_initcode_size_limit_failure_osaka() { + let large_bytecode = vec![opcode::STOP; eip7907::MAX_INITCODE_SIZE + 1]; + let bytecode: Bytes = large_bytecode.into(); + let result = deploy_contract(bytecode, Some(SpecId::OSAKA)); + assert!(matches!( + result, + Err(EVMError::Transaction( + InvalidTransaction::CreateInitCodeSizeLimit + )) + )); + } + + #[test] + fn test_eip7907_code_size_limit_failure() { + // EIP-7907: MAX_CODE_SIZE = 0x40000 + // use the simplest method to return a contract code size greater than 0x40000 + // PUSH3 0x40001 (greater than 0x40000) - return size + // PUSH1 0x00 - memory position 0 + // RETURN - return uninitialized memory, will be filled with 0 + let init_code = vec![ + 0x62, 0x04, 0x00, 0x01, // PUSH3 0x40001 (greater than 0x40000) + 0x60, 0x00, // PUSH1 0 + 0xf3, // RETURN + ]; + let bytecode: Bytes = init_code.into(); + let result = deploy_contract(bytecode, Some(SpecId::OSAKA)); + assert!(matches!( + result, + Ok(ExecutionResult::Halt { + reason: HaltReason::CreateContractSizeLimit, + .. + },) + )); + } + + #[test] + fn test_eip170_code_size_limit_failure() { + // use the simplest method to return a contract code size greater than 0x6000 + // PUSH3 0x6001 (greater than 0x6000) - return size + // PUSH1 0x00 - memory position 0 + // RETURN - return uninitialized memory, will be filled with 0 + let init_code = vec![ + 0x62, 0x00, 0x60, 0x01, // PUSH3 0x6001 (greater than 0x6000) + 0x60, 0x00, // PUSH1 0 + 0xf3, // RETURN + ]; + let bytecode: Bytes = init_code.into(); + let result = deploy_contract(bytecode, Some(SpecId::PRAGUE)); + assert!(matches!( + result, + Ok(ExecutionResult::Halt { + reason: HaltReason::CreateContractSizeLimit, + .. + },) + )); + } + + #[test] + fn test_eip170_code_size_limit_success() { + // use the simplest method to return a contract code size equal to 0x6000 + // PUSH3 0x6000 - return size + // PUSH1 0x00 - memory position 0 + // RETURN - return uninitialized memory, will be filled with 0 + let init_code = vec![ + 0x62, 0x00, 0x60, 0x00, // PUSH3 0x6000 + 0x60, 0x00, // PUSH1 0 + 0xf3, // RETURN + ]; + let bytecode: Bytes = init_code.into(); + let result = deploy_contract(bytecode, None); + assert!(matches!(result, Ok(ExecutionResult::Success { .. },))); + } + + #[test] + fn test_eip170_create_opcode_size_limit_failure() { + // 1. create a "factory" contract, which will use the CREATE opcode to create another large contract + // 2. because the sub contract exceeds the EIP-170 limit, the CREATE operation should fail + + // the bytecode of the factory contract: + // PUSH1 0x01 - the value for MSTORE + // PUSH1 0x00 - the memory position + // MSTORE - store a non-zero value at the beginning of memory + + // PUSH3 0x6001 - the return size (exceeds 0x6000) + // PUSH1 0x00 - the memory offset + // PUSH1 0x00 - the amount of ETH sent + // CREATE - create contract instruction (create contract from current memory) + + // PUSH1 0x00 - the return value storage position + // MSTORE - store the address returned by CREATE to the memory position 0 + // PUSH1 0x20 - the return size (32 bytes) + // PUSH1 0x00 - the return offset + // RETURN - return the result + + let factory_code = vec![ + // 1. store a non-zero value at the beginning of memory + 0x60, 0x01, // PUSH1 0x01 + 0x60, 0x00, // PUSH1 0x00 + 0x52, // MSTORE + // 2. prepare to create a large contract + 0x62, 0x00, 0x60, 0x01, // PUSH3 0x6001 (exceeds 0x6000) + 0x60, 0x00, // PUSH1 0x00 (the memory offset) + 0x60, 0x00, // PUSH1 0x00 (the amount of ETH sent) + 0xf0, // CREATE + // 3. store the address returned by CREATE to the memory position 0 + 0x60, 0x00, // PUSH1 0x00 + 0x52, // MSTORE (store the address returned by CREATE to the memory position 0) + // 4. return the result + 0x60, 0x20, // PUSH1 0x20 (32 bytes) + 0x60, 0x00, // PUSH1 0x00 + 0xf3, // RETURN + ]; + + // deploy factory contract + let factory_bytecode: Bytes = factory_code.into(); + let factory_result = deploy_contract(factory_bytecode, Some(SpecId::PRAGUE)) + .expect("factory contract deployment failed"); + + // get factory contract address + let factory_address = match &factory_result { + ExecutionResult::Success { + output: Output::Create(_, Some(addr)), + .. + } => *addr, + _ => panic!("factory contract deployment failed: {factory_result:?}"), + }; + + // call factory contract to create sub contract + let tx_caller = address!("0x0000000000000000000000000000000000100000"); + let call_result = Context::mainnet() + .with_db(CacheDB::::default()) + .build_mainnet() + .transact_commit( + TxEnv::builder() + .caller(tx_caller) + .kind(TxKind::Call(factory_address)) + .data(Bytes::new()) + .build() + .unwrap(), + ) + .expect("call factory contract failed"); + + match &call_result { + ExecutionResult::Success { output, .. } => match output { + Output::Call(bytes) => { + if !bytes.is_empty() { + assert!( + bytes.iter().all(|&b| b == 0), + "When CREATE operation failed, it should return all zero address" + ); + } + } + _ => panic!("unexpected output type"), + }, + _ => panic!("execution result is not Success"), + } + } + + #[test] + fn test_eip170_create_opcode_size_limit_success() { + // 1. create a "factory" contract, which will use the CREATE opcode to create another contract + // 2. the sub contract generated by the factory contract does not exceed the EIP-170 limit, so it should be created successfully + + // the bytecode of the factory contract: + // PUSH1 0x01 - the value for MSTORE + // PUSH1 0x00 - the memory position + // MSTORE - store a non-zero value at the beginning of memory + + // PUSH3 0x6000 - the return size (0x6000) + // PUSH1 0x00 - the memory offset + // PUSH1 0x00 - the amount of ETH sent + // CREATE - create contract instruction (create contract from current memory) + + // PUSH1 0x00 - the return value storage position + // MSTORE - store the address returned by CREATE to the memory position 0 + // PUSH1 0x20 - the return size (32 bytes) + // PUSH1 0x00 - the return offset + // RETURN - return the result + + let factory_code = vec![ + // 1. store a non-zero value at the beginning of memory + 0x60, 0x01, // PUSH1 0x01 + 0x60, 0x00, // PUSH1 0x00 + 0x52, // MSTORE + // 2. prepare to create a contract + 0x62, 0x00, 0x60, 0x00, // PUSH3 0x6000 (0x6000) + 0x60, 0x00, // PUSH1 0x00 (the memory offset) + 0x60, 0x00, // PUSH1 0x00 (the amount of ETH sent) + 0xf0, // CREATE + // 3. store the address returned by CREATE to the memory position 0 + 0x60, 0x00, // PUSH1 0x00 + 0x52, // MSTORE (store the address returned by CREATE to the memory position 0) + // 4. return the result + 0x60, 0x20, // PUSH1 0x20 (32 bytes) + 0x60, 0x00, // PUSH1 0x00 + 0xf3, // RETURN + ]; + + // deploy factory contract + let factory_bytecode: Bytes = factory_code.into(); + let factory_result = deploy_contract(factory_bytecode, Some(SpecId::PRAGUE)) + .expect("factory contract deployment failed"); + // get factory contract address + let factory_address = match &factory_result { + ExecutionResult::Success { + output: Output::Create(_, Some(addr)), + .. + } => *addr, + _ => panic!("factory contract deployment failed: {factory_result:?}"), + }; + + // call factory contract to create sub contract + let tx_caller = address!("0x0000000000000000000000000000000000100000"); + let call_result = Context::mainnet() + .with_db(CacheDB::::default()) + .build_mainnet() + .transact_commit( + TxEnv::builder() + .caller(tx_caller) + .kind(TxKind::Call(factory_address)) + .data(Bytes::new()) + .build() + .unwrap(), + ) + .expect("call factory contract failed"); + + match &call_result { + ExecutionResult::Success { output, .. } => { + match output { + Output::Call(bytes) => { + // check if CREATE operation is successful (return non-zero address) + if !bytes.is_empty() { + assert!(bytes.iter().any(|&b| b != 0), "create sub contract failed"); + } + } + _ => panic!("unexpected output type"), + } + } + _ => panic!("execution result is not Success"), + } + } +} diff --git a/crates/inspector/CHANGELOG.md b/crates/inspector/CHANGELOG.md new file mode 100644 index 0000000000..2c6729f593 --- /dev/null +++ b/crates/inspector/CHANGELOG.md @@ -0,0 +1,299 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [8.1.0](https://github.com/bluealloy/revm/compare/revm-inspector-v8.0.3...revm-inspector-v8.1.0) - 2025-07-23 + +### Added + +- count inspector and bench test ([#2730](https://github.com/bluealloy/revm/pull/2730)) + +### Fixed + +- fully deprecate serde-json ([#2767](https://github.com/bluealloy/revm/pull/2767)) +- features and check in ci ([#2766](https://github.com/bluealloy/revm/pull/2766)) + +### Other + +- *(inspector)* simplify create_end docs and intrp.bytecode.set_action ([#2723](https://github.com/bluealloy/revm/pull/2723)) +- *(inspector)* update obsolete current_opcode() comment ([#2722](https://github.com/bluealloy/revm/pull/2722)) + +## [8.0.3](https://github.com/bluealloy/revm/compare/revm-inspector-v8.0.2...revm-inspector-v8.0.3) - 2025-07-14 + +### Fixed + +- *(Inspector)* call_end not calle on first call fast return ([#2697](https://github.com/bluealloy/revm/pull/2697)) + +## [8.0.2](https://github.com/bluealloy/revm/compare/revm-inspector-v8.0.1...revm-inspector-v8.0.2) - 2025-07-03 + +### Fixed + +- *(inspector)* revert pointer before calling step_end ([#2687](https://github.com/bluealloy/revm/pull/2687)) + +### Other + +- minor fixes ([#2686](https://github.com/bluealloy/revm/pull/2686)) + +## [8.0.1](https://github.com/bluealloy/revm/compare/revm-inspector-v7.0.1...revm-inspector-v8.0.1) - 2025-06-30 + +### Other + +- cargo clippy --fix --all ([#2671](https://github.com/bluealloy/revm/pull/2671)) +- use TxEnv::builder ([#2652](https://github.com/bluealloy/revm/pull/2652)) + +## [7.0.1](https://github.com/bluealloy/revm/compare/revm-inspector-v7.0.0...revm-inspector-v7.0.1) - 2025-06-20 + +### Other + +- updated the following local packages: revm-context, revm-handler, revm-interpreter + +## [7.0.0](https://github.com/bluealloy/revm/compare/revm-inspector-v6.0.0...revm-inspector-v7.0.0) - 2025-06-19 + +### Added + +- remove EOF ([#2644](https://github.com/bluealloy/revm/pull/2644)) +- *(precompile)* rug/gmp-based modexp ([#2596](https://github.com/bluealloy/revm/pull/2596)) +- add Inspector implementation for either::Either ([#2614](https://github.com/bluealloy/revm/pull/2614)) +- *(InspectEvm)* add inspect_finalize method for tx+inspector with state ([#2593](https://github.com/bluealloy/revm/pull/2593)) + +### Other + +- lints handler inspector interpreter ([#2646](https://github.com/bluealloy/revm/pull/2646)) +- re-use frame allocation ([#2636](https://github.com/bluealloy/revm/pull/2636)) +- rename `transact` methods ([#2616](https://github.com/bluealloy/revm/pull/2616)) + +## [6.0.0](https://github.com/bluealloy/revm/compare/revm-inspector-v5.0.1...revm-inspector-v6.0.0) - 2025-06-06 + +### Added + +- transact multi tx ([#2517](https://github.com/bluealloy/revm/pull/2517)) + +### Other + +- tag v75 revm v24.0.1 ([#2563](https://github.com/bluealloy/revm/pull/2563)) ([#2589](https://github.com/bluealloy/revm/pull/2589)) +- ContextTr rm *_ref, and add *_mut fn ([#2560](https://github.com/bluealloy/revm/pull/2560)) +- simplify Interpreter loop ([#2544](https://github.com/bluealloy/revm/pull/2544)) +- Add InstructionContext instead of Host and Interpreter ([#2548](https://github.com/bluealloy/revm/pull/2548)) + +## [5.0.1](https://github.com/bluealloy/revm/compare/revm-inspector-v5.0.0...revm-inspector-v5.0.1) - 2025-05-31 + +### Other + +- updated the following local packages: revm-context, revm-handler + +## [5.0.0](https://github.com/bluealloy/revm/compare/revm-inspector-v4.1.0...revm-inspector-v5.0.0) - 2025-05-22 + +### Added + +- *(op-revm)* add testdata comparison utility for EVM execution output ([#2525](https://github.com/bluealloy/revm/pull/2525)) + +### Other + +- make crates.io version badge clickable ([#2526](https://github.com/bluealloy/revm/pull/2526)) + +## [4.1.0](https://github.com/bluealloy/revm/compare/revm-inspector-v4.0.0...revm-inspector-v4.1.0) - 2025-05-07 + +Dependency bump + +## [4.0.0](https://github.com/bluealloy/revm/compare/revm-inspector-v3.0.1...revm-inspector-v4.0.0) - 2025-05-07 + +### Fixed + +- *(inspector)* call frame_end after frame_start returns Some ([#2481](https://github.com/bluealloy/revm/pull/2481)) +- *(inspector)* fix call return with Some ([#2469](https://github.com/bluealloy/revm/pull/2469)) +- *(tracing)* Fix the ordering of EOFCREATE frame traces ([#2398](https://github.com/bluealloy/revm/pull/2398)) + +### Other + +- copy edit The Book ([#2463](https://github.com/bluealloy/revm/pull/2463)) +- *(journal)* flatten journal entries ([#2440](https://github.com/bluealloy/revm/pull/2440)) +- bump dependency version ([#2431](https://github.com/bluealloy/revm/pull/2431)) +- fixed broken link ([#2421](https://github.com/bluealloy/revm/pull/2421)) +- backport from release branch ([#2415](https://github.com/bluealloy/revm/pull/2415)) ([#2416](https://github.com/bluealloy/revm/pull/2416)) +- *(lints)* revm-context lints ([#2404](https://github.com/bluealloy/revm/pull/2404)) + +## [3.0.1](https://github.com/bluealloy/revm/compare/revm-inspector-v3.0.0...revm-inspector-v3.0.1) - 2025-04-15 + +### Other + +## [3.0.0](https://github.com/bluealloy/revm/compare/revm-inspector-v2.0.0...revm-inspector-v3.0.0) - 2025-04-09 + +### Added + +- support for system calls ([#2350](https://github.com/bluealloy/revm/pull/2350)) + +## [2.0.0](https://github.com/bluealloy/revm/compare/revm-inspector-v1.0.0...revm-inspector-v2.0.0) - 2025-03-28 + +### Added + +- cache precompile warming ([#2317](https://github.com/bluealloy/revm/pull/2317)) + +## [1.0.0](https://github.com/bluealloy/revm/compare/revm-inspector-v1.0.0-alpha.7...revm-inspector-v1.0.0) - 2025-03-24 + +### Other + +- updated the following local packages: revm-database + +## [1.0.0-alpha.7](https://github.com/bluealloy/revm/compare/revm-inspector-v1.0.0-alpha.6...revm-inspector-v1.0.0-alpha.7) - 2025-03-21 + +### Added + +- InspectEvm fn renames, inspector docs, book cleanup ([#2275](https://github.com/bluealloy/revm/pull/2275)) +- Remove PrecompileError from PrecompileProvider ([#2233](https://github.com/bluealloy/revm/pull/2233)) + +### Other + +- Add custom instruction example ([#2261](https://github.com/bluealloy/revm/pull/2261)) + +## [1.0.0-alpha.6](https://github.com/bluealloy/revm/compare/revm-inspector-v1.0.0-alpha.5...revm-inspector-v1.0.0-alpha.6) - 2025-03-16 + +### Added + +- *(docs)* MyEvm example and book cleanup ([#2218](https://github.com/bluealloy/revm/pull/2218)) + +## [1.0.0-alpha.5](https://github.com/bluealloy/revm/compare/revm-inspector-v1.0.0-alpha.4...revm-inspector-v1.0.0-alpha.5) - 2025-03-12 + +### Added + +- add custom error to context ([#2197](https://github.com/bluealloy/revm/pull/2197)) +- Add tx/block to EvmExecution trait ([#2195](https://github.com/bluealloy/revm/pull/2195)) +- rename inspect_previous to inspect_replay ([#2194](https://github.com/bluealloy/revm/pull/2194)) + +## [1.0.0-alpha.4](https://github.com/bluealloy/revm/compare/revm-inspector-v1.0.0-alpha.3...revm-inspector-v1.0.0-alpha.4) - 2025-03-11 + +### Added + +- decouple first_frame_input from inspector ([#2180](https://github.com/bluealloy/revm/pull/2180)) + +### Fixed + +- remove wrong Clone Macro in WrapDatabaseRef ([#2181](https://github.com/bluealloy/revm/pull/2181)) +- correct propagate features ([#2177](https://github.com/bluealloy/revm/pull/2177)) + +### Other + +- remove CTX phantomdata from precompile providers ([#2178](https://github.com/bluealloy/revm/pull/2178)) + +## [1.0.0-alpha.3](https://github.com/bluealloy/revm/compare/revm-inspector-v1.0.0-alpha.2...revm-inspector-v1.0.0-alpha.3) - 2025-03-10 + +### Other + +- updated the following local packages: revm-interpreter, revm-precompile + +## [1.0.0-alpha.2](https://github.com/bluealloy/revm/compare/revm-inspector-v1.0.0-alpha.1...revm-inspector-v1.0.0-alpha.2) - 2025-03-10 + +### Fixed + +- *(op)* Handler deposit tx halt, catch_error handle ([#2144](https://github.com/bluealloy/revm/pull/2144)) + +### Other + +- JournalTr, JournalOutput, op only using revm crate ([#2155](https://github.com/bluealloy/revm/pull/2155)) +- docs and cleanup (rm Custom Inst) ([#2151](https://github.com/bluealloy/revm/pull/2151)) +- move mainnet builder to handler crate ([#2138](https://github.com/bluealloy/revm/pull/2138)) +- add immutable gas API to LoopControl ([#2134](https://github.com/bluealloy/revm/pull/2134)) +- PrecompileErrors to PrecompileError ([#2103](https://github.com/bluealloy/revm/pull/2103)) +- move all dependencies to workspace ([#2092](https://github.com/bluealloy/revm/pull/2092)) +- remove unused generics from TracerEip3155 ([#2090](https://github.com/bluealloy/revm/pull/2090)) +- re-export all crates from `revm` ([#2088](https://github.com/bluealloy/revm/pull/2088)) + +## [1.0.0-alpha.1](https://github.com/bluealloy/revm/releases/tag/revm-inspector-v1.0.0-alpha.1) - 2025-02-16 + +### Added + +- Split Inspector trait from EthHandler into standalone crate (#2075) +- Evm structure (Cached Instructions and Precompiles) (#2049) +- simplify InspectorContext (#2036) +- Add essential EIP-7756 tracing fields (#2023) +- Context execution (#2013) +- EthHandler trait (#2001) +- *(eip7702)* apply latest EIP-7702 changes, backport from v52 (#1969) +- *(EIP-7623)* Increase calldata cost. backport from rel/v51 (#1965) +- simplify Transaction trait (#1959) +- Split inspector.rs (#1958) +- expose precompile address in Journal, DB::Error: StdError (#1956) +- Make Ctx journal generic (#1933) +- Restucturing Part7 Handler and Context rework (#1865) +- restructuring Part6 transaction crate (#1814) +- Merge validation/analyzis with Bytecode (#1793) +- Restructuring Part3 inspector crate (#1788) +- restructure Part2 database crate (#1784) +- project restructuring Part1 (#1776) +- *(examples)* generate block traces (#895) +- implement EIP-4844 (#668) +- *(Shanghai)* All EIPs: push0, warm coinbase, limit/measure initcode (#376) +- Migrate `primitive_types::U256` to `ruint::Uint<256, 4>` (#239) +- Introduce ByteCode format, Update Readme (#156) + +### Fixed + +- *(tracer)* Flush buffer (#2080) +- *(Inspector)* frame_end called multiple times (#2037) +- *(Inspector)* call handler functions (#2026) +- Clear journal (#1927) +- fix typos ([#620](https://github.com/bluealloy/revm/pull/620)) + +### Other + +- set alpha.1 version +- Bump licence year to 2025 (#2058) +- improve EIP-3155 tracer (#2033) +- simplify some generics (#2032) +- Make inspector use generics, rm associated types (#1934) +- fix comments and docs into more sensible (#1920) +- add depth to GasInspector (#1922) +- Simplify GasInspector (#1919) +- Move CfgEnv from context-interface to context crate (#1910) +- Bump new logo (#1735) +- *(README)* add rbuilder to used-by (#1585) +- added simular to used-by (#1521) +- add Trin to used by list (#1393) +- Fix typo in readme ([#1185](https://github.com/bluealloy/revm/pull/1185)) +- Add Hardhat to the "Used by" list ([#1164](https://github.com/bluealloy/revm/pull/1164)) +- Add VERBS to used by list ([#1141](https://github.com/bluealloy/revm/pull/1141)) +- license date and revm docs (#1080) +- *(docs)* Update the benchmark docs to point to revm package (#906) +- *(docs)* Update top-level benchmark docs (#894) +- clang requirement (#784) +- Readme Updates (#756) +- Logo (#743) +- book workflow ([#537](https://github.com/bluealloy/revm/pull/537)) +- add example to revm crate ([#468](https://github.com/bluealloy/revm/pull/468)) +- Update README.md ([#424](https://github.com/bluealloy/revm/pull/424)) +- add no_std to primitives ([#366](https://github.com/bluealloy/revm/pull/366)) +- revm-precompiles to revm-precompile +- Bump v20, changelog ([#350](https://github.com/bluealloy/revm/pull/350)) +- typos (#232) +- Add support for old forks. ([#191](https://github.com/bluealloy/revm/pull/191)) +- revm bump 1.8. update libs. snailtracer rename ([#159](https://github.com/bluealloy/revm/pull/159)) +- typo fixes +- fix readme typo +- Big Refactor. Machine to Interpreter. refactor instructions. call/create struct ([#52](https://github.com/bluealloy/revm/pull/52)) +- readme. debuger update +- Bump revm v0.3.0. README updated +- readme +- Add time elapsed for tests +- readme updated +- Include Basefee into cost calc. readme change +- Initialize precompile accounts +- Status update. Taking a break +- Merkle calc. Tweaks and debugging for eip158 +- Replace aurora bn lib with parity's. All Bn128Add/Mul/Pair tests passes +- TEMP +- one tab removed +- readme +- README Example simplified +- Gas calculation for Call/Create. Example Added +- readme usage +- README changes +- Static gas cost added +- Subroutine changelogs and reverts +- Readme postulates +- Spelling +- Restructure project +- First iteration. Machine is looking okay diff --git a/crates/inspector/Cargo.toml b/crates/inspector/Cargo.toml new file mode 100644 index 0000000000..1777ade610 --- /dev/null +++ b/crates/inspector/Cargo.toml @@ -0,0 +1,72 @@ +[package] +name = "revm-inspector" +description = "Revm inspector interface" +version = "8.1.0" +authors.workspace = true +edition.workspace = true +keywords.workspace = true +license.workspace = true +repository.workspace = true +readme.workspace = true + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] + +[lints] +workspace = true + +[dependencies] +# revm +context.workspace = true +database-interface.workspace = true +handler.workspace = true +primitives.workspace = true +state.workspace = true +interpreter.workspace = true + +auto_impl.workspace = true +either.workspace = true + +# Optional +serde = { workspace = true, features = ["derive", "rc"], optional = true } +serde_json = { workspace = true, features = [ + "alloc", + "preserve_order", +], optional = true } + +[dev-dependencies] +database = { workspace = true, features = ["serde"] } + +[features] +default = ["std"] +# Preserve order of json field +std = [ + "serde?/std", + "serde_json?/std", + "serde_json?/preserve_order", + "context/std", + "database/std", + "database-interface/std", + "handler/std", + "interpreter/std", + "primitives/std", + "state/std", + "either/std", +] +serde = [ + "dep:serde", + "database/serde", + "context/serde", + "database-interface/serde", + "handler/serde", + "interpreter/serde", + "primitives/serde", + "state/serde", + "either/serde", +] + +tracer = ["std", "serde", "dep:serde_json"] + +# Deprecated, please use `tracer` feature instead. +serde-json = ["tracer"] diff --git a/crates/inspector/LICENSE b/crates/inspector/LICENSE new file mode 100644 index 0000000000..be6d350ebe --- /dev/null +++ b/crates/inspector/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021-2025 draganrakita + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/crates/inspector/src/count_inspector.rs b/crates/inspector/src/count_inspector.rs new file mode 100644 index 0000000000..dd29efe15f --- /dev/null +++ b/crates/inspector/src/count_inspector.rs @@ -0,0 +1,337 @@ +//! CountInspector - Inspector that counts all opcodes that were called. +use crate::inspector::Inspector; +use interpreter::{interpreter_types::Jumps, InterpreterTypes}; +use primitives::HashMap; + +/// Inspector that counts all opcodes that were called during execution. +#[derive(Clone, Debug, Default)] +pub struct CountInspector { + /// Map from opcode value to count of times it was executed. + opcode_counts: HashMap, + /// Count of initialize_interp calls. + initialize_interp_count: u64, + /// Count of step calls. + step_count: u64, + /// Count of step_end calls. + step_end_count: u64, + /// Count of log calls. + log_count: u64, + /// Count of call calls. + call_count: u64, + /// Count of call_end calls. + call_end_count: u64, + /// Count of create calls. + create_count: u64, + /// Count of create_end calls. + create_end_count: u64, + /// Count of selfdestruct calls. + selfdestruct_count: u64, +} + +impl CountInspector { + /// Create a new CountInspector. + pub fn new() -> Self { + Self { + opcode_counts: HashMap::default(), + initialize_interp_count: 0, + step_count: 0, + step_end_count: 0, + log_count: 0, + call_count: 0, + call_end_count: 0, + create_count: 0, + create_end_count: 0, + selfdestruct_count: 0, + } + } + + /// Get the count for a specific opcode. + pub fn get_count(&self, opcode: u8) -> u64 { + self.opcode_counts.get(&opcode).copied().unwrap_or(0) + } + + /// Get a reference to all opcode counts. + pub fn opcode_counts(&self) -> &HashMap { + &self.opcode_counts + } + + /// Get the total number of opcodes executed. + pub fn total_opcodes(&self) -> u64 { + self.opcode_counts.values().sum() + } + + /// Get the number of unique opcodes executed. + pub fn unique_opcodes(&self) -> usize { + self.opcode_counts.len() + } + + /// Clear all counts. + pub fn clear(&mut self) { + self.opcode_counts.clear(); + self.initialize_interp_count = 0; + self.step_count = 0; + self.step_end_count = 0; + self.log_count = 0; + self.call_count = 0; + self.call_end_count = 0; + self.create_count = 0; + self.create_end_count = 0; + self.selfdestruct_count = 0; + } + + /// Get the count of initialize_interp calls. + pub fn initialize_interp_count(&self) -> u64 { + self.initialize_interp_count + } + + /// Get the count of step calls. + pub fn step_count(&self) -> u64 { + self.step_count + } + + /// Get the count of step_end calls. + pub fn step_end_count(&self) -> u64 { + self.step_end_count + } + + /// Get the count of log calls. + pub fn log_count(&self) -> u64 { + self.log_count + } + + /// Get the count of call calls. + pub fn call_count(&self) -> u64 { + self.call_count + } + + /// Get the count of call_end calls. + pub fn call_end_count(&self) -> u64 { + self.call_end_count + } + + /// Get the count of create calls. + pub fn create_count(&self) -> u64 { + self.create_count + } + + /// Get the count of create_end calls. + pub fn create_end_count(&self) -> u64 { + self.create_end_count + } + + /// Get the count of selfdestruct calls. + pub fn selfdestruct_count(&self) -> u64 { + self.selfdestruct_count + } +} + +impl Inspector for CountInspector { + fn initialize_interp( + &mut self, + _interp: &mut interpreter::Interpreter, + _context: &mut CTX, + ) { + self.initialize_interp_count += 1; + } + + fn step(&mut self, interp: &mut interpreter::Interpreter, _context: &mut CTX) { + self.step_count += 1; + let opcode = interp.bytecode.opcode(); + *self.opcode_counts.entry(opcode).or_insert(0) += 1; + } + + fn step_end(&mut self, _interp: &mut interpreter::Interpreter, _context: &mut CTX) { + self.step_end_count += 1; + } + + fn log( + &mut self, + _interp: &mut interpreter::Interpreter, + _context: &mut CTX, + _log: primitives::Log, + ) { + self.log_count += 1; + } + + fn call( + &mut self, + _context: &mut CTX, + _inputs: &mut interpreter::CallInputs, + ) -> Option { + self.call_count += 1; + None + } + + fn call_end( + &mut self, + _context: &mut CTX, + _inputs: &interpreter::CallInputs, + _outcome: &mut interpreter::CallOutcome, + ) { + self.call_end_count += 1; + } + + fn create( + &mut self, + _context: &mut CTX, + _inputs: &mut interpreter::CreateInputs, + ) -> Option { + self.create_count += 1; + None + } + + fn create_end( + &mut self, + _context: &mut CTX, + _inputs: &interpreter::CreateInputs, + _outcome: &mut interpreter::CreateOutcome, + ) { + self.create_end_count += 1; + } + + fn selfdestruct( + &mut self, + _contract: primitives::Address, + _target: primitives::Address, + _value: primitives::U256, + ) { + self.selfdestruct_count += 1; + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::InspectEvm; + use context::Context; + use database::BenchmarkDB; + use handler::{MainBuilder, MainContext}; + use primitives::{Bytes, TxKind}; + use state::bytecode::{opcode, Bytecode}; + + #[test] + fn test_count_inspector() { + // Create simple bytecode that just adds two numbers and stops + let contract_data: Bytes = Bytes::from(vec![ + opcode::PUSH1, + 0x10, // 0: PUSH1 16 + opcode::PUSH1, + 0x20, // 2: PUSH1 32 + opcode::ADD, // 4: ADD + opcode::DUP1, // 5: DUP1 (duplicate the result) + opcode::PUSH1, + 0x00, // 6: PUSH1 0 + opcode::MSTORE, // 8: MSTORE (store result in memory) + opcode::STOP, // 9: STOP + ]); + let bytecode = Bytecode::new_raw(contract_data); + + let ctx = Context::mainnet().with_db(BenchmarkDB::new_bytecode(bytecode.clone())); + let mut count_inspector = CountInspector::new(); + + let mut evm = ctx.build_mainnet_with_inspector(&mut count_inspector); + + // Execute the contract + evm.inspect_one_tx( + context::TxEnv::builder() + .kind(TxKind::Call(database::BENCH_TARGET)) + .gas_limit(30000) + .build() + .unwrap(), + ) + .unwrap(); + + // Check opcode counts + assert_eq!(count_inspector.get_count(opcode::PUSH1), 3); + assert_eq!(count_inspector.get_count(opcode::ADD), 1); + assert_eq!(count_inspector.get_count(opcode::DUP1), 1); + assert_eq!(count_inspector.get_count(opcode::MSTORE), 1); + assert_eq!(count_inspector.get_count(opcode::STOP), 1); + + // Check totals + assert_eq!(count_inspector.total_opcodes(), 7); + assert_eq!(count_inspector.unique_opcodes(), 5); + + // Check inspector function counts + assert_eq!(count_inspector.initialize_interp_count(), 1); + assert_eq!(count_inspector.step_count(), 7); // Each opcode triggers a step + assert_eq!(count_inspector.step_end_count(), 7); // Each opcode triggers a step_end + assert_eq!(count_inspector.log_count(), 0); // No LOG opcodes + assert_eq!(count_inspector.call_count(), 1); // The transaction itself is a call + assert_eq!(count_inspector.call_end_count(), 1); + assert_eq!(count_inspector.create_count(), 0); // No CREATE opcodes + assert_eq!(count_inspector.create_end_count(), 0); + assert_eq!(count_inspector.selfdestruct_count(), 0); // No SELFDESTRUCT opcodes + } + + #[test] + fn test_count_inspector_clear() { + let mut inspector = CountInspector::new(); + + // Add some counts manually for testing + *inspector.opcode_counts.entry(opcode::PUSH1).or_insert(0) += 5; + *inspector.opcode_counts.entry(opcode::ADD).or_insert(0) += 3; + inspector.initialize_interp_count = 2; + inspector.step_count = 10; + inspector.step_end_count = 10; + inspector.log_count = 1; + inspector.call_count = 3; + inspector.call_end_count = 3; + inspector.create_count = 1; + inspector.create_end_count = 1; + inspector.selfdestruct_count = 1; + + assert_eq!(inspector.total_opcodes(), 8); + assert_eq!(inspector.unique_opcodes(), 2); + assert_eq!(inspector.initialize_interp_count(), 2); + assert_eq!(inspector.step_count(), 10); + + // Clear and verify + inspector.clear(); + assert_eq!(inspector.total_opcodes(), 0); + assert_eq!(inspector.unique_opcodes(), 0); + assert!(inspector.opcode_counts().is_empty()); + assert_eq!(inspector.initialize_interp_count(), 0); + assert_eq!(inspector.step_count(), 0); + assert_eq!(inspector.step_end_count(), 0); + assert_eq!(inspector.log_count(), 0); + assert_eq!(inspector.call_count(), 0); + assert_eq!(inspector.call_end_count(), 0); + assert_eq!(inspector.create_count(), 0); + assert_eq!(inspector.create_end_count(), 0); + assert_eq!(inspector.selfdestruct_count(), 0); + } + + #[test] + fn test_count_inspector_with_logs() { + // Create bytecode that emits a log + let contract_data: Bytes = Bytes::from(vec![ + opcode::PUSH1, + 0x20, // 0: PUSH1 32 (length) + opcode::PUSH1, + 0x00, // 2: PUSH1 0 (offset) + opcode::LOG0, // 4: LOG0 - emit log with no topics + opcode::STOP, // 5: STOP + ]); + let bytecode = Bytecode::new_raw(contract_data); + + let ctx = Context::mainnet().with_db(BenchmarkDB::new_bytecode(bytecode.clone())); + let mut count_inspector = CountInspector::new(); + + let mut evm = ctx.build_mainnet_with_inspector(&mut count_inspector); + + // Execute the contract + evm.inspect_one_tx( + context::TxEnv::builder() + .kind(TxKind::Call(database::BENCH_TARGET)) + .gas_limit(30000) + .build() + .unwrap(), + ) + .unwrap(); + + // Check that log was counted + assert_eq!(count_inspector.log_count(), 1); + assert_eq!(count_inspector.step_count(), 4); // 2 PUSH1 + LOG0 + STOP + } +} diff --git a/crates/inspector/src/eip3155.rs b/crates/inspector/src/eip3155.rs new file mode 100644 index 0000000000..a81ebfbc9b --- /dev/null +++ b/crates/inspector/src/eip3155.rs @@ -0,0 +1,316 @@ +use crate::inspectors::GasInspector; +use crate::Inspector; +use context::{Cfg, ContextTr, JournalTr, Transaction}; +use interpreter::{ + interpreter_types::{Jumps, LoopControl, MemoryTr, StackTr}, + CallInputs, CallOutcome, CreateInputs, CreateOutcome, Interpreter, InterpreterResult, + InterpreterTypes, Stack, +}; +use primitives::{hex, HashMap, B256, U256}; +use serde::Serialize; +use state::bytecode::opcode::OpCode; +use std::io::Write; + +/// [EIP-3155](https://eips.ethereum.org/EIPS/eip-3155) tracer [Inspector]. +pub struct TracerEip3155 { + output: Box, + gas_inspector: GasInspector, + /// Print summary of the execution. + print_summary: bool, + stack: Vec, + pc: u64, + opcode: u8, + gas: u64, + refunded: i64, + mem_size: usize, + skip: bool, + include_memory: bool, + memory: Option, +} + +impl std::fmt::Debug for TracerEip3155 { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("TracerEip3155") + .field("gas_inspector", &self.gas_inspector) + .field("print_summary", &self.print_summary) + .field("stack", &self.stack) + .field("pc", &self.pc) + .field("opcode", &self.opcode) + .field("gas", &self.gas) + .field("refunded", &self.refunded) + .field("mem_size", &self.mem_size) + .field("skip", &self.skip) + .field("include_memory", &self.include_memory) + .field("memory", &self.memory) + .finish() + } +} + +// # Output +// The CUT MUST output a `json` object for EACH operation. +#[derive(Serialize)] +#[serde(rename_all = "camelCase")] +struct Output<'a> { + // Required fields: + /// Program counter + pc: u64, + /// OpCode + op: u8, + /// Gas left before executing this operation + #[serde(serialize_with = "serde_hex_u64")] + gas: u64, + /// Gas cost of this operation + #[serde(serialize_with = "serde_hex_u64")] + gas_cost: u64, + /// Array of all values on the stack + stack: &'a [U256], + /// Depth of the call stack + depth: u64, + /// Data returned by the function call + return_data: &'static str, + /// Amount of **global** gas refunded + #[serde(serialize_with = "serde_hex_u64")] + refund: u64, + /// Size of memory array + #[serde(serialize_with = "serde_hex_u64")] + mem_size: u64, + + // Optional fields: + /// Name of the operation + #[serde(default, skip_serializing_if = "Option::is_none")] + op_name: Option<&'static str>, + /// Description of an error (should contain revert reason if supported) + #[serde(default, skip_serializing_if = "Option::is_none")] + error: Option, + /// Array of all allocated values + #[serde(default, skip_serializing_if = "Option::is_none")] + memory: Option, + /// Array of all stored values + #[serde(default, skip_serializing_if = "Option::is_none")] + storage: Option>, + /// Array of values, Stack of the called function + #[serde(default, skip_serializing_if = "Option::is_none")] + return_stack: Option>, +} + +// # Summary and error handling +#[derive(Serialize)] +#[serde(rename_all = "camelCase")] +struct Summary { + // Required fields: + /// Root of the state trie after executing the transaction + state_root: String, + /// Return values of the function + output: String, + /// All gas used by the transaction + #[serde(serialize_with = "serde_hex_u64")] + gas_used: u64, + /// Bool whether transaction was executed successfully + pass: bool, + + // Optional fields: + /// Time in nanoseconds needed to execute the transaction + #[serde(default, skip_serializing_if = "Option::is_none")] + time: Option, + /// Name of the fork rules used for execution + #[serde(default, skip_serializing_if = "Option::is_none")] + fork: Option, +} + +impl TracerEip3155 { + /// Creates a new EIP-3155 tracer with the given output writer, by first wrapping it in a + /// [`BufWriter`](std::io::BufWriter). + pub fn buffered(output: impl Write + 'static) -> Self { + Self::new(Box::new(std::io::BufWriter::new(output))) + } + + /// Creates a new EIP-3155 tracer with a stdout output. + pub fn new_stdout() -> Self { + Self::buffered(std::io::stdout()) + } + + /// Creates a new EIP-3155 tracer with the given output writer. + pub fn new(output: Box) -> Self { + Self { + output, + gas_inspector: GasInspector::new(), + print_summary: true, + include_memory: false, + stack: Default::default(), + memory: Default::default(), + pc: 0, + opcode: 0, + gas: 0, + refunded: 0, + mem_size: 0, + skip: false, + } + } + + /// Sets the writer to use for the output. + pub fn set_writer(&mut self, writer: Box) { + self.output = writer; + } + + /// Don't include a summary at the end of the trace + pub fn without_summary(mut self) -> Self { + self.print_summary = false; + self + } + + /// Include a memory field for each step. This significantly increases processing time and output size. + pub fn with_memory(mut self) -> Self { + self.include_memory = true; + self + } + + /// Resets the tracer to its initial state of [`Self::new`]. + /// + /// This makes the inspector ready to be used again. + pub fn clear(&mut self) { + let Self { + gas_inspector, + stack, + pc, + opcode, + gas, + refunded, + mem_size, + skip, + .. + } = self; + *gas_inspector = GasInspector::new(); + stack.clear(); + *pc = 0; + *opcode = 0; + *gas = 0; + *refunded = 0; + *mem_size = 0; + *skip = false; + } + + fn print_summary(&mut self, result: &InterpreterResult, context: &mut impl ContextTr) { + if !self.print_summary { + return; + } + let spec = context.cfg().spec().into(); + let gas_limit = context.tx().gas_limit(); + let value = Summary { + state_root: B256::ZERO.to_string(), + output: result.output.to_string(), + gas_used: gas_limit - self.gas_inspector.gas_remaining(), + pass: result.is_ok(), + time: None, + fork: Some(spec.to_string()), + }; + let _ = self.write_value(&value); + } + + fn write_value(&mut self, value: &impl serde::Serialize) -> std::io::Result<()> { + write_value(&mut *self.output, value) + } +} + +pub trait CloneStack { + fn clone_into(&self, stack: &mut Vec); +} + +impl CloneStack for Stack { + fn clone_into(&self, stack: &mut Vec) { + stack.extend_from_slice(self.data()); + } +} + +impl Inspector for TracerEip3155 +where + CTX: ContextTr, + INTR: InterpreterTypes, +{ + fn initialize_interp(&mut self, interp: &mut Interpreter, _: &mut CTX) { + self.gas_inspector.initialize_interp(&interp.gas); + } + + fn step(&mut self, interp: &mut Interpreter, _: &mut CTX) { + self.gas_inspector.step(&interp.gas); + self.stack.clear(); + interp.stack.clone_into(&mut self.stack); + self.memory = if self.include_memory { + Some(hex::encode_prefixed( + interp.memory.slice(0..interp.memory.size()).as_ref(), + )) + } else { + None + }; + self.pc = interp.bytecode.pc() as u64; + self.opcode = interp.bytecode.opcode(); + self.mem_size = interp.memory.size(); + self.gas = interp.gas.remaining(); + self.refunded = interp.gas.refunded(); + } + + fn step_end(&mut self, interp: &mut Interpreter, context: &mut CTX) { + self.gas_inspector.step_end(&mut interp.gas); + if self.skip { + self.skip = false; + return; + } + + let value = Output { + pc: self.pc, + op: self.opcode, + gas: self.gas, + gas_cost: self.gas_inspector.last_gas_cost(), + stack: &self.stack, + depth: context.journal_mut().depth() as u64, + return_data: "0x", + refund: self.refunded as u64, + mem_size: self.mem_size as u64, + + op_name: OpCode::new(self.opcode).map(|i| i.as_str()), + error: interp + .bytecode + .action() + .as_ref() + .and_then(|a| a.instruction_result()) + .map(|ir| format!("{ir:?}")), + memory: self.memory.take(), + storage: None, + return_stack: None, + }; + let _ = write_value(&mut self.output, &value); + } + + fn call_end(&mut self, context: &mut CTX, _: &CallInputs, outcome: &mut CallOutcome) { + self.gas_inspector.call_end(outcome); + + if context.journal_mut().depth() == 0 { + self.print_summary(&outcome.result, context); + let _ = self.output.flush(); + // Clear the state if we are at the top level. + self.clear(); + } + } + + fn create_end(&mut self, context: &mut CTX, _: &CreateInputs, outcome: &mut CreateOutcome) { + self.gas_inspector.create_end(outcome); + + if context.journal_mut().depth() == 0 { + self.print_summary(&outcome.result, context); + let _ = self.output.flush(); + // Clear the state if we are at the top level. + self.clear(); + } + } +} + +fn write_value( + output: &mut dyn std::io::Write, + value: &impl serde::Serialize, +) -> std::io::Result<()> { + serde_json::to_writer(&mut *output, value)?; + output.write_all(b"\n") +} + +fn serde_hex_u64(n: &u64, serializer: S) -> Result { + serializer.serialize_str(&format!("{:#x}", *n)) +} diff --git a/crates/inspector/src/either.rs b/crates/inspector/src/either.rs new file mode 100644 index 0000000000..7b4da7249b --- /dev/null +++ b/crates/inspector/src/either.rs @@ -0,0 +1,119 @@ +use crate::inspector::Inspector; +use either::Either; +use interpreter::{ + CallInputs, CallOutcome, CreateInputs, CreateOutcome, Interpreter, InterpreterTypes, +}; +use primitives::{Address, Log, U256}; + +impl Inspector for Either +where + L: Inspector, + R: Inspector, +{ + #[inline] + fn initialize_interp(&mut self, interp: &mut Interpreter, context: &mut CTX) { + match self { + Either::Left(inspector) => inspector.initialize_interp(interp, context), + Either::Right(inspector) => inspector.initialize_interp(interp, context), + } + } + + #[inline] + fn step(&mut self, interp: &mut Interpreter, context: &mut CTX) { + match self { + Either::Left(inspector) => inspector.step(interp, context), + Either::Right(inspector) => inspector.step(interp, context), + } + } + + #[inline] + fn step_end(&mut self, interp: &mut Interpreter, context: &mut CTX) { + match self { + Either::Left(inspector) => inspector.step_end(interp, context), + Either::Right(inspector) => inspector.step_end(interp, context), + } + } + + #[inline] + fn log(&mut self, interp: &mut Interpreter, context: &mut CTX, log: Log) { + match self { + Either::Left(inspector) => inspector.log(interp, context, log), + Either::Right(inspector) => inspector.log(interp, context, log), + } + } + + #[inline] + fn call(&mut self, context: &mut CTX, inputs: &mut CallInputs) -> Option { + match self { + Either::Left(inspector) => inspector.call(context, inputs), + Either::Right(inspector) => inspector.call(context, inputs), + } + } + + #[inline] + fn call_end(&mut self, context: &mut CTX, inputs: &CallInputs, outcome: &mut CallOutcome) { + match self { + Either::Left(inspector) => inspector.call_end(context, inputs, outcome), + Either::Right(inspector) => inspector.call_end(context, inputs, outcome), + } + } + + #[inline] + fn create(&mut self, context: &mut CTX, inputs: &mut CreateInputs) -> Option { + match self { + Either::Left(inspector) => inspector.create(context, inputs), + Either::Right(inspector) => inspector.create(context, inputs), + } + } + + #[inline] + fn create_end( + &mut self, + context: &mut CTX, + inputs: &CreateInputs, + outcome: &mut CreateOutcome, + ) { + match self { + Either::Left(inspector) => inspector.create_end(context, inputs, outcome), + Either::Right(inspector) => inspector.create_end(context, inputs, outcome), + } + } + + #[inline] + fn selfdestruct(&mut self, contract: Address, target: Address, value: U256) { + match self { + Either::Left(inspector) => inspector.selfdestruct(contract, target, value), + Either::Right(inspector) => inspector.selfdestruct(contract, target, value), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::noop::NoOpInspector; + use interpreter::interpreter::EthInterpreter; + + #[derive(Default)] + struct DummyInsp; + + impl Inspector for DummyInsp {} + + #[test] + fn test_either_inspector_type_check() { + use interpreter::interpreter::EthInterpreter; + + // This test verifies that Either + // implements the Inspector trait as required by the issue + fn _requires_inspector>(inspector: T) -> T { + inspector + } + + let left_inspector = Either::::Left(NoOpInspector); + let right_inspector = Either::::Right(DummyInsp); + + // These calls should compile successfully, proving that the Inspector trait is implemented + let _left = _requires_inspector(left_inspector); + let _right = _requires_inspector(right_inspector); + } +} diff --git a/crates/inspector/src/gas.rs b/crates/inspector/src/gas.rs new file mode 100644 index 0000000000..db286d4ca1 --- /dev/null +++ b/crates/inspector/src/gas.rs @@ -0,0 +1,268 @@ +//! GasIspector. Helper Inspector to calculate gas for others. +use interpreter::{CallOutcome, CreateOutcome, Gas}; + +/// Helper that keeps track of gas. +#[allow(dead_code)] +#[derive(Clone, Copy, Debug)] +pub struct GasInspector { + gas_remaining: u64, + last_gas_cost: u64, +} + +impl Default for GasInspector { + fn default() -> Self { + Self::new() + } +} + +impl GasInspector { + /// Returns the remaining gas. + #[inline] + pub fn gas_remaining(&self) -> u64 { + self.gas_remaining + } + + /// Returns the last gas cost. + #[inline] + pub fn last_gas_cost(&self) -> u64 { + self.last_gas_cost + } + + /// Create a new gas inspector. + pub fn new() -> Self { + Self { + gas_remaining: 0, + last_gas_cost: 0, + } + } + + /// Sets remaining gas to gas limit. + #[inline] + pub fn initialize_interp(&mut self, gas: &Gas) { + self.gas_remaining = gas.limit(); + } + + /// Sets the remaining gas. + #[inline] + pub fn step(&mut self, gas: &Gas) { + self.gas_remaining = gas.remaining(); + } + + /// calculate last gas cost and remaining gas. + #[inline] + pub fn step_end(&mut self, gas: &mut Gas) { + let remaining = gas.remaining(); + self.last_gas_cost = self.gas_remaining.saturating_sub(remaining); + self.gas_remaining = remaining; + } + + /// Spend all gas if call failed. + #[inline] + pub fn call_end(&mut self, outcome: &mut CallOutcome) { + if outcome.result.result.is_error() { + outcome.result.gas.spend_all(); + self.gas_remaining = 0; + } + } + + /// Spend all gas if create failed. + #[inline] + pub fn create_end(&mut self, outcome: &mut CreateOutcome) { + if outcome.result.result.is_error() { + outcome.result.gas.spend_all(); + self.gas_remaining = 0; + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{InspectEvm, Inspector}; + use context::{Context, TxEnv}; + use database::{BenchmarkDB, BENCH_CALLER, BENCH_TARGET}; + use handler::{MainBuilder, MainContext}; + use interpreter::{ + interpreter_types::{Jumps, ReturnData}, + CallInputs, CreateInputs, Interpreter, InterpreterResult, InterpreterTypes, + }; + use primitives::{Address, Bytes, TxKind}; + use state::bytecode::{opcode, Bytecode}; + + #[derive(Default, Debug)] + struct StackInspector { + pc: usize, + opcode: u8, + gas_inspector: GasInspector, + gas_remaining_steps: Vec<(usize, u64)>, + } + + impl Inspector for StackInspector { + fn initialize_interp(&mut self, interp: &mut Interpreter, _context: &mut CTX) { + self.gas_inspector.initialize_interp(&interp.gas); + } + + fn step(&mut self, interp: &mut Interpreter, _context: &mut CTX) { + self.pc = interp.bytecode.pc(); + self.opcode = interp.bytecode.opcode(); + self.gas_inspector.step(&interp.gas); + } + + fn step_end(&mut self, interp: &mut Interpreter, _context: &mut CTX) { + interp.bytecode.pc(); + interp.bytecode.opcode(); + self.gas_inspector.step_end(&mut interp.gas); + self.gas_remaining_steps + .push((self.pc, self.gas_inspector.gas_remaining())); + } + + fn call_end(&mut self, _c: &mut CTX, _i: &CallInputs, outcome: &mut CallOutcome) { + self.gas_inspector.call_end(outcome) + } + + fn create_end(&mut self, _c: &mut CTX, _i: &CreateInputs, outcome: &mut CreateOutcome) { + self.gas_inspector.create_end(outcome) + } + } + + #[test] + fn test_gas_inspector() { + let contract_data: Bytes = Bytes::from(vec![ + opcode::PUSH1, + 0x1, + opcode::PUSH1, + 0xb, + opcode::JUMPI, + opcode::PUSH1, + 0x1, + opcode::PUSH1, + 0x1, + opcode::PUSH1, + 0x1, + opcode::JUMPDEST, + opcode::STOP, + ]); + let bytecode = Bytecode::new_raw(contract_data); + + let ctx = Context::mainnet().with_db(BenchmarkDB::new_bytecode(bytecode.clone())); + + let mut evm = ctx.build_mainnet_with_inspector(StackInspector::default()); + + // Run evm. + evm.inspect_one_tx( + TxEnv::builder() + .caller(BENCH_CALLER) + .kind(TxKind::Call(BENCH_TARGET)) + .gas_limit(21100) + .build() + .unwrap(), + ) + .unwrap(); + + let inspector = &evm.inspector; + + // Starting from 100gas + let steps = vec![ + // push1 -3 + (0, 97), + // push1 -3 + (2, 94), + // jumpi -10 + (4, 84), + // jumpdest 1 + (11, 83), + // stop 0 + (12, 83), + ]; + + assert_eq!(inspector.gas_remaining_steps, steps); + } + + #[derive(Default, Debug)] + struct CallOverrideInspector { + call_override: Vec>, + create_override: Vec>, + return_buffer: Vec, + } + + impl Inspector for CallOverrideInspector { + fn call(&mut self, _context: &mut CTX, _inputs: &mut CallInputs) -> Option { + self.call_override.pop().unwrap_or_default() + } + + fn step(&mut self, interpreter: &mut Interpreter, _context: &mut CTX) { + let this_buffer = interpreter.return_data.buffer(); + let Some(buffer) = self.return_buffer.last() else { + self.return_buffer.push(this_buffer.clone()); + return; + }; + if this_buffer != buffer { + self.return_buffer.push(this_buffer.clone()); + } + } + + fn create( + &mut self, + _context: &mut CTX, + _inputs: &mut CreateInputs, + ) -> Option { + self.create_override.pop().unwrap_or_default() + } + } + + #[test] + fn test_call_override_inspector() { + use interpreter::{CallOutcome, CreateOutcome, InstructionResult}; + + let mut inspector = CallOverrideInspector::default(); + inspector.call_override.push(Some(CallOutcome::new( + InterpreterResult::new(InstructionResult::Return, [0x01].into(), Gas::new(100_000)), + 0..1, + ))); + inspector.call_override.push(None); + inspector.create_override.push(Some(CreateOutcome::new( + InterpreterResult::new(InstructionResult::Revert, [0x02].into(), Gas::new(100_000)), + Some(Address::ZERO), + ))); + + let contract_data: Bytes = Bytes::from(vec![ + opcode::PUSH1, + 0x01, + opcode::PUSH1, + 0x0, + opcode::DUP1, + opcode::DUP1, + opcode::DUP1, + opcode::DUP1, + opcode::ADDRESS, + opcode::CALL, + opcode::PUSH1, + 0x01, + opcode::PUSH1, + 0x0, + opcode::DUP1, + opcode::DUP1, + opcode::DUP1, + opcode::DUP1, + opcode::DUP1, + opcode::ADDRESS, + opcode::CREATE, + opcode::STOP, + ]); + + let bytecode = Bytecode::new_raw(contract_data); + + let mut evm = Context::mainnet() + .with_db(BenchmarkDB::new_bytecode(bytecode.clone())) + .build_mainnet_with_inspector(inspector); + + let _ = evm + .inspect_one_tx(TxEnv::builder_for_bench().build().unwrap()) + .unwrap(); + assert_eq!(evm.inspector.return_buffer.len(), 3); + assert_eq!( + evm.inspector.return_buffer, + [Bytes::new(), Bytes::from([0x01]), Bytes::from([0x02])].to_vec() + ); + } +} diff --git a/crates/inspector/src/handler.rs b/crates/inspector/src/handler.rs new file mode 100644 index 0000000000..ba2b8570d5 --- /dev/null +++ b/crates/inspector/src/handler.rs @@ -0,0 +1,256 @@ +use crate::{Inspector, InspectorEvmTr, JournalExt}; +use context::{result::ExecutionResult, ContextTr, JournalEntry, Transaction}; +use handler::{evm::FrameTr, EvmTr, FrameResult, Handler, ItemOrResult}; +use interpreter::{ + instructions::InstructionTable, + interpreter_types::{Jumps, LoopControl}, + FrameInput, Host, InitialAndFloorGas, InstructionContext, InstructionResult, Interpreter, + InterpreterAction, InterpreterTypes, +}; + +/// Trait that extends [`Handler`] with inspection functionality. +/// +/// Similar how [`Handler::run`] method serves as the entry point, +/// [`InspectorHandler::inspect_run`] method serves as the entry point for inspection. +/// +/// Notice that when inspection is run it skips few functions from handler, this can be +/// a problem if custom EVM is implemented and some of skipped functions have changed logic. +/// For custom EVM, those changed functions would need to be also changed in [`InspectorHandler`]. +/// +/// List of functions that are skipped in [`InspectorHandler`]: +/// * [`Handler::run`] replaced with [`InspectorHandler::inspect_run`] +/// * [`Handler::run_without_catch_error`] replaced with [`InspectorHandler::inspect_run_without_catch_error`] +/// * [`Handler::execution`] replaced with [`InspectorHandler::inspect_execution`] +/// * [`Handler::run_exec_loop`] replaced with [`InspectorHandler::inspect_run_exec_loop`] +/// * `run_exec_loop` calls `inspect_frame_init` and `inspect_frame_run` that call inspector inside. +pub trait InspectorHandler: Handler +where + Self::Evm: + InspectorEvmTr::Evm as EvmTr>::Context, Self::IT>>, +{ + /// The interpreter types used by this handler. + type IT: InterpreterTypes; + + /// Entry point for inspection. + /// + /// This method is acts as [`Handler::run`] method for inspection. + fn inspect_run( + &mut self, + evm: &mut Self::Evm, + ) -> Result, Self::Error> { + match self.inspect_run_without_catch_error(evm) { + Ok(output) => Ok(output), + Err(e) => self.catch_error(evm, e), + } + } + + /// Run inspection without catching error. + /// + /// This method is acts as [`Handler::run_without_catch_error`] method for inspection. + fn inspect_run_without_catch_error( + &mut self, + evm: &mut Self::Evm, + ) -> Result, Self::Error> { + let init_and_floor_gas = self.validate(evm)?; + let eip7702_refund = self.pre_execution(evm)? as i64; + let mut frame_result = self.inspect_execution(evm, &init_and_floor_gas)?; + self.post_execution(evm, &mut frame_result, init_and_floor_gas, eip7702_refund)?; + self.execution_result(evm, frame_result) + } + + /// Run execution loop with inspection support + /// + /// This method acts as [`Handler::execution`] method for inspection. + fn inspect_execution( + &mut self, + evm: &mut Self::Evm, + init_and_floor_gas: &InitialAndFloorGas, + ) -> Result { + let gas_limit = evm.ctx().tx().gas_limit() - init_and_floor_gas.initial_gas; + // Create first frame action + let first_frame_input = self.first_frame_input(evm, gas_limit)?; + + // Run execution loop + let mut frame_result = self.inspect_run_exec_loop(evm, first_frame_input)?; + + // Handle last frame result + self.last_frame_result(evm, &mut frame_result)?; + Ok(frame_result) + } + + /* FRAMES */ + + /// Run inspection on execution loop. + /// + /// This method acts as [`Handler::run_exec_loop`] method for inspection. + /// + /// It will call: + /// * [`Inspector::call`],[`Inspector::create`] to inspect call, create and eofcreate. + /// * [`Inspector::call_end`],[`Inspector::create_end`] to inspect call, create and eofcreate end. + /// * [`Inspector::initialize_interp`] to inspect initialized interpreter. + fn inspect_run_exec_loop( + &mut self, + evm: &mut Self::Evm, + first_frame_input: <::Frame as FrameTr>::FrameInit, + ) -> Result { + let res = evm.inspect_frame_init(first_frame_input)?; + + if let ItemOrResult::Result(frame_result) = res { + return Ok(frame_result); + } + + loop { + let call_or_result = evm.inspect_frame_run()?; + + let result = match call_or_result { + ItemOrResult::Item(init) => { + match evm.inspect_frame_init(init)? { + ItemOrResult::Item(_) => { + continue; + } + // Do not pop the frame since no new frame was created + ItemOrResult::Result(result) => result, + } + } + ItemOrResult::Result(result) => result, + }; + + if let Some(result) = evm.frame_return_result(result)? { + return Ok(result); + } + } + } +} + +/// Handles the start of a frame by calling the appropriate inspector method. +pub fn frame_start( + context: &mut CTX, + inspector: &mut impl Inspector, + frame_input: &mut FrameInput, +) -> Option { + match frame_input { + FrameInput::Call(i) => { + if let Some(output) = inspector.call(context, i) { + return Some(FrameResult::Call(output)); + } + } + FrameInput::Create(i) => { + if let Some(output) = inspector.create(context, i) { + return Some(FrameResult::Create(output)); + } + } + FrameInput::Empty => unreachable!(), + } + None +} + +/// Handles the end of a frame by calling the appropriate inspector method. +pub fn frame_end( + context: &mut CTX, + inspector: &mut impl Inspector, + frame_input: &FrameInput, + frame_output: &mut FrameResult, +) { + match frame_output { + FrameResult::Call(outcome) => { + let FrameInput::Call(i) = frame_input else { + panic!("FrameInput::Call expected {frame_input:?}"); + }; + inspector.call_end(context, i, outcome); + } + FrameResult::Create(outcome) => { + let FrameInput::Create(i) = frame_input else { + panic!("FrameInput::Create expected {frame_input:?}"); + }; + inspector.create_end(context, i, outcome); + } + } +} + +/// Run Interpreter loop with inspection support. +/// +/// This function is used to inspect the Interpreter loop. +/// It will call [`Inspector::step`] and [`Inspector::step_end`] after each instruction. +/// And [`Inspector::log`],[`Inspector::selfdestruct`] for each log and selfdestruct instruction. +pub fn inspect_instructions( + context: &mut CTX, + interpreter: &mut Interpreter, + mut inspector: impl Inspector, + instructions: &InstructionTable, +) -> InterpreterAction +where + CTX: ContextTr + Host, + IT: InterpreterTypes, +{ + let mut log_num = context.journal_mut().logs().len(); + // Main loop + while interpreter.bytecode.is_not_end() { + // Get current opcode. + let opcode = interpreter.bytecode.opcode(); + + // Call Inspector step. + inspector.step(interpreter, context); + if interpreter.bytecode.is_end() { + break; + } + + // SAFETY: In analysis we are doing padding of bytecode so that we are sure that last + // byte instruction is STOP so we are safe to just increment program_counter bcs on last instruction + // it will do noop and just stop execution of this contract + interpreter.bytecode.relative_jump(1); + + // Execute instruction. + let instruction_context = InstructionContext { + interpreter, + host: context, + }; + instructions[opcode as usize](instruction_context); + + // check if new log is added + let new_log = context.journal_mut().logs().len(); + if log_num < new_log { + // as there is a change in log number this means new log is added + let log = context.journal_mut().logs().last().unwrap().clone(); + inspector.log(interpreter, context, log); + log_num = new_log; + } + + // if loops is ending, break the loop so we can revert to the previous pointer and then call step_end. + if interpreter.bytecode.is_end() { + break; + } + + // Call step_end. + inspector.step_end(interpreter, context); + } + + interpreter.bytecode.revert_to_previous_pointer(); + // call step_end again to handle the last instruction + inspector.step_end(interpreter, context); + + let next_action = interpreter.take_next_action(); + + // handle selfdestruct + if let InterpreterAction::Return(result) = &next_action { + if result.result == InstructionResult::SelfDestruct { + match context.journal_mut().journal().last() { + Some(JournalEntry::AccountDestroyed { + address, + target, + had_balance, + .. + }) => { + inspector.selfdestruct(*address, *target, *had_balance); + } + Some(JournalEntry::BalanceTransfer { + from, to, balance, .. + }) => { + inspector.selfdestruct(*from, *to, *balance); + } + _ => {} + } + } + } + + next_action +} diff --git a/crates/inspector/src/inspect.rs b/crates/inspector/src/inspect.rs new file mode 100644 index 0000000000..5ac1ada4a6 --- /dev/null +++ b/crates/inspector/src/inspect.rs @@ -0,0 +1,78 @@ +use context::result::ExecResultAndState; +use handler::{ExecuteCommitEvm, ExecuteEvm}; + +/// InspectEvm is a API that allows inspecting the EVM. +/// +/// It extends the `ExecuteEvm` trait and enabled setting inspector +/// +pub trait InspectEvm: ExecuteEvm { + /// The inspector type used for inspecting EVM execution. + type Inspector; + + /// Set the inspector for the EVM. + /// + /// this function is used to change inspector during execution. + /// This function can't change Inspector type, changing inspector type can be done in + /// `Evm` with `with_inspector` function. + fn set_inspector(&mut self, inspector: Self::Inspector); + + /// Inspect the EVM with the given transaction. + fn inspect_one_tx(&mut self, tx: Self::Tx) -> Result; + + /// Inspect the EVM and finalize the state. + fn inspect_tx( + &mut self, + tx: Self::Tx, + ) -> Result, Self::Error> { + let output = self.inspect_one_tx(tx)?; + let state = self.finalize(); + Ok(ExecResultAndState::new(output, state)) + } + + /// Inspect the EVM with the given inspector and transaction, and finalize the state. + fn inspect( + &mut self, + tx: Self::Tx, + inspector: Self::Inspector, + ) -> Result, Self::Error> { + let output = self.inspect_one(tx, inspector)?; + let state = self.finalize(); + Ok(ExecResultAndState::new(output, state)) + } + + /// Inspect the EVM with the given inspector and transaction. + fn inspect_one( + &mut self, + tx: Self::Tx, + inspector: Self::Inspector, + ) -> Result { + self.set_inspector(inspector); + self.inspect_one_tx(tx) + } +} + +/// InspectCommitEvm is a API that allows inspecting similar to `InspectEvm` but it has +/// functions that commit the state diff to the database. +/// +/// Functions return CommitOutput from [`ExecuteCommitEvm`] trait. +pub trait InspectCommitEvm: InspectEvm + ExecuteCommitEvm { + /// Inspect the EVM with the current inspector and previous transaction by replaying, similar to [`InspectEvm::inspect_tx`] + /// and commit the state diff to the database. + fn inspect_tx_commit(&mut self, tx: Self::Tx) -> Result { + let output = self.inspect_one_tx(tx)?; + self.commit_inner(); + Ok(output) + } + + /// Inspect the EVM with the given transaction and inspector similar to [`InspectEvm::inspect`] + /// and commit the state diff to the database. + fn inspect_commit( + &mut self, + tx: Self::Tx, + inspector: Self::Inspector, + ) -> Result { + let output = self.inspect_one(tx, inspector)?; + self.commit_inner(); + Ok(output) + } +} diff --git a/crates/inspector/src/inspector.rs b/crates/inspector/src/inspector.rs new file mode 100644 index 0000000000..7a2101c377 --- /dev/null +++ b/crates/inspector/src/inspector.rs @@ -0,0 +1,153 @@ +use auto_impl::auto_impl; +use context::{Database, Journal, JournalEntry}; +use interpreter::{ + interpreter::EthInterpreter, CallInputs, CallOutcome, CreateInputs, CreateOutcome, Interpreter, + InterpreterTypes, +}; +use primitives::{Address, Log, U256}; +use state::EvmState; + +/// EVM hooks into execution. +/// +/// This trait is used to enabled tracing of the EVM execution. +/// +/// Object that is implemented this trait is used in `InspectorHandler` to trace the EVM execution. +/// And API that allow calling the inspector can be found in [`crate::InspectEvm`] and [`crate::InspectCommitEvm`]. +#[auto_impl(&mut, Box)] +pub trait Inspector { + /// Called before the interpreter is initialized. + /// + /// If `interp.bytecode.set_action` is set the execution of the interpreter is skipped. + #[inline] + fn initialize_interp(&mut self, interp: &mut Interpreter, context: &mut CTX) { + let _ = interp; + let _ = context; + } + + /// Called on each step of the interpreter. + /// + /// Information about the current execution, including the memory, stack and more is available + /// on `interp` (see [Interpreter]). + /// + /// # Example + /// + /// To get the current opcode, use `interp.bytecode.opcode()`. + #[inline] + fn step(&mut self, interp: &mut Interpreter, context: &mut CTX) { + let _ = interp; + let _ = context; + } + + /// Called after `step` when the instruction has been executed. + /// + /// Setting `interp.bytecode.set_action` will result in stopping the execution of the interpreter. + #[inline] + fn step_end(&mut self, interp: &mut Interpreter, context: &mut CTX) { + let _ = interp; + let _ = context; + } + + /// Called when a log is emitted. + #[inline] + fn log(&mut self, interp: &mut Interpreter, context: &mut CTX, log: Log) { + let _ = interp; + let _ = context; + let _ = log; + } + + /// Called whenever a call to a contract is about to start. + /// + /// Returning `CallOutcome` will override the result of the call. + #[inline] + fn call(&mut self, context: &mut CTX, inputs: &mut CallInputs) -> Option { + let _ = context; + let _ = inputs; + None + } + + /// Called when a call to a contract has concluded. + /// + /// The returned [CallOutcome] is used as the result of the call. + /// + /// This allows the inspector to modify the given `result` before returning it. + #[inline] + fn call_end(&mut self, context: &mut CTX, inputs: &CallInputs, outcome: &mut CallOutcome) { + let _ = context; + let _ = inputs; + let _ = outcome; + } + + /// Called when a contract is about to be created. + /// + /// If this returns `Some` then the [CreateOutcome] is used to override the result of the creation. + /// + /// If this returns `None` then the creation proceeds as normal. + #[inline] + fn create(&mut self, context: &mut CTX, inputs: &mut CreateInputs) -> Option { + let _ = context; + let _ = inputs; + None + } + + /// Called when a contract has been created. + /// + /// Modifying the outcome will alter the result of the create operation. + #[inline] + fn create_end( + &mut self, + context: &mut CTX, + inputs: &CreateInputs, + outcome: &mut CreateOutcome, + ) { + let _ = context; + let _ = inputs; + let _ = outcome; + } + + /// Called when a contract has been self-destructed with funds transferred to target. + #[inline] + fn selfdestruct(&mut self, contract: Address, target: Address, value: U256) { + let _ = contract; + let _ = target; + let _ = value; + } +} + +/// Extends the journal with additional methods that are used by the inspector. +#[auto_impl(&mut, Box)] +pub trait JournalExt { + /// Get all logs from the journal. + fn logs(&self) -> &[Log]; + + /// Get the journal entries that are created from last checkpoint. + /// new checkpoint is created when sub call is made. + fn journal(&self) -> &[JournalEntry]; + + /// Return the current Journaled state. + fn evm_state(&self) -> &EvmState; + + /// Return the mutable current Journaled state. + fn evm_state_mut(&mut self) -> &mut EvmState; +} + +impl JournalExt for Journal { + #[inline] + fn logs(&self) -> &[Log] { + &self.logs + } + + #[inline] + fn journal(&self) -> &[JournalEntry] { + &self.journal + } + + #[inline] + fn evm_state(&self) -> &EvmState { + &self.state + } + + #[inline] + fn evm_state_mut(&mut self) -> &mut EvmState { + &mut self.state + } +} diff --git a/crates/inspector/src/inspector_tests.rs b/crates/inspector/src/inspector_tests.rs new file mode 100644 index 0000000000..29cfa54c94 --- /dev/null +++ b/crates/inspector/src/inspector_tests.rs @@ -0,0 +1,734 @@ +#[cfg(test)] +mod tests { + use crate::{InspectEvm, Inspector}; + use context::{Context, TxEnv}; + use database::{BenchmarkDB, BENCH_CALLER, BENCH_TARGET}; + use handler::{MainBuilder, MainContext}; + use interpreter::{ + interpreter_types::{Jumps, MemoryTr, StackTr}, + CallInputs, CallOutcome, CreateInputs, CreateOutcome, Interpreter, InterpreterTypes, + }; + use primitives::{address, Address, Bytes, Log, TxKind, U256}; + use state::{bytecode::opcode, AccountInfo, Bytecode}; + + #[derive(Debug, Clone)] + struct InterpreterState { + pc: usize, + stack_len: usize, + memory_size: usize, + } + + #[derive(Debug, Clone)] + struct StepRecord { + before: InterpreterState, + after: Option, + opcode_name: String, + } + + #[derive(Debug, Clone)] + enum InspectorEvent { + Step(StepRecord), + Call { + inputs: CallInputs, + outcome: Option, + }, + Create { + inputs: CreateInputs, + outcome: Option, + }, + Log(Log), + Selfdestruct { + address: Address, + beneficiary: Address, + value: U256, + }, + } + + #[derive(Debug, Default)] + struct TestInspector { + events: Vec, + step_count: usize, + call_depth: usize, + } + + impl TestInspector { + fn new() -> Self { + Self { + events: Vec::new(), + step_count: 0, + call_depth: 0, + } + } + + fn capture_interpreter_state( + interp: &Interpreter, + ) -> InterpreterState + where + INTR::Bytecode: Jumps, + INTR::Stack: StackTr, + INTR::Memory: MemoryTr, + { + InterpreterState { + pc: interp.bytecode.pc(), + stack_len: interp.stack.len(), + memory_size: interp.memory.size(), + } + } + + fn get_events(&self) -> Vec { + self.events.clone() + } + + fn get_step_count(&self) -> usize { + self.step_count + } + } + + impl Inspector for TestInspector + where + INTR: InterpreterTypes, + INTR::Bytecode: Jumps, + INTR::Stack: StackTr, + INTR::Memory: MemoryTr, + { + fn step(&mut self, interp: &mut Interpreter, _context: &mut CTX) { + self.step_count += 1; + + let state = Self::capture_interpreter_state(interp); + let opcode = interp.bytecode.opcode(); + let opcode_name = if let Some(op) = state::bytecode::opcode::OpCode::new(opcode) { + format!("{op}") + } else { + format!("Unknown(0x{opcode:02x})") + }; + + self.events.push(InspectorEvent::Step(StepRecord { + before: state, + after: None, + opcode_name, + })); + } + + fn step_end(&mut self, interp: &mut Interpreter, _context: &mut CTX) { + let state = Self::capture_interpreter_state(interp); + + if let Some(InspectorEvent::Step(record)) = self.events.last_mut() { + record.after = Some(state); + } + } + + fn log(&mut self, _interp: &mut Interpreter, _ctx: &mut CTX, log: Log) { + self.events.push(InspectorEvent::Log(log)); + } + + fn call(&mut self, _ctx: &mut CTX, inputs: &mut CallInputs) -> Option { + self.call_depth += 1; + self.events.push(InspectorEvent::Call { + inputs: inputs.clone(), + outcome: None, + }); + None + } + + fn call_end(&mut self, _ctx: &mut CTX, _inputs: &CallInputs, outcome: &mut CallOutcome) { + self.call_depth -= 1; + if let Some(InspectorEvent::Call { + outcome: ref mut out, + .. + }) = self + .events + .iter_mut() + .rev() + .find(|e| matches!(e, InspectorEvent::Call { outcome: None, .. })) + { + *out = Some(outcome.clone()); + } + } + + fn create(&mut self, _ctx: &mut CTX, inputs: &mut CreateInputs) -> Option { + self.events.push(InspectorEvent::Create { + inputs: inputs.clone(), + outcome: None, + }); + None + } + + fn create_end( + &mut self, + _ctx: &mut CTX, + _inputs: &CreateInputs, + outcome: &mut CreateOutcome, + ) { + if let Some(InspectorEvent::Create { + outcome: ref mut out, + .. + }) = self + .events + .iter_mut() + .rev() + .find(|e| matches!(e, InspectorEvent::Create { outcome: None, .. })) + { + *out = Some(outcome.clone()); + } + } + + fn selfdestruct(&mut self, contract: Address, beneficiary: Address, value: U256) { + self.events.push(InspectorEvent::Selfdestruct { + address: contract, + beneficiary, + value, + }); + } + } + + #[test] + fn test_push_opcodes_and_stack_operations() { + // PUSH1 0x42, PUSH2 0x1234, ADD, PUSH1 0x00, MSTORE, STOP + let code = Bytes::from(vec![ + opcode::PUSH1, + 0x42, + opcode::PUSH2, + 0x12, + 0x34, + opcode::ADD, + opcode::PUSH1, + 0x00, + opcode::MSTORE, + opcode::STOP, + ]); + + let bytecode = Bytecode::new_raw(code); + let ctx = Context::mainnet().with_db(BenchmarkDB::new_bytecode(bytecode)); + let mut evm = ctx.build_mainnet_with_inspector(TestInspector::new()); + + // Run transaction + let _ = evm.inspect_one_tx( + TxEnv::builder() + .caller(BENCH_CALLER) + .kind(TxKind::Call(BENCH_TARGET)) + .gas_limit(100_000) + .build() + .unwrap(), + ); + + let inspector = &evm.inspector; + let events = inspector.get_events(); + let step_events: Vec<_> = events + .iter() + .filter_map(|e| { + if let InspectorEvent::Step(record) = e { + Some(record) + } else { + None + } + }) + .collect(); + + // Verify PUSH1 0x42 + let push1_event = &step_events[0]; + assert_eq!(push1_event.opcode_name, "PUSH1"); + assert_eq!(push1_event.before.stack_len, 0); + assert_eq!(push1_event.after.as_ref().unwrap().stack_len, 1); + + // Verify PUSH2 0x1234 + let push2_event = &step_events[1]; + assert_eq!(push2_event.opcode_name, "PUSH2"); + assert_eq!(push2_event.before.stack_len, 1); + assert_eq!(push2_event.after.as_ref().unwrap().stack_len, 2); + + // Verify ADD + let add_event = &step_events[2]; + assert_eq!(add_event.opcode_name, "ADD"); + assert_eq!(add_event.before.stack_len, 2); + assert_eq!(add_event.after.as_ref().unwrap().stack_len, 1); + + // Verify all opcodes were tracked + assert!(inspector.get_step_count() >= 5); // PUSH1, PUSH2, ADD, PUSH1, MSTORE, STOP + } + + #[test] + fn test_jump_and_jumpi_control_flow() { + // PUSH1 0x08, JUMP, INVALID, JUMPDEST, PUSH1 0x01, PUSH1 0x0F, JUMPI, INVALID, JUMPDEST, STOP + let code = Bytes::from(vec![ + opcode::PUSH1, + 0x08, + opcode::JUMP, + opcode::INVALID, + opcode::INVALID, + opcode::INVALID, + opcode::INVALID, + opcode::INVALID, + opcode::JUMPDEST, // offset 0x08 + opcode::PUSH1, + 0x01, + opcode::PUSH1, + 0x0F, + opcode::JUMPI, + opcode::INVALID, + opcode::JUMPDEST, // offset 0x0F + opcode::STOP, + ]); + + let bytecode = Bytecode::new_raw(code); + let ctx = Context::mainnet().with_db(BenchmarkDB::new_bytecode(bytecode)); + let mut evm = ctx.build_mainnet_with_inspector(TestInspector::new()); + + // Run transaction + let _ = evm.inspect_one_tx( + TxEnv::builder() + .caller(BENCH_CALLER) + .kind(TxKind::Call(BENCH_TARGET)) + .gas_limit(100_000) + .build() + .unwrap(), + ); + + let inspector = &evm.inspector; + let events = inspector.get_events(); + let step_events: Vec<_> = events + .iter() + .filter_map(|e| { + if let InspectorEvent::Step(record) = e { + Some(record) + } else { + None + } + }) + .collect(); + + // Find JUMP instruction + let jump_event = step_events + .iter() + .find(|e| e.opcode_name == "JUMP") + .unwrap(); + assert_eq!(jump_event.before.pc, 2); // After PUSH1 0x08 + assert_eq!(jump_event.after.as_ref().unwrap().pc, 8); // Jumped to JUMPDEST + + // Find JUMPI instruction + let jumpi_event = step_events + .iter() + .find(|e| e.opcode_name == "JUMPI") + .unwrap(); + assert!(jumpi_event.before.stack_len >= 2); // Has condition and destination + // JUMPI should have jumped since condition is 1 (true) + assert_eq!(jumpi_event.after.as_ref().unwrap().pc, 0x0F); + } + + #[test] + fn test_call_operations() { + // For CALL tests, we need a more complex setup with multiple contracts + // Deploy a simple contract that returns a value + let callee_code = Bytes::from(vec![ + opcode::PUSH1, + 0x42, // Push return value + opcode::PUSH1, + 0x00, // Push memory offset + opcode::MSTORE, + opcode::PUSH1, + 0x20, // Push return size + opcode::PUSH1, + 0x00, // Push return offset + opcode::RETURN, + ]); + + // Caller contract that calls the callee + let caller_code = Bytes::from(vec![ + // Setup CALL parameters + opcode::PUSH1, + 0x20, // retSize + opcode::PUSH1, + 0x00, // retOffset + opcode::PUSH1, + 0x00, // argsSize + opcode::PUSH1, + 0x00, // argsOffset + opcode::PUSH1, + 0x00, // value + opcode::PUSH20, + // address: 20 bytes to match callee_address exactly + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x01, + opcode::PUSH2, + 0xFF, + 0xFF, // gas + opcode::CALL, + opcode::STOP, + ]); + + // Create a custom database with two contracts + let mut db = database::InMemoryDB::default(); + + // Add caller contract at BENCH_TARGET + db.insert_account_info( + BENCH_TARGET, + AccountInfo { + balance: U256::from(1_000_000_000_000_000_000u64), + nonce: 0, + code_hash: primitives::keccak256(&caller_code), + code: Some(Bytecode::new_raw(caller_code)), + }, + ); + + // Add callee contract at a specific address + let callee_address = Address::new([ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + ]); + db.insert_account_info( + callee_address, + AccountInfo { + balance: U256::ZERO, + nonce: 0, + code_hash: primitives::keccak256(&callee_code), + code: Some(Bytecode::new_raw(callee_code)), + }, + ); + + let ctx = Context::mainnet().with_db(db); + let mut evm = ctx.build_mainnet_with_inspector(TestInspector::new()); + + // Run transaction + let _ = evm.inspect_one_tx( + TxEnv::builder() + .caller(BENCH_CALLER) + .kind(TxKind::Call(BENCH_TARGET)) + .gas_limit(100_000) + .build() + .unwrap(), + ); + + let inspector = &evm.inspector; + let events = inspector.get_events(); + + // Find CALL events + let call_events: Vec<_> = events + .iter() + .filter_map(|e| { + if let InspectorEvent::Call { inputs, outcome } = e { + Some((inputs, outcome)) + } else { + None + } + }) + .collect(); + + assert!(!call_events.is_empty(), "Should have recorded CALL events"); + let (call_inputs, call_outcome) = &call_events[0]; + // The test setup might be using BENCH_CALLER as the default target + // Just verify that a call was made and completed successfully + assert_eq!(call_inputs.target_address, BENCH_TARGET); + assert!(call_outcome.is_some(), "Call should have completed"); + } + + #[test] + fn test_create_opcodes() { + // CREATE test: deploy a contract that creates another contract + let init_code = vec![ + opcode::PUSH1, + 0x42, // Push constructor value + opcode::PUSH1, + 0x00, // Push memory offset + opcode::MSTORE, + opcode::PUSH1, + 0x20, // Push return size + opcode::PUSH1, + 0x00, // Push return offset + opcode::RETURN, + ]; + + let create_code = vec![ + // First, store init code in memory using CODECOPY + opcode::PUSH1, + init_code.len() as u8, // size + opcode::PUSH1, + 0x20, // code offset (after CREATE params) + opcode::PUSH1, + 0x00, // memory offset + opcode::CODECOPY, + // CREATE parameters + opcode::PUSH1, + init_code.len() as u8, // size + opcode::PUSH1, + 0x00, // offset + opcode::PUSH1, + 0x00, // value + opcode::CREATE, + opcode::STOP, + ]; + + let mut full_code = create_code; + full_code.extend_from_slice(&init_code); + + let bytecode = Bytecode::new_raw(Bytes::from(full_code)); + let ctx = Context::mainnet().with_db(BenchmarkDB::new_bytecode(bytecode)); + let mut evm = ctx.build_mainnet_with_inspector(TestInspector::new()); + + // Run transaction + let _ = evm.inspect_one_tx( + TxEnv::builder() + .caller(BENCH_CALLER) + .kind(TxKind::Call(BENCH_TARGET)) + .gas_limit(100_000) + .build() + .unwrap(), + ); + + let inspector = &evm.inspector; + let events = inspector.get_events(); + + // Find CREATE events + let create_events: Vec<_> = events + .iter() + .filter_map(|e| { + if let InspectorEvent::Create { inputs, outcome } = e { + Some((inputs, outcome)) + } else { + None + } + }) + .collect(); + + assert!( + !create_events.is_empty(), + "Should have recorded CREATE events" + ); + let (_create_inputs, create_outcome) = &create_events[0]; + assert!(create_outcome.is_some(), "CREATE should have completed"); + } + + #[test] + fn test_log_operations() { + // Simple LOG0 test - no topics + let code = vec![ + // Store some data in memory for the log + opcode::PUSH1, + 0x42, + opcode::PUSH1, + 0x00, + opcode::MSTORE, + // LOG0 parameters + opcode::PUSH1, + 0x20, // size + opcode::PUSH1, + 0x00, // offset + opcode::LOG0, + opcode::STOP, + ]; + + let bytecode = Bytecode::new_raw(Bytes::from(code)); + let ctx = Context::mainnet().with_db(BenchmarkDB::new_bytecode(bytecode)); + let mut evm = ctx.build_mainnet_with_inspector(TestInspector::new()); + + // Run transaction + let _ = evm.inspect_one_tx( + TxEnv::builder() + .caller(BENCH_CALLER) + .kind(TxKind::Call(BENCH_TARGET)) + .gas_limit(100_000) + .build() + .unwrap(), + ); + + let inspector = &evm.inspector; + let events = inspector.get_events(); + + // Find LOG events + let log_events: Vec<_> = events + .iter() + .filter_map(|e| { + if let InspectorEvent::Log(log) = e { + Some(log) + } else { + None + } + }) + .collect(); + + // Remove debug code - test should work now + + assert_eq!(log_events.len(), 1, "Should have recorded one LOG event"); + let log = &log_events[0]; + assert_eq!(log.topics().len(), 0, "LOG0 should have 0 topics"); + } + + #[test] + fn test_selfdestruct() { + // SELFDESTRUCT test + let beneficiary = address!("3000000000000000000000000000000000000000"); + let mut code = vec![opcode::PUSH20]; + code.extend_from_slice(beneficiary.as_ref()); + code.push(opcode::SELFDESTRUCT); + + let bytecode = Bytecode::new_raw(Bytes::from(code)); + let ctx = Context::mainnet().with_db(BenchmarkDB::new_bytecode(bytecode)); + let mut evm = ctx.build_mainnet_with_inspector(TestInspector::new()); + + // Run transaction + let _ = evm.inspect_one_tx( + TxEnv::builder() + .caller(BENCH_CALLER) + .kind(TxKind::Call(BENCH_TARGET)) + .gas_limit(100_000) + .build() + .unwrap(), + ); + + let inspector = &evm.inspector; + let events = inspector.get_events(); + + // Find SELFDESTRUCT events + let selfdestruct_events: Vec<_> = events + .iter() + .filter_map(|e| { + if let InspectorEvent::Selfdestruct { + address, + beneficiary, + value, + } = e + { + Some((address, beneficiary, value)) + } else { + None + } + }) + .collect(); + + assert_eq!( + selfdestruct_events.len(), + 1, + "Should have recorded SELFDESTRUCT event" + ); + let (_address, event_beneficiary, _value) = selfdestruct_events[0]; + assert_eq!(*event_beneficiary, beneficiary); + } + + #[test] + fn test_comprehensive_inspector_integration() { + // Complex contract with multiple operations: + // 1. PUSH and arithmetic + // 2. Memory operations + // 3. Conditional jump + // 4. LOG0 + + let code = vec![ + // Stack operations + opcode::PUSH1, + 0x10, + opcode::PUSH1, + 0x20, + opcode::ADD, + opcode::DUP1, + opcode::PUSH1, + 0x00, + opcode::MSTORE, + // Conditional jump + opcode::PUSH1, + 0x01, + opcode::PUSH1, + 0x00, + opcode::MLOAD, + opcode::GT, + opcode::PUSH1, + 0x17, // Jump destination (adjusted) + opcode::JUMPI, + // This should be skipped + opcode::PUSH1, + 0x00, + opcode::PUSH1, + 0x00, + opcode::REVERT, + // Jump destination + opcode::JUMPDEST, // offset 0x14 + // LOG0 + opcode::PUSH1, + 0x20, + opcode::PUSH1, + 0x00, + opcode::LOG0, + opcode::STOP, + ]; + + let bytecode = Bytecode::new_raw(Bytes::from(code)); + let ctx = Context::mainnet().with_db(BenchmarkDB::new_bytecode(bytecode)); + let mut evm = ctx.build_mainnet_with_inspector(TestInspector::new()); + + // Run transaction + let _ = evm.inspect_one_tx( + TxEnv::builder() + .caller(BENCH_CALLER) + .kind(TxKind::Call(BENCH_TARGET)) + .gas_limit(100_000) + .build() + .unwrap(), + ); + + let inspector = &evm.inspector; + let events = inspector.get_events(); + + // Verify we captured various event types + let step_count = events + .iter() + .filter(|e| matches!(e, InspectorEvent::Step(_))) + .count(); + let log_count = events + .iter() + .filter(|e| matches!(e, InspectorEvent::Log(_))) + .count(); + + assert!(step_count > 10, "Should have multiple step events"); + assert_eq!(log_count, 1, "Should have one log event"); + + // Verify stack operations were tracked + let step_events: Vec<_> = events + .iter() + .filter_map(|e| { + if let InspectorEvent::Step(record) = e { + Some(record) + } else { + None + } + }) + .collect(); + + // Find ADD operation + let add_event = step_events.iter().find(|e| e.opcode_name == "ADD").unwrap(); + assert_eq!(add_event.before.stack_len, 2); + assert_eq!(add_event.after.as_ref().unwrap().stack_len, 1); + + // Verify memory was written + let mstore_event = step_events + .iter() + .find(|e| e.opcode_name == "MSTORE") + .unwrap(); + assert!(mstore_event.after.as_ref().unwrap().memory_size > 0); + + // Verify conditional jump worked correctly + let jumpi_event = step_events + .iter() + .find(|e| e.opcode_name == "JUMPI") + .unwrap(); + assert_eq!( + jumpi_event.after.as_ref().unwrap().pc, + 0x17, + "Should have jumped to JUMPDEST" + ); + } +} diff --git a/crates/inspector/src/lib.rs b/crates/inspector/src/lib.rs new file mode 100644 index 0000000000..3c7f331b2b --- /dev/null +++ b/crates/inspector/src/lib.rs @@ -0,0 +1,36 @@ +//! Inspector is a crate that provides a set of traits that allow inspecting the EVM execution. +//! +//! It is used to implement tracers that can be used to inspect the EVM execution. +//! Implementing inspection is optional and it does not effect the core execution. +#![cfg_attr(not(test), warn(unused_crate_dependencies))] +#![cfg_attr(not(feature = "std"), no_std)] + +mod count_inspector; +#[cfg(feature = "tracer")] +mod eip3155; +mod either; +mod gas; +/// Handler implementations for inspector integration. +pub mod handler; +mod inspect; +mod inspector; +mod mainnet_inspect; +mod noop; +mod traits; + +#[cfg(test)] +mod inspector_tests; + +/// Inspector implementations. +pub mod inspectors { + #[cfg(feature = "tracer")] + pub use super::eip3155::TracerEip3155; + pub use super::gas::GasInspector; +} + +pub use count_inspector::CountInspector; +pub use handler::{inspect_instructions, InspectorHandler}; +pub use inspect::{InspectCommitEvm, InspectEvm}; +pub use inspector::*; +pub use noop::NoOpInspector; +pub use traits::*; diff --git a/crates/inspector/src/mainnet_inspect.rs b/crates/inspector/src/mainnet_inspect.rs new file mode 100644 index 0000000000..33afea5512 --- /dev/null +++ b/crates/inspector/src/mainnet_inspect.rs @@ -0,0 +1,99 @@ +use crate::{ + inspect::{InspectCommitEvm, InspectEvm}, + Inspector, InspectorEvmTr, InspectorHandler, JournalExt, +}; +use context::{ContextSetters, ContextTr, Evm, JournalTr}; +use database_interface::DatabaseCommit; +use handler::{ + instructions::InstructionProvider, EthFrame, EvmTr, EvmTrError, Handler, MainnetHandler, + PrecompileProvider, +}; +use interpreter::{interpreter::EthInterpreter, InterpreterResult}; +use state::EvmState; + +// Implementing InspectorHandler for MainnetHandler. +impl InspectorHandler for MainnetHandler> +where + EVM: InspectorEvmTr< + Context: ContextTr>, + Frame = EthFrame, + Inspector: Inspector<<::Evm as EvmTr>::Context, EthInterpreter>, + >, + ERROR: EvmTrError, +{ + type IT = EthInterpreter; +} + +// Implementing InspectEvm for Evm +impl InspectEvm + for Evm> +where + CTX: ContextSetters + ContextTr + JournalExt>, + INSP: Inspector, + INST: InstructionProvider, + PRECOMPILES: PrecompileProvider, +{ + type Inspector = INSP; + + fn set_inspector(&mut self, inspector: Self::Inspector) { + self.inspector = inspector; + } + + fn inspect_one_tx(&mut self, tx: Self::Tx) -> Result { + self.set_tx(tx); + MainnetHandler::default().inspect_run(self) + } +} + +// Implementing InspectCommitEvm for Evm +impl InspectCommitEvm + for Evm> +where + CTX: ContextSetters + + ContextTr + JournalExt, Db: DatabaseCommit>, + INSP: Inspector, + INST: InstructionProvider, + PRECOMPILES: PrecompileProvider, +{ +} + +// Implementing InspectorEvmTr for Evm +impl InspectorEvmTr for Evm> +where + CTX: ContextTr + ContextSetters, + I: InstructionProvider, + P: PrecompileProvider, + INSP: Inspector, +{ + type Inspector = INSP; + + fn inspector(&mut self) -> &mut Self::Inspector { + &mut self.inspector + } + + fn ctx_inspector(&mut self) -> (&mut Self::Context, &mut Self::Inspector) { + (&mut self.ctx, &mut self.inspector) + } + + fn ctx_inspector_frame( + &mut self, + ) -> (&mut Self::Context, &mut Self::Inspector, &mut Self::Frame) { + (&mut self.ctx, &mut self.inspector, self.frame_stack.get()) + } + + fn ctx_inspector_frame_instructions( + &mut self, + ) -> ( + &mut Self::Context, + &mut Self::Inspector, + &mut Self::Frame, + &mut Self::Instructions, + ) { + ( + &mut self.ctx, + &mut self.inspector, + self.frame_stack.get(), + &mut self.instruction, + ) + } +} diff --git a/crates/revm/src/inspector/noop.rs b/crates/inspector/src/noop.rs similarity index 52% rename from crates/revm/src/inspector/noop.rs rename to crates/inspector/src/noop.rs index 9e9556e286..09a97804ec 100644 --- a/crates/revm/src/inspector/noop.rs +++ b/crates/inspector/src/noop.rs @@ -1,6 +1,8 @@ -use crate::{Database, Inspector}; +use crate::inspector::Inspector; +use interpreter::InterpreterTypes; + /// Dummy [Inspector], helpful as standalone replacement. #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct NoOpInspector; -impl Inspector for NoOpInspector {} +impl Inspector for NoOpInspector {} diff --git a/crates/inspector/src/traits.rs b/crates/inspector/src/traits.rs new file mode 100644 index 0000000000..9fc098f377 --- /dev/null +++ b/crates/inspector/src/traits.rs @@ -0,0 +1,129 @@ +use context::ContextTr; +use handler::{ + evm::{ContextDbError, FrameInitResult, FrameTr}, + instructions::InstructionProvider, + EthFrame, EvmTr, FrameInitOrResult, ItemOrResult, +}; +use interpreter::{interpreter::EthInterpreter, FrameInput, Interpreter, InterpreterTypes}; + +use crate::{ + handler::{frame_end, frame_start}, + inspect_instructions, Inspector, JournalExt, +}; + +/// Inspector EVM trait. Extends the [`EvmTr`] trait with inspector related methods. +/// +/// It contains execution of interpreter with [`crate::Inspector`] calls [`crate::Inspector::step`] and [`crate::Inspector::step_end`] calls. +/// +/// It is used inside [`crate::InspectorHandler`] to extend evm with support for inspection. +pub trait InspectorEvmTr: + EvmTr< + Frame = EthFrame, + Instructions: InstructionProvider, + Context: ContextTr, +> +{ + /// The inspector type used for EVM execution inspection. + type Inspector: Inspector; + + /// Returns a mutable reference to the inspector. + fn inspector(&mut self) -> &mut Self::Inspector; + + /// Returns a tuple of mutable references to the context and the inspector. + /// + /// Useful when you want to allow inspector to modify the context. + fn ctx_inspector(&mut self) -> (&mut Self::Context, &mut Self::Inspector); + + /// Returns a tuple of mutable references to the context, the inspector and the frame. + /// + /// Useful when you want to allow inspector to modify the context and the frame. + fn ctx_inspector_frame( + &mut self, + ) -> (&mut Self::Context, &mut Self::Inspector, &mut Self::Frame); + + /// Returns a tuple of mutable references to the context, the inspector, the frame and the instructions. + fn ctx_inspector_frame_instructions( + &mut self, + ) -> ( + &mut Self::Context, + &mut Self::Inspector, + &mut Self::Frame, + &mut Self::Instructions, + ); + + /// Initializes the frame for the given frame input. Frame is pushed to the frame stack. + #[inline] + fn inspect_frame_init( + &mut self, + mut frame_init: ::FrameInit, + ) -> Result, ContextDbError> { + let (ctx, inspector) = self.ctx_inspector(); + if let Some(mut output) = frame_start(ctx, inspector, &mut frame_init.frame_input) { + frame_end(ctx, inspector, &frame_init.frame_input, &mut output); + return Ok(ItemOrResult::Result(output)); + } + + let frame_input = frame_init.frame_input.clone(); + if let ItemOrResult::Result(mut output) = self.frame_init(frame_init)? { + let (ctx, inspector) = self.ctx_inspector(); + frame_end(ctx, inspector, &frame_input, &mut output); + return Ok(ItemOrResult::Result(output)); + } + + // if it is new frame, initialize the interpreter. + let (ctx, inspector, frame) = self.ctx_inspector_frame(); + let interp = frame.interpreter(); + inspector.initialize_interp(interp, ctx); + Ok(ItemOrResult::Item(frame)) + } + + /// Run the frame from the top of the stack. Returns the frame init or result. + /// + /// If frame has returned result it would mark it as finished. + #[inline] + fn inspect_frame_run( + &mut self, + ) -> Result, ContextDbError> { + let (ctx, inspector, frame, instructions) = self.ctx_inspector_frame_instructions(); + + let next_action = inspect_instructions( + ctx, + frame.interpreter(), + inspector, + instructions.instruction_table(), + ); + let mut result = frame.process_next_action(ctx, next_action); + + if let Ok(ItemOrResult::Result(frame_result)) = &mut result { + let (ctx, inspector, frame) = self.ctx_inspector_frame(); + frame_end(ctx, inspector, frame.frame_input(), frame_result); + frame.set_finished(true); + }; + result + } +} + +/// Trait that extends the [`FrameTr`] trait with additional functionality that is needed for inspection. +pub trait InspectorFrame: FrameTr { + /// The interpreter types used by this frame. + type IT: InterpreterTypes; + + /// Returns a mutable reference to the interpreter. + fn interpreter(&mut self) -> &mut Interpreter; + + /// Returns a reference to the frame input. Frame input is needed for call/create/eofcreate [`crate::Inspector`] methods + fn frame_input(&self) -> &FrameInput; +} + +/// Impl InspectorFrame for EthFrame. +impl InspectorFrame for EthFrame { + type IT = EthInterpreter; + + fn interpreter(&mut self) -> &mut Interpreter { + &mut self.interpreter + } + + fn frame_input(&self) -> &FrameInput { + &self.input + } +} diff --git a/crates/interpreter/CHANGELOG.md b/crates/interpreter/CHANGELOG.md index be64279f7d..473ea6dea4 100644 --- a/crates/interpreter/CHANGELOG.md +++ b/crates/interpreter/CHANGELOG.md @@ -6,6 +6,426 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [24.0.0](https://github.com/bluealloy/revm/compare/revm-interpreter-v23.0.2...revm-interpreter-v24.0.0) - 2025-07-23 + +### Added + +- *(interpreter)* update CLZ cost ([#2739](https://github.com/bluealloy/revm/pull/2739)) + +### Fixed + +- features and check in ci ([#2766](https://github.com/bluealloy/revm/pull/2766)) + +### Other + +- un-Box frames ([#2761](https://github.com/bluealloy/revm/pull/2761)) +- interpreter improvements ([#2760](https://github.com/bluealloy/revm/pull/2760)) +- evaluate instruction table initializer at compile time ([#2762](https://github.com/bluealloy/revm/pull/2762)) +- discard generic host implementation ([#2738](https://github.com/bluealloy/revm/pull/2738)) +- add release safety section for SharedMemory fn ([#2718](https://github.com/bluealloy/revm/pull/2718)) +- *(interpreter)* update docs for slice_mut and slice_range ([#2714](https://github.com/bluealloy/revm/pull/2714)) + +## [23.0.2](https://github.com/bluealloy/revm/compare/revm-interpreter-v23.0.1...revm-interpreter-v23.0.2) - 2025-07-14 + +### Other + +- simplify gas calculations by introducing a used() method ([#2703](https://github.com/bluealloy/revm/pull/2703)) + +## [23.0.1](https://github.com/bluealloy/revm/compare/revm-interpreter-v23.0.0...revm-interpreter-v23.0.1) - 2025-07-03 + +### Other + +- updated the following local packages: revm-bytecode, revm-context-interface + +## [22.1.0](https://github.com/bluealloy/revm/compare/revm-interpreter-v22.0.1...revm-interpreter-v22.1.0) - 2025-06-30 + +### Added + +- blake2 avx2 ([#2670](https://github.com/bluealloy/revm/pull/2670)) + +### Other + +- cargo clippy --fix --all ([#2671](https://github.com/bluealloy/revm/pull/2671)) + +## [22.0.1](https://github.com/bluealloy/revm/compare/revm-interpreter-v22.0.0...revm-interpreter-v22.0.1) - 2025-06-20 + +### Other + +- updated the following local packages: revm-context-interface + +## [22.0.0](https://github.com/bluealloy/revm/compare/revm-interpreter-v21.0.0...revm-interpreter-v22.0.0) - 2025-06-19 + +### Added + +- remove EOF ([#2644](https://github.com/bluealloy/revm/pull/2644)) +- configurable contract size limit ([#2611](https://github.com/bluealloy/revm/pull/2611)) ([#2642](https://github.com/bluealloy/revm/pull/2642)) +- *(precompile)* rug/gmp-based modexp ([#2596](https://github.com/bluealloy/revm/pull/2596)) +- add clz opcode ([#2598](https://github.com/bluealloy/revm/pull/2598)) +- added instruction_result fn in LoopControl trait ([#2595](https://github.com/bluealloy/revm/pull/2595)) + +### Other + +- lints handler inspector interpreter ([#2646](https://github.com/bluealloy/revm/pull/2646)) +- bump all deps ([#2647](https://github.com/bluealloy/revm/pull/2647)) +- re-use frame allocation ([#2636](https://github.com/bluealloy/revm/pull/2636)) +- make CallInput default 0..0 ([#2621](https://github.com/bluealloy/revm/pull/2621)) + +## [21.0.0](https://github.com/bluealloy/revm/compare/revm-interpreter-v20.0.0...revm-interpreter-v21.0.0) - 2025-06-06 + +### Added + +- expand timestamp/block_number to u256 ([#2546](https://github.com/bluealloy/revm/pull/2546)) +- transact multi tx ([#2517](https://github.com/bluealloy/revm/pull/2517)) + +### Other + +- ContextTr rm *_ref, and add *_mut fn ([#2560](https://github.com/bluealloy/revm/pull/2560)) +- simplify Interpreter loop ([#2544](https://github.com/bluealloy/revm/pull/2544)) +- Add InstructionContext instead of Host and Interpreter ([#2548](https://github.com/bluealloy/revm/pull/2548)) + +## [20.0.0](https://github.com/bluealloy/revm/compare/revm-interpreter-v19.1.0...revm-interpreter-v20.0.0) - 2025-05-22 + +### Added + +- expose Gas::memory field ([#2512](https://github.com/bluealloy/revm/pull/2512)) +- added CallInput::bytes(ctx: &CTX) -> Bytes {} function ([#2507](https://github.com/bluealloy/revm/pull/2507)) + +### Other + +- make crates.io version badge clickable ([#2526](https://github.com/bluealloy/revm/pull/2526)) +- fix clippy ([#2523](https://github.com/bluealloy/revm/pull/2523)) +- Storage Types Alias ([#2461](https://github.com/bluealloy/revm/pull/2461)) + +## [19.1.0](https://github.com/bluealloy/revm/compare/revm-interpreter-v19.0.0...revm-interpreter-v19.1.0) - 2025-05-07 + +Dependency bump + +## [19.0.0](https://github.com/bluealloy/revm/compare/revm-interpreter-v18.0.0...revm-interpreter-v19.0.0) - 2025-05-07 + +### Added + +- *(Osaka)* disable EOF ([#2480](https://github.com/bluealloy/revm/pull/2480)) +- skip cloning of call input from shared memory ([#2462](https://github.com/bluealloy/revm/pull/2462)) +- Add a custom address to the CreateScheme. ([#2464](https://github.com/bluealloy/revm/pull/2464)) +- replace input Bytes and refactored code where required ([#2453](https://github.com/bluealloy/revm/pull/2453)) +- *(EOF)* Changes needed for devnet-1 ([#2377](https://github.com/bluealloy/revm/pull/2377)) +- Move SharedMemory buffer to context ([#2382](https://github.com/bluealloy/revm/pull/2382)) + +### Fixed + +- *(inspector)* fix call return with Some ([#2469](https://github.com/bluealloy/revm/pull/2469)) +- skip account list for legacy ([#2400](https://github.com/bluealloy/revm/pull/2400)) + +### Other + +- Add Bytecode address to Interpreter ([#2479](https://github.com/bluealloy/revm/pull/2479)) +- make ReturnDataImpl and LoopControlImpl public ([#2470](https://github.com/bluealloy/revm/pull/2470)) +- copy edit The Book ([#2463](https://github.com/bluealloy/revm/pull/2463)) +- Replace InterpreterAction with InterpreterTypes::Output ([#2424](https://github.com/bluealloy/revm/pull/2424)) +- simplify reading signed integers ([#2456](https://github.com/bluealloy/revm/pull/2456)) +- *(revm-interpreter)* remove unused deps ([#2447](https://github.com/bluealloy/revm/pull/2447)) +- bump dependency version ([#2431](https://github.com/bluealloy/revm/pull/2431)) +- fixed broken link ([#2421](https://github.com/bluealloy/revm/pull/2421)) + +## [18.0.0](https://github.com/bluealloy/revm/compare/revm-interpreter-v17.0.0...revm-interpreter-v18.0.0) - 2025-04-09 + +### Added + +- *(tests)* Add dupn, swapn and exhange tests ([#2343](https://github.com/bluealloy/revm/pull/2343)) +- support for system calls ([#2350](https://github.com/bluealloy/revm/pull/2350)) + +### Other + +- *(test)* uncommented bitwise.rs and system.rs tests ([#2370](https://github.com/bluealloy/revm/pull/2370)) +- *(tests)* fix program counter for eof jump instructions ([#2368](https://github.com/bluealloy/revm/pull/2368)) +- fix tests in data.rs file ([#2365](https://github.com/bluealloy/revm/pull/2365)) +- remove redundant U256 conversions in instructions ([#2364](https://github.com/bluealloy/revm/pull/2364)) +- add 0x prefix to b256! and address! calls ([#2345](https://github.com/bluealloy/revm/pull/2345)) + +## [17.0.0](https://github.com/bluealloy/revm/compare/revm-interpreter-v16.0.0...revm-interpreter-v17.0.0) - 2025-03-28 + +### Other + +- remove redundant clone ([#2293](https://github.com/bluealloy/revm/pull/2293)) +- Remove LATEST variant from SpecId enum ([#2299](https://github.com/bluealloy/revm/pull/2299)) +- make number more readable ([#2300](https://github.com/bluealloy/revm/pull/2300)) + +## [16.0.0](https://github.com/bluealloy/revm/compare/revm-interpreter-v16.0.0-alpha.7...revm-interpreter-v16.0.0) - 2025-03-24 + +Stable version + +## [16.0.0-alpha.7](https://github.com/bluealloy/revm/compare/revm-interpreter-v16.0.0-alpha.6...revm-interpreter-v16.0.0-alpha.7) - 2025-03-21 + +### Added + +- allow reuse of API for calculating initial tx gas for tx ([#2215](https://github.com/bluealloy/revm/pull/2215)) + +### Other + +- make clippy happy ([#2274](https://github.com/bluealloy/revm/pull/2274)) +- fix clippy ([#2238](https://github.com/bluealloy/revm/pull/2238)) + +## [16.0.0-alpha.6](https://github.com/bluealloy/revm/compare/revm-interpreter-v16.0.0-alpha.5...revm-interpreter-v16.0.0-alpha.6) - 2025-03-16 + +### Other + +- updated the following local packages: revm-primitives, revm-bytecode, revm-context-interface + +## [16.0.0-alpha.5](https://github.com/bluealloy/revm/compare/revm-interpreter-v16.0.0-alpha.4...revm-interpreter-v16.0.0-alpha.5) - 2025-03-12 + +### Added + +- add custom error to context ([#2197](https://github.com/bluealloy/revm/pull/2197)) + +## [16.0.0-alpha.4](https://github.com/bluealloy/revm/compare/revm-interpreter-v16.0.0-alpha.3...revm-interpreter-v16.0.0-alpha.4) - 2025-03-11 + +### Fixed + +- correct propagate features ([#2177](https://github.com/bluealloy/revm/pull/2177)) + +## [16.0.0-alpha.3](https://github.com/bluealloy/revm/compare/revm-interpreter-v16.0.0-alpha.2...revm-interpreter-v16.0.0-alpha.3) - 2025-03-10 + +### Fixed + +- set zero if blockhash is out of range ([#2173](https://github.com/bluealloy/revm/pull/2173)) + +## [16.0.0-alpha.2](https://github.com/bluealloy/revm/compare/revm-interpreter-v16.0.0-alpha.1...revm-interpreter-v16.0.0-alpha.2) - 2025-03-10 + +### Added + +- remove specification crate ([#2165](https://github.com/bluealloy/revm/pull/2165)) +- Standalone Host, remove default fn from context ([#2147](https://github.com/bluealloy/revm/pull/2147)) +- allow host to be implemented on custom context ([#2112](https://github.com/bluealloy/revm/pull/2112)) + +### Other + +- JournalTr, JournalOutput, op only using revm crate ([#2155](https://github.com/bluealloy/revm/pull/2155)) +- docs and cleanup (rm Custom Inst) ([#2151](https://github.com/bluealloy/revm/pull/2151)) +- add immutable gas API to LoopControl ([#2134](https://github.com/bluealloy/revm/pull/2134)) +- expose popn macros ([#2113](https://github.com/bluealloy/revm/pull/2113)) +- Add docs to revm-bytecode crate ([#2108](https://github.com/bluealloy/revm/pull/2108)) +- fix wrong comment & remove useless struct ([#2105](https://github.com/bluealloy/revm/pull/2105)) +- move all dependencies to workspace ([#2092](https://github.com/bluealloy/revm/pull/2092)) + +## [16.0.0-alpha.1](https://github.com/bluealloy/revm/compare/revm-interpreter-v15.2.0...revm-interpreter-v16.0.0-alpha.1) - 2025-02-16 + +### Added + +- Evm structure (Cached Instructions and Precompiles) (#2049) +- Add essential EIP-7756 tracing fields (#2023) +- Context execution (#2013) +- EthHandler trait (#2001) +- *(EIP-7623)* adjuct floor gas check order (main) (#1991) +- *(eip7702)* apply latest EIP-7702 changes, backport from v52 (#1969) +- *(EIP-7623)* Increase calldata cost. backport from rel/v51 (#1965) +- simplify Transaction trait (#1959) +- align Block trait (#1957) +- Make Ctx journal generic (#1933) +- Restucturing Part7 Handler and Context rework (#1865) +- *(interpreter)* impl Clone for Stack (#1820) +- restructuring Part6 transaction crate (#1814) +- Merge validation/analyzis with Bytecode (#1793) +- restructure Part2 database crate (#1784) +- project restructuring Part1 (#1776) +- introducing EvmWiring, a chain-specific configuration (#1672) + +### Fixed + +- make macro crate-agnostic (#1802) + +### Other + +- backport op l1 fetch perf (#2076) +- add default generics for InterpreterTypes (#2070) +- Check performance of gas with i64 [#1884](https://github.com/bluealloy/revm/pull/1884) ([#2062](https://github.com/bluealloy/revm/pull/2062)) +- Bump licence year to 2025 (#2058) +- relax halt reason bounds (#2041) +- remove duplicate instructions (#2029) +- align crates versions (#1983) +- Add bytecode hash in interpreter [#1888](https://github.com/bluealloy/revm/pull/1888) ([#1952](https://github.com/bluealloy/revm/pull/1952)) +- Make inspector use generics, rm associated types (#1934) +- use MemoryOOG (#1941) +- fix comments and docs into more sensible (#1920) +- Move CfgEnv from context-interface to context crate (#1910) +- implement serde for interpreter ([#1909](https://github.com/bluealloy/revm/pull/1909)) +- make ExtBytecode pointer private (#1904) +- fix typos (#1868) +- *(primitives)* replace HashMap re-exports with alloy_primitives::map (#1805) +- refactor -copy common code (#1799) +- add ReentrancySentryOOG for SSTORE (#1795) +- simplify SuccessOrHalt trait bound (#1768) + +## [15.2.0](https://github.com/bluealloy/revm/compare/revm-interpreter-v15.1.0...revm-interpreter-v15.2.0) - 2025-02-11 + +### Other + +- revm v19.4.0 tag v54 + +## [15.1.0](https://github.com/bluealloy/revm/compare/revm-interpreter-v15.0.0...revm-interpreter-v15.1.0) - 2025-01-13 + +### Added + +- *(EIP-7623)* adjuct floor gas check order ([#1990](https://github.com/bluealloy/revm/pull/1990)) + +## [15.0.0](https://github.com/bluealloy/revm/compare/revm-interpreter-v14.0.0...revm-interpreter-v15.0.0) - 2024-12-26 + +### Added + +- apply latest EIP-7702 changes ([#1850](https://github.com/bluealloy/revm/pull/1850)) +- *(Prague)* EIP-7623 Increase Calldata Cost ([#1744](https://github.com/bluealloy/revm/pull/1744)) + +## [14.0.0](https://github.com/bluealloy/revm/compare/revm-interpreter-v13.0.0...revm-interpreter-v14.0.0) - 2024-11-06 + +### Other + +- bump alloy-eip7702 and remove `Parity` re-export ([#1842](https://github.com/bluealloy/revm/pull/1842)) + +## [13.0.0](https://github.com/bluealloy/revm/compare/revm-interpreter-v12.0.0...revm-interpreter-v13.0.0) - 2024-10-23 + +### Other + +- updated the following local packages: revm-primitives + +## [12.0.0](https://github.com/bluealloy/revm/compare/revm-interpreter-v11.0.0...revm-interpreter-v12.0.0) - 2024-10-17 + +### Other + +- updated the following local packages: revm-primitives + +## [11.0.0](https://github.com/bluealloy/revm/compare/revm-interpreter-v10.0.3...revm-interpreter-v11.0.0) - 2024-10-17 + +### Other + +- updated the following local packages: revm-primitives + +## [10.0.3](https://github.com/bluealloy/revm/compare/revm-interpreter-v10.0.2...revm-interpreter-v10.0.3) - 2024-09-26 + +### Other + +- updated the following local packages: revm-primitives + +## [10.0.2](https://github.com/bluealloy/revm/compare/revm-interpreter-v10.0.1...revm-interpreter-v10.0.2) - 2024-09-18 + +### Other + +- make clippy happy ([#1755](https://github.com/bluealloy/revm/pull/1755)) + +## [10.0.1](https://github.com/bluealloy/revm/compare/revm-interpreter-v10.0.0...revm-interpreter-v10.0.1) - 2024-08-30 + +### Other +- Bump new logo ([#1735](https://github.com/bluealloy/revm/pull/1735)) + +## [10.0.0](https://github.com/bluealloy/revm/compare/revm-interpreter-v9.0.0...revm-interpreter-v10.0.0) - 2024-08-29 + +### Added +- *(eip7702)* Impl newest version of EIP ([#1695](https://github.com/bluealloy/revm/pull/1695)) + +## [9.0.0](https://github.com/bluealloy/revm/compare/revm-interpreter-v8.1.0...revm-interpreter-v9.0.0) - 2024-08-08 + +### Added +- *(EOF)* add evmone test suite ([#1689](https://github.com/bluealloy/revm/pull/1689)) +- check for typos in CI ([#1686](https://github.com/bluealloy/revm/pull/1686)) +- *(EOF)* Add non-returning CALLF/JUMPF checks ([#1663](https://github.com/bluealloy/revm/pull/1663)) +- *(EOF)* EOF Validation add code type and sub container tracker ([#1648](https://github.com/bluealloy/revm/pull/1648)) +- *(EOF)* implement std::error::Error trait for EofValidationError and EofError ([#1649](https://github.com/bluealloy/revm/pull/1649)) +- *(interpreter)* derive traits on FunctionStack ([#1640](https://github.com/bluealloy/revm/pull/1640)) + +### Fixed +- add DATACOPY to OpCode::modifies_memory ([#1639](https://github.com/bluealloy/revm/pull/1639)) +- *(EOF)* returning to non-returning jumpf, enable valition error ([#1664](https://github.com/bluealloy/revm/pull/1664)) +- *(EOF)* Validate code access in stack ([#1659](https://github.com/bluealloy/revm/pull/1659)) +- *(eof)* deny static context in EOFCREATE ([#1644](https://github.com/bluealloy/revm/pull/1644)) + +### Other +- improve `InstructionResult` documentation ([#1673](https://github.com/bluealloy/revm/pull/1673)) +- Add EOF Layout Fuzz Loop to `revme bytecode` ([#1677](https://github.com/bluealloy/revm/pull/1677)) +- *(eof)* Add opcodes that expand memory ([#1665](https://github.com/bluealloy/revm/pull/1665)) +- *(clippy)* 1.80 rust clippy list paragraph ident ([#1661](https://github.com/bluealloy/revm/pull/1661)) +- avoid cloning original_bytes ([#1646](https://github.com/bluealloy/revm/pull/1646)) +- use `is_zero` for `U256` and `B256` ([#1638](https://github.com/bluealloy/revm/pull/1638)) +- fix some typos & remove useless Arc::clone ([#1621](https://github.com/bluealloy/revm/pull/1621)) +- *(eof)* avoid some allocations ([#1632](https://github.com/bluealloy/revm/pull/1632)) +- bump versions bcs of primitives ([#1631](https://github.com/bluealloy/revm/pull/1631)) + +## [8.0.0](https://github.com/bluealloy/revm/compare/revm-interpreter-v7.0.0...revm-interpreter-v8.0.0) - 2024-07-16 + +### Added +- *(eof)* cli eof-validation ([#1622](https://github.com/bluealloy/revm/pull/1622)) +- use `kzg-rs` for kzg point evaluation ([#1558](https://github.com/bluealloy/revm/pull/1558)) + +### Fixed +- *(eip7702)* Add tests and fix some bugs ([#1605](https://github.com/bluealloy/revm/pull/1605)) +- *(EOF)* MIN_CALLEE_GAS light failure, static-mode check ([#1599](https://github.com/bluealloy/revm/pull/1599)) + +## [7.0.0](https://github.com/bluealloy/revm/compare/revm-interpreter-v6.0.0...revm-interpreter-v7.0.0) - 2024-07-08 + +### Added +- *(Precompiles)* Throw fatal error if c-kzg is disabled ([#1589](https://github.com/bluealloy/revm/pull/1589)) +- add bytecode_address from CallInputs to Contract during construction. ([#1568](https://github.com/bluealloy/revm/pull/1568)) +- support selfdestruct for dummyhost ([#1578](https://github.com/bluealloy/revm/pull/1578)) +- *(Prague)* Add EIP-7702 ([#1565](https://github.com/bluealloy/revm/pull/1565)) +- *(EOF)* disallow ExtDelegateCall to legacy bytecode ([#1572](https://github.com/bluealloy/revm/pull/1572)) +- *(EOF)* Add target address expansion checks ([#1570](https://github.com/bluealloy/revm/pull/1570)) + +### Fixed +- *(eof)* ExtDelegateCall caller/target switch ([#1571](https://github.com/bluealloy/revm/pull/1571)) + +### Other +- *(README)* add rbuilder to used-by ([#1585](https://github.com/bluealloy/revm/pull/1585)) +- use const blocks ([#1522](https://github.com/bluealloy/revm/pull/1522)) +- fix compile for alloydb ([#1559](https://github.com/bluealloy/revm/pull/1559)) +- replace AccessList with alloy version ([#1552](https://github.com/bluealloy/revm/pull/1552)) +- replace U256 with u64 in BLOCKHASH ([#1505](https://github.com/bluealloy/revm/pull/1505)) + +## [6.0.0](https://github.com/bluealloy/revm/compare/revm-interpreter-v5.0.0...revm-interpreter-v6.0.0) - 2024-06-20 + +### Added +- *(EOF)* Put EOF bytecode behind an Arc ([#1517](https://github.com/bluealloy/revm/pull/1517)) +- *(EOF)* EXTCODECOPY,EXTCODESIZE,EXTCODEHASH eof support ([#1504](https://github.com/bluealloy/revm/pull/1504)) +- add helpers for working with instruction tables ([#1493](https://github.com/bluealloy/revm/pull/1493)) +- *(EOF)* change oob behavior of RETURNDATALOAD and RETURNDATACOPY ([#1476](https://github.com/bluealloy/revm/pull/1476)) +- *(EOF)* EIP-7698 eof creation transaction ([#1467](https://github.com/bluealloy/revm/pull/1467)) +- adjust gas-costs for EIP-2935 BLOCKHASH ([#1422](https://github.com/bluealloy/revm/pull/1422)) +- add Opcode::modifies_memory back ([#1421](https://github.com/bluealloy/revm/pull/1421)) +- *(EOF)* Add CALLF/JUMPF stack checks ([#1417](https://github.com/bluealloy/revm/pull/1417)) +- *(EOF)* remove TXCREATE ([#1415](https://github.com/bluealloy/revm/pull/1415)) + +### Fixed +- *(eof)* fixture 2 tests ([#1550](https://github.com/bluealloy/revm/pull/1550)) +- *(eof)* output gas for eofcreate ([#1540](https://github.com/bluealloy/revm/pull/1540)) +- *(EOF)* set CallOrCreate result in EOFCREATE ([#1535](https://github.com/bluealloy/revm/pull/1535)) +- *(EOF)* target needed for EOFCREATE created address ([#1536](https://github.com/bluealloy/revm/pull/1536)) +- *(EOF)* ext*call return values ([#1515](https://github.com/bluealloy/revm/pull/1515)) +- *(EOF)* Remove redundunt ext call gas cost ([#1513](https://github.com/bluealloy/revm/pull/1513)) +- *(EOF)* add DATACOPY copy gas ([#1510](https://github.com/bluealloy/revm/pull/1510)) +- *(EOF)* extstaticcall make static ([#1508](https://github.com/bluealloy/revm/pull/1508)) +- *(EOF)* jumpf gas was changes ([#1507](https://github.com/bluealloy/revm/pull/1507)) +- *(EOF)* panic on empty input range, and continue exec after eofcreate ([#1477](https://github.com/bluealloy/revm/pull/1477)) +- *(eof)* EOFCREATE spend gas and apply 63/64 rule ([#1471](https://github.com/bluealloy/revm/pull/1471)) +- *(stack)* pop with five items was not correct ([#1472](https://github.com/bluealloy/revm/pull/1472)) +- *(EOF)* returncontract immediate is one byte ([#1468](https://github.com/bluealloy/revm/pull/1468)) +- *(Interpreter)* wrong block number used ([#1458](https://github.com/bluealloy/revm/pull/1458)) +- *(interpreter)* avoid overflow when checking if mem limit reached ([#1429](https://github.com/bluealloy/revm/pull/1429)) +- blockchash for devnet-0 ([#1427](https://github.com/bluealloy/revm/pull/1427)) + +### Other +- replace TransactTo with TxKind ([#1542](https://github.com/bluealloy/revm/pull/1542)) +- simplify Interpreter serde ([#1544](https://github.com/bluealloy/revm/pull/1544)) +- *(interpreter)* use U256::arithmetic_shr in SAR ([#1525](https://github.com/bluealloy/revm/pull/1525)) +- pluralize EOFCreateInput ([#1523](https://github.com/bluealloy/revm/pull/1523)) +- added simular to used-by ([#1521](https://github.com/bluealloy/revm/pull/1521)) +- Removed .clone() in ExecutionHandler::call, and reusing output buffer in Interpreter ([#1512](https://github.com/bluealloy/revm/pull/1512)) +- *(revme)* add new line in revme EOF printer ([#1503](https://github.com/bluealloy/revm/pull/1503)) +- remove old deprecated items ([#1489](https://github.com/bluealloy/revm/pull/1489)) +- *(interpreter)* use max gas limit in `impl Default for Interpreter` ([#1478](https://github.com/bluealloy/revm/pull/1478)) +- *(interpreter)* optimisation for BYTE, SHL, SHR and SAR ([#1418](https://github.com/bluealloy/revm/pull/1418)) +- Revert "Revert "feat: implement EIP-2935 ([#1354](https://github.com/bluealloy/revm/pull/1354))" ([#1424](https://github.com/bluealloy/revm/pull/1424))" ([#1426](https://github.com/bluealloy/revm/pull/1426)) +- Revert "feat: implement EIP-2935 ([#1354](https://github.com/bluealloy/revm/pull/1354))" ([#1424](https://github.com/bluealloy/revm/pull/1424)) +- *(EOF)* rename extcall opcode/names ([#1416](https://github.com/bluealloy/revm/pull/1416)) +- point to gas! in Gas::record_cost ([#1413](https://github.com/bluealloy/revm/pull/1413)) +- pop_address should use crate scope ([#1410](https://github.com/bluealloy/revm/pull/1410)) +- Remove Host constrain from calc_call_gas ([#1409](https://github.com/bluealloy/revm/pull/1409)) + ## [5.0.0](https://github.com/bluealloy/revm/compare/revm-interpreter-v4.0.0...revm-interpreter-v5.0.0) - 2024-05-12 ### Added @@ -13,7 +433,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - parse opcodes from strings ([#1358](https://github.com/bluealloy/revm/pull/1358)) - *(interpreter)* add helpers for spending all gas ([#1360](https://github.com/bluealloy/revm/pull/1360)) - add helper methods to CallInputs ([#1345](https://github.com/bluealloy/revm/pull/1345)) -- *(revm)* make `FrameOrResult` serializable ([#1282](https://github.com/bluealloy/revm/pull/1282)) +- *(revm)* make `ItemOrResult` serializable ([#1282](https://github.com/bluealloy/revm/pull/1282)) - add flag to force hashbrown usage ([#1284](https://github.com/bluealloy/revm/pull/1284)) - EOF (Ethereum Object Format) ([#1143](https://github.com/bluealloy/revm/pull/1143)) - *(interpreter)* derive Eq for InterpreterAction ([#1262](https://github.com/bluealloy/revm/pull/1262)) diff --git a/crates/interpreter/Cargo.toml b/crates/interpreter/Cargo.toml index cd6b3d9668..a03818785f 100644 --- a/crates/interpreter/Cargo.toml +++ b/crates/interpreter/Cargo.toml @@ -1,83 +1,49 @@ [package] -authors = ["Dragan Rakita "] -description = "revm Interpreter" -edition = "2021" -keywords = ["no_std", "ethereum", "evm", "revm", "interpreter"] -license = "MIT" name = "revm-interpreter" -repository = "https://github.com/bluealloy/revm" -version = "5.0.0" -readme = "../../README.md" +description = "Revm Interpreter that executes bytecode." +version = "24.0.0" +authors.workspace = true +edition.workspace = true +keywords.workspace = true +license.workspace = true +repository.workspace = true +readme.workspace = true [package.metadata.docs.rs] all-features = true rustdoc-args = ["--cfg", "docsrs"] -[lints.rust] -unreachable_pub = "warn" -unused_must_use = "deny" -rust_2018_idioms = "deny" - -[lints.rustdoc] -all = "warn" +[lints] +workspace = true [dependencies] -revm-primitives = { path = "../primitives", version = "4.0.0", default-features = false } - -paste = { version = "1.0", optional = true } -phf = { version = "0.11", default-features = false, optional = true, features = [ - "macros", -] } +# revm +bytecode.workspace = true +primitives.workspace = true +context-interface.workspace = true # optional -serde = { version = "1.0", default-features = false, features = [ - "derive", - "rc", -], optional = true } +serde = { workspace = true, features = ["derive", "rc"], optional = true } [dev-dependencies] -walkdir = "2.5" -serde_json = "1.0" -bincode = "1.3" - -[[test]] -name = "eof" -path = "tests/eof.rs" -required-features = ["serde"] +bincode.workspace = true [features] -default = ["std", "parse"] -std = ["serde?/std", "revm-primitives/std"] -hashbrown = ["revm-primitives/hashbrown"] -serde = ["dep:serde", "revm-primitives/serde"] -arbitrary = ["std", "revm-primitives/arbitrary"] -asm-keccak = ["revm-primitives/asm-keccak"] -portable = ["revm-primitives/portable"] -parse = ["dep:paste", "dep:phf"] - -optimism = ["revm-primitives/optimism"] -# Optimism default handler enabled Optimism handler register by default in EvmBuilder. -optimism-default-handler = [ - "optimism", - "revm-primitives/optimism-default-handler", -] -negate-optimism-default-handler = [ - "revm-primitives/negate-optimism-default-handler", +default = ["std"] +std = [ + "serde?/std", + "primitives/std", + "context-interface/std", + "bytecode/std" ] - -dev = [ - "memory_limit", - "optional_balance_check", - "optional_block_gas_limit", - "optional_eip3607", - "optional_gas_refund", - "optional_no_base_fee", - "optional_beneficiary_reward", +hashbrown = ["primitives/hashbrown"] +serde = [ + "dep:serde", + "primitives/serde", + "bytecode/serde", + "context-interface/serde", + "bincode/serde", ] -memory_limit = ["revm-primitives/memory_limit"] -optional_balance_check = ["revm-primitives/optional_balance_check"] -optional_block_gas_limit = ["revm-primitives/optional_block_gas_limit"] -optional_eip3607 = ["revm-primitives/optional_eip3607"] -optional_gas_refund = ["revm-primitives/optional_gas_refund"] -optional_no_base_fee = ["revm-primitives/optional_no_base_fee"] -optional_beneficiary_reward = ["revm-primitives/optional_beneficiary_reward"] +arbitrary = ["std", "primitives/arbitrary"] +# TODO : Should be set from Context or from crate that consumes this PR. +memory_limit = [] diff --git a/crates/interpreter/LICENSE b/crates/interpreter/LICENSE index ad98ff22cc..be6d350ebe 100644 --- a/crates/interpreter/LICENSE +++ b/crates/interpreter/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2021-2024 draganrakita +Copyright (c) 2021-2025 draganrakita Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/crates/interpreter/src/function_stack.rs b/crates/interpreter/src/function_stack.rs deleted file mode 100644 index e6482d8e40..0000000000 --- a/crates/interpreter/src/function_stack.rs +++ /dev/null @@ -1,64 +0,0 @@ -use std::vec::Vec; - -/// Function return frame. -/// Needed information for returning from a function. -#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FunctionReturnFrame { - /// The index of the code container that this frame is executing. - pub idx: usize, - /// The program counter where frame execution should continue. - pub pc: usize, -} - -impl FunctionReturnFrame { - /// Return new function frame. - pub fn new(idx: usize, pc: usize) -> Self { - Self { idx, pc } - } -} - -/// Function Stack -#[derive(Debug, Default)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FunctionStack { - pub return_stack: Vec, - pub current_code_idx: usize, -} - -impl FunctionStack { - /// Returns new function stack. - pub fn new() -> Self { - Self { - return_stack: Vec::new(), - current_code_idx: 0, - } - } - - /// Pushes a new frame to the stack. and sets current_code_idx to new value. - pub fn push(&mut self, program_counter: usize, new_idx: usize) { - self.return_stack.push(FunctionReturnFrame { - idx: self.current_code_idx, - pc: program_counter, - }); - self.current_code_idx = new_idx; - } - - /// Return stack length - pub fn return_stack_len(&self) -> usize { - self.return_stack.len() - } - - /// Pops a frame from the stack and sets current_code_idx to the popped frame's idx. - pub fn pop(&mut self) -> Option { - self.return_stack.pop().map(|frame| { - self.current_code_idx = frame.idx; - frame - }) - } - - /// Sets current_code_idx, this is needed for JUMPF opcode. - pub fn set_current_code_idx(&mut self, idx: usize) { - self.current_code_idx = idx; - } -} diff --git a/crates/interpreter/src/gas.rs b/crates/interpreter/src/gas.rs index ac0af3079d..e270224069 100644 --- a/crates/interpreter/src/gas.rs +++ b/crates/interpreter/src/gas.rs @@ -16,6 +16,8 @@ pub struct Gas { remaining: u64, /// Refunded gas. This is used only at the end of execution. refunded: i64, + /// Memoisation of values for memory expansion cost. + memory: MemoryGas, } impl Gas { @@ -26,6 +28,7 @@ impl Gas { limit, remaining: limit, refunded: 0, + memory: MemoryGas::new(), } } @@ -36,6 +39,7 @@ impl Gas { limit, remaining: 0, refunded: 0, + memory: MemoryGas::new(), } } @@ -45,13 +49,16 @@ impl Gas { self.limit } - /// Returns the **last** memory expansion cost. + /// Returns the memory gas. #[inline] - #[deprecated = "memory expansion cost is not tracked anymore; \ - calculate it using `SharedMemory::current_expansion_cost` instead"] - #[doc(hidden)] - pub const fn memory(&self) -> u64 { - 0 + pub fn memory(&self) -> &MemoryGas { + &self.memory + } + + /// Returns the memory gas. + #[inline] + pub fn memory_mut(&mut self) -> &mut MemoryGas { + &mut self.memory } /// Returns the total amount of gas that was refunded. @@ -66,11 +73,16 @@ impl Gas { self.limit - self.remaining } - #[doc(hidden)] + /// Returns the final amount of gas used by subtracting the refund from spent gas. + #[inline] + pub const fn used(&self) -> u64 { + self.spent().saturating_sub(self.refunded() as u64) + } + + /// Returns the total amount of gas spent, minus the refunded gas. #[inline] - #[deprecated(note = "use `spent` instead")] - pub const fn spend(&self) -> u64 { - self.spent() + pub const fn spent_sub_refunded(&self) -> u64 { + self.spent().saturating_sub(self.refunded as u64) } /// Returns the amount of gas remaining. @@ -79,6 +91,11 @@ impl Gas { self.remaining } + /// Return remaining gas after subtracting 63/64 parts. + pub const fn remaining_63_of_64_parts(&self) -> u64 { + self.remaining - self.remaining / 64 + } + /// Erases a gas cost from the totals. #[inline] pub fn erase_cost(&mut self, returned: u64) { @@ -117,17 +134,87 @@ impl Gas { self.refunded = refund; } + /// Set a spent value. This overrides the current spent value. + #[inline] + pub fn set_spent(&mut self, spent: u64) { + self.remaining = self.limit.saturating_sub(spent); + } + /// Records an explicit cost. /// /// Returns `false` if the gas limit is exceeded. #[inline] #[must_use = "prefer using `gas!` instead to return an out-of-gas error on failure"] pub fn record_cost(&mut self, cost: u64) -> bool { - let (remaining, overflow) = self.remaining.overflowing_sub(cost); - let success = !overflow; - if success { - self.remaining = remaining; + if let Some(new_remaining) = self.remaining.checked_sub(cost) { + self.remaining = new_remaining; + return true; + } + false + } + + /// Record memory expansion + #[inline] + #[must_use = "internally uses record_cost that flags out of gas error"] + pub fn record_memory_expansion(&mut self, new_len: usize) -> MemoryExtensionResult { + let Some(additional_cost) = self.memory.record_new_len(new_len) else { + return MemoryExtensionResult::Same; + }; + + if !self.record_cost(additional_cost) { + return MemoryExtensionResult::OutOfGas; + } + + MemoryExtensionResult::Extended + } +} + +/// Result of attempting to extend memory during execution. +#[derive(Debug)] +pub enum MemoryExtensionResult { + /// Memory was extended. + Extended, + /// Memory size stayed the same. + Same, + /// Not enough gas to extend memory. + OutOfGas, +} + +/// Utility struct that speeds up calculation of memory expansion +/// It contains the current memory length and its memory expansion cost. +/// +/// It allows us to split gas accounting from memory structure. +#[derive(Clone, Copy, Default, Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct MemoryGas { + /// Current memory length + pub words_num: usize, + /// Current memory expansion cost + pub expansion_cost: u64, +} + +impl MemoryGas { + /// Creates a new `MemoryGas` instance with zero memory allocation. + #[inline] + pub const fn new() -> Self { + Self { + words_num: 0, + expansion_cost: 0, + } + } + + /// Records a new memory length and calculates additional cost if memory is expanded. + /// Returns the additional gas cost required, or None if no expansion is needed. + #[inline] + pub fn record_new_len(&mut self, new_num: usize) -> Option { + if new_num <= self.words_num { + return None; } - success + self.words_num = new_num; + let mut cost = crate::gas::calc::memory_gas(new_num); + core::mem::swap(&mut self.expansion_cost, &mut cost); + // Safe to subtract because we know that new_len > length + // Notice the swap above. + Some(self.expansion_cost - cost) } } diff --git a/crates/interpreter/src/gas/calc.rs b/crates/interpreter/src/gas/calc.rs index dd434fcd27..08ec9c0f07 100644 --- a/crates/interpreter/src/gas/calc.rs +++ b/crates/interpreter/src/gas/calc.rs @@ -1,25 +1,14 @@ use super::constants::*; -use crate::{ - num_words, - primitives::{Address, SpecId, U256}, - SelfDestructResult, +use crate::{num_words, tri, SStoreResult, SelfDestructResult, StateLoad}; +use context_interface::{ + journaled_state::AccountLoad, transaction::AccessListItemTr as _, Transaction, TransactionType, }; -use std::vec::Vec; - -/// `const` Option `?`. -macro_rules! tri { - ($e:expr) => { - match $e { - Some(v) => v, - None => return None, - } - }; -} +use primitives::{eip7702, hardfork::SpecId, U256}; /// `SSTORE` opcode refund calculation. #[allow(clippy::collapsible_else_if)] #[inline] -pub fn sstore_refund(spec_id: SpecId, original: U256, current: U256, new: U256) -> i64 { +pub fn sstore_refund(spec_id: SpecId, vals: &SStoreResult) -> i64 { if spec_id.is_enabled_in(SpecId::ISTANBUL) { // EIP-3529: Reduction in refunds let sstore_clears_schedule = if spec_id.is_enabled_in(SpecId::LONDON) { @@ -27,29 +16,29 @@ pub fn sstore_refund(spec_id: SpecId, original: U256, current: U256, new: U256) } else { REFUND_SSTORE_CLEARS }; - if current == new { + if vals.is_new_eq_present() { 0 } else { - if original == current && new == U256::ZERO { + if vals.is_original_eq_present() && vals.is_new_zero() { sstore_clears_schedule } else { let mut refund = 0; - if original != U256::ZERO { - if current == U256::ZERO { + if !vals.is_original_zero() { + if vals.is_present_zero() { refund -= sstore_clears_schedule; - } else if new == U256::ZERO { + } else if vals.is_new_zero() { refund += sstore_clears_schedule; } } - if original == new { + if vals.is_original_eq_new() { let (gas_sstore_reset, gas_sload) = if spec_id.is_enabled_in(SpecId::BERLIN) { (SSTORE_RESET - COLD_SLOAD_COST, WARM_STORAGE_READ_COST) } else { (SSTORE_RESET, sload_cost(spec_id, false)) }; - if original == U256::ZERO { + if vals.is_original_zero() { refund += (SSTORE_SET - gas_sload) as i64; } else { refund += (gas_sstore_reset - gas_sload) as i64; @@ -60,7 +49,7 @@ pub fn sstore_refund(spec_id: SpecId, original: U256, current: U256, new: U256) } } } else { - if current != U256::ZERO && new == U256::ZERO { + if !vals.is_present_zero() && vals.is_new_zero() { REFUND_SSTORE_CLEARS } else { 0 @@ -70,7 +59,7 @@ pub fn sstore_refund(spec_id: SpecId, original: U256, current: U256, new: U256) /// `CREATE2` opcode cost calculation. #[inline] -pub const fn create2_cost(len: u64) -> Option { +pub const fn create2_cost(len: usize) -> Option { CREATE.checked_add(tri!(cost_per_word(len, KECCAK256WORD))) } @@ -100,7 +89,7 @@ const fn log2floor(value: U256) -> u64 { /// `EXP` opcode cost calculation. #[inline] pub fn exp_cost(spec_id: SpecId, power: U256) -> Option { - if power == U256::ZERO { + if power.is_zero() { Some(EXP) } else { // EIP-160: EXP cost increase @@ -118,13 +107,13 @@ pub fn exp_cost(spec_id: SpecId, power: U256) -> Option { /// `*COPY` opcodes cost calculation. #[inline] -pub const fn verylowcopy_cost(len: u64) -> Option { - VERYLOW.checked_add(tri!(cost_per_word(len, COPY))) +pub const fn copy_cost_verylow(len: usize) -> Option { + copy_cost(VERYLOW, len) } /// `EXTCODECOPY` opcode cost calculation. #[inline] -pub const fn extcodecopy_cost(spec_id: SpecId, len: u64, is_cold: bool) -> Option { +pub const fn extcodecopy_cost(spec_id: SpecId, len: usize, is_cold: bool) -> Option { let base_gas = if spec_id.is_enabled_in(SpecId::BERLIN) { warm_cold_cost(is_cold) } else if spec_id.is_enabled_in(SpecId::TANGERINE) { @@ -132,7 +121,13 @@ pub const fn extcodecopy_cost(spec_id: SpecId, len: u64, is_cold: bool) -> Optio } else { 20 }; - base_gas.checked_add(tri!(cost_per_word(len, COPY))) + copy_cost(base_gas, len) +} + +#[inline] +/// Calculates the gas cost for copy operations based on data length. +pub const fn copy_cost(base_cost: u64, len: usize) -> Option { + base_cost.checked_add(tri!(cost_per_word(len, COPY))) } /// `LOG` opcode cost calculation. @@ -143,14 +138,14 @@ pub const fn log_cost(n: u8, len: u64) -> Option { /// `KECCAK256` opcode cost calculation. #[inline] -pub const fn keccak256_cost(len: u64) -> Option { +pub const fn keccak256_cost(len: usize) -> Option { KECCAK256.checked_add(tri!(cost_per_word(len, KECCAK256WORD))) } /// Calculate the cost of buffer per word. #[inline] -pub const fn cost_per_word(len: u64, multiple: u64) -> Option { - multiple.checked_mul(num_words(len)) +pub const fn cost_per_word(len: usize, multiple: u64) -> Option { + multiple.checked_mul(num_words(len) as u64) } /// EIP-3860: Limit and meter initcode @@ -159,7 +154,7 @@ pub const fn cost_per_word(len: u64, multiple: u64) -> Option { /// /// This cannot overflow as the initcode length is assumed to be checked. #[inline] -pub const fn initcode_cost(len: u64) -> u64 { +pub const fn initcode_cost(len: usize) -> u64 { let Some(cost) = cost_per_word(len, INITCODE_WORD_COST) else { panic!("initcode cost overflow") }; @@ -177,7 +172,7 @@ pub const fn sload_cost(spec_id: SpecId, is_cold: bool) -> u64 { } } else if spec_id.is_enabled_in(SpecId::ISTANBUL) { // EIP-1884: Repricing for trie-size-dependent opcodes - INSTANBUL_SLOAD_GAS + ISTANBUL_SLOAD_GAS } else if spec_id.is_enabled_in(SpecId::TANGERINE) { // EIP-150: Gas cost changes for IO-heavy operations 200 @@ -188,52 +183,34 @@ pub const fn sload_cost(spec_id: SpecId, is_cold: bool) -> u64 { /// `SSTORE` opcode cost calculation. #[inline] -pub fn sstore_cost( - spec_id: SpecId, - original: U256, - current: U256, - new: U256, - gas: u64, - is_cold: bool, -) -> Option { - // EIP-1706 Disable SSTORE with gasleft lower than call stipend - if spec_id.is_enabled_in(SpecId::ISTANBUL) && gas <= CALL_STIPEND { - return None; - } - +pub fn sstore_cost(spec_id: SpecId, vals: &SStoreResult, is_cold: bool) -> u64 { if spec_id.is_enabled_in(SpecId::BERLIN) { // Berlin specification logic - let mut gas_cost = istanbul_sstore_cost::( - original, current, new, - ); + let mut gas_cost = istanbul_sstore_cost::(vals); if is_cold { gas_cost += COLD_SLOAD_COST; } - Some(gas_cost) + gas_cost } else if spec_id.is_enabled_in(SpecId::ISTANBUL) { // Istanbul logic - Some(istanbul_sstore_cost::( - original, current, new, - )) + istanbul_sstore_cost::(vals) } else { // Frontier logic - Some(frontier_sstore_cost(current, new)) + frontier_sstore_cost(vals) } } /// EIP-2200: Structured Definitions for Net Gas Metering #[inline] fn istanbul_sstore_cost( - original: U256, - current: U256, - new: U256, + vals: &SStoreResult, ) -> u64 { - if new == current { + if vals.is_new_eq_present() { SLOAD_GAS - } else if original == current && original == U256::ZERO { + } else if vals.is_original_eq_present() && vals.is_original_zero() { SSTORE_SET - } else if original == current { + } else if vals.is_original_eq_present() { SSTORE_RESET_GAS } else { SLOAD_GAS @@ -242,8 +219,8 @@ fn istanbul_sstore_cost( /// Frontier sstore cost just had two cases set and reset values. #[inline] -fn frontier_sstore_cost(current: U256, new: U256) -> u64 { - if current == U256::ZERO && new != U256::ZERO { +fn frontier_sstore_cost(vals: &SStoreResult) -> u64 { + if vals.is_present_zero() && !vals.is_new_zero() { SSTORE_SET } else { SSTORE_RESET @@ -252,12 +229,12 @@ fn frontier_sstore_cost(current: U256, new: U256) -> u64 { /// `SELFDESTRUCT` opcode cost calculation. #[inline] -pub const fn selfdestruct_cost(spec_id: SpecId, res: SelfDestructResult) -> u64 { +pub const fn selfdestruct_cost(spec_id: SpecId, res: StateLoad) -> u64 { // EIP-161: State trie clearing (invariant-preserving alternative) let should_charge_topup = if spec_id.is_enabled_in(SpecId::SPURIOUS_DRAGON) { - res.had_value && !res.target_exists + res.data.had_value && !res.data.target_exists } else { - !res.target_exists + !res.data.target_exists }; // EIP-150: Gas cost changes for IO-heavy operations @@ -288,17 +265,24 @@ pub const fn selfdestruct_cost(spec_id: SpecId, res: SelfDestructResult) -> u64 /// * Account access gas. after berlin it can be cold or warm. /// * Transfer value gas. If value is transferred and balance of target account is updated. /// * If account is not existing and needs to be created. After Spurious dragon -/// this is only accounted if value is transferred. +/// this is only accounted if value is transferred. +/// +/// account_load.is_empty will be accounted only if hardfork is SPURIOUS_DRAGON and +/// there is transfer value. [`bytecode::opcode::CALL`] use this field. +/// +/// While [`bytecode::opcode::STATICCALL`], [`bytecode::opcode::DELEGATECALL`], +/// [`bytecode::opcode::CALLCODE`] need to have this field hardcoded to false +/// as they were present before SPURIOUS_DRAGON hardfork. #[inline] pub const fn call_cost( spec_id: SpecId, transfers_value: bool, - is_cold: bool, - new_account_accounting: bool, + account_load: StateLoad, ) -> u64 { + let is_empty = account_load.data.is_empty; // Account access. let mut gas = if spec_id.is_enabled_in(SpecId::BERLIN) { - warm_cold_cost(is_cold) + warm_cold_cost_with_delegation(account_load) } else if spec_id.is_enabled_in(SpecId::TANGERINE) { // EIP-150: Gas cost changes for IO-heavy operations 700 @@ -306,16 +290,16 @@ pub const fn call_cost( 40 }; - // transfer value cost + // Transfer value cost if transfers_value { gas += CALLVALUE; } - // new account cost - if new_account_accounting { + // New account cost + if is_empty { // EIP-161: State trie clearing (invariant-preserving alternative) if spec_id.is_enabled_in(SpecId::SPURIOUS_DRAGON) { - // account only if there is value transferred. + // Account only if there is value transferred. if transfers_value { gas += NEWACCOUNT; } @@ -337,53 +321,82 @@ pub const fn warm_cold_cost(is_cold: bool) -> u64 { } } -/// Memory expansion cost calculation for a given memory length. +/// Berlin warm and cold storage access cost for account access. +/// +/// If delegation is Some, add additional cost for delegation account load. #[inline] -pub const fn memory_gas_for_len(len: usize) -> u64 { - memory_gas(crate::interpreter::num_words(len as u64)) +pub const fn warm_cold_cost_with_delegation(load: StateLoad) -> u64 { + let mut gas = warm_cold_cost(load.is_cold); + if let Some(is_cold) = load.data.is_delegate_account_cold { + gas += warm_cold_cost(is_cold); + } + gas } /// Memory expansion cost calculation for a given number of words. #[inline] -pub const fn memory_gas(num_words: u64) -> u64 { +pub const fn memory_gas(num_words: usize) -> u64 { + let num_words = num_words as u64; MEMORY .saturating_mul(num_words) .saturating_add(num_words.saturating_mul(num_words) / 512) } +/// Init and floor gas from transaction +#[derive(Clone, Copy, Debug, Default)] +pub struct InitialAndFloorGas { + /// Initial gas for transaction. + pub initial_gas: u64, + /// If transaction is a Call and Prague is enabled + /// floor_gas is at least amount of gas that is going to be spent. + pub floor_gas: u64, +} + +impl InitialAndFloorGas { + /// Create a new InitialAndFloorGas instance. + #[inline] + pub const fn new(initial_gas: u64, floor_gas: u64) -> Self { + Self { + initial_gas, + floor_gas, + } + } +} + /// Initial gas that is deducted for transaction to be included. /// Initial gas contains initial stipend gas, gas for access list and input data. -pub fn validate_initial_tx_gas( +/// +/// # Returns +/// +/// - Intrinsic gas +/// - Number of tokens in calldata +pub fn calculate_initial_tx_gas( spec_id: SpecId, input: &[u8], is_create: bool, - access_list: &[(Address, Vec)], -) -> u64 { - let mut initial_gas = 0; - let zero_data_len = input.iter().filter(|v| **v == 0).count() as u64; - let non_zero_data_len = input.len() as u64 - zero_data_len; + access_list_accounts: u64, + access_list_storages: u64, + authorization_list_num: u64, +) -> InitialAndFloorGas { + let mut gas = InitialAndFloorGas::default(); - // initdate stipend - initial_gas += zero_data_len * TRANSACTION_ZERO_DATA; - // EIP-2028: Transaction data gas cost reduction - initial_gas += non_zero_data_len - * if spec_id.is_enabled_in(SpecId::ISTANBUL) { - 16 - } else { - 68 - }; + // Initdate stipend + let tokens_in_calldata = get_tokens_in_calldata(input, spec_id.is_enabled_in(SpecId::ISTANBUL)); - // get number of access list account and storages. - if spec_id.is_enabled_in(SpecId::BERLIN) { - let accessed_slots = access_list - .iter() - .fold(0, |slot_count, (_, slots)| slot_count + slots.len() as u64); - initial_gas += access_list.len() as u64 * ACCESS_LIST_ADDRESS; - initial_gas += accessed_slots * ACCESS_LIST_STORAGE_KEY; - } + // TODO(EOF) Tx type is removed + // initcode stipend + // for initcode in initcodes { + // tokens_in_calldata += get_tokens_in_calldata(initcode.as_ref(), true); + // } + + gas.initial_gas += tokens_in_calldata * STANDARD_TOKEN_COST; - // base stipend - initial_gas += if is_create { + // Get number of access list account and storages. + gas.initial_gas += access_list_accounts * ACCESS_LIST_ADDRESS; + gas.initial_gas += access_list_storages * ACCESS_LIST_STORAGE_KEY; + + // Base stipend + gas.initial_gas += if is_create { if spec_id.is_enabled_in(SpecId::HOMESTEAD) { // EIP-2: Homestead Hard-fork Changes 53000 @@ -397,8 +410,80 @@ pub fn validate_initial_tx_gas( // EIP-3860: Limit and meter initcode // Init code stipend for bytecode analysis if spec_id.is_enabled_in(SpecId::SHANGHAI) && is_create { - initial_gas += initcode_cost(input.len() as u64) + gas.initial_gas += initcode_cost(input.len()) + } + + // EIP-7702 + if spec_id.is_enabled_in(SpecId::PRAGUE) { + gas.initial_gas += authorization_list_num * eip7702::PER_EMPTY_ACCOUNT_COST; + + // Calculate gas floor for EIP-7623 + gas.floor_gas = calc_tx_floor_cost(tokens_in_calldata); } - initial_gas + gas +} + +/// Initial gas that is deducted for transaction to be included. +/// Initial gas contains initial stipend gas, gas for access list and input data. +/// +/// # Returns +/// +/// - Intrinsic gas +/// - Number of tokens in calldata +pub fn calculate_initial_tx_gas_for_tx(tx: impl Transaction, spec: SpecId) -> InitialAndFloorGas { + let mut accounts = 0; + let mut storages = 0; + // legacy is only tx type that does not have access list. + if tx.tx_type() != TransactionType::Legacy { + (accounts, storages) = tx + .access_list() + .map(|al| { + al.fold((0, 0), |(mut num_accounts, mut num_storage_slots), item| { + num_accounts += 1; + num_storage_slots += item.storage_slots().count(); + + (num_accounts, num_storage_slots) + }) + }) + .unwrap_or_default(); + } + + // Access initcodes only if tx is Eip7873. + // TODO(EOF) Tx type is removed + // let initcodes = if tx.tx_type() == TransactionType::Eip7873 { + // tx.initcodes() + // } else { + // &[] + // }; + + calculate_initial_tx_gas( + spec, + tx.input(), + tx.kind().is_create(), + accounts as u64, + storages as u64, + tx.authorization_list_len() as u64, + //initcodes, + ) +} + +/// Retrieve the total number of tokens in calldata. +#[inline] +pub fn get_tokens_in_calldata(input: &[u8], is_istanbul: bool) -> u64 { + let zero_data_len = input.iter().filter(|v| **v == 0).count() as u64; + let non_zero_data_len = input.len() as u64 - zero_data_len; + let non_zero_data_multiplier = if is_istanbul { + // EIP-2028: Transaction data gas cost reduction + NON_ZERO_BYTE_MULTIPLIER_ISTANBUL + } else { + NON_ZERO_BYTE_MULTIPLIER + }; + zero_data_len + non_zero_data_len * non_zero_data_multiplier +} + +/// Calculate the transaction cost floor as specified in EIP-7623. +#[inline] +pub fn calc_tx_floor_cost(tokens_in_calldata: u64) -> u64 { + tokens_in_calldata * TOTAL_COST_FLOOR_PER_TOKEN + 21_000 } diff --git a/crates/interpreter/src/gas/constants.rs b/crates/interpreter/src/gas/constants.rs index 9475e3b33a..057d2d899f 100644 --- a/crates/interpreter/src/gas/constants.rs +++ b/crates/interpreter/src/gas/constants.rs @@ -1,53 +1,102 @@ +/// Gas cost for operations that consume zero gas. pub const ZERO: u64 = 0; +/// Base gas cost for basic operations. pub const BASE: u64 = 2; +/// Gas cost for very low-cost operations. pub const VERYLOW: u64 = 3; +/// Gas cost for DATALOADN instruction. pub const DATA_LOADN_GAS: u64 = 3; +/// Gas cost for conditional jump instructions. pub const CONDITION_JUMP_GAS: u64 = 4; -pub const RETF_GAS: u64 = 4; +/// Gas cost for RETF instruction. +pub const RETF_GAS: u64 = 3; +/// Gas cost for DATALOAD instruction. pub const DATA_LOAD_GAS: u64 = 4; +/// Gas cost for low-cost operations. pub const LOW: u64 = 5; +/// Gas cost for medium-cost operations. pub const MID: u64 = 8; +/// Gas cost for high-cost operations. pub const HIGH: u64 = 10; +/// Gas cost for JUMPDEST instruction. pub const JUMPDEST: u64 = 1; +/// Gas cost for SELFDESTRUCT instruction. pub const SELFDESTRUCT: i64 = 24000; +/// Gas cost for CREATE instruction. pub const CREATE: u64 = 32000; +/// Additional gas cost when a call transfers value. pub const CALLVALUE: u64 = 9000; +/// Gas cost for creating a new account. pub const NEWACCOUNT: u64 = 25000; +/// Base gas cost for EXP instruction. pub const EXP: u64 = 10; +/// Gas cost per word for memory operations. pub const MEMORY: u64 = 3; +/// Base gas cost for LOG instructions. pub const LOG: u64 = 375; +/// Gas cost per byte of data in LOG instructions. pub const LOGDATA: u64 = 8; +/// Gas cost per topic in LOG instructions. pub const LOGTOPIC: u64 = 375; +/// Base gas cost for KECCAK256 instruction. pub const KECCAK256: u64 = 30; +/// Gas cost per word for KECCAK256 instruction. pub const KECCAK256WORD: u64 = 6; +/// Gas cost per word for copy operations. pub const COPY: u64 = 3; +/// Gas cost for BLOCKHASH instruction. pub const BLOCKHASH: u64 = 20; +/// Gas cost per byte for code deposit during contract creation. pub const CODEDEPOSIT: u64 = 200; /// EIP-1884: Repricing for trie-size-dependent opcodes -pub const INSTANBUL_SLOAD_GAS: u64 = 800; +pub const ISTANBUL_SLOAD_GAS: u64 = 800; +/// Gas cost for SSTORE when setting a storage slot from zero to non-zero. pub const SSTORE_SET: u64 = 20000; +/// Gas cost for SSTORE when modifying an existing non-zero storage slot. pub const SSTORE_RESET: u64 = 5000; +/// Gas refund for SSTORE when clearing a storage slot (setting to zero). pub const REFUND_SSTORE_CLEARS: i64 = 15000; -pub const TRANSACTION_ZERO_DATA: u64 = 4; -pub const TRANSACTION_NON_ZERO_DATA_INIT: u64 = 16; -pub const TRANSACTION_NON_ZERO_DATA_FRONTIER: u64 = 68; +/// The standard cost of calldata token. +pub const STANDARD_TOKEN_COST: u64 = 4; +/// The cost of a non-zero byte in calldata. +pub const NON_ZERO_BYTE_DATA_COST: u64 = 68; +/// The multiplier for a non zero byte in calldata. +pub const NON_ZERO_BYTE_MULTIPLIER: u64 = NON_ZERO_BYTE_DATA_COST / STANDARD_TOKEN_COST; +/// The cost of a non-zero byte in calldata adjusted by [EIP-2028](https://eips.ethereum.org/EIPS/eip-2028). +pub const NON_ZERO_BYTE_DATA_COST_ISTANBUL: u64 = 16; +/// The multiplier for a non zero byte in calldata adjusted by [EIP-2028](https://eips.ethereum.org/EIPS/eip-2028). +pub const NON_ZERO_BYTE_MULTIPLIER_ISTANBUL: u64 = + NON_ZERO_BYTE_DATA_COST_ISTANBUL / STANDARD_TOKEN_COST; +// The cost floor per token as defined by [EIP-2028](https://eips.ethereum.org/EIPS/eip-2028). +/// The cost floor per token as defined by EIP-2028. +pub const TOTAL_COST_FLOOR_PER_TOKEN: u64 = 10; +/// Gas cost for EOF CREATE instruction. pub const EOF_CREATE_GAS: u64 = 32000; -// berlin eip2929 constants +// Berlin eip2929 constants +/// Gas cost for accessing an address in the access list (EIP-2929). pub const ACCESS_LIST_ADDRESS: u64 = 2400; +/// Gas cost for accessing a storage key in the access list (EIP-2929). pub const ACCESS_LIST_STORAGE_KEY: u64 = 1900; +/// Gas cost for SLOAD when accessing a cold storage slot (EIP-2929). pub const COLD_SLOAD_COST: u64 = 2100; +/// Gas cost for accessing a cold account (EIP-2929). pub const COLD_ACCOUNT_ACCESS_COST: u64 = 2600; +/// Gas cost for reading from a warm storage slot (EIP-2929). pub const WARM_STORAGE_READ_COST: u64 = 100; +/// Gas cost for SSTORE reset operation on a warm storage slot. pub const WARM_SSTORE_RESET: u64 = SSTORE_RESET - COLD_SLOAD_COST; /// EIP-3860 : Limit and meter initcode pub const INITCODE_WORD_COST: u64 = 2; +/// Gas stipend provided to the recipient of a CALL with value transfer. pub const CALL_STIPEND: u64 = 2300; +/// Minimum gas that must be provided to a callee. +pub const MIN_CALLEE_GAS: u64 = CALL_STIPEND; diff --git a/crates/interpreter/src/host.rs b/crates/interpreter/src/host.rs deleted file mode 100644 index 49ffbd02a6..0000000000 --- a/crates/interpreter/src/host.rs +++ /dev/null @@ -1,96 +0,0 @@ -use crate::primitives::{Address, Bytecode, Env, Log, B256, U256}; - -mod dummy; -pub use dummy::DummyHost; - -/// EVM context host. -pub trait Host { - /// Returns a reference to the environment. - fn env(&self) -> &Env; - - /// Returns a mutable reference to the environment. - fn env_mut(&mut self) -> &mut Env; - - /// Load an account. - /// - /// Returns (is_cold, is_new_account) - fn load_account(&mut self, address: Address) -> Option; - - /// Get the block hash of the given block `number`. - fn block_hash(&mut self, number: U256) -> Option; - - /// Get balance of `address` and if the account is cold. - fn balance(&mut self, address: Address) -> Option<(U256, bool)>; - - /// Get code of `address` and if the account is cold. - fn code(&mut self, address: Address) -> Option<(Bytecode, bool)>; - - /// Get code hash of `address` and if the account is cold. - fn code_hash(&mut self, address: Address) -> Option<(B256, bool)>; - - /// Get storage value of `address` at `index` and if the account is cold. - fn sload(&mut self, address: Address, index: U256) -> Option<(U256, bool)>; - - /// Set storage value of account address at index. - /// - /// Returns (original, present, new, is_cold). - fn sstore(&mut self, address: Address, index: U256, value: U256) -> Option; - - /// Get the transient storage value of `address` at `index`. - fn tload(&mut self, address: Address, index: U256) -> U256; - - /// Set the transient storage value of `address` at `index`. - fn tstore(&mut self, address: Address, index: U256, value: U256); - - /// Emit a log owned by `address` with given `LogData`. - fn log(&mut self, log: Log); - - /// Mark `address` to be deleted, with funds transferred to `target`. - fn selfdestruct(&mut self, address: Address, target: Address) -> Option; -} - -/// Represents the result of an `sstore` operation. -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct SStoreResult { - /// Value of the storage when it is first read - pub original_value: U256, - /// Current value of the storage - pub present_value: U256, - /// New value that is set - pub new_value: U256, - /// Is storage slot loaded from database - pub is_cold: bool, -} - -/// Result of the account load from Journal state. -#[derive(Debug, Clone, Default, PartialEq, Eq)] -pub struct LoadAccountResult { - /// Is account cold loaded - pub is_cold: bool, - /// Is account empty, if true account is not created. - pub is_empty: bool, -} - -/// Result of a selfdestruct instruction. -#[derive(Default, Clone, Debug, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct SelfDestructResult { - pub had_value: bool, - pub target_exists: bool, - pub is_cold: bool, - pub previously_destroyed: bool, -} - -#[cfg(test)] -mod tests { - use super::*; - - fn assert_host() {} - - #[test] - fn object_safety() { - assert_host::(); - assert_host::(); - } -} diff --git a/crates/interpreter/src/host/dummy.rs b/crates/interpreter/src/host/dummy.rs deleted file mode 100644 index 4a069bfa63..0000000000 --- a/crates/interpreter/src/host/dummy.rs +++ /dev/null @@ -1,124 +0,0 @@ -use crate::primitives::{hash_map::Entry, Bytecode, HashMap, U256}; -use crate::{ - primitives::{Address, Env, Log, B256, KECCAK_EMPTY}, - Host, SStoreResult, SelfDestructResult, -}; -use std::vec::Vec; - -use super::LoadAccountResult; - -/// A dummy [Host] implementation. -#[derive(Clone, Debug, Default, PartialEq, Eq)] -pub struct DummyHost { - pub env: Env, - pub storage: HashMap, - pub transient_storage: HashMap, - pub log: Vec, -} - -impl DummyHost { - /// Create a new dummy host with the given [`Env`]. - #[inline] - pub fn new(env: Env) -> Self { - Self { - env, - ..Default::default() - } - } - - /// Clears the storage and logs of the dummy host. - #[inline] - pub fn clear(&mut self) { - self.storage.clear(); - self.log.clear(); - } -} - -impl Host for DummyHost { - #[inline] - fn env(&self) -> &Env { - &self.env - } - - #[inline] - fn env_mut(&mut self) -> &mut Env { - &mut self.env - } - - #[inline] - fn load_account(&mut self, _address: Address) -> Option { - Some(LoadAccountResult::default()) - } - - #[inline] - fn block_hash(&mut self, _number: U256) -> Option { - Some(B256::ZERO) - } - - #[inline] - fn balance(&mut self, _address: Address) -> Option<(U256, bool)> { - Some((U256::ZERO, false)) - } - - #[inline] - fn code(&mut self, _address: Address) -> Option<(Bytecode, bool)> { - Some((Bytecode::default(), false)) - } - - #[inline] - fn code_hash(&mut self, __address: Address) -> Option<(B256, bool)> { - Some((KECCAK_EMPTY, false)) - } - - #[inline] - fn sload(&mut self, __address: Address, index: U256) -> Option<(U256, bool)> { - match self.storage.entry(index) { - Entry::Occupied(entry) => Some((*entry.get(), false)), - Entry::Vacant(entry) => { - entry.insert(U256::ZERO); - Some((U256::ZERO, true)) - } - } - } - - #[inline] - fn sstore(&mut self, _address: Address, index: U256, value: U256) -> Option { - let (present, is_cold) = match self.storage.entry(index) { - Entry::Occupied(mut entry) => (entry.insert(value), false), - Entry::Vacant(entry) => { - entry.insert(value); - (U256::ZERO, true) - } - }; - - Some(SStoreResult { - original_value: U256::ZERO, - present_value: present, - new_value: value, - is_cold, - }) - } - - #[inline] - fn tload(&mut self, _address: Address, index: U256) -> U256 { - self.transient_storage - .get(&index) - .copied() - .unwrap_or_default() - } - - #[inline] - fn tstore(&mut self, _address: Address, index: U256, value: U256) { - self.transient_storage.insert(index, value); - } - - #[inline] - fn log(&mut self, log: Log) { - self.log.push(log) - } - - #[inline] - fn selfdestruct(&mut self, _address: Address, _target: Address) -> Option { - panic!("Selfdestruct is not supported for this host") - } -} diff --git a/crates/interpreter/src/instruction_context.rs b/crates/interpreter/src/instruction_context.rs new file mode 100644 index 0000000000..d8aa146829 --- /dev/null +++ b/crates/interpreter/src/instruction_context.rs @@ -0,0 +1,41 @@ +use crate::{interpreter_types::Jumps, Interpreter, InterpreterTypes}; + +use super::Instruction; + +/// Context passed to instruction implementations containing the host and interpreter. +/// This struct provides access to both the host interface for external state operations +/// and the interpreter state for stack, memory, and gas operations. +pub struct InstructionContext<'a, H: ?Sized, ITy: InterpreterTypes> { + /// Reference to the interpreter containing execution state (stack, memory, gas, etc). + pub interpreter: &'a mut Interpreter, + /// Reference to the host interface for accessing external blockchain state. + pub host: &'a mut H, +} + +impl std::fmt::Debug for InstructionContext<'_, H, ITy> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("InstructionContext") + .field("host", &"") + .field("interpreter", &"") + .finish() + } +} + +impl InstructionContext<'_, H, ITy> { + /// Executes the instruction at the current instruction pointer. + /// + /// Internally it will increment instruction pointer by one. + #[inline] + pub(crate) fn step(self, instruction_table: &[Instruction; 256]) { + // Get current opcode. + let opcode = self.interpreter.bytecode.opcode(); + + // SAFETY: In analysis we are doing padding of bytecode so that we are sure that last + // byte instruction is STOP so we are safe to just increment program_counter bcs on last instruction + // it will do noop and just stop execution of this contract + self.interpreter.bytecode.relative_jump(1); + + // Execute instruction. + instruction_table[opcode as usize](self) + } +} diff --git a/crates/interpreter/src/instruction_result.rs b/crates/interpreter/src/instruction_result.rs index 9e0f6e1264..a5c7485c55 100644 --- a/crates/interpreter/src/instruction_result.rs +++ b/crates/interpreter/src/instruction_result.rs @@ -1,58 +1,95 @@ -use crate::primitives::{HaltReason, OutOfGasError, SuccessReason}; +use context_interface::{ + journaled_state::TransferError, + result::{HaltReason, OutOfGasError, SuccessReason}, +}; +use core::fmt::Debug; #[repr(u8)] #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +/// Result of executing an EVM instruction. +/// This enum represents all possible outcomes when executing an instruction, +/// including successful execution, reverts, and various error conditions. pub enum InstructionResult { - // success codes + /// Encountered a `STOP` opcode #[default] - Continue = 0x00, Stop, + /// Return from the current call. Return, + /// Self-destruct the current contract. SelfDestruct, - ReturnContract, - // revert codes - Revert = 0x10, // revert opcode + // Revert Codes + /// Revert the transaction. + Revert = 0x10, + /// Exceeded maximum call depth. CallTooDeep, + /// Insufficient funds for transfer. OutOfFunds, + /// Revert if `CREATE`/`CREATE2` starts with `0xEF00`. + CreateInitCodeStartingEF00, + /// Invalid EVM Object Format (EOF) init code. + InvalidEOFInitCode, + /// `ExtDelegateCall` calling a non EOF contract. + InvalidExtDelegateCallTarget, - // Actions - CallOrCreate = 0x20, - - // error codes + // Error Codes + /// Out of gas error. OutOfGas = 0x50, + /// Out of gas error encountered during memory expansion. MemoryOOG, + /// The memory limit of the EVM has been exceeded. MemoryLimitOOG, + /// Out of gas error encountered during the execution of a precompiled contract. PrecompileOOG, + /// Out of gas error encountered while calling an invalid operand. InvalidOperandOOG, + /// Out of gas error encountered while checking for reentrancy sentry. + ReentrancySentryOOG, + /// Unknown or invalid opcode. OpcodeNotFound, + /// Invalid `CALL` with value transfer in static context. CallNotAllowedInsideStatic, + /// Invalid state modification in static call. StateChangeDuringStaticCall, + /// An undefined bytecode value encountered during execution. InvalidFEOpcode, + /// Invalid jump destination. Dynamic jumps points to invalid not jumpdest opcode. InvalidJump, + /// The feature or opcode is not activated in this version of the EVM. NotActivated, + /// Attempting to pop a value from an empty stack. StackUnderflow, + /// Attempting to push a value onto a full stack. StackOverflow, + /// Invalid memory or storage offset. OutOfOffset, + /// Address collision during contract creation. CreateCollision, + /// Payment amount overflow. OverflowPayment, + /// Error in precompiled contract execution. PrecompileError, + /// Nonce overflow. NonceOverflow, - /// Create init code size exceeds limit (runtime). + /// Exceeded contract size limit during creation. CreateContractSizeLimit, - /// Error on created contract that begins with EF + /// Created contract starts with invalid bytes (`0xEF`). CreateContractStartingWithEF, - /// EIP-3860: Limit and meter initcode. Initcode size limit exceeded. + /// Exceeded init code size limit (EIP-3860: Limit and meter initcode). CreateInitCodeSizeLimit, /// Fatal external error. Returned by database. FatalExternalError, - /// RETURNCONTRACT called in not init eof code. - ReturnContractInNotInitEOF, - /// Legacy contract is calling opcode that is enabled only in EOF. - EOFOpcodeDisabledInLegacy, - /// EOF function stack overflow - EOFFunctionStackOverflow, +} + +impl From for InstructionResult { + fn from(e: TransferError) -> Self { + match e { + TransferError::OutOfFunds => InstructionResult::OutOfFunds, + TransferError::OverflowPayment => InstructionResult::OverflowPayment, + TransferError::CreateCollision => InstructionResult::CreateCollision, + } + } } impl From for InstructionResult { @@ -74,6 +111,7 @@ impl From for InstructionResult { OutOfGasError::Memory => Self::MemoryOOG, OutOfGasError::MemoryLimit => Self::MemoryLimitOOG, OutOfGasError::Precompile => Self::PrecompileOOG, + OutOfGasError::ReentrancySentry => Self::ReentrancySentryOOG, }, HaltReason::OpcodeNotFound => Self::OpcodeNotFound, HaltReason::InvalidFEOpcode => Self::InvalidFEOpcode, @@ -93,58 +131,63 @@ impl From for InstructionResult { HaltReason::CallNotAllowedInsideStatic => Self::CallNotAllowedInsideStatic, HaltReason::OutOfFunds => Self::OutOfFunds, HaltReason::CallTooDeep => Self::CallTooDeep, - #[cfg(feature = "optimism")] - HaltReason::FailedDeposit => Self::FatalExternalError, } } } +/// Macro that matches all successful instruction results. +/// Used in pattern matching to handle all successful execution outcomes. #[macro_export] macro_rules! return_ok { () => { - InstructionResult::Continue - | InstructionResult::Stop - | InstructionResult::Return - | InstructionResult::SelfDestruct - | InstructionResult::ReturnContract + $crate::InstructionResult::Stop + | $crate::InstructionResult::Return + | $crate::InstructionResult::SelfDestruct }; } +/// Macro that matches all revert instruction results. +/// Used in pattern matching to handle all revert outcomes. #[macro_export] macro_rules! return_revert { () => { - InstructionResult::Revert | InstructionResult::CallTooDeep | InstructionResult::OutOfFunds + $crate::InstructionResult::Revert + | $crate::InstructionResult::CallTooDeep + | $crate::InstructionResult::OutOfFunds + | $crate::InstructionResult::InvalidEOFInitCode + | $crate::InstructionResult::CreateInitCodeStartingEF00 + | $crate::InstructionResult::InvalidExtDelegateCallTarget }; } +/// Macro that matches all error instruction results. +/// Used in pattern matching to handle all error outcomes. #[macro_export] macro_rules! return_error { () => { - InstructionResult::OutOfGas - | InstructionResult::MemoryOOG - | InstructionResult::MemoryLimitOOG - | InstructionResult::PrecompileOOG - | InstructionResult::InvalidOperandOOG - | InstructionResult::OpcodeNotFound - | InstructionResult::CallNotAllowedInsideStatic - | InstructionResult::StateChangeDuringStaticCall - | InstructionResult::InvalidFEOpcode - | InstructionResult::InvalidJump - | InstructionResult::NotActivated - | InstructionResult::StackUnderflow - | InstructionResult::StackOverflow - | InstructionResult::OutOfOffset - | InstructionResult::CreateCollision - | InstructionResult::OverflowPayment - | InstructionResult::PrecompileError - | InstructionResult::NonceOverflow - | InstructionResult::CreateContractSizeLimit - | InstructionResult::CreateContractStartingWithEF - | InstructionResult::CreateInitCodeSizeLimit - | InstructionResult::FatalExternalError - | InstructionResult::ReturnContractInNotInitEOF - | InstructionResult::EOFOpcodeDisabledInLegacy - | InstructionResult::EOFFunctionStackOverflow + $crate::InstructionResult::OutOfGas + | $crate::InstructionResult::MemoryOOG + | $crate::InstructionResult::MemoryLimitOOG + | $crate::InstructionResult::PrecompileOOG + | $crate::InstructionResult::InvalidOperandOOG + | $crate::InstructionResult::ReentrancySentryOOG + | $crate::InstructionResult::OpcodeNotFound + | $crate::InstructionResult::CallNotAllowedInsideStatic + | $crate::InstructionResult::StateChangeDuringStaticCall + | $crate::InstructionResult::InvalidFEOpcode + | $crate::InstructionResult::InvalidJump + | $crate::InstructionResult::NotActivated + | $crate::InstructionResult::StackUnderflow + | $crate::InstructionResult::StackOverflow + | $crate::InstructionResult::OutOfOffset + | $crate::InstructionResult::CreateCollision + | $crate::InstructionResult::OverflowPayment + | $crate::InstructionResult::PrecompileError + | $crate::InstructionResult::NonceOverflow + | $crate::InstructionResult::CreateContractSizeLimit + | $crate::InstructionResult::CreateContractStartingWithEF + | $crate::InstructionResult::CreateInitCodeSizeLimit + | $crate::InstructionResult::FatalExternalError }; } @@ -155,6 +198,12 @@ impl InstructionResult { matches!(self, crate::return_ok!()) } + #[inline] + /// Returns whether the result is a success or revert (not an error). + pub const fn is_ok_or_revert(self) -> bool { + matches!(self, crate::return_ok!() | crate::return_revert!()) + } + /// Returns whether the result is a revert. #[inline] pub const fn is_revert(self) -> bool { @@ -168,19 +217,32 @@ impl InstructionResult { } } +/// Internal results that are not exposed externally #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub enum SuccessOrHalt { +pub enum InternalResult { + /// Internal CREATE/CREATE starts with 0xEF00 + CreateInitCodeStartingEF00, + /// Internal to ExtDelegateCall + InvalidExtDelegateCallTarget, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +/// Represents the outcome of instruction execution, distinguishing between +/// success, revert, halt (error), fatal external errors, and internal results. +pub enum SuccessOrHalt { + /// Successful execution with the specific success reason. Success(SuccessReason), + /// Execution reverted. Revert, - Halt(HaltReason), + /// Execution halted due to an error. + Halt(HaltReasonTr), + /// Fatal external error occurred. FatalExternalError, - /// Internal instruction that signals Interpreter should continue running. - InternalContinue, - /// Internal instruction that signals call or create. - InternalCallOrCreate, + /// Internal execution result not exposed externally. + Internal(InternalResult), } -impl SuccessOrHalt { +impl SuccessOrHalt { /// Returns true if the transaction returned successfully without halts. #[inline] pub fn is_success(self) -> bool { @@ -210,7 +272,7 @@ impl SuccessOrHalt { /// Returns the [HaltReason] value the EVM has experienced an exceptional halt #[inline] - pub fn to_halt(self) -> Option { + pub fn to_halt(self) -> Option { match self { SuccessOrHalt::Halt(reason) => Some(reason), _ => None, @@ -218,59 +280,69 @@ impl SuccessOrHalt { } } -impl From for SuccessOrHalt { +impl> From for SuccessOrHalt { + fn from(reason: HaltReason) -> Self { + SuccessOrHalt::Halt(reason.into()) + } +} + +impl> From for SuccessOrHalt { fn from(result: InstructionResult) -> Self { match result { - InstructionResult::Continue => Self::InternalContinue, // used only in interpreter loop InstructionResult::Stop => Self::Success(SuccessReason::Stop), InstructionResult::Return => Self::Success(SuccessReason::Return), InstructionResult::SelfDestruct => Self::Success(SuccessReason::SelfDestruct), InstructionResult::Revert => Self::Revert, - InstructionResult::CallOrCreate => Self::InternalCallOrCreate, // used only in interpreter loop - InstructionResult::CallTooDeep => Self::Halt(HaltReason::CallTooDeep), // not gonna happen for first call - InstructionResult::OutOfFunds => Self::Halt(HaltReason::OutOfFunds), // Check for first call is done separately. - InstructionResult::OutOfGas => Self::Halt(HaltReason::OutOfGas(OutOfGasError::Basic)), + InstructionResult::CreateInitCodeStartingEF00 => Self::Revert, + InstructionResult::CallTooDeep => Self::Halt(HaltReason::CallTooDeep.into()), // not gonna happen for first call + InstructionResult::OutOfFunds => Self::Halt(HaltReason::OutOfFunds.into()), // Check for first call is done separately. + InstructionResult::OutOfGas => { + Self::Halt(HaltReason::OutOfGas(OutOfGasError::Basic).into()) + } InstructionResult::MemoryLimitOOG => { - Self::Halt(HaltReason::OutOfGas(OutOfGasError::MemoryLimit)) + Self::Halt(HaltReason::OutOfGas(OutOfGasError::MemoryLimit).into()) + } + InstructionResult::MemoryOOG => { + Self::Halt(HaltReason::OutOfGas(OutOfGasError::Memory).into()) } - InstructionResult::MemoryOOG => Self::Halt(HaltReason::OutOfGas(OutOfGasError::Memory)), InstructionResult::PrecompileOOG => { - Self::Halt(HaltReason::OutOfGas(OutOfGasError::Precompile)) + Self::Halt(HaltReason::OutOfGas(OutOfGasError::Precompile).into()) } InstructionResult::InvalidOperandOOG => { - Self::Halt(HaltReason::OutOfGas(OutOfGasError::InvalidOperand)) + Self::Halt(HaltReason::OutOfGas(OutOfGasError::InvalidOperand).into()) } - InstructionResult::OpcodeNotFound | InstructionResult::ReturnContractInNotInitEOF => { - Self::Halt(HaltReason::OpcodeNotFound) + InstructionResult::ReentrancySentryOOG => { + Self::Halt(HaltReason::OutOfGas(OutOfGasError::ReentrancySentry).into()) } + InstructionResult::OpcodeNotFound => Self::Halt(HaltReason::OpcodeNotFound.into()), InstructionResult::CallNotAllowedInsideStatic => { - Self::Halt(HaltReason::CallNotAllowedInsideStatic) + Self::Halt(HaltReason::CallNotAllowedInsideStatic.into()) } // first call is not static call InstructionResult::StateChangeDuringStaticCall => { - Self::Halt(HaltReason::StateChangeDuringStaticCall) + Self::Halt(HaltReason::StateChangeDuringStaticCall.into()) } - InstructionResult::InvalidFEOpcode => Self::Halt(HaltReason::InvalidFEOpcode), - InstructionResult::InvalidJump => Self::Halt(HaltReason::InvalidJump), - InstructionResult::NotActivated => Self::Halt(HaltReason::NotActivated), - InstructionResult::StackUnderflow => Self::Halt(HaltReason::StackUnderflow), - InstructionResult::StackOverflow => Self::Halt(HaltReason::StackOverflow), - InstructionResult::OutOfOffset => Self::Halt(HaltReason::OutOfOffset), - InstructionResult::CreateCollision => Self::Halt(HaltReason::CreateCollision), - InstructionResult::OverflowPayment => Self::Halt(HaltReason::OverflowPayment), // Check for first call is done separately. - InstructionResult::PrecompileError => Self::Halt(HaltReason::PrecompileError), - InstructionResult::NonceOverflow => Self::Halt(HaltReason::NonceOverflow), + InstructionResult::InvalidFEOpcode => Self::Halt(HaltReason::InvalidFEOpcode.into()), + InstructionResult::InvalidJump => Self::Halt(HaltReason::InvalidJump.into()), + InstructionResult::NotActivated => Self::Halt(HaltReason::NotActivated.into()), + InstructionResult::StackUnderflow => Self::Halt(HaltReason::StackUnderflow.into()), + InstructionResult::StackOverflow => Self::Halt(HaltReason::StackOverflow.into()), + InstructionResult::OutOfOffset => Self::Halt(HaltReason::OutOfOffset.into()), + InstructionResult::CreateCollision => Self::Halt(HaltReason::CreateCollision.into()), + InstructionResult::OverflowPayment => Self::Halt(HaltReason::OverflowPayment.into()), // Check for first call is done separately. + InstructionResult::PrecompileError => Self::Halt(HaltReason::PrecompileError.into()), + InstructionResult::NonceOverflow => Self::Halt(HaltReason::NonceOverflow.into()), InstructionResult::CreateContractSizeLimit | InstructionResult::CreateContractStartingWithEF => { - Self::Halt(HaltReason::CreateContractSizeLimit) + Self::Halt(HaltReason::CreateContractSizeLimit.into()) } InstructionResult::CreateInitCodeSizeLimit => { - Self::Halt(HaltReason::CreateInitCodeSizeLimit) + Self::Halt(HaltReason::CreateInitCodeSizeLimit.into()) } + // TODO : (EOF) Add proper Revert subtype. + InstructionResult::InvalidEOFInitCode => Self::Revert, InstructionResult::FatalExternalError => Self::FatalExternalError, - InstructionResult::EOFOpcodeDisabledInLegacy => Self::Halt(HaltReason::OpcodeNotFound), - InstructionResult::EOFFunctionStackOverflow => Self::FatalExternalError, - InstructionResult::ReturnContract => { - panic!("Unexpected EOF internal Return Contract") + InstructionResult::InvalidExtDelegateCallTarget => { + Self::Internal(InternalResult::InvalidExtDelegateCallTarget) } } } @@ -282,18 +354,16 @@ mod tests { #[test] fn all_results_are_covered() { - match InstructionResult::Continue { + match InstructionResult::Stop { return_error!() => {} return_revert!() => {} return_ok!() => {} - InstructionResult::CallOrCreate => {} } } #[test] fn test_results() { let ok_results = vec![ - InstructionResult::Continue, InstructionResult::Stop, InstructionResult::Return, InstructionResult::SelfDestruct, diff --git a/crates/interpreter/src/instructions.rs b/crates/interpreter/src/instructions.rs index 7f11f93f4d..63ff98f6b6 100644 --- a/crates/interpreter/src/instructions.rs +++ b/crates/interpreter/src/instructions.rs @@ -2,15 +2,236 @@ #[macro_use] pub mod macros; +/// Arithmetic operations (ADD, SUB, MUL, DIV, etc.). pub mod arithmetic; +/// Bitwise operations (AND, OR, XOR, NOT, etc.). pub mod bitwise; +/// Block information instructions (COINBASE, TIMESTAMP, etc.). +pub mod block_info; +/// Contract operations (CALL, CREATE, DELEGATECALL, etc.). pub mod contract; +/// Control flow instructions (JUMP, JUMPI, REVERT, etc.). pub mod control; -pub mod data; +/// Host environment interactions (SLOAD, SSTORE, LOG, etc.). pub mod host; -pub mod host_env; +/// Signed 256-bit integer operations. pub mod i256; +/// Memory operations (MLOAD, MSTORE, MSIZE, etc.). pub mod memory; +/// Stack operations (PUSH, POP, DUP, SWAP, etc.). pub mod stack; +/// System information instructions (ADDRESS, CALLER, etc.). pub mod system; +/// Transaction information instructions (ORIGIN, GASPRICE, etc.). +pub mod tx_info; +/// Utility functions and helpers for instruction implementation. pub mod utility; + +use crate::{interpreter_types::InterpreterTypes, Host, InstructionContext}; + +/// EVM opcode function signature. +pub type Instruction = fn(InstructionContext<'_, H, W>); + +/// Instruction table is list of instruction function pointers mapped to 256 EVM opcodes. +pub type InstructionTable = [Instruction; 256]; + +/// Returns the default instruction table for the given interpreter types and host. +#[inline] +pub const fn instruction_table( +) -> [Instruction; 256] { + const { instruction_table_impl::() } +} + +const fn instruction_table_impl( +) -> [Instruction; 256] { + use bytecode::opcode::*; + let mut table = [control::unknown as Instruction; 256]; + + table[STOP as usize] = control::stop; + table[ADD as usize] = arithmetic::add; + table[MUL as usize] = arithmetic::mul; + table[SUB as usize] = arithmetic::sub; + table[DIV as usize] = arithmetic::div; + table[SDIV as usize] = arithmetic::sdiv; + table[MOD as usize] = arithmetic::rem; + table[SMOD as usize] = arithmetic::smod; + table[ADDMOD as usize] = arithmetic::addmod; + table[MULMOD as usize] = arithmetic::mulmod; + table[EXP as usize] = arithmetic::exp; + table[SIGNEXTEND as usize] = arithmetic::signextend; + + table[LT as usize] = bitwise::lt; + table[GT as usize] = bitwise::gt; + table[SLT as usize] = bitwise::slt; + table[SGT as usize] = bitwise::sgt; + table[EQ as usize] = bitwise::eq; + table[ISZERO as usize] = bitwise::iszero; + table[AND as usize] = bitwise::bitand; + table[OR as usize] = bitwise::bitor; + table[XOR as usize] = bitwise::bitxor; + table[NOT as usize] = bitwise::not; + table[BYTE as usize] = bitwise::byte; + table[SHL as usize] = bitwise::shl; + table[SHR as usize] = bitwise::shr; + table[SAR as usize] = bitwise::sar; + table[CLZ as usize] = bitwise::clz; + + table[KECCAK256 as usize] = system::keccak256; + + table[ADDRESS as usize] = system::address; + table[BALANCE as usize] = host::balance; + table[ORIGIN as usize] = tx_info::origin; + table[CALLER as usize] = system::caller; + table[CALLVALUE as usize] = system::callvalue; + table[CALLDATALOAD as usize] = system::calldataload; + table[CALLDATASIZE as usize] = system::calldatasize; + table[CALLDATACOPY as usize] = system::calldatacopy; + table[CODESIZE as usize] = system::codesize; + table[CODECOPY as usize] = system::codecopy; + + table[GASPRICE as usize] = tx_info::gasprice; + table[EXTCODESIZE as usize] = host::extcodesize; + table[EXTCODECOPY as usize] = host::extcodecopy; + table[RETURNDATASIZE as usize] = system::returndatasize; + table[RETURNDATACOPY as usize] = system::returndatacopy; + table[EXTCODEHASH as usize] = host::extcodehash; + table[BLOCKHASH as usize] = host::blockhash; + table[COINBASE as usize] = block_info::coinbase; + table[TIMESTAMP as usize] = block_info::timestamp; + table[NUMBER as usize] = block_info::block_number; + table[DIFFICULTY as usize] = block_info::difficulty; + table[GASLIMIT as usize] = block_info::gaslimit; + table[CHAINID as usize] = block_info::chainid; + table[SELFBALANCE as usize] = host::selfbalance; + table[BASEFEE as usize] = block_info::basefee; + table[BLOBHASH as usize] = tx_info::blob_hash; + table[BLOBBASEFEE as usize] = block_info::blob_basefee; + + table[POP as usize] = stack::pop; + table[MLOAD as usize] = memory::mload; + table[MSTORE as usize] = memory::mstore; + table[MSTORE8 as usize] = memory::mstore8; + table[SLOAD as usize] = host::sload; + table[SSTORE as usize] = host::sstore; + table[JUMP as usize] = control::jump; + table[JUMPI as usize] = control::jumpi; + table[PC as usize] = control::pc; + table[MSIZE as usize] = memory::msize; + table[GAS as usize] = system::gas; + table[JUMPDEST as usize] = control::jumpdest; + table[TLOAD as usize] = host::tload; + table[TSTORE as usize] = host::tstore; + table[MCOPY as usize] = memory::mcopy; + + table[PUSH0 as usize] = stack::push0; + table[PUSH1 as usize] = stack::push::<1, _, _>; + table[PUSH2 as usize] = stack::push::<2, _, _>; + table[PUSH3 as usize] = stack::push::<3, _, _>; + table[PUSH4 as usize] = stack::push::<4, _, _>; + table[PUSH5 as usize] = stack::push::<5, _, _>; + table[PUSH6 as usize] = stack::push::<6, _, _>; + table[PUSH7 as usize] = stack::push::<7, _, _>; + table[PUSH8 as usize] = stack::push::<8, _, _>; + table[PUSH9 as usize] = stack::push::<9, _, _>; + table[PUSH10 as usize] = stack::push::<10, _, _>; + table[PUSH11 as usize] = stack::push::<11, _, _>; + table[PUSH12 as usize] = stack::push::<12, _, _>; + table[PUSH13 as usize] = stack::push::<13, _, _>; + table[PUSH14 as usize] = stack::push::<14, _, _>; + table[PUSH15 as usize] = stack::push::<15, _, _>; + table[PUSH16 as usize] = stack::push::<16, _, _>; + table[PUSH17 as usize] = stack::push::<17, _, _>; + table[PUSH18 as usize] = stack::push::<18, _, _>; + table[PUSH19 as usize] = stack::push::<19, _, _>; + table[PUSH20 as usize] = stack::push::<20, _, _>; + table[PUSH21 as usize] = stack::push::<21, _, _>; + table[PUSH22 as usize] = stack::push::<22, _, _>; + table[PUSH23 as usize] = stack::push::<23, _, _>; + table[PUSH24 as usize] = stack::push::<24, _, _>; + table[PUSH25 as usize] = stack::push::<25, _, _>; + table[PUSH26 as usize] = stack::push::<26, _, _>; + table[PUSH27 as usize] = stack::push::<27, _, _>; + table[PUSH28 as usize] = stack::push::<28, _, _>; + table[PUSH29 as usize] = stack::push::<29, _, _>; + table[PUSH30 as usize] = stack::push::<30, _, _>; + table[PUSH31 as usize] = stack::push::<31, _, _>; + table[PUSH32 as usize] = stack::push::<32, _, _>; + + table[DUP1 as usize] = stack::dup::<1, _, _>; + table[DUP2 as usize] = stack::dup::<2, _, _>; + table[DUP3 as usize] = stack::dup::<3, _, _>; + table[DUP4 as usize] = stack::dup::<4, _, _>; + table[DUP5 as usize] = stack::dup::<5, _, _>; + table[DUP6 as usize] = stack::dup::<6, _, _>; + table[DUP7 as usize] = stack::dup::<7, _, _>; + table[DUP8 as usize] = stack::dup::<8, _, _>; + table[DUP9 as usize] = stack::dup::<9, _, _>; + table[DUP10 as usize] = stack::dup::<10, _, _>; + table[DUP11 as usize] = stack::dup::<11, _, _>; + table[DUP12 as usize] = stack::dup::<12, _, _>; + table[DUP13 as usize] = stack::dup::<13, _, _>; + table[DUP14 as usize] = stack::dup::<14, _, _>; + table[DUP15 as usize] = stack::dup::<15, _, _>; + table[DUP16 as usize] = stack::dup::<16, _, _>; + + table[SWAP1 as usize] = stack::swap::<1, _, _>; + table[SWAP2 as usize] = stack::swap::<2, _, _>; + table[SWAP3 as usize] = stack::swap::<3, _, _>; + table[SWAP4 as usize] = stack::swap::<4, _, _>; + table[SWAP5 as usize] = stack::swap::<5, _, _>; + table[SWAP6 as usize] = stack::swap::<6, _, _>; + table[SWAP7 as usize] = stack::swap::<7, _, _>; + table[SWAP8 as usize] = stack::swap::<8, _, _>; + table[SWAP9 as usize] = stack::swap::<9, _, _>; + table[SWAP10 as usize] = stack::swap::<10, _, _>; + table[SWAP11 as usize] = stack::swap::<11, _, _>; + table[SWAP12 as usize] = stack::swap::<12, _, _>; + table[SWAP13 as usize] = stack::swap::<13, _, _>; + table[SWAP14 as usize] = stack::swap::<14, _, _>; + table[SWAP15 as usize] = stack::swap::<15, _, _>; + table[SWAP16 as usize] = stack::swap::<16, _, _>; + + table[LOG0 as usize] = host::log::<0, _>; + table[LOG1 as usize] = host::log::<1, _>; + table[LOG2 as usize] = host::log::<2, _>; + table[LOG3 as usize] = host::log::<3, _>; + table[LOG4 as usize] = host::log::<4, _>; + + table[CREATE as usize] = contract::create::<_, false, _>; + table[CALL as usize] = contract::call; + table[CALLCODE as usize] = contract::call_code; + table[RETURN as usize] = control::ret; + table[DELEGATECALL as usize] = contract::delegate_call; + table[CREATE2 as usize] = contract::create::<_, true, _>; + + table[STATICCALL as usize] = contract::static_call; + table[REVERT as usize] = control::revert; + table[INVALID as usize] = control::invalid; + table[SELFDESTRUCT as usize] = host::selfdestruct; + table +} + +#[cfg(test)] +mod tests { + use super::instruction_table; + use crate::{host::DummyHost, interpreter::EthInterpreter}; + use bytecode::opcode::*; + + #[test] + fn all_instructions_and_opcodes_used() { + // known unknown instruction we compare it with other instructions from table. + let unknown_instruction = 0x0C_usize; + let instr_table = instruction_table::(); + + let unknown_istr = instr_table[unknown_instruction]; + for (i, instr) in instr_table.iter().enumerate() { + let is_opcode_unknown = OpCode::new(i as u8).is_none(); + // + let is_instr_unknown = std::ptr::fn_addr_eq(*instr, unknown_istr); + assert_eq!( + is_instr_unknown, is_opcode_unknown, + "Opcode 0x{i:X?} is not handled", + ); + } + } +} diff --git a/crates/interpreter/src/instructions/arithmetic.rs b/crates/interpreter/src/instructions/arithmetic.rs index 34c98a348b..7575cd167d 100644 --- a/crates/interpreter/src/instructions/arithmetic.rs +++ b/crates/interpreter/src/instructions/arithmetic.rs @@ -1,92 +1,128 @@ use super::i256::{i256_div, i256_mod}; use crate::{ gas, - primitives::{Spec, U256}, - Host, Interpreter, + interpreter_types::{InterpreterTypes, RuntimeFlag, StackTr}, + InstructionContext, }; +use primitives::U256; -pub fn add(interpreter: &mut Interpreter, _host: &mut H) { - gas!(interpreter, gas::VERYLOW); - pop_top!(interpreter, op1, op2); +/// Implements the ADD instruction - adds two values from stack. +pub fn add(context: InstructionContext<'_, H, WIRE>) { + gas!(context.interpreter, gas::VERYLOW); + popn_top!([op1], op2, context.interpreter); *op2 = op1.wrapping_add(*op2); } -pub fn mul(interpreter: &mut Interpreter, _host: &mut H) { - gas!(interpreter, gas::LOW); - pop_top!(interpreter, op1, op2); +/// Implements the MUL instruction - multiplies two values from stack. +pub fn mul(context: InstructionContext<'_, H, WIRE>) { + gas!(context.interpreter, gas::LOW); + popn_top!([op1], op2, context.interpreter); *op2 = op1.wrapping_mul(*op2); } -pub fn sub(interpreter: &mut Interpreter, _host: &mut H) { - gas!(interpreter, gas::VERYLOW); - pop_top!(interpreter, op1, op2); +/// Implements the SUB instruction - subtracts two values from stack. +pub fn sub(context: InstructionContext<'_, H, WIRE>) { + gas!(context.interpreter, gas::VERYLOW); + popn_top!([op1], op2, context.interpreter); *op2 = op1.wrapping_sub(*op2); } -pub fn div(interpreter: &mut Interpreter, _host: &mut H) { - gas!(interpreter, gas::LOW); - pop_top!(interpreter, op1, op2); - if *op2 != U256::ZERO { +/// Implements the DIV instruction - divides two values from stack. +pub fn div(context: InstructionContext<'_, H, WIRE>) { + gas!(context.interpreter, gas::LOW); + popn_top!([op1], op2, context.interpreter); + if !op2.is_zero() { *op2 = op1.wrapping_div(*op2); } } -pub fn sdiv(interpreter: &mut Interpreter, _host: &mut H) { - gas!(interpreter, gas::LOW); - pop_top!(interpreter, op1, op2); +/// Implements the SDIV instruction. +/// +/// Performs signed division of two values from stack. +pub fn sdiv(context: InstructionContext<'_, H, WIRE>) { + gas!(context.interpreter, gas::LOW); + popn_top!([op1], op2, context.interpreter); *op2 = i256_div(op1, *op2); } -pub fn rem(interpreter: &mut Interpreter, _host: &mut H) { - gas!(interpreter, gas::LOW); - pop_top!(interpreter, op1, op2); - if *op2 != U256::ZERO { +/// Implements the MOD instruction. +/// +/// Pops two values from stack and pushes the remainder of their division. +pub fn rem(context: InstructionContext<'_, H, WIRE>) { + gas!(context.interpreter, gas::LOW); + popn_top!([op1], op2, context.interpreter); + if !op2.is_zero() { *op2 = op1.wrapping_rem(*op2); } } -pub fn smod(interpreter: &mut Interpreter, _host: &mut H) { - gas!(interpreter, gas::LOW); - pop_top!(interpreter, op1, op2); +/// Implements the SMOD instruction. +/// +/// Performs signed modulo of two values from stack. +pub fn smod(context: InstructionContext<'_, H, WIRE>) { + gas!(context.interpreter, gas::LOW); + popn_top!([op1], op2, context.interpreter); *op2 = i256_mod(op1, *op2) } -pub fn addmod(interpreter: &mut Interpreter, _host: &mut H) { - gas!(interpreter, gas::MID); - pop_top!(interpreter, op1, op2, op3); +/// Implements the ADDMOD instruction. +/// +/// Pops three values from stack and pushes (a + b) % n. +pub fn addmod(context: InstructionContext<'_, H, WIRE>) { + gas!(context.interpreter, gas::MID); + popn_top!([op1, op2], op3, context.interpreter); *op3 = op1.add_mod(op2, *op3) } -pub fn mulmod(interpreter: &mut Interpreter, _host: &mut H) { - gas!(interpreter, gas::MID); - pop_top!(interpreter, op1, op2, op3); +/// Implements the MULMOD instruction. +/// +/// Pops three values from stack and pushes (a * b) % n. +pub fn mulmod(context: InstructionContext<'_, H, WIRE>) { + gas!(context.interpreter, gas::MID); + popn_top!([op1, op2], op3, context.interpreter); *op3 = op1.mul_mod(op2, *op3) } -pub fn exp(interpreter: &mut Interpreter, _host: &mut H) { - pop_top!(interpreter, op1, op2); - gas_or_fail!(interpreter, gas::exp_cost(SPEC::SPEC_ID, *op2)); +/// Implements the EXP instruction - exponentiates two values from stack. +pub fn exp(context: InstructionContext<'_, H, WIRE>) { + let spec_id = context.interpreter.runtime_flag.spec_id(); + popn_top!([op1], op2, context.interpreter); + gas_or_fail!(context.interpreter, gas::exp_cost(spec_id, *op2)); *op2 = op1.pow(*op2); } +/// Implements the `SIGNEXTEND` opcode as defined in the Ethereum Yellow Paper. +/// /// In the yellow paper `SIGNEXTEND` is defined to take two inputs, we will call them -/// `x` and `y`, and produce one output. The first `t` bits of the output (numbering from the -/// left, starting from 0) are equal to the `t`-th bit of `y`, where `t` is equal to -/// `256 - 8(x + 1)`. The remaining bits of the output are equal to the corresponding bits of `y`. -/// Note: if `x >= 32` then the output is equal to `y` since `t <= 0`. To efficiently implement -/// this algorithm in the case `x < 32` we do the following. Let `b` be equal to the `t`-th bit -/// of `y` and let `s = 255 - t = 8x + 7` (this is effectively the same index as `t`, but -/// numbering the bits from the right instead of the left). We can create a bit mask which is all -/// zeros up to and including the `t`-th bit, and all ones afterwards by computing the quantity -/// `2^s - 1`. We can use this mask to compute the output depending on the value of `b`. +/// `x` and `y`, and produce one output. +/// +/// The first `t` bits of the output (numbering from the left, starting from 0) are +/// equal to the `t`-th bit of `y`, where `t` is equal to `256 - 8(x + 1)`. +/// +/// The remaining bits of the output are equal to the corresponding bits of `y`. +/// +/// **Note**: If `x >= 32` then the output is equal to `y` since `t <= 0`. +/// +/// To efficiently implement this algorithm in the case `x < 32` we do the following. +/// +/// Let `b` be equal to the `t`-th bit of `y` and let `s = 255 - t = 8x + 7` +/// (this is effectively the same index as `t`, but numbering the bits from the +/// right instead of the left). +/// +/// We can create a bit mask which is all zeros up to and including the `t`-th bit, +/// and all ones afterwards by computing the quantity `2^s - 1`. +/// +/// We can use this mask to compute the output depending on the value of `b`. +/// /// If `b == 1` then the yellow paper says the output should be all ones up to /// and including the `t`-th bit, followed by the remaining bits of `y`; this is equal to -/// `y | !mask` where `|` is the bitwise `OR` and `!` is bitwise negation. Similarly, if -/// `b == 0` then the yellow paper says the output should start with all zeros, then end with -/// bits from `b`; this is equal to `y & mask` where `&` is bitwise `AND`. -pub fn signextend(interpreter: &mut Interpreter, _host: &mut H) { - gas!(interpreter, gas::LOW); - pop_top!(interpreter, ext, x); +/// `y | !mask` where `|` is the bitwise `OR` and `!` is bitwise negation. +/// +/// Similarly, if `b == 0` then the yellow paper says the output should start with all zeros, +/// then end with bits from `b`; this is equal to `y & mask` where `&` is bitwise `AND`. +pub fn signextend(context: InstructionContext<'_, H, WIRE>) { + gas!(context.interpreter, gas::LOW); + popn_top!([ext], x, context.interpreter); // For 31 we also don't need to do anything. if ext < U256::from(31) { let ext = ext.as_limbs()[0]; diff --git a/crates/interpreter/src/instructions/bitwise.rs b/crates/interpreter/src/instructions/bitwise.rs index 62edf11c5a..18696e7871 100644 --- a/crates/interpreter/src/instructions/bitwise.rs +++ b/crates/interpreter/src/instructions/bitwise.rs @@ -1,74 +1,121 @@ use super::i256::i256_cmp; use crate::{ gas, - primitives::{Spec, U256}, - Host, Interpreter, + interpreter_types::{InterpreterTypes, RuntimeFlag, StackTr}, + InstructionContext, }; use core::cmp::Ordering; +use primitives::U256; -pub fn lt(interpreter: &mut Interpreter, _host: &mut H) { - gas!(interpreter, gas::VERYLOW); - pop_top!(interpreter, op1, op2); +/// Implements the LT instruction - less than comparison. +pub fn lt(context: InstructionContext<'_, H, WIRE>) { + gas!(context.interpreter, gas::VERYLOW); + popn_top!([op1], op2, context.interpreter); *op2 = U256::from(op1 < *op2); } -pub fn gt(interpreter: &mut Interpreter, _host: &mut H) { - gas!(interpreter, gas::VERYLOW); - pop_top!(interpreter, op1, op2); +/// Implements the GT instruction - greater than comparison. +pub fn gt(context: InstructionContext<'_, H, WIRE>) { + gas!(context.interpreter, gas::VERYLOW); + popn_top!([op1], op2, context.interpreter); + *op2 = U256::from(op1 > *op2); } -pub fn slt(interpreter: &mut Interpreter, _host: &mut H) { - gas!(interpreter, gas::VERYLOW); - pop_top!(interpreter, op1, op2); +/// Implements the CLZ instruction - count leading zeros. +pub fn clz(context: InstructionContext<'_, H, WIRE>) { + check!(context.interpreter, OSAKA); + gas!(context.interpreter, gas::LOW); + popn_top!([], op1, context.interpreter); + + let leading_zeros = op1.leading_zeros(); + *op1 = U256::from(leading_zeros); +} + +/// Implements the SLT instruction. +/// +/// Signed less than comparison of two values from stack. +pub fn slt(context: InstructionContext<'_, H, WIRE>) { + gas!(context.interpreter, gas::VERYLOW); + popn_top!([op1], op2, context.interpreter); + *op2 = U256::from(i256_cmp(&op1, op2) == Ordering::Less); } -pub fn sgt(interpreter: &mut Interpreter, _host: &mut H) { - gas!(interpreter, gas::VERYLOW); - pop_top!(interpreter, op1, op2); +/// Implements the SGT instruction. +/// +/// Signed greater than comparison of two values from stack. +pub fn sgt(context: InstructionContext<'_, H, WIRE>) { + gas!(context.interpreter, gas::VERYLOW); + popn_top!([op1], op2, context.interpreter); + *op2 = U256::from(i256_cmp(&op1, op2) == Ordering::Greater); } -pub fn eq(interpreter: &mut Interpreter, _host: &mut H) { - gas!(interpreter, gas::VERYLOW); - pop_top!(interpreter, op1, op2); +/// Implements the EQ instruction. +/// +/// Equality comparison of two values from stack. +pub fn eq(context: InstructionContext<'_, H, WIRE>) { + gas!(context.interpreter, gas::VERYLOW); + popn_top!([op1], op2, context.interpreter); + *op2 = U256::from(op1 == *op2); } -pub fn iszero(interpreter: &mut Interpreter, _host: &mut H) { - gas!(interpreter, gas::VERYLOW); - pop_top!(interpreter, op1); - *op1 = U256::from(*op1 == U256::ZERO); +/// Implements the ISZERO instruction. +/// +/// Checks if the top stack value is zero. +pub fn iszero(context: InstructionContext<'_, H, WIRE>) { + gas!(context.interpreter, gas::VERYLOW); + popn_top!([], op1, context.interpreter); + *op1 = U256::from(op1.is_zero()); } -pub fn bitand(interpreter: &mut Interpreter, _host: &mut H) { - gas!(interpreter, gas::VERYLOW); - pop_top!(interpreter, op1, op2); +/// Implements the AND instruction. +/// +/// Bitwise AND of two values from stack. +pub fn bitand(context: InstructionContext<'_, H, WIRE>) { + gas!(context.interpreter, gas::VERYLOW); + popn_top!([op1], op2, context.interpreter); *op2 = op1 & *op2; } -pub fn bitor(interpreter: &mut Interpreter, _host: &mut H) { - gas!(interpreter, gas::VERYLOW); - pop_top!(interpreter, op1, op2); +/// Implements the OR instruction. +/// +/// Bitwise OR of two values from stack. +pub fn bitor(context: InstructionContext<'_, H, WIRE>) { + gas!(context.interpreter, gas::VERYLOW); + popn_top!([op1], op2, context.interpreter); + *op2 = op1 | *op2; } -pub fn bitxor(interpreter: &mut Interpreter, _host: &mut H) { - gas!(interpreter, gas::VERYLOW); - pop_top!(interpreter, op1, op2); +/// Implements the XOR instruction. +/// +/// Bitwise XOR of two values from stack. +pub fn bitxor(context: InstructionContext<'_, H, WIRE>) { + gas!(context.interpreter, gas::VERYLOW); + popn_top!([op1], op2, context.interpreter); + *op2 = op1 ^ *op2; } -pub fn not(interpreter: &mut Interpreter, _host: &mut H) { - gas!(interpreter, gas::VERYLOW); - pop_top!(interpreter, op1); +/// Implements the NOT instruction. +/// +/// Bitwise NOT (negation) of the top stack value. +pub fn not(context: InstructionContext<'_, H, WIRE>) { + gas!(context.interpreter, gas::VERYLOW); + popn_top!([], op1, context.interpreter); + *op1 = !*op1; } -pub fn byte(interpreter: &mut Interpreter, _host: &mut H) { - gas!(interpreter, gas::VERYLOW); - pop_top!(interpreter, op1, op2); +/// Implements the BYTE instruction. +/// +/// Extracts a single byte from a word at a given index. +pub fn byte(context: InstructionContext<'_, H, WIRE>) { + gas!(context.interpreter, gas::VERYLOW); + popn_top!([op1], op2, context.interpreter); let o1 = as_usize_saturated!(op1); *op2 = if o1 < 32 { @@ -80,10 +127,11 @@ pub fn byte(interpreter: &mut Interpreter, _host: &mut H) { } /// EIP-145: Bitwise shifting instructions in EVM -pub fn shl(interpreter: &mut Interpreter, _host: &mut H) { - check!(interpreter, CONSTANTINOPLE); - gas!(interpreter, gas::VERYLOW); - pop_top!(interpreter, op1, op2); +pub fn shl(context: InstructionContext<'_, H, WIRE>) { + check!(context.interpreter, CONSTANTINOPLE); + gas!(context.interpreter, gas::VERYLOW); + popn_top!([op1], op2, context.interpreter); + let shift = as_usize_saturated!(op1); *op2 = if shift < 256 { *op2 << shift @@ -93,10 +141,11 @@ pub fn shl(interpreter: &mut Interpreter, _host: & } /// EIP-145: Bitwise shifting instructions in EVM -pub fn shr(interpreter: &mut Interpreter, _host: &mut H) { - check!(interpreter, CONSTANTINOPLE); - gas!(interpreter, gas::VERYLOW); - pop_top!(interpreter, op1, op2); +pub fn shr(context: InstructionContext<'_, H, WIRE>) { + check!(context.interpreter, CONSTANTINOPLE); + gas!(context.interpreter, gas::VERYLOW); + popn_top!([op1], op2, context.interpreter); + let shift = as_usize_saturated!(op1); *op2 = if shift < 256 { *op2 >> shift @@ -106,44 +155,33 @@ pub fn shr(interpreter: &mut Interpreter, _host: & } /// EIP-145: Bitwise shifting instructions in EVM -pub fn sar(interpreter: &mut Interpreter, _host: &mut H) { - check!(interpreter, CONSTANTINOPLE); - gas!(interpreter, gas::VERYLOW); - pop_top!(interpreter, op1, op2); +pub fn sar(context: InstructionContext<'_, H, WIRE>) { + check!(context.interpreter, CONSTANTINOPLE); + gas!(context.interpreter, gas::VERYLOW); + popn_top!([op1], op2, context.interpreter); let shift = as_usize_saturated!(op1); - *op2 = if shift >= 256 { - // If the shift is 256 or more, the result depends on the sign of the last bit. - if op2.bit(255) { - U256::MAX // Negative number, all bits set to one. - } else { - U256::ZERO // Non-negative number, all bits set to zero. - } + *op2 = if shift < 256 { + op2.arithmetic_shr(shift) + } else if op2.bit(255) { + U256::MAX } else { - // Normal shift - if op2.bit(255) { - // Check the most significant bit. - // Arithmetic right shift for negative numbers. - let shifted_value = *op2 >> shift; - let mask = U256::MAX << (256 - shift); // Mask for the sign bits. - shifted_value | mask // Apply the mask to simulate the filling of sign bits. - } else { - // Logical right shift for non-negative numbers. - *op2 >> shift - } + U256::ZERO }; } #[cfg(test)] mod tests { - use crate::instructions::bitwise::{byte, sar, shl, shr}; - use crate::{Contract, DummyHost, Interpreter}; - use revm_primitives::{uint, Env, LatestSpec, U256}; + use crate::{ + host::DummyHost, + instructions::bitwise::{byte, clz, sar, shl, shr}, + InstructionContext, Interpreter, + }; + use primitives::{hardfork::SpecId, uint, U256}; #[test] fn test_shift_left() { - let mut host = DummyHost::new(Env::default()); - let mut interpreter = Interpreter::new(Contract::default(), u64::MAX, false); + let mut interpreter = Interpreter::default(); struct TestCase { value: U256, @@ -212,19 +250,21 @@ mod tests { } for test in test_cases { - host.clear(); push!(interpreter, test.value); push!(interpreter, test.shift); - shl::(&mut interpreter, &mut host); - pop!(interpreter, res); + let context = InstructionContext { + host: &mut DummyHost, + interpreter: &mut interpreter, + }; + shl(context); + let res = interpreter.stack.pop().unwrap(); assert_eq!(res, test.expected); } } #[test] fn test_logical_shift_right() { - let mut host = DummyHost::new(Env::default()); - let mut interpreter = Interpreter::new(Contract::default(), u64::MAX, false); + let mut interpreter = Interpreter::default(); struct TestCase { value: U256, @@ -293,19 +333,21 @@ mod tests { } for test in test_cases { - host.clear(); push!(interpreter, test.value); push!(interpreter, test.shift); - shr::(&mut interpreter, &mut host); - pop!(interpreter, res); + let context = InstructionContext { + host: &mut DummyHost, + interpreter: &mut interpreter, + }; + shr(context); + let res = interpreter.stack.pop().unwrap(); assert_eq!(res, test.expected); } } #[test] fn test_arithmetic_shift_right() { - let mut host = DummyHost::new(Env::default()); - let mut interpreter = Interpreter::new(Contract::default(), u64::MAX, false); + let mut interpreter = Interpreter::default(); struct TestCase { value: U256, @@ -399,11 +441,14 @@ mod tests { } for test in test_cases { - host.clear(); push!(interpreter, test.value); push!(interpreter, test.shift); - sar::(&mut interpreter, &mut host); - pop!(interpreter, res); + let context = InstructionContext { + host: &mut DummyHost, + interpreter: &mut interpreter, + }; + sar(context); + let res = interpreter.stack.pop().unwrap(); assert_eq!(res, test.expected); } } @@ -416,8 +461,7 @@ mod tests { expected: U256, } - let mut host = DummyHost::new(Env::default()); - let mut interpreter = Interpreter::new(Contract::default(), u64::MAX, false); + let mut interpreter = Interpreter::default(); let input_value = U256::from(0x1234567890abcdef1234567890abcdef_u128); let test_cases = (0..32) @@ -437,9 +481,70 @@ mod tests { for test in test_cases.iter() { push!(interpreter, test.input); push!(interpreter, U256::from(test.index)); - byte(&mut interpreter, &mut host); - pop!(interpreter, res); + let context = InstructionContext { + host: &mut DummyHost, + interpreter: &mut interpreter, + }; + byte(context); + let res = interpreter.stack.pop().unwrap(); assert_eq!(res, test.expected, "Failed at index: {}", test.index); } } + + #[test] + fn test_clz() { + let mut interpreter = Interpreter::default(); + interpreter.set_spec_id(SpecId::OSAKA); + + struct TestCase { + value: U256, + expected: U256, + } + + uint! { + let test_cases = [ + TestCase { value: 0x0_U256, expected: 256_U256 }, + TestCase { value: 0x1_U256, expected: 255_U256 }, + TestCase { value: 0x2_U256, expected: 254_U256 }, + TestCase { value: 0x3_U256, expected: 254_U256 }, + TestCase { value: 0x4_U256, expected: 253_U256 }, + TestCase { value: 0x7_U256, expected: 253_U256 }, + TestCase { value: 0x8_U256, expected: 252_U256 }, + TestCase { value: 0xff_U256, expected: 248_U256 }, + TestCase { value: 0x100_U256, expected: 247_U256 }, + TestCase { value: 0xffff_U256, expected: 240_U256 }, + TestCase { + value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256, // U256::MAX + expected: 0_U256, + }, + TestCase { + value: 0x8000000000000000000000000000000000000000000000000000000000000000_U256, // 1 << 255 + expected: 0_U256, + }, + TestCase { // Smallest value with 1 leading zero + value: 0x4000000000000000000000000000000000000000000000000000000000000000_U256, // 1 << 254 + expected: 1_U256, + }, + TestCase { // Value just below 1 << 255 + value: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256, + expected: 1_U256, + }, + ]; + } + + for test in test_cases { + push!(interpreter, test.value); + let context = InstructionContext { + host: &mut DummyHost, + interpreter: &mut interpreter, + }; + clz(context); + let res = interpreter.stack.pop().unwrap(); + assert_eq!( + res, test.expected, + "CLZ for value {:#x} failed. Expected: {}, Got: {}", + test.value, test.expected, res + ); + } + } } diff --git a/crates/interpreter/src/instructions/block_info.rs b/crates/interpreter/src/instructions/block_info.rs new file mode 100644 index 0000000000..2e7b251c4b --- /dev/null +++ b/crates/interpreter/src/instructions/block_info.rs @@ -0,0 +1,94 @@ +use crate::{ + gas, + interpreter_types::{InterpreterTypes, RuntimeFlag, StackTr}, + Host, +}; +use primitives::{hardfork::SpecId::*, U256}; + +use crate::InstructionContext; + +/// EIP-1344: ChainID opcode +pub fn chainid(context: InstructionContext<'_, H, WIRE>) { + check!(context.interpreter, ISTANBUL); + gas!(context.interpreter, gas::BASE); + push!(context.interpreter, context.host.chain_id()); +} + +/// Implements the COINBASE instruction. +/// +/// Pushes the current block's beneficiary address onto the stack. +pub fn coinbase( + context: InstructionContext<'_, H, WIRE>, +) { + gas!(context.interpreter, gas::BASE); + push!( + context.interpreter, + context.host.beneficiary().into_word().into() + ); +} + +/// Implements the TIMESTAMP instruction. +/// +/// Pushes the current block's timestamp onto the stack. +pub fn timestamp( + context: InstructionContext<'_, H, WIRE>, +) { + gas!(context.interpreter, gas::BASE); + push!(context.interpreter, context.host.timestamp()); +} + +/// Implements the NUMBER instruction. +/// +/// Pushes the current block number onto the stack. +pub fn block_number( + context: InstructionContext<'_, H, WIRE>, +) { + gas!(context.interpreter, gas::BASE); + push!(context.interpreter, U256::from(context.host.block_number())); +} + +/// Implements the DIFFICULTY/PREVRANDAO instruction. +/// +/// Pushes the block difficulty (pre-merge) or prevrandao (post-merge) onto the stack. +pub fn difficulty( + context: InstructionContext<'_, H, WIRE>, +) { + gas!(context.interpreter, gas::BASE); + if context + .interpreter + .runtime_flag + .spec_id() + .is_enabled_in(MERGE) + { + // Unwrap is safe as this fields is checked in validation handler. + push!(context.interpreter, context.host.prevrandao().unwrap()); + } else { + push!(context.interpreter, context.host.difficulty()); + } +} + +/// Implements the GASLIMIT instruction. +/// +/// Pushes the current block's gas limit onto the stack. +pub fn gaslimit( + context: InstructionContext<'_, H, WIRE>, +) { + gas!(context.interpreter, gas::BASE); + push!(context.interpreter, context.host.gas_limit()); +} + +/// EIP-3198: BASEFEE opcode +pub fn basefee(context: InstructionContext<'_, H, WIRE>) { + check!(context.interpreter, LONDON); + gas!(context.interpreter, gas::BASE); + push!(context.interpreter, context.host.basefee()); +} + +/// EIP-7516: BLOBBASEFEE opcode +pub fn blob_basefee( + context: InstructionContext<'_, H, WIRE>, +) { + check!(context.interpreter, CANCUN); + gas!(context.interpreter, gas::BASE); + push!(context.interpreter, context.host.blob_gasprice()); +} diff --git a/crates/interpreter/src/instructions/contract.rs b/crates/interpreter/src/instructions/contract.rs index 9e2cd81d2c..731fb1e50b 100644 --- a/crates/interpreter/src/instructions/contract.rs +++ b/crates/interpreter/src/instructions/contract.rs @@ -1,558 +1,325 @@ mod call_helpers; -pub use call_helpers::{ - calc_call_gas, get_memory_input_and_out_ranges, resize_memory_and_return_range, -}; -use revm_primitives::{keccak256, BerlinSpec}; +pub use call_helpers::{calc_call_gas, get_memory_input_and_out_ranges, resize_memory}; use crate::{ - gas::{self, cost_per_word, EOF_CREATE_GAS, KECCAK256WORD}, - instructions::utility::read_u16, - interpreter::Interpreter, - primitives::{Address, Bytes, Eof, Spec, SpecId::*, U256}, - CallInputs, CallScheme, CallValue, CreateInputs, CreateScheme, EOFCreateInput, Host, - InstructionResult, InterpreterAction, InterpreterResult, LoadAccountResult, MAX_INITCODE_SIZE, + gas, + instructions::utility::IntoAddress, + interpreter_action::FrameInput, + interpreter_types::{InputsTr, InterpreterTypes, LoopControl, MemoryTr, RuntimeFlag, StackTr}, + CallInput, CallInputs, CallScheme, CallValue, CreateInputs, Host, InstructionResult, + InterpreterAction, }; -use core::{cmp::max, ops::Range}; +use context_interface::CreateScheme; +use primitives::{hardfork::SpecId, Address, Bytes, B256, U256}; use std::boxed::Box; -/// Resize memory and return memory range if successful. -/// Return `None` if there is not enough gas. And if `len` -/// is zero return `Some(usize::MAX..usize::MAX)`. -pub fn resize_memory( - interpreter: &mut Interpreter, - offset: U256, - len: U256, -) -> Option> { - let len = as_usize_or_fail_ret!(interpreter, len, None); - if len != 0 { - let offset = as_usize_or_fail_ret!(interpreter, offset, None); - resize_memory!(interpreter, offset, len, None); - // range is checked in resize_memory! macro and it is bounded by usize. - Some(offset..offset + len) - } else { - //unrealistic value so we are sure it is not used - Some(usize::MAX..usize::MAX) - } -} - -/// EOF Create instruction -pub fn eofcreate(interpreter: &mut Interpreter, _host: &mut H) { - require_eof!(interpreter); - gas!(interpreter, EOF_CREATE_GAS); - let initcontainer_index = unsafe { *interpreter.instruction_pointer }; - pop!(interpreter, value, salt, data_offset, data_size); - - let sub_container = interpreter - .eof() - .expect("EOF is set") - .body - .container_section - .get(initcontainer_index as usize) - .cloned() - .expect("EOF is checked"); - - // resize memory and get return range. - let Some(return_range) = resize_memory(interpreter, data_offset, data_size) else { - return; - }; - - let eof = Eof::decode(sub_container.clone()).expect("Subcontainer is verified"); - - if !eof.body.is_data_filled { - // should be always false as it is verified by eof verification. - panic!("Panic if data section is not full"); - } - - // deduct gas for hash that is needed to calculate address. - gas_or_fail!( - interpreter, - cost_per_word(sub_container.len() as u64, KECCAK256WORD) - ); - - let created_address = interpreter - .contract - .caller - .create2(salt.to_be_bytes(), keccak256(sub_container)); - - // Send container for execution container is preverified. - interpreter.next_action = InterpreterAction::EOFCreate { - inputs: Box::new(EOFCreateInput::new( - interpreter.contract.target_address, - created_address, - value, - eof, - interpreter.gas().remaining(), - return_range, - )), - }; - - interpreter.instruction_pointer = unsafe { interpreter.instruction_pointer.offset(1) }; -} - -pub fn return_contract(interpreter: &mut Interpreter, _host: &mut H) { - require_init_eof!(interpreter); - let deploy_container_index = unsafe { read_u16(interpreter.instruction_pointer) }; - pop!(interpreter, aux_data_offset, aux_data_size); - let aux_data_size = as_usize_or_fail!(interpreter, aux_data_size); - // important: offset must be ignored if len is zeros - let container = interpreter - .eof() - .expect("EOF is set") - .body - .container_section - .get(deploy_container_index as usize) - .expect("EOF is checked"); - - // convert to EOF so we can check data section size. - let new_eof = Eof::decode(container.clone()).expect("Container is verified"); - - let aux_slice = if aux_data_size != 0 { - let aux_data_offset = as_usize_or_fail!(interpreter, aux_data_offset); - resize_memory!(interpreter, aux_data_offset, aux_data_size); - - interpreter - .shared_memory - .slice(aux_data_offset, aux_data_size) - } else { - &[] - }; - - let new_data_size = new_eof.body.data_section.len() + aux_slice.len(); - if new_data_size > 0xFFFF { - // aux data is too big - interpreter.instruction_result = InstructionResult::FatalExternalError; - return; - } - if new_data_size < new_eof.header.data_size as usize { - // aux data is too small - interpreter.instruction_result = InstructionResult::FatalExternalError; - return; - } - - // append data bytes - let output = [new_eof.raw(), aux_slice].concat().into(); - - let result = InstructionResult::ReturnContract; - interpreter.instruction_result = result; - interpreter.next_action = crate::InterpreterAction::Return { - result: InterpreterResult { - output, - gas: interpreter.gas, - result, - }, - }; -} - -pub fn extcall_input(interpreter: &mut Interpreter) -> Option { - pop_ret!(interpreter, input_offset, input_size, None); - - let return_memory_offset = - resize_memory_and_return_range(interpreter, input_offset, input_size)?; - - Some(Bytes::copy_from_slice( - interpreter - .shared_memory - .slice_range(return_memory_offset.clone()), - )) -} - -pub fn extcall_gas_calc( - interpreter: &mut Interpreter, - host: &mut H, - target: Address, - transfers_value: bool, -) -> Option { - let Some(load_result) = host.load_account(target) else { - interpreter.instruction_result = InstructionResult::FatalExternalError; - return None; - }; - - if load_result.is_cold { - gas!(interpreter, gas::COLD_ACCOUNT_ACCESS_COST, None); - } - - // TODO(EOF) is_empty should only be checked on delegatecall - let call_cost = gas::call_cost( - BerlinSpec::SPEC_ID, - transfers_value, - load_result.is_cold, - load_result.is_empty, - ); - gas!(interpreter, call_cost, None); - - // 7. Calculate the gas available to callee as caller’s - // remaining gas reduced by max(ceil(gas/64), MIN_RETAINED_GAS) (MIN_RETAINED_GAS is 5000). - let gas_reduce = max(interpreter.gas.remaining() / 64, 5000); - let gas_limit = interpreter.gas().remaining().saturating_sub(gas_reduce); - - if gas_limit < 2300 { - interpreter.instruction_result = InstructionResult::CallNotAllowedInsideStatic; - // TODO(EOF) error; - // interpreter.instruction_result = InstructionResult::CallGasTooLow; - return None; - } - - // TODO check remaining gas more then N - - gas!(interpreter, gas_limit, None); - Some(gas_limit) -} - -pub fn extcall(interpreter: &mut Interpreter, host: &mut H) { - require_eof!(interpreter); - pop_address!(interpreter, target_address); - - // input call - let Some(input) = extcall_input(interpreter) else { - return; - }; - - pop!(interpreter, value); - let has_transfer = value != U256::ZERO; - - let Some(gas_limit) = extcall_gas_calc(interpreter, host, target_address, has_transfer) else { - return; - }; - // TODO Check if static and value 0 +use crate::InstructionContext; - // Call host to interact with target contract - interpreter.next_action = InterpreterAction::Call { - inputs: Box::new(CallInputs { - input, - gas_limit, - target_address, - caller: interpreter.contract.target_address, - bytecode_address: target_address, - value: CallValue::Transfer(value), - scheme: CallScheme::Call, - is_static: interpreter.is_static, - is_eof: true, - return_memory_offset: 0..0, - }), - }; - interpreter.instruction_result = InstructionResult::CallOrCreate; -} - -pub fn extdelegatecall(interpreter: &mut Interpreter, host: &mut H) { - require_eof!(interpreter); - pop_address!(interpreter, target_address); - - // input call - let Some(input) = extcall_input(interpreter) else { - return; - }; - - let Some(gas_limit) = extcall_gas_calc(interpreter, host, target_address, false) else { - return; - }; - // TODO Check if static and value 0 - - // Call host to interact with target contract - interpreter.next_action = InterpreterAction::Call { - inputs: Box::new(CallInputs { - input, - gas_limit, - target_address, - caller: interpreter.contract.target_address, - bytecode_address: target_address, - value: CallValue::Apparent(interpreter.contract.call_value), - // TODO(EOF) should be EofDelegateCall? - scheme: CallScheme::DelegateCall, - is_static: interpreter.is_static, - is_eof: true, - return_memory_offset: 0..0, - }), - }; - interpreter.instruction_result = InstructionResult::CallOrCreate; -} - -pub fn extstaticcall(interpreter: &mut Interpreter, host: &mut H) { - require_eof!(interpreter); - pop_address!(interpreter, target_address); - - // input call - let Some(input) = extcall_input(interpreter) else { - return; - }; - - let Some(gas_limit) = extcall_gas_calc(interpreter, host, target_address, false) else { - return; - }; - - // Call host to interact with target contract - interpreter.next_action = InterpreterAction::Call { - inputs: Box::new(CallInputs { - input, - gas_limit, - target_address, - caller: interpreter.contract.target_address, - bytecode_address: target_address, - value: CallValue::Transfer(U256::ZERO), - scheme: CallScheme::Call, - is_static: interpreter.is_static, - is_eof: true, - return_memory_offset: 0..0, - }), - }; - interpreter.instruction_result = InstructionResult::CallOrCreate; -} - -pub fn create( - interpreter: &mut Interpreter, - host: &mut H, +/// Implements the CREATE/CREATE2 instruction. +/// +/// Creates a new contract with provided bytecode. +pub fn create( + context: InstructionContext<'_, H, WIRE>, ) { - require_non_staticcall!(interpreter); + require_non_staticcall!(context.interpreter); // EIP-1014: Skinny CREATE2 if IS_CREATE2 { - check!(interpreter, PETERSBURG); + check!(context.interpreter, PETERSBURG); } - pop!(interpreter, value, code_offset, len); - let len = as_usize_or_fail!(interpreter, len); + popn!([value, code_offset, len], context.interpreter); + let len = as_usize_or_fail!(context.interpreter, len); let mut code = Bytes::new(); if len != 0 { // EIP-3860: Limit and meter initcode - if SPEC::enabled(SHANGHAI) { + if context + .interpreter + .runtime_flag + .spec_id() + .is_enabled_in(SpecId::SHANGHAI) + { // Limit is set as double of max contract bytecode size - let max_initcode_size = host - .env() - .cfg - .limit_contract_code_size - .map(|limit| limit.saturating_mul(2)) - .unwrap_or(MAX_INITCODE_SIZE); - if len > max_initcode_size { - interpreter.instruction_result = InstructionResult::CreateInitCodeSizeLimit; + if len > context.host.max_initcode_size() { + context + .interpreter + .halt(InstructionResult::CreateInitCodeSizeLimit); return; } - gas!(interpreter, gas::initcode_cost(len as u64)); + gas!(context.interpreter, gas::initcode_cost(len)); } - let code_offset = as_usize_or_fail!(interpreter, code_offset); - resize_memory!(interpreter, code_offset, len); - code = Bytes::copy_from_slice(interpreter.shared_memory.slice(code_offset, len)); + let code_offset = as_usize_or_fail!(context.interpreter, code_offset); + resize_memory!(context.interpreter, code_offset, len); + code = Bytes::copy_from_slice( + context + .interpreter + .memory + .slice_len(code_offset, len) + .as_ref(), + ); } // EIP-1014: Skinny CREATE2 let scheme = if IS_CREATE2 { - pop!(interpreter, salt); - // SAFETY: len is reasonable in size as gas for it is already deducted. - gas_or_fail!(interpreter, gas::create2_cost(len.try_into().unwrap())); + popn!([salt], context.interpreter); + // SAFETY: `len` is reasonable in size as gas for it is already deducted. + gas_or_fail!(context.interpreter, gas::create2_cost(len)); CreateScheme::Create2 { salt } } else { - gas!(interpreter, gas::CREATE); + gas!(context.interpreter, gas::CREATE); CreateScheme::Create }; - let mut gas_limit = interpreter.gas().remaining(); + let mut gas_limit = context.interpreter.gas.remaining(); // EIP-150: Gas cost changes for IO-heavy operations - if SPEC::enabled(TANGERINE) { - // take remaining gas and deduce l64 part of it. + if context + .interpreter + .runtime_flag + .spec_id() + .is_enabled_in(SpecId::TANGERINE) + { + // Take remaining gas and deduce l64 part of it. gas_limit -= gas_limit / 64 } - gas!(interpreter, gas_limit); + gas!(context.interpreter, gas_limit); // Call host to interact with target contract - interpreter.next_action = InterpreterAction::Create { - inputs: Box::new(CreateInputs { - caller: interpreter.contract.target_address, - scheme, - value, - init_code: code, - gas_limit, - }), - }; - interpreter.instruction_result = InstructionResult::CallOrCreate; + context + .interpreter + .bytecode + .set_action(InterpreterAction::NewFrame(FrameInput::Create(Box::new( + CreateInputs { + caller: context.interpreter.input.target_address(), + scheme, + value, + init_code: code, + gas_limit, + }, + )))); } -pub fn call(interpreter: &mut Interpreter, host: &mut H) { - pop!(interpreter, local_gas_limit); - pop_address!(interpreter, to); - // max gas limit is not possible in real ethereum situation. +/// Implements the CALL instruction. +/// +/// Message call with value transfer to another account. +pub fn call(context: InstructionContext<'_, H, WIRE>) { + popn!([local_gas_limit, to, value], context.interpreter); + let to = to.into_address(); + // Max gas limit is not possible in real ethereum situation. let local_gas_limit = u64::try_from(local_gas_limit).unwrap_or(u64::MAX); - pop!(interpreter, value); - let has_transfer = value != U256::ZERO; - if interpreter.is_static && has_transfer { - interpreter.instruction_result = InstructionResult::CallNotAllowedInsideStatic; + let has_transfer = !value.is_zero(); + if context.interpreter.runtime_flag.is_static() && has_transfer { + context + .interpreter + .halt(InstructionResult::CallNotAllowedInsideStatic); return; } - let Some((input, return_memory_offset)) = get_memory_input_and_out_ranges(interpreter) else { + let Some((input, return_memory_offset)) = get_memory_input_and_out_ranges(context.interpreter) + else { return; }; - let Some(LoadAccountResult { is_cold, is_empty }) = host.load_account(to) else { - interpreter.instruction_result = InstructionResult::FatalExternalError; + let Some(account_load) = context.host.load_account_delegated(to) else { + context + .interpreter + .halt(InstructionResult::FatalExternalError); return; }; - let Some(mut gas_limit) = calc_call_gas::( - interpreter, - is_cold, + + let Some(mut gas_limit) = calc_call_gas( + context.interpreter, + account_load, has_transfer, - is_empty, local_gas_limit, ) else { return; }; - gas!(interpreter, gas_limit); + gas!(context.interpreter, gas_limit); - // add call stipend if there is value to be transferred. + // Add call stipend if there is value to be transferred. if has_transfer { gas_limit = gas_limit.saturating_add(gas::CALL_STIPEND); } // Call host to interact with target contract - interpreter.next_action = InterpreterAction::Call { - inputs: Box::new(CallInputs { - input, - gas_limit, - target_address: to, - caller: interpreter.contract.target_address, - bytecode_address: to, - value: CallValue::Transfer(value), - scheme: CallScheme::Call, - is_static: interpreter.is_static, - is_eof: false, - return_memory_offset, - }), - }; - interpreter.instruction_result = InstructionResult::CallOrCreate; + context + .interpreter + .bytecode + .set_action(InterpreterAction::NewFrame(FrameInput::Call(Box::new( + CallInputs { + input: CallInput::SharedBuffer(input), + gas_limit, + target_address: to, + caller: context.interpreter.input.target_address(), + bytecode_address: to, + value: CallValue::Transfer(value), + scheme: CallScheme::Call, + is_static: context.interpreter.runtime_flag.is_static(), + return_memory_offset, + }, + )))); } -pub fn call_code(interpreter: &mut Interpreter, host: &mut H) { - pop!(interpreter, local_gas_limit); - pop_address!(interpreter, to); - // max gas limit is not possible in real ethereum situation. +/// Implements the CALLCODE instruction. +/// +/// Message call with alternative account's code. +pub fn call_code( + context: InstructionContext<'_, H, WIRE>, +) { + popn!([local_gas_limit, to, value], context.interpreter); + let to = Address::from_word(B256::from(to)); + // Max gas limit is not possible in real ethereum situation. let local_gas_limit = u64::try_from(local_gas_limit).unwrap_or(u64::MAX); - pop!(interpreter, value); - let Some((input, return_memory_offset)) = get_memory_input_and_out_ranges(interpreter) else { + //pop!(context.interpreter, value); + let Some((input, return_memory_offset)) = get_memory_input_and_out_ranges(context.interpreter) + else { return; }; - let Some(LoadAccountResult { is_cold, .. }) = host.load_account(to) else { - interpreter.instruction_result = InstructionResult::FatalExternalError; + let Some(mut load) = context.host.load_account_delegated(to) else { + context + .interpreter + .halt(InstructionResult::FatalExternalError); return; }; - let Some(mut gas_limit) = calc_call_gas::( - interpreter, - is_cold, - value != U256::ZERO, - false, - local_gas_limit, - ) else { + // Set `is_empty` to false as we are not creating this account. + load.is_empty = false; + let Some(mut gas_limit) = + calc_call_gas(context.interpreter, load, !value.is_zero(), local_gas_limit) + else { return; }; - gas!(interpreter, gas_limit); + gas!(context.interpreter, gas_limit); - // add call stipend if there is value to be transferred. - if value != U256::ZERO { + // Add call stipend if there is value to be transferred. + if !value.is_zero() { gas_limit = gas_limit.saturating_add(gas::CALL_STIPEND); } // Call host to interact with target contract - interpreter.next_action = InterpreterAction::Call { - inputs: Box::new(CallInputs { - input, - gas_limit, - target_address: interpreter.contract.target_address, - caller: interpreter.contract.target_address, - bytecode_address: to, - value: CallValue::Transfer(value), - scheme: CallScheme::CallCode, - is_static: interpreter.is_static, - is_eof: false, - return_memory_offset, - }), - }; - interpreter.instruction_result = InstructionResult::CallOrCreate; + context + .interpreter + .bytecode + .set_action(InterpreterAction::NewFrame(FrameInput::Call(Box::new( + CallInputs { + input: CallInput::SharedBuffer(input), + gas_limit, + target_address: context.interpreter.input.target_address(), + caller: context.interpreter.input.target_address(), + bytecode_address: to, + value: CallValue::Transfer(value), + scheme: CallScheme::CallCode, + is_static: context.interpreter.runtime_flag.is_static(), + return_memory_offset, + }, + )))); } -pub fn delegate_call(interpreter: &mut Interpreter, host: &mut H) { - check!(interpreter, HOMESTEAD); - pop!(interpreter, local_gas_limit); - pop_address!(interpreter, to); - // max gas limit is not possible in real ethereum situation. +/// Implements the DELEGATECALL instruction. +/// +/// Message call with alternative account's code but same sender and value. +pub fn delegate_call( + context: InstructionContext<'_, H, WIRE>, +) { + check!(context.interpreter, HOMESTEAD); + popn!([local_gas_limit, to], context.interpreter); + let to = Address::from_word(B256::from(to)); + // Max gas limit is not possible in real ethereum situation. let local_gas_limit = u64::try_from(local_gas_limit).unwrap_or(u64::MAX); - let Some((input, return_memory_offset)) = get_memory_input_and_out_ranges(interpreter) else { + let Some((input, return_memory_offset)) = get_memory_input_and_out_ranges(context.interpreter) + else { return; }; - let Some(LoadAccountResult { is_cold, .. }) = host.load_account(to) else { - interpreter.instruction_result = InstructionResult::FatalExternalError; + let Some(mut load) = context.host.load_account_delegated(to) else { + context + .interpreter + .halt(InstructionResult::FatalExternalError); return; }; - let Some(gas_limit) = - calc_call_gas::(interpreter, is_cold, false, false, local_gas_limit) - else { + + // Set is_empty to false as we are not creating this account. + load.is_empty = false; + let Some(gas_limit) = calc_call_gas(context.interpreter, load, false, local_gas_limit) else { return; }; - gas!(interpreter, gas_limit); + gas!(context.interpreter, gas_limit); // Call host to interact with target contract - interpreter.next_action = InterpreterAction::Call { - inputs: Box::new(CallInputs { - input, - gas_limit, - target_address: interpreter.contract.target_address, - caller: interpreter.contract.caller, - bytecode_address: to, - value: CallValue::Apparent(interpreter.contract.call_value), - scheme: CallScheme::DelegateCall, - is_static: interpreter.is_static, - is_eof: false, - return_memory_offset, - }), - }; - interpreter.instruction_result = InstructionResult::CallOrCreate; + context + .interpreter + .bytecode + .set_action(InterpreterAction::NewFrame(FrameInput::Call(Box::new( + CallInputs { + input: CallInput::SharedBuffer(input), + gas_limit, + target_address: context.interpreter.input.target_address(), + caller: context.interpreter.input.caller_address(), + bytecode_address: to, + value: CallValue::Apparent(context.interpreter.input.call_value()), + scheme: CallScheme::DelegateCall, + is_static: context.interpreter.runtime_flag.is_static(), + return_memory_offset, + }, + )))); } -pub fn static_call(interpreter: &mut Interpreter, host: &mut H) { - check!(interpreter, BYZANTIUM); - pop!(interpreter, local_gas_limit); - pop_address!(interpreter, to); - // max gas limit is not possible in real ethereum situation. +/// Implements the STATICCALL instruction. +/// +/// Static message call (cannot modify state). +pub fn static_call( + context: InstructionContext<'_, H, WIRE>, +) { + check!(context.interpreter, BYZANTIUM); + popn!([local_gas_limit, to], context.interpreter); + let to = Address::from_word(B256::from(to)); + // Max gas limit is not possible in real ethereum situation. let local_gas_limit = u64::try_from(local_gas_limit).unwrap_or(u64::MAX); - let Some((input, return_memory_offset)) = get_memory_input_and_out_ranges(interpreter) else { + let Some((input, return_memory_offset)) = get_memory_input_and_out_ranges(context.interpreter) + else { return; }; - let Some(LoadAccountResult { is_cold, .. }) = host.load_account(to) else { - interpreter.instruction_result = InstructionResult::FatalExternalError; + let Some(mut load) = context.host.load_account_delegated(to) else { + context + .interpreter + .halt(InstructionResult::FatalExternalError); return; }; - - let Some(gas_limit) = - calc_call_gas::(interpreter, is_cold, false, false, local_gas_limit) - else { + // Set `is_empty` to false as we are not creating this account. + load.is_empty = false; + let Some(gas_limit) = calc_call_gas(context.interpreter, load, false, local_gas_limit) else { return; }; - gas!(interpreter, gas_limit); + gas!(context.interpreter, gas_limit); // Call host to interact with target contract - interpreter.next_action = InterpreterAction::Call { - inputs: Box::new(CallInputs { - input, - gas_limit, - target_address: to, - caller: interpreter.contract.target_address, - bytecode_address: to, - value: CallValue::Transfer(U256::ZERO), - scheme: CallScheme::StaticCall, - is_static: true, - is_eof: false, - return_memory_offset, - }), - }; - interpreter.instruction_result = InstructionResult::CallOrCreate; + context + .interpreter + .bytecode + .set_action(InterpreterAction::NewFrame(FrameInput::Call(Box::new( + CallInputs { + input: CallInput::SharedBuffer(input), + gas_limit, + target_address: to, + caller: context.interpreter.input.target_address(), + bytecode_address: to, + value: CallValue::Transfer(U256::ZERO), + scheme: CallScheme::StaticCall, + is_static: true, + return_memory_offset, + }, + )))); } diff --git a/crates/interpreter/src/instructions/contract/call_helpers.rs b/crates/interpreter/src/instructions/contract/call_helpers.rs index 5570efe3ac..37cf571466 100644 --- a/crates/interpreter/src/instructions/contract/call_helpers.rs +++ b/crates/interpreter/src/instructions/contract/call_helpers.rs @@ -1,32 +1,35 @@ use crate::{ gas, interpreter::Interpreter, - primitives::{Bytes, Spec, SpecId::*, U256}, + interpreter_types::{InterpreterTypes, MemoryTr, RuntimeFlag, StackTr}, }; +use context_interface::{context::StateLoad, journaled_state::AccountLoad}; use core::{cmp::min, ops::Range}; +use primitives::{hardfork::SpecId::*, U256}; +/// Gets memory input and output ranges for call instructions. #[inline] pub fn get_memory_input_and_out_ranges( - interpreter: &mut Interpreter, -) -> Option<(Bytes, Range)> { - pop_ret!(interpreter, in_offset, in_len, out_offset, out_len, None); + interpreter: &mut Interpreter, +) -> Option<(Range, Range)> { + popn!([in_offset, in_len, out_offset, out_len], interpreter, None); - let in_range = resize_memory_and_return_range(interpreter, in_offset, in_len)?; + let mut in_range = resize_memory(interpreter, in_offset, in_len)?; - let mut input = Bytes::new(); if !in_range.is_empty() { - input = Bytes::copy_from_slice(interpreter.shared_memory.slice_range(in_range)); + let offset = interpreter.memory.local_memory_offset(); + in_range = in_range.start.saturating_add(offset)..in_range.end.saturating_add(offset); } - let ret_range = resize_memory_and_return_range(interpreter, out_offset, out_len)?; - Some((input, ret_range)) + let ret_range = resize_memory(interpreter, out_offset, out_len)?; + Some((in_range, ret_range)) } /// Resize memory and return range of memory. /// If `len` is 0 dont touch memory and return `usize::MAX` as offset and 0 as length. #[inline] -pub fn resize_memory_and_return_range( - interpreter: &mut Interpreter, +pub fn resize_memory( + interpreter: &mut Interpreter, offset: U256, len: U256, ) -> Option> { @@ -41,23 +44,25 @@ pub fn resize_memory_and_return_range( Some(offset..offset + len) } +/// Calculates gas cost and limit for call instructions. #[inline] -pub fn calc_call_gas( - interpreter: &mut Interpreter, - is_cold: bool, +pub fn calc_call_gas( + interpreter: &mut Interpreter, + account_load: StateLoad, has_transfer: bool, - new_account_accounting: bool, local_gas_limit: u64, ) -> Option { - let call_cost = gas::call_cost(SPEC::SPEC_ID, has_transfer, is_cold, new_account_accounting); - + let call_cost = gas::call_cost( + interpreter.runtime_flag.spec_id(), + has_transfer, + account_load, + ); gas!(interpreter, call_cost, None); // EIP-150: Gas cost changes for IO-heavy operations - let gas_limit = if SPEC::enabled(TANGERINE) { - let gas = interpreter.gas().remaining(); - // take l64 part of gas_limit - min(gas - gas / 64, local_gas_limit) + let gas_limit = if interpreter.runtime_flag.spec_id().is_enabled_in(TANGERINE) { + // Take l64 part of gas_limit + min(interpreter.gas.remaining_63_of_64_parts(), local_gas_limit) } else { local_gas_limit }; diff --git a/crates/interpreter/src/instructions/control.rs b/crates/interpreter/src/instructions/control.rs index db2bc70adf..58502560ca 100644 --- a/crates/interpreter/src/instructions/control.rs +++ b/crates/interpreter/src/instructions/control.rs @@ -1,439 +1,120 @@ -use super::utility::{read_i16, read_u16}; use crate::{ gas, - primitives::{Bytes, Spec, U256}, - Host, InstructionResult, Interpreter, InterpreterResult, + interpreter::Interpreter, + interpreter_types::{InterpreterTypes, Jumps, LoopControl, MemoryTr, RuntimeFlag, StackTr}, + InstructionResult, InterpreterAction, }; +use primitives::{Bytes, U256}; -pub fn rjump(interpreter: &mut Interpreter, _host: &mut H) { - require_eof!(interpreter); - gas!(interpreter, gas::BASE); - let offset = unsafe { read_i16(interpreter.instruction_pointer) } as isize; - // In spec it is +3 but pointer is already incremented in - // `Interpreter::step` so for revm is +2. - interpreter.instruction_pointer = unsafe { interpreter.instruction_pointer.offset(offset + 2) }; -} - -pub fn rjumpi(interpreter: &mut Interpreter, _host: &mut H) { - require_eof!(interpreter); - gas!(interpreter, gas::CONDITION_JUMP_GAS); - pop!(interpreter, condition); - // In spec it is +3 but pointer is already incremented in - // `Interpreter::step` so for revm is +2. - let mut offset = 2; - if !condition.is_zero() { - offset += unsafe { read_i16(interpreter.instruction_pointer) } as isize; - } - - interpreter.instruction_pointer = unsafe { interpreter.instruction_pointer.offset(offset) }; -} - -pub fn rjumpv(interpreter: &mut Interpreter, _host: &mut H) { - require_eof!(interpreter); - gas!(interpreter, gas::CONDITION_JUMP_GAS); - pop!(interpreter, case); - let case = as_isize_saturated!(case); +use crate::InstructionContext; - let max_index = unsafe { *interpreter.instruction_pointer } as isize; - // for number of items we are adding 1 to max_index, multiply by 2 as each offset is 2 bytes - // and add 1 for max_index itself. Note that revm already incremented the instruction pointer - let mut offset = (max_index + 1) * 2 + 1; - - if case <= max_index { - offset += unsafe { - read_i16( - interpreter - .instruction_pointer - // offset for max_index that is one byte - .offset(1 + case * 2), - ) - } as isize; - } - - interpreter.instruction_pointer = unsafe { interpreter.instruction_pointer.offset(offset) }; +/// Implements the JUMP instruction. +/// +/// Unconditional jump to a valid destination. +pub fn jump(context: InstructionContext<'_, H, ITy>) { + gas!(context.interpreter, gas::MID); + popn!([target], context.interpreter); + jump_inner(context.interpreter, target); } -pub fn jump(interpreter: &mut Interpreter, _host: &mut H) { - gas!(interpreter, gas::MID); - pop!(interpreter, target); - jump_inner(interpreter, target); -} +/// Implements the JUMPI instruction. +/// +/// Conditional jump to a valid destination if condition is true. +pub fn jumpi(context: InstructionContext<'_, H, WIRE>) { + gas!(context.interpreter, gas::HIGH); + popn!([target, cond], context.interpreter); -pub fn jumpi(interpreter: &mut Interpreter, _host: &mut H) { - gas!(interpreter, gas::HIGH); - pop!(interpreter, target, cond); - if cond != U256::ZERO { - jump_inner(interpreter, target); + if !cond.is_zero() { + jump_inner(context.interpreter, target); } } -#[inline] -fn jump_inner(interpreter: &mut Interpreter, target: U256) { +/// Internal helper function for jump operations. +/// +/// Validates jump target and performs the actual jump. +#[inline(always)] +fn jump_inner(interpreter: &mut Interpreter, target: U256) { let target = as_usize_or_fail!(interpreter, target, InstructionResult::InvalidJump); - if !interpreter.contract.is_valid_jump(target) { - interpreter.instruction_result = InstructionResult::InvalidJump; + if !interpreter.bytecode.is_valid_legacy_jump(target) { + interpreter.halt(InstructionResult::InvalidJump); return; } // SAFETY: `is_valid_jump` ensures that `dest` is in bounds. - interpreter.instruction_pointer = unsafe { interpreter.bytecode.as_ptr().add(target) }; -} - -pub fn jumpdest_or_nop(interpreter: &mut Interpreter, _host: &mut H) { - gas!(interpreter, gas::JUMPDEST); -} - -pub fn callf(interpreter: &mut Interpreter, _host: &mut H) { - require_eof!(interpreter); - gas!(interpreter, gas::LOW); - - let idx = unsafe { read_u16(interpreter.instruction_pointer) } as usize; - - if interpreter.function_stack.return_stack_len() >= 1024 { - interpreter.instruction_result = InstructionResult::EOFFunctionStackOverflow; - return; - } - - // get target types - let Some(types) = interpreter.eof().unwrap().body.types_section.get(idx) else { - panic!("Invalid EOF in execution, expecting correct intermediate in callf") - }; - - // Check max stack height for target code section. - // safe to subtract as max_stack_height is always more than inputs. - if interpreter.stack.len() + (types.max_stack_size - types.inputs as u16) as usize > 1024 { - interpreter.instruction_result = InstructionResult::StackOverflow; - return; - } - - // push current idx and PC to the callf stack. - // PC is incremented by 2 to point to the next instruction after callf. - interpreter - .function_stack - .push(interpreter.program_counter() + 2, idx); - - interpreter.load_eof_code(idx, 0) -} - -pub fn retf(interpreter: &mut Interpreter, _host: &mut H) { - require_eof!(interpreter); - gas!(interpreter, gas::RETF_GAS); - - let Some(fframe) = interpreter.function_stack.pop() else { - panic!("Expected function frame") - }; - - interpreter.load_eof_code(fframe.idx, fframe.pc); + interpreter.bytecode.absolute_jump(target); } -pub fn jumpf(interpreter: &mut Interpreter, _host: &mut H) { - require_eof!(interpreter); - gas!(interpreter, gas::LOW); - - let idx = unsafe { read_u16(interpreter.instruction_pointer) } as usize; - - // get target types - let Some(types) = interpreter.eof().unwrap().body.types_section.get(idx) else { - panic!("Invalid EOF in execution, expecting correct intermediate in jumpf") - }; - - // Check max stack height for target code section. - // safe to subtract as max_stack_height is always more than inputs. - if interpreter.stack.len() + (types.max_stack_size - types.inputs as u16) as usize > 1024 { - interpreter.instruction_result = InstructionResult::StackOverflow; - return; - } - - interpreter.function_stack.set_current_code_idx(idx); - interpreter.load_eof_code(idx, 0) +/// Implements the JUMPDEST instruction. +/// +/// Marks a valid destination for jump operations. +pub fn jumpdest(context: InstructionContext<'_, H, WIRE>) { + gas!(context.interpreter, gas::JUMPDEST); } -pub fn pc(interpreter: &mut Interpreter, _host: &mut H) { - gas!(interpreter, gas::BASE); +/// Implements the PC instruction. +/// +/// Pushes the current program counter onto the stack. +pub fn pc(context: InstructionContext<'_, H, WIRE>) { + gas!(context.interpreter, gas::BASE); // - 1 because we have already advanced the instruction pointer in `Interpreter::step` - push!(interpreter, U256::from(interpreter.program_counter() - 1)); + push!( + context.interpreter, + U256::from(context.interpreter.bytecode.pc() - 1) + ); } #[inline] -fn return_inner(interpreter: &mut Interpreter, instruction_result: InstructionResult) { - // zero gas cost - // gas!(interpreter, gas::ZERO); - pop!(interpreter, offset, len); +/// Internal helper function for return operations. +/// +/// Handles memory data retrieval and sets the return action. +fn return_inner( + interpreter: &mut Interpreter, + instruction_result: InstructionResult, +) { + // Zero gas cost + // gas!(interpreter, gas::ZERO) + popn!([offset, len], interpreter); let len = as_usize_or_fail!(interpreter, len); - // important: offset must be ignored if len is zeros + // Important: Offset must be ignored if len is zeros let mut output = Bytes::default(); if len != 0 { let offset = as_usize_or_fail!(interpreter, offset); resize_memory!(interpreter, offset, len); - - output = interpreter.shared_memory.slice(offset, len).to_vec().into() + output = interpreter.memory.slice_len(offset, len).to_vec().into() } - interpreter.instruction_result = instruction_result; - interpreter.next_action = crate::InterpreterAction::Return { - result: InterpreterResult { + + interpreter + .bytecode + .set_action(InterpreterAction::new_return( + instruction_result, output, - gas: interpreter.gas, - result: instruction_result, - }, - }; + interpreter.gas, + )); } -pub fn ret(interpreter: &mut Interpreter, _host: &mut H) { - return_inner(interpreter, InstructionResult::Return); +/// Implements the RETURN instruction. +/// +/// Halts execution and returns data from memory. +pub fn ret(context: InstructionContext<'_, H, WIRE>) { + return_inner(context.interpreter, InstructionResult::Return); } /// EIP-140: REVERT instruction -pub fn revert(interpreter: &mut Interpreter, _host: &mut H) { - check!(interpreter, BYZANTIUM); - return_inner(interpreter, InstructionResult::Revert); +pub fn revert(context: InstructionContext<'_, H, WIRE>) { + check!(context.interpreter, BYZANTIUM); + return_inner(context.interpreter, InstructionResult::Revert); } /// Stop opcode. This opcode halts the execution. -pub fn stop(interpreter: &mut Interpreter, _host: &mut H) { - interpreter.instruction_result = InstructionResult::Stop; +pub fn stop(context: InstructionContext<'_, H, WIRE>) { + context.interpreter.halt(InstructionResult::Stop); } /// Invalid opcode. This opcode halts the execution. -pub fn invalid(interpreter: &mut Interpreter, _host: &mut H) { - interpreter.instruction_result = InstructionResult::InvalidFEOpcode; +pub fn invalid(context: InstructionContext<'_, H, WIRE>) { + context.interpreter.halt(InstructionResult::InvalidFEOpcode); } /// Unknown opcode. This opcode halts the execution. -pub fn unknown(interpreter: &mut Interpreter, _host: &mut H) { - interpreter.instruction_result = InstructionResult::OpcodeNotFound; -} - -#[cfg(test)] -mod test { - use revm_primitives::{bytes, eof::TypesSection, Bytecode, Eof, PragueSpec}; - - use super::*; - use crate::{ - opcode::{make_instruction_table, CALLF, JUMPF, NOP, RETF, RJUMP, RJUMPI, RJUMPV, STOP}, - DummyHost, FunctionReturnFrame, Gas, Interpreter, - }; - - #[test] - fn rjump() { - let table = make_instruction_table::<_, PragueSpec>(); - let mut host = DummyHost::default(); - let mut interp = Interpreter::new_bytecode(Bytecode::LegacyRaw(Bytes::from([ - RJUMP, 0x00, 0x02, STOP, STOP, - ]))); - interp.is_eof = true; - interp.gas = Gas::new(10000); - - interp.step(&table, &mut host); - assert_eq!(interp.program_counter(), 5); - } - - #[test] - fn rjumpi() { - let table = make_instruction_table::<_, PragueSpec>(); - let mut host = DummyHost::default(); - let mut interp = Interpreter::new_bytecode(Bytecode::LegacyRaw(Bytes::from([ - RJUMPI, 0x00, 0x03, RJUMPI, 0x00, 0x01, STOP, STOP, - ]))); - interp.is_eof = true; - interp.stack.push(U256::from(1)).unwrap(); - interp.stack.push(U256::from(0)).unwrap(); - interp.gas = Gas::new(10000); - - // dont jump - interp.step(&table, &mut host); - assert_eq!(interp.program_counter(), 3); - // jumps to last opcode - interp.step(&table, &mut host); - assert_eq!(interp.program_counter(), 7); - } - - #[test] - fn rjumpv() { - let table = make_instruction_table::<_, PragueSpec>(); - let mut host = DummyHost::default(); - let mut interp = Interpreter::new_bytecode(Bytecode::LegacyRaw(Bytes::from([ - RJUMPV, - 0x01, // max index, 0 and 1 - 0x00, // first x0001 - 0x01, - 0x00, // second 0x002 - 0x02, - NOP, - NOP, - NOP, - RJUMP, - 0xFF, - (-12i8) as u8, - STOP, - ]))); - interp.is_eof = true; - interp.gas = Gas::new(1000); - - // more then max_index - interp.stack.push(U256::from(10)).unwrap(); - interp.step(&table, &mut host); - assert_eq!(interp.program_counter(), 6); - - // cleanup - interp.step(&table, &mut host); - interp.step(&table, &mut host); - interp.step(&table, &mut host); - interp.step(&table, &mut host); - assert_eq!(interp.program_counter(), 0); - - // jump to first index of vtable - interp.stack.push(U256::from(0)).unwrap(); - interp.step(&table, &mut host); - assert_eq!(interp.program_counter(), 7); - - // cleanup - interp.step(&table, &mut host); - interp.step(&table, &mut host); - interp.step(&table, &mut host); - assert_eq!(interp.program_counter(), 0); - - // jump to second index of vtable - interp.stack.push(U256::from(1)).unwrap(); - interp.step(&table, &mut host); - assert_eq!(interp.program_counter(), 8); - } - - fn dummy_eof() -> Eof { - let bytes = bytes!("ef000101000402000100010400000000800000fe"); - Eof::decode(bytes).unwrap() - } - - fn eof_setup(bytes1: Bytes, bytes2: Bytes) -> Interpreter { - eof_setup_with_types(bytes1, bytes2, TypesSection::default()) - } - - /// Two code section and types section is for last code. - fn eof_setup_with_types(bytes1: Bytes, bytes2: Bytes, types: TypesSection) -> Interpreter { - let mut eof = dummy_eof(); - - eof.body.code_section.clear(); - eof.body.types_section.clear(); - eof.header.code_sizes.clear(); - - eof.header.code_sizes.push(bytes1.len() as u16); - eof.body.code_section.push(bytes1.clone()); - eof.body.types_section.push(TypesSection::new(0, 0, 11)); - - eof.header.code_sizes.push(bytes2.len() as u16); - eof.body.code_section.push(bytes2.clone()); - eof.body.types_section.push(types); - - let mut interp = Interpreter::new_bytecode(Bytecode::Eof(eof)); - interp.gas = Gas::new(10000); - interp - } - - #[test] - fn callf_retf_stop() { - let table = make_instruction_table::<_, PragueSpec>(); - let mut host = DummyHost::default(); - - let bytes1 = Bytes::from([CALLF, 0x00, 0x01, STOP]); - let bytes2 = Bytes::from([RETF]); - let mut interp = eof_setup(bytes1, bytes2.clone()); - - // CALLF - interp.step(&table, &mut host); - - assert_eq!(interp.function_stack.current_code_idx, 1); - assert_eq!( - interp.function_stack.return_stack[0], - FunctionReturnFrame::new(0, 3) - ); - assert_eq!(interp.instruction_pointer, bytes2.as_ptr()); - - // RETF - interp.step(&table, &mut host); - - assert_eq!(interp.function_stack.current_code_idx, 0); - assert_eq!(interp.function_stack.return_stack, Vec::new()); - assert_eq!(interp.program_counter(), 3); - - // STOP - interp.step(&table, &mut host); - assert_eq!(interp.instruction_result, InstructionResult::Stop); - } - - #[test] - fn callf_stop() { - let table = make_instruction_table::<_, PragueSpec>(); - let mut host = DummyHost::default(); - - let bytes1 = Bytes::from([CALLF, 0x00, 0x01]); - let bytes2 = Bytes::from([STOP]); - let mut interp = eof_setup(bytes1, bytes2.clone()); - - // CALLF - interp.step(&table, &mut host); - - assert_eq!(interp.function_stack.current_code_idx, 1); - assert_eq!( - interp.function_stack.return_stack[0], - FunctionReturnFrame::new(0, 3) - ); - assert_eq!(interp.instruction_pointer, bytes2.as_ptr()); - - // STOP - interp.step(&table, &mut host); - assert_eq!(interp.instruction_result, InstructionResult::Stop); - } - - #[test] - fn callf_stack_overflow() { - let table = make_instruction_table::<_, PragueSpec>(); - let mut host = DummyHost::default(); - - let bytes1 = Bytes::from([CALLF, 0x00, 0x01]); - let bytes2 = Bytes::from([STOP]); - let mut interp = - eof_setup_with_types(bytes1, bytes2.clone(), TypesSection::new(0, 0, 1025)); - - // CALLF - interp.step(&table, &mut host); - - // stack overflow - assert_eq!(interp.instruction_result, InstructionResult::StackOverflow); - } - - #[test] - fn jumpf_stop() { - let table = make_instruction_table::<_, PragueSpec>(); - let mut host = DummyHost::default(); - - let bytes1 = Bytes::from([JUMPF, 0x00, 0x01]); - let bytes2 = Bytes::from([STOP]); - let mut interp = eof_setup(bytes1, bytes2.clone()); - - // JUMPF - interp.step(&table, &mut host); - - assert_eq!(interp.function_stack.current_code_idx, 1); - assert!(interp.function_stack.return_stack.is_empty()); - assert_eq!(interp.instruction_pointer, bytes2.as_ptr()); - - // STOP - interp.step(&table, &mut host); - assert_eq!(interp.instruction_result, InstructionResult::Stop); - } - - #[test] - fn jumpf_stack_overflow() { - let table = make_instruction_table::<_, PragueSpec>(); - let mut host = DummyHost::default(); - - let bytes1 = Bytes::from([JUMPF, 0x00, 0x01]); - let bytes2 = Bytes::from([STOP]); - let mut interp = - eof_setup_with_types(bytes1, bytes2.clone(), TypesSection::new(0, 0, 1025)); - - // JUMPF - interp.step(&table, &mut host); - - // stack overflow - assert_eq!(interp.instruction_result, InstructionResult::StackOverflow); - } +pub fn unknown(context: InstructionContext<'_, H, WIRE>) { + context.interpreter.halt(InstructionResult::OpcodeNotFound); } diff --git a/crates/interpreter/src/instructions/data.rs b/crates/interpreter/src/instructions/data.rs deleted file mode 100644 index 5d18a89899..0000000000 --- a/crates/interpreter/src/instructions/data.rs +++ /dev/null @@ -1,214 +0,0 @@ -use crate::{ - gas::{BASE, DATA_LOAD_GAS, VERYLOW}, - instructions::utility::read_u16, - interpreter::Interpreter, - primitives::U256, - Host, -}; - -pub fn data_load(interpreter: &mut Interpreter, _host: &mut H) { - require_eof!(interpreter); - gas!(interpreter, DATA_LOAD_GAS); - pop_top!(interpreter, offset); - - let offset_usize = as_usize_saturated!(offset); - - let slice = interpreter - .contract - .bytecode - .eof() - .expect("eof") - .data_slice(offset_usize, 32); - - let mut word = [0u8; 32]; - word[..slice.len()].copy_from_slice(slice); - - *offset = U256::from_be_bytes(word); -} - -pub fn data_loadn(interpreter: &mut Interpreter, _host: &mut H) { - require_eof!(interpreter); - gas!(interpreter, VERYLOW); - let offset = unsafe { read_u16(interpreter.instruction_pointer) } as usize; - - let slice = interpreter - .contract - .bytecode - .eof() - .expect("eof") - .data_slice(offset, 32); - - let mut word = [0u8; 32]; - word[..slice.len()].copy_from_slice(slice); - - push_b256!(interpreter, word.into()); - - // add +2 to the instruction pointer to skip the offset - interpreter.instruction_pointer = unsafe { interpreter.instruction_pointer.offset(2) }; -} - -pub fn data_size(interpreter: &mut Interpreter, _host: &mut H) { - require_eof!(interpreter); - gas!(interpreter, BASE); - let data_size = interpreter.eof().expect("eof").header.data_size; - - push!(interpreter, U256::from(data_size)); -} - -pub fn data_copy(interpreter: &mut Interpreter, _host: &mut H) { - require_eof!(interpreter); - gas!(interpreter, VERYLOW); - pop!(interpreter, mem_offset, offset, size); - - // sizes more than u64::MAX will spend all the gas in memmory resize. - let size = as_usize_or_fail!(interpreter, size); - // size of zero should not change the memory - if size == 0 { - return; - } - // fail if mem offset is big as it will spend all the gas - let mem_offset = as_usize_or_fail!(interpreter, mem_offset); - resize_memory!(interpreter, mem_offset, size); - - let offset = as_usize_saturated!(offset); - let data = interpreter.contract.bytecode.eof().expect("EOF").data(); - - // set data from the eof to the shared memory. Padd it with zeros. - interpreter - .shared_memory - .set_data(mem_offset, offset, size, data); -} - -#[cfg(test)] -mod test { - use revm_primitives::{b256, bytes, Bytecode, Bytes, Eof, PragueSpec}; - - use super::*; - use crate::{ - opcode::{make_instruction_table, DATACOPY, DATALOAD, DATALOADN, DATASIZE}, - DummyHost, Gas, Interpreter, - }; - - fn dummy_eof(code_bytes: Bytes) -> Bytecode { - let bytes = bytes!("ef000101000402000100010400000000800000fe"); - let mut eof = Eof::decode(bytes).unwrap(); - - eof.body.data_section = - bytes!("000000000000000000000000000000000000000000000000000000000000000102030405"); - eof.header.data_size = eof.body.data_section.len() as u16; - - eof.header.code_sizes[0] = code_bytes.len() as u16; - eof.body.code_section[0] = code_bytes; - Bytecode::Eof(eof) - } - - #[test] - fn dataload_dataloadn() { - let table = make_instruction_table::<_, PragueSpec>(); - let mut host = DummyHost::default(); - let eof = dummy_eof(Bytes::from([ - DATALOAD, DATALOADN, 0x00, 0x00, DATALOAD, DATALOADN, 0x00, 35, DATALOAD, DATALOADN, - 0x00, 36, DATASIZE, - ])); - - let mut interp = Interpreter::new_bytecode(eof); - interp.gas = Gas::new(10000); - - // DATALOAD - interp.stack.push(U256::from(0)).unwrap(); - interp.step(&table, &mut host); - assert_eq!(interp.stack.data(), &vec![U256::from(0x01)]); - interp.stack.pop().unwrap(); - - // DATALOADN - interp.step(&table, &mut host); - assert_eq!(interp.stack.data(), &vec![U256::from(0x01)]); - interp.stack.pop().unwrap(); - - // DATALOAD (padding) - interp.stack.push(U256::from(35)).unwrap(); - interp.step(&table, &mut host); - assert_eq!( - interp.stack.data(), - &vec![b256!("0500000000000000000000000000000000000000000000000000000000000000").into()] - ); - interp.stack.pop().unwrap(); - - // DATALOADN (padding) - interp.step(&table, &mut host); - assert_eq!( - interp.stack.data(), - &vec![b256!("0500000000000000000000000000000000000000000000000000000000000000").into()] - ); - interp.stack.pop().unwrap(); - - // DATALOAD (out of bounds) - interp.stack.push(U256::from(36)).unwrap(); - interp.step(&table, &mut host); - assert_eq!(interp.stack.data(), &vec![U256::ZERO]); - interp.stack.pop().unwrap(); - - // DATALOADN (out of bounds) - interp.step(&table, &mut host); - assert_eq!(interp.stack.data(), &vec![U256::ZERO]); - interp.stack.pop().unwrap(); - - // DATA SIZE - interp.step(&table, &mut host); - assert_eq!(interp.stack.data(), &vec![U256::from(36)]); - } - - #[test] - fn data_copy() { - let table = make_instruction_table::<_, PragueSpec>(); - let mut host = DummyHost::default(); - let eof = dummy_eof(Bytes::from([DATACOPY, DATACOPY, DATACOPY, DATACOPY])); - - let mut interp = Interpreter::new_bytecode(eof); - interp.gas = Gas::new(10000); - - // Data copy - // size, offset mem_offset, - interp.stack.push(U256::from(32)).unwrap(); - interp.stack.push(U256::from(0)).unwrap(); - interp.stack.push(U256::from(0)).unwrap(); - interp.step(&table, &mut host); - assert_eq!( - interp.shared_memory.context_memory(), - &bytes!("0000000000000000000000000000000000000000000000000000000000000001") - ); - - // Data copy (Padding) - // size, offset mem_offset, - interp.stack.push(U256::from(2)).unwrap(); - interp.stack.push(U256::from(35)).unwrap(); - interp.stack.push(U256::from(1)).unwrap(); - interp.step(&table, &mut host); - assert_eq!( - interp.shared_memory.context_memory(), - &bytes!("0005000000000000000000000000000000000000000000000000000000000001") - ); - - // Data copy (Out of bounds) - // size, offset mem_offset, - interp.stack.push(U256::from(2)).unwrap(); - interp.stack.push(U256::from(37)).unwrap(); - interp.stack.push(U256::from(1)).unwrap(); - interp.step(&table, &mut host); - assert_eq!( - interp.shared_memory.context_memory(), - &bytes!("0000000000000000000000000000000000000000000000000000000000000001") - ); - - // Data copy (Size == 0) - // mem_offset, offset, size - interp.stack.push(U256::from(0)).unwrap(); - interp.stack.push(U256::from(37)).unwrap(); - interp.stack.push(U256::from(1)).unwrap(); - interp.step(&table, &mut host); - assert_eq!( - interp.shared_memory.context_memory(), - &bytes!("0000000000000000000000000000000000000000000000000000000000000001") - ); - } -} diff --git a/crates/interpreter/src/instructions/host.rs b/crates/interpreter/src/instructions/host.rs index 0bc777c341..70245220e8 100644 --- a/crates/interpreter/src/instructions/host.rs +++ b/crates/interpreter/src/instructions/host.rs @@ -1,222 +1,359 @@ use crate::{ - gas::{self, warm_cold_cost}, - interpreter::Interpreter, - primitives::{Bytes, Log, LogData, Spec, SpecId::*, B256, U256}, - Host, InstructionResult, SStoreResult, + gas::{self, warm_cold_cost, CALL_STIPEND}, + instructions::utility::{IntoAddress, IntoU256}, + interpreter_types::{InputsTr, InterpreterTypes, MemoryTr, RuntimeFlag, StackTr}, + Host, InstructionResult, }; use core::cmp::min; -use std::vec::Vec; +use primitives::{hardfork::SpecId::*, Bytes, Log, LogData, B256, BLOCK_HASH_HISTORY, U256}; -pub fn balance(interpreter: &mut Interpreter, host: &mut H) { - pop_address!(interpreter, address); - let Some((balance, is_cold)) = host.balance(address) else { - interpreter.instruction_result = InstructionResult::FatalExternalError; +use crate::InstructionContext; + +/// Implements the BALANCE instruction. +/// +/// Gets the balance of the given account. +pub fn balance(context: InstructionContext<'_, H, WIRE>) { + popn_top!([], top, context.interpreter); + let address = top.into_address(); + let Some(balance) = context.host.balance(address) else { + context + .interpreter + .halt(InstructionResult::FatalExternalError); return; }; + let spec_id = context.interpreter.runtime_flag.spec_id(); gas!( - interpreter, - if SPEC::enabled(BERLIN) { - warm_cold_cost(is_cold) - } else if SPEC::enabled(ISTANBUL) { + context.interpreter, + if spec_id.is_enabled_in(BERLIN) { + warm_cold_cost(balance.is_cold) + } else if spec_id.is_enabled_in(ISTANBUL) { // EIP-1884: Repricing for trie-size-dependent opcodes 700 - } else if SPEC::enabled(TANGERINE) { + } else if spec_id.is_enabled_in(TANGERINE) { 400 } else { 20 } ); - push!(interpreter, balance); + *top = balance.data; } /// EIP-1884: Repricing for trie-size-dependent opcodes -pub fn selfbalance(interpreter: &mut Interpreter, host: &mut H) { - check!(interpreter, ISTANBUL); - gas!(interpreter, gas::LOW); - let Some((balance, _)) = host.balance(interpreter.contract.target_address) else { - interpreter.instruction_result = InstructionResult::FatalExternalError; +pub fn selfbalance( + context: InstructionContext<'_, H, WIRE>, +) { + check!(context.interpreter, ISTANBUL); + gas!(context.interpreter, gas::LOW); + + let Some(balance) = context + .host + .balance(context.interpreter.input.target_address()) + else { + context + .interpreter + .halt(InstructionResult::FatalExternalError); return; }; - push!(interpreter, balance); + push!(context.interpreter, balance.data); } -pub fn extcodesize(interpreter: &mut Interpreter, host: &mut H) { - pop_address!(interpreter, address); - let Some((code, is_cold)) = host.code(address) else { - interpreter.instruction_result = InstructionResult::FatalExternalError; +/// Implements the EXTCODESIZE instruction. +/// +/// Gets the size of an account's code. +pub fn extcodesize( + context: InstructionContext<'_, H, WIRE>, +) { + popn_top!([], top, context.interpreter); + let address = top.into_address(); + let Some(code) = context.host.load_account_code(address) else { + context + .interpreter + .halt(InstructionResult::FatalExternalError); return; }; - if SPEC::enabled(BERLIN) { - gas!(interpreter, warm_cold_cost(is_cold)); - } else if SPEC::enabled(TANGERINE) { - gas!(interpreter, 700); + let spec_id = context.interpreter.runtime_flag.spec_id(); + if spec_id.is_enabled_in(BERLIN) { + gas!(context.interpreter, warm_cold_cost(code.is_cold)); + } else if spec_id.is_enabled_in(TANGERINE) { + gas!(context.interpreter, 700); } else { - gas!(interpreter, 20); + gas!(context.interpreter, 20); } - push!(interpreter, U256::from(code.len())); + *top = U256::from(code.len()); } /// EIP-1052: EXTCODEHASH opcode -pub fn extcodehash(interpreter: &mut Interpreter, host: &mut H) { - check!(interpreter, CONSTANTINOPLE); - pop_address!(interpreter, address); - let Some((code_hash, is_cold)) = host.code_hash(address) else { - interpreter.instruction_result = InstructionResult::FatalExternalError; +pub fn extcodehash( + context: InstructionContext<'_, H, WIRE>, +) { + check!(context.interpreter, CONSTANTINOPLE); + popn_top!([], top, context.interpreter); + let address = top.into_address(); + let Some(code_hash) = context.host.load_account_code_hash(address) else { + context + .interpreter + .halt(InstructionResult::FatalExternalError); return; }; - if SPEC::enabled(BERLIN) { - gas!(interpreter, warm_cold_cost(is_cold)); - } else if SPEC::enabled(ISTANBUL) { - gas!(interpreter, 700); + let spec_id = context.interpreter.runtime_flag.spec_id(); + if spec_id.is_enabled_in(BERLIN) { + gas!(context.interpreter, warm_cold_cost(code_hash.is_cold)); + } else if spec_id.is_enabled_in(ISTANBUL) { + gas!(context.interpreter, 700); } else { - gas!(interpreter, 400); + gas!(context.interpreter, 400); } - push_b256!(interpreter, code_hash); + *top = code_hash.into_u256(); } -pub fn extcodecopy(interpreter: &mut Interpreter, host: &mut H) { - pop_address!(interpreter, address); - pop!(interpreter, memory_offset, code_offset, len_u256); - - let Some((code, is_cold)) = host.code(address) else { - interpreter.instruction_result = InstructionResult::FatalExternalError; +/// Implements the EXTCODECOPY instruction. +/// +/// Copies a portion of an account's code to memory. +pub fn extcodecopy( + context: InstructionContext<'_, H, WIRE>, +) { + popn!( + [address, memory_offset, code_offset, len_u256], + context.interpreter + ); + let address = address.into_address(); + let Some(code) = context.host.load_account_code(address) else { + context + .interpreter + .halt(InstructionResult::FatalExternalError); return; }; - let len = as_usize_or_fail!(interpreter, len_u256); + let len = as_usize_or_fail!(context.interpreter, len_u256); gas_or_fail!( - interpreter, - gas::extcodecopy_cost(SPEC::SPEC_ID, len as u64, is_cold) + context.interpreter, + gas::extcodecopy_cost( + context.interpreter.runtime_flag.spec_id(), + len, + code.is_cold + ) ); if len == 0 { return; } - let memory_offset = as_usize_or_fail!(interpreter, memory_offset); + let memory_offset = as_usize_or_fail!(context.interpreter, memory_offset); let code_offset = min(as_usize_saturated!(code_offset), code.len()); - resize_memory!(interpreter, memory_offset, len); + resize_memory!(context.interpreter, memory_offset, len); - // Note: this can't panic because we resized memory to fit. - interpreter - .shared_memory - .set_data(memory_offset, code_offset, len, &code.original_bytes()); + // Note: This can't panic because we resized memory to fit. + context + .interpreter + .memory + .set_data(memory_offset, code_offset, len, &code); } -pub fn blockhash(interpreter: &mut Interpreter, host: &mut H) { - gas!(interpreter, gas::BLOCKHASH); - pop_top!(interpreter, number); +/// Implements the BLOCKHASH instruction. +/// +/// Gets the hash of one of the 256 most recent complete blocks. +pub fn blockhash( + context: InstructionContext<'_, H, WIRE>, +) { + gas!(context.interpreter, gas::BLOCKHASH); + popn_top!([], number, context.interpreter); - let Some(hash) = host.block_hash(*number) else { - interpreter.instruction_result = InstructionResult::FatalExternalError; + let requested_number = *number; + let block_number = context.host.block_number(); + + let Some(diff) = block_number.checked_sub(requested_number) else { + *number = U256::ZERO; return; }; - *number = U256::from_be_bytes(hash.0); + + let diff = as_u64_saturated!(diff); + + // blockhash should push zero if number is same as current block number. + if diff == 0 { + *number = U256::ZERO; + return; + } + + *number = if diff <= BLOCK_HASH_HISTORY { + let Some(hash) = context.host.block_hash(as_u64_saturated!(requested_number)) else { + context + .interpreter + .halt(InstructionResult::FatalExternalError); + return; + }; + U256::from_be_bytes(hash.0) + } else { + U256::ZERO + } } -pub fn sload(interpreter: &mut Interpreter, host: &mut H) { - pop_top!(interpreter, index); - let Some((value, is_cold)) = host.sload(interpreter.contract.target_address, *index) else { - interpreter.instruction_result = InstructionResult::FatalExternalError; +/// Implements the SLOAD instruction. +/// +/// Loads a word from storage. +pub fn sload(context: InstructionContext<'_, H, WIRE>) { + popn_top!([], index, context.interpreter); + + let Some(value) = context + .host + .sload(context.interpreter.input.target_address(), *index) + else { + context + .interpreter + .halt(InstructionResult::FatalExternalError); return; }; - gas!(interpreter, gas::sload_cost(SPEC::SPEC_ID, is_cold)); - *index = value; + + gas!( + context.interpreter, + gas::sload_cost(context.interpreter.runtime_flag.spec_id(), value.is_cold) + ); + *index = value.data; } -pub fn sstore(interpreter: &mut Interpreter, host: &mut H) { - require_non_staticcall!(interpreter); +/// Implements the SSTORE instruction. +/// +/// Stores a word to storage. +pub fn sstore(context: InstructionContext<'_, H, WIRE>) { + require_non_staticcall!(context.interpreter); + + popn!([index, value], context.interpreter); - pop!(interpreter, index, value); - let Some(SStoreResult { - original_value: original, - present_value: old, - new_value: new, - is_cold, - }) = host.sstore(interpreter.contract.target_address, index, value) + let Some(state_load) = + context + .host + .sstore(context.interpreter.input.target_address(), index, value) else { - interpreter.instruction_result = InstructionResult::FatalExternalError; + context + .interpreter + .halt(InstructionResult::FatalExternalError); return; }; - gas_or_fail!(interpreter, { - let remaining_gas = interpreter.gas.remaining(); - gas::sstore_cost(SPEC::SPEC_ID, original, old, new, remaining_gas, is_cold) - }); - refund!( - interpreter, - gas::sstore_refund(SPEC::SPEC_ID, original, old, new) + + // EIP-1706 Disable SSTORE with gasleft lower than call stipend + if context + .interpreter + .runtime_flag + .spec_id() + .is_enabled_in(ISTANBUL) + && context.interpreter.gas.remaining() <= CALL_STIPEND + { + context + .interpreter + .halt(InstructionResult::ReentrancySentryOOG); + return; + } + gas!( + context.interpreter, + gas::sstore_cost( + context.interpreter.runtime_flag.spec_id(), + &state_load.data, + state_load.is_cold + ) ); + + context.interpreter.gas.record_refund(gas::sstore_refund( + context.interpreter.runtime_flag.spec_id(), + &state_load.data, + )); } /// EIP-1153: Transient storage opcodes /// Store value to transient storage -pub fn tstore(interpreter: &mut Interpreter, host: &mut H) { - check!(interpreter, CANCUN); - require_non_staticcall!(interpreter); - gas!(interpreter, gas::WARM_STORAGE_READ_COST); +pub fn tstore(context: InstructionContext<'_, H, WIRE>) { + check!(context.interpreter, CANCUN); + require_non_staticcall!(context.interpreter); + gas!(context.interpreter, gas::WARM_STORAGE_READ_COST); - pop!(interpreter, index, value); + popn!([index, value], context.interpreter); - host.tstore(interpreter.contract.target_address, index, value); + context + .host + .tstore(context.interpreter.input.target_address(), index, value); } /// EIP-1153: Transient storage opcodes /// Load value from transient storage -pub fn tload(interpreter: &mut Interpreter, host: &mut H) { - check!(interpreter, CANCUN); - gas!(interpreter, gas::WARM_STORAGE_READ_COST); +pub fn tload(context: InstructionContext<'_, H, WIRE>) { + check!(context.interpreter, CANCUN); + gas!(context.interpreter, gas::WARM_STORAGE_READ_COST); - pop_top!(interpreter, index); + popn_top!([], index, context.interpreter); - *index = host.tload(interpreter.contract.target_address, *index); + *index = context + .host + .tload(context.interpreter.input.target_address(), *index); } -pub fn log(interpreter: &mut Interpreter, host: &mut H) { - require_non_staticcall!(interpreter); +/// Implements the LOG0-LOG4 instructions. +/// +/// Appends log record with N topics. +pub fn log( + context: InstructionContext<'_, H, impl InterpreterTypes>, +) { + require_non_staticcall!(context.interpreter); - pop!(interpreter, offset, len); - let len = as_usize_or_fail!(interpreter, len); - gas_or_fail!(interpreter, gas::log_cost(N as u8, len as u64)); + popn!([offset, len], context.interpreter); + let len = as_usize_or_fail!(context.interpreter, len); + gas_or_fail!(context.interpreter, gas::log_cost(N as u8, len as u64)); let data = if len == 0 { Bytes::new() } else { - let offset = as_usize_or_fail!(interpreter, offset); - resize_memory!(interpreter, offset, len); - Bytes::copy_from_slice(interpreter.shared_memory.slice(offset, len)) + let offset = as_usize_or_fail!(context.interpreter, offset); + resize_memory!(context.interpreter, offset, len); + Bytes::copy_from_slice(context.interpreter.memory.slice_len(offset, len).as_ref()) }; - - if interpreter.stack.len() < N { - interpreter.instruction_result = InstructionResult::StackUnderflow; + if context.interpreter.stack.len() < N { + context.interpreter.halt(InstructionResult::StackUnderflow); return; } - - let mut topics = Vec::with_capacity(N); - for _ in 0..N { - // SAFETY: stack bounds already checked few lines above - topics.push(B256::from(unsafe { interpreter.stack.pop_unsafe() })); - } + let Some(topics) = context.interpreter.stack.popn::() else { + context.interpreter.halt(InstructionResult::StackUnderflow); + return; + }; let log = Log { - address: interpreter.contract.target_address, - data: LogData::new(topics, data).expect("LogData should have <=4 topics"), + address: context.interpreter.input.target_address(), + data: LogData::new(topics.into_iter().map(B256::from).collect(), data) + .expect("LogData should have <=4 topics"), }; - host.log(log); + context.host.log(log); } -pub fn selfdestruct(interpreter: &mut Interpreter, host: &mut H) { - require_non_staticcall!(interpreter); - pop_address!(interpreter, target); +/// Implements the SELFDESTRUCT instruction. +/// +/// Halt execution and register account for later deletion. +pub fn selfdestruct( + context: InstructionContext<'_, H, WIRE>, +) { + require_non_staticcall!(context.interpreter); + popn!([target], context.interpreter); + let target = target.into_address(); - let Some(res) = host.selfdestruct(interpreter.contract.target_address, target) else { - interpreter.instruction_result = InstructionResult::FatalExternalError; + let Some(res) = context + .host + .selfdestruct(context.interpreter.input.target_address(), target) + else { + context + .interpreter + .halt(InstructionResult::FatalExternalError); return; }; // EIP-3529: Reduction in refunds - if !SPEC::enabled(LONDON) && !res.previously_destroyed { - refund!(interpreter, gas::SELFDESTRUCT) + if !context + .interpreter + .runtime_flag + .spec_id() + .is_enabled_in(LONDON) + && !res.previously_destroyed + { + context.interpreter.gas.record_refund(gas::SELFDESTRUCT) } - gas!(interpreter, gas::selfdestruct_cost(SPEC::SPEC_ID, res)); - interpreter.instruction_result = InstructionResult::SelfDestruct; + gas!( + context.interpreter, + gas::selfdestruct_cost(context.interpreter.runtime_flag.spec_id(), res) + ); + + context.interpreter.halt(InstructionResult::SelfDestruct); } diff --git a/crates/interpreter/src/instructions/host_env.rs b/crates/interpreter/src/instructions/host_env.rs deleted file mode 100644 index ce934d492f..0000000000 --- a/crates/interpreter/src/instructions/host_env.rs +++ /dev/null @@ -1,80 +0,0 @@ -use crate::{ - gas, - primitives::{Spec, SpecId::*, U256}, - Host, Interpreter, -}; - -/// EIP-1344: ChainID opcode -pub fn chainid(interpreter: &mut Interpreter, host: &mut H) { - check!(interpreter, ISTANBUL); - gas!(interpreter, gas::BASE); - push!(interpreter, U256::from(host.env().cfg.chain_id)); -} - -pub fn coinbase(interpreter: &mut Interpreter, host: &mut H) { - gas!(interpreter, gas::BASE); - push_b256!(interpreter, host.env().block.coinbase.into_word()); -} - -pub fn timestamp(interpreter: &mut Interpreter, host: &mut H) { - gas!(interpreter, gas::BASE); - push!(interpreter, host.env().block.timestamp); -} - -pub fn block_number(interpreter: &mut Interpreter, host: &mut H) { - gas!(interpreter, gas::BASE); - push!(interpreter, host.env().block.number); -} - -pub fn difficulty(interpreter: &mut Interpreter, host: &mut H) { - gas!(interpreter, gas::BASE); - if SPEC::enabled(MERGE) { - push_b256!(interpreter, host.env().block.prevrandao.unwrap()); - } else { - push!(interpreter, host.env().block.difficulty); - } -} - -pub fn gaslimit(interpreter: &mut Interpreter, host: &mut H) { - gas!(interpreter, gas::BASE); - push!(interpreter, host.env().block.gas_limit); -} - -pub fn gasprice(interpreter: &mut Interpreter, host: &mut H) { - gas!(interpreter, gas::BASE); - push!(interpreter, host.env().effective_gas_price()); -} - -/// EIP-3198: BASEFEE opcode -pub fn basefee(interpreter: &mut Interpreter, host: &mut H) { - check!(interpreter, LONDON); - gas!(interpreter, gas::BASE); - push!(interpreter, host.env().block.basefee); -} - -pub fn origin(interpreter: &mut Interpreter, host: &mut H) { - gas!(interpreter, gas::BASE); - push_b256!(interpreter, host.env().tx.caller.into_word()); -} - -// EIP-4844: Shard Blob Transactions -pub fn blob_hash(interpreter: &mut Interpreter, host: &mut H) { - check!(interpreter, CANCUN); - gas!(interpreter, gas::VERYLOW); - pop_top!(interpreter, index); - let i = as_usize_saturated!(index); - *index = match host.env().tx.blob_hashes.get(i) { - Some(hash) => U256::from_be_bytes(hash.0), - None => U256::ZERO, - }; -} - -/// EIP-7516: BLOBBASEFEE opcode -pub fn blob_basefee(interpreter: &mut Interpreter, host: &mut H) { - check!(interpreter, CANCUN); - gas!(interpreter, gas::BASE); - push!( - interpreter, - U256::from(host.env().block.get_blob_gasprice().unwrap_or_default()) - ); -} diff --git a/crates/interpreter/src/instructions/i256.rs b/crates/interpreter/src/instructions/i256.rs index d7f72446d9..e8f61b35d6 100644 --- a/crates/interpreter/src/instructions/i256.rs +++ b/crates/interpreter/src/instructions/i256.rs @@ -1,16 +1,21 @@ -use crate::primitives::U256; use core::cmp::Ordering; +use primitives::U256; +/// Represents the sign of a 256-bit signed integer value. #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(i8)] pub enum Sign { - // same as `cmp::Ordering` + // Same as `cmp::Ordering` + /// Negative value sign Minus = -1, + /// Zero value sign Zero = 0, #[allow(dead_code)] // "constructed" with `mem::transmute` in `i256_sign` below + /// Positive value sign Plus = 1, } +/// The maximum positive value for a 256-bit signed integer. pub const MAX_POSITIVE_VALUE: U256 = U256::from_limbs([ 0xffffffffffffffff, 0xffffffffffffffff, @@ -18,6 +23,7 @@ pub const MAX_POSITIVE_VALUE: U256 = U256::from_limbs([ 0x7fffffffffffffff, ]); +/// The minimum negative value for a 256-bit signed integer. pub const MIN_NEGATIVE_VALUE: U256 = U256::from_limbs([ 0x0000000000000000, 0x0000000000000000, @@ -25,18 +31,20 @@ pub const MIN_NEGATIVE_VALUE: U256 = U256::from_limbs([ 0x8000000000000000, ]); -const FLIPH_BITMASK_U64: u64 = 0x7FFFFFFFFFFFFFFF; +const FLIPH_BITMASK_U64: u64 = 0x7FFF_FFFF_FFFF_FFFF; +/// Determines the sign of a 256-bit signed integer. #[inline] pub fn i256_sign(val: &U256) -> Sign { if val.bit(U256::BITS - 1) { Sign::Minus } else { // SAFETY: false == 0 == Zero, true == 1 == Plus - unsafe { core::mem::transmute::(*val != U256::ZERO) } + unsafe { core::mem::transmute::(!val.is_zero()) } } } +/// Determines the sign of a 256-bit signed integer and converts it to its absolute value. #[inline] pub fn i256_sign_compl(val: &mut U256) -> Sign { let sign = i256_sign(val); @@ -54,28 +62,32 @@ fn u256_remove_sign(val: &mut U256) { } } +/// Computes the two's complement of a U256 value in place. #[inline] pub fn two_compl_mut(op: &mut U256) { *op = two_compl(*op); } +/// Computes the two's complement of a U256 value. #[inline] pub fn two_compl(op: U256) -> U256 { op.wrapping_neg() } +/// Compares two 256-bit signed integers. #[inline] pub fn i256_cmp(first: &U256, second: &U256) -> Ordering { let first_sign = i256_sign(first); let second_sign = i256_sign(second); match first_sign.cmp(&second_sign) { - // note: adding `if first_sign != Sign::Zero` to short circuit zero comparisons performs + // Note: Adding `if first_sign != Sign::Zero` to short circuit zero comparisons performs // slower on average, as of #582 Ordering::Equal => first.cmp(second), o => o, } } +/// Performs signed division of two 256-bit integers. #[inline] pub fn i256_div(mut first: U256, mut second: U256) -> U256 { let second_sign = i256_sign_compl(&mut second); @@ -88,14 +100,14 @@ pub fn i256_div(mut first: U256, mut second: U256) -> U256 { return two_compl(MIN_NEGATIVE_VALUE); } - // necessary overflow checks are done above, perform the division + // Necessary overflow checks are done above, perform the division let mut d = first / second; - // set sign bit to zero + // Set sign bit to zero u256_remove_sign(&mut d); - // two's complement only if the signs are different - // note: this condition has better codegen than an exhaustive match, as of #582 + // Two's complement only if the signs are different + // Note: This condition has better codegen than an exhaustive match, as of #582 if (first_sign == Sign::Minus && second_sign != Sign::Minus) || (second_sign == Sign::Minus && first_sign != Sign::Minus) { @@ -105,6 +117,7 @@ pub fn i256_div(mut first: U256, mut second: U256) -> U256 { } } +/// Performs signed modulo of two 256-bit integers. #[inline] pub fn i256_mod(mut first: U256, mut second: U256) -> U256 { let first_sign = i256_sign_compl(&mut first); @@ -119,7 +132,7 @@ pub fn i256_mod(mut first: U256, mut second: U256) -> U256 { let mut r = first % second; - // set sign bit to zero + // Set sign bit to zero u256_remove_sign(&mut r); if first_sign == Sign::Minus { @@ -132,8 +145,8 @@ pub fn i256_mod(mut first: U256, mut second: U256) -> U256 { #[cfg(test)] mod tests { use super::*; - use crate::primitives::uint; use core::num::Wrapping; + use primitives::uint; #[test] fn div_i256() { diff --git a/crates/interpreter/src/instructions/macros.rs b/crates/interpreter/src/instructions/macros.rs index 2592956ec7..b361c0369a 100644 --- a/crates/interpreter/src/instructions/macros.rs +++ b/crates/interpreter/src/instructions/macros.rs @@ -1,33 +1,45 @@ //! Utility macros to help implementing opcode instruction functions. +/// `const` Option `?`. +#[macro_export] +macro_rules! tri { + ($e:expr) => { + match $e { + Some(v) => v, + None => return None, + } + }; +} + /// Fails the instruction if the current call is static. #[macro_export] macro_rules! require_non_staticcall { - ($interp:expr) => { - if $interp.is_static { - $interp.instruction_result = $crate::InstructionResult::StateChangeDuringStaticCall; + ($interpreter:expr) => { + if $interpreter.runtime_flag.is_static() { + $interpreter.halt($crate::InstructionResult::StateChangeDuringStaticCall); return; } }; } -/// Error if the current call is executing EOF. +/// Macro for optional try - returns early if the expression evaluates to None. +/// Similar to the `?` operator but for use in instruction implementations. #[macro_export] -macro_rules! require_eof { - ($interp:expr) => { - if !$interp.is_eof { - $interp.instruction_result = $crate::InstructionResult::EOFOpcodeDisabledInLegacy; +macro_rules! otry { + ($expression: expr) => {{ + let Some(value) = $expression else { return; - } - }; + }; + value + }}; } -/// Error if not init eof call. +/// Error if the current call is executing EOF. #[macro_export] -macro_rules! require_init_eof { - ($interp:expr) => { - if !$interp.is_eof_init { - $interp.instruction_result = $crate::InstructionResult::ReturnContractInNotInitEOF; +macro_rules! require_eof { + ($interpreter:expr) => { + if !$interpreter.runtime_flag.is_eof() { + $interpreter.halt($crate::InstructionResult::EOFOpcodeDisabledInLegacy); return; } }; @@ -36,10 +48,13 @@ macro_rules! require_init_eof { /// Check if the `SPEC` is enabled, and fail the instruction if it is not. #[macro_export] macro_rules! check { - ($interp:expr, $min:ident) => { - // TODO: Force const-eval on the condition with a `const {}` block once they are stable - if !::enabled($crate::primitives::SpecId::$min) { - $interp.instruction_result = $crate::InstructionResult::NotActivated; + ($interpreter:expr, $min:ident) => { + if !$interpreter + .runtime_flag + .spec_id() + .is_enabled_in(primitives::hardfork::SpecId::$min) + { + $interpreter.halt($crate::InstructionResult::NotActivated); return; } }; @@ -48,229 +63,102 @@ macro_rules! check { /// Records a `gas` cost and fails the instruction if it would exceed the available gas. #[macro_export] macro_rules! gas { - ($interp:expr, $gas:expr) => { - $crate::gas!($interp, $gas, ()) + ($interpreter:expr, $gas:expr) => { + $crate::gas!($interpreter, $gas, ()) }; - ($interp:expr, $gas:expr, $ret:expr) => { - if !$interp.gas.record_cost($gas) { - $interp.instruction_result = $crate::InstructionResult::OutOfGas; + ($interpreter:expr, $gas:expr, $ret:expr) => { + if !$interpreter.gas.record_cost($gas) { + $interpreter.halt($crate::InstructionResult::OutOfGas); return $ret; } }; } -/// Records a `gas` refund. -#[macro_export] -macro_rules! refund { - ($interp:expr, $gas:expr) => { - $interp.gas.record_refund($gas) - }; -} - /// Same as [`gas!`], but with `gas` as an option. #[macro_export] macro_rules! gas_or_fail { - ($interp:expr, $gas:expr) => { + ($interpreter:expr, $gas:expr) => { + $crate::gas_or_fail!($interpreter, $gas, ()) + }; + ($interpreter:expr, $gas:expr, $ret:expr) => { match $gas { - Some(gas_used) => $crate::gas!($interp, gas_used), + Some(gas_used) => $crate::gas!($interpreter, gas_used, $ret), None => { - $interp.instruction_result = $crate::InstructionResult::OutOfGas; - return; + $interpreter.halt($crate::InstructionResult::OutOfGas); + return $ret; } } }; } -/// Resizes the interpreter memory if necessary. Fails the instruction if the memory or gas limit +/// Resizes the interpreterreter memory if necessary. Fails the instruction if the memory or gas limit /// is exceeded. #[macro_export] macro_rules! resize_memory { - ($interp:expr, $offset:expr, $len:expr) => { - $crate::resize_memory!($interp, $offset, $len, ()) - }; - ($interp:expr, $offset:expr, $len:expr, $ret:expr) => { - let new_size = $offset.saturating_add($len); - if new_size > $interp.shared_memory.len() { - #[cfg(feature = "memory_limit")] - if $interp.shared_memory.limit_reached(new_size) { - $interp.instruction_result = $crate::InstructionResult::MemoryLimitOOG; - return $ret; - } - - // Note: we can't use `Interpreter` directly here because of potential double-borrows. - if !$crate::interpreter::resize_memory( - &mut $interp.shared_memory, - &mut $interp.gas, - new_size, - ) { - $interp.instruction_result = $crate::InstructionResult::MemoryOOG; - return $ret; - } - } - }; -} - -/// Pops `Address` values from the stack. Fails the instruction if the stack is too small. -#[macro_export] -macro_rules! pop_address { - ($interp:expr, $x1:ident) => { - $crate::pop_address_ret!($interp, $x1, ()) - }; - ($interp:expr, $x1:ident, $x2:ident) => { - $crate::pop_address_ret!($interp, $x1, $x2, ()) - }; -} - -/// Pop `Address` values from the stack, returns `ret` on stack underflow. -#[macro_export] -macro_rules! pop_address_ret { - ($interp:expr, $x1:ident, $ret:expr) => { - if $interp.stack.len() < 1 { - $interp.instruction_result = $crate::InstructionResult::StackUnderflow; - return $ret; - } - // SAFETY: Length is checked above. - let $x1 = $crate::primitives::Address::from_word($crate::primitives::B256::from(unsafe { - $interp.stack.pop_unsafe() - })); - }; - ($interp:expr, $x1:ident, $x2:ident, $ret:expr) => { - if $interp.stack.len() < 2 { - $interp.instruction_result = $crate::InstructionResult::StackUnderflow; + ($interpreter:expr, $offset:expr, $len:expr) => { + $crate::resize_memory!($interpreter, $offset, $len, ()) + }; + ($interpreter:expr, $offset:expr, $len:expr, $ret:expr) => { + if !$crate::interpreter::resize_memory( + &mut $interpreter.gas, + &mut $interpreter.memory, + $offset, + $len, + ) { + $interpreter.halt($crate::InstructionResult::MemoryOOG); return $ret; } - // SAFETY: Length is checked above. - let $x1 = $crate::primitives::Address::from_word($crate::primitives::B256::from(unsafe { - $interp.stack.pop_unsafe() - })); - let $x2 = $crate::primitives::Address::from_word($crate::primitives::B256::from(unsafe { - $interp.stack.pop_unsafe() - })); }; } -/// Pops `U256` values from the stack. Fails the instruction if the stack is too small. +/// Pops n values from the stack. Fails the instruction if n values can't be popped. #[macro_export] -macro_rules! pop { - ($interp:expr, $x1:ident) => { - $crate::pop_ret!($interp, $x1, ()) - }; - ($interp:expr, $x1:ident, $x2:ident) => { - $crate::pop_ret!($interp, $x1, $x2, ()) - }; - ($interp:expr, $x1:ident, $x2:ident, $x3:ident) => { - $crate::pop_ret!($interp, $x1, $x2, $x3, ()) - }; - ($interp:expr, $x1:ident, $x2:ident, $x3:ident, $x4:ident) => { - $crate::pop_ret!($interp, $x1, $x2, $x3, $x4, ()) - }; - ($interp:expr, $x1:ident, $x2:ident, $x3:ident, $x4:ident, $x5:ident) => { - pop_ret!($interp, $x1, $x2, $x3, $x4, $x5, ()) +macro_rules! popn { + ([ $($x:ident),* ],$interpreterreter:expr $(,$ret:expr)? ) => { + let Some([$( $x ),*]) = $interpreterreter.stack.popn() else { + $interpreterreter.halt($crate::InstructionResult::StackUnderflow); + return $($ret)?; + }; }; } -/// Pops `U256` values from the stack, and returns `ret`. -/// Fails the instruction if the stack is too small. +#[doc(hidden)] #[macro_export] -macro_rules! pop_ret { - ($interp:expr, $x1:ident, $ret:expr) => { - if $interp.stack.len() < 1 { - $interp.instruction_result = $crate::InstructionResult::StackUnderflow; - return $ret; - } - // SAFETY: Length is checked above. - let $x1 = unsafe { $interp.stack.pop_unsafe() }; - }; - ($interp:expr, $x1:ident, $x2:ident, $ret:expr) => { - if $interp.stack.len() < 2 { - $interp.instruction_result = $crate::InstructionResult::StackUnderflow; - return $ret; - } - // SAFETY: Length is checked above. - let ($x1, $x2) = unsafe { $interp.stack.pop2_unsafe() }; - }; - ($interp:expr, $x1:ident, $x2:ident, $x3:ident, $ret:expr) => { - if $interp.stack.len() < 3 { - $interp.instruction_result = $crate::InstructionResult::StackUnderflow; - return $ret; - } - // SAFETY: Length is checked above. - let ($x1, $x2, $x3) = unsafe { $interp.stack.pop3_unsafe() }; - }; - ($interp:expr, $x1:ident, $x2:ident, $x3:ident, $x4:ident, $ret:expr) => { - if $interp.stack.len() < 4 { - $interp.instruction_result = $crate::InstructionResult::StackUnderflow; - return $ret; - } - // SAFETY: Length is checked above. - let ($x1, $x2, $x3, $x4) = unsafe { $interp.stack.pop4_unsafe() }; - }; - ($interp:expr, $x1:ident, $x2:ident, $x3:ident, $x4:ident, $x5:ident, $ret:expr) => { - if $interp.stack.len() < 4 { - $interp.instruction_result = $crate::InstructionResult::StackUnderflow; - return $ret; - } - // SAFETY: Length is checked above. - let ($x1, $x2, $x3, $x4, $x5) = unsafe { $interp.stack.pop5_unsafe() }; - }; +macro_rules! _count { + (@count) => { 0 }; + (@count $head:tt $($tail:tt)*) => { 1 + _count!(@count $($tail)*) }; + ($($arg:tt)*) => { _count!(@count $($arg)*) }; } -/// Pops `U256` values from the stack, and returns a reference to the top of the stack. -/// Fails the instruction if the stack is too small. +/// Pops n values from the stack and returns the top value. Fails the instruction if n values can't be popped. #[macro_export] -macro_rules! pop_top { - ($interp:expr, $x1:ident) => { - if $interp.stack.len() < 1 { - $interp.instruction_result = $crate::InstructionResult::StackUnderflow; - return; - } - // SAFETY: Length is checked above. - let $x1 = unsafe { $interp.stack.top_unsafe() }; - }; - ($interp:expr, $x1:ident, $x2:ident) => { - if $interp.stack.len() < 2 { - $interp.instruction_result = $crate::InstructionResult::StackUnderflow; - return; - } - // SAFETY: Length is checked above. - let ($x1, $x2) = unsafe { $interp.stack.pop_top_unsafe() }; - }; - ($interp:expr, $x1:ident, $x2:ident, $x3:ident) => { - if $interp.stack.len() < 3 { - $interp.instruction_result = $crate::InstructionResult::StackUnderflow; - return; - } - // SAFETY: Length is checked above. - let ($x1, $x2, $x3) = unsafe { $interp.stack.pop2_top_unsafe() }; - }; -} +macro_rules! popn_top { + ([ $($x:ident),* ], $top:ident, $interpreter:expr $(,$ret:expr)? ) => { + /* + let Some(([$( $x ),*], $top)) = $interpreter.stack.popn_top() else { + $interpreter.halt($crate::InstructionResult::StackUnderflow); + return $($ret)?; + }; + */ -/// Pushes `B256` values onto the stack. Fails the instruction if the stack is full. -#[macro_export] -macro_rules! push_b256 { - ($interp:expr, $($x:expr),* $(,)?) => ($( - match $interp.stack.push_b256($x) { - Ok(()) => {}, - Err(e) => { - $interp.instruction_result = e; - return; - }, + // Workaround for https://github.com/rust-lang/rust/issues/144329. + if $interpreter.stack.len() < (1 + $crate::_count!($($x)*)) { + $interpreter.halt($crate::InstructionResult::StackUnderflow); + return $($ret)?; } - )*) + let ([$( $x ),*], $top) = unsafe { $interpreter.stack.popn_top().unwrap_unchecked() }; + }; } /// Pushes a `B256` value onto the stack. Fails the instruction if the stack is full. #[macro_export] macro_rules! push { - ($interp:expr, $($x:expr),* $(,)?) => ($( - match $interp.stack.push($x) { - Ok(()) => {}, - Err(e) => { - $interp.instruction_result = e; - return; - } + ($interpreter:expr, $x:expr $(,$ret:item)?) => ( + if !($interpreter.stack.push($x)) { + $interpreter.halt($crate::InstructionResult::StackOverflow); + return $($ret)?; } - )*) + ) } /// Converts a `U256` value to a `u64`, saturating to `MAX` if the value is too large. @@ -302,7 +190,7 @@ macro_rules! as_usize_saturated { macro_rules! as_isize_saturated { ($v:expr) => { // `isize_try_from(u64::MAX)`` will fail and return isize::MAX - // this is expected behavior as we are saturating the value. + // This is expected behavior as we are saturating the value. isize::try_from($crate::as_u64_saturated!($v)).unwrap_or(isize::MAX) }; } @@ -310,11 +198,11 @@ macro_rules! as_isize_saturated { /// Converts a `U256` value to a `usize`, failing the instruction if the value is too large. #[macro_export] macro_rules! as_usize_or_fail { - ($interp:expr, $v:expr) => { - $crate::as_usize_or_fail_ret!($interp, $v, ()) + ($interpreter:expr, $v:expr) => { + $crate::as_usize_or_fail_ret!($interpreter, $v, ()) }; - ($interp:expr, $v:expr, $reason:expr) => { - $crate::as_usize_or_fail_ret!($interp, $v, $reason, ()) + ($interpreter:expr, $v:expr, $reason:expr) => { + $crate::as_usize_or_fail_ret!($interpreter, $v, $reason, ()) }; } @@ -322,20 +210,20 @@ macro_rules! as_usize_or_fail { /// failing the instruction if the value is too large. #[macro_export] macro_rules! as_usize_or_fail_ret { - ($interp:expr, $v:expr, $ret:expr) => { + ($interpreter:expr, $v:expr, $ret:expr) => { $crate::as_usize_or_fail_ret!( - $interp, + $interpreter, $v, $crate::InstructionResult::InvalidOperandOOG, $ret ) }; - ($interp:expr, $v:expr, $reason:expr, $ret:expr) => { + ($interpreter:expr, $v:expr, $reason:expr, $ret:expr) => { match $v.as_limbs() { x => { if (x[0] > usize::MAX as u64) | (x[1] != 0) | (x[2] != 0) | (x[3] != 0) { - $interp.instruction_result = $reason; + $interpreter.halt($reason); return $ret; } x[0] as usize diff --git a/crates/interpreter/src/instructions/memory.rs b/crates/interpreter/src/instructions/memory.rs index e5bdde911c..dff34d12c1 100644 --- a/crates/interpreter/src/instructions/memory.rs +++ b/crates/interpreter/src/instructions/memory.rs @@ -1,56 +1,79 @@ use crate::{ gas, - primitives::{Spec, U256}, - Host, Interpreter, + interpreter_types::{InterpreterTypes, MemoryTr, RuntimeFlag, StackTr}, }; use core::cmp::max; +use primitives::U256; -pub fn mload(interpreter: &mut Interpreter, _host: &mut H) { - gas!(interpreter, gas::VERYLOW); - pop_top!(interpreter, top); - let offset = as_usize_or_fail!(interpreter, top); - resize_memory!(interpreter, offset, 32); - *top = interpreter.shared_memory.get_u256(offset); +use crate::InstructionContext; + +/// Implements the MLOAD instruction. +/// +/// Loads a 32-byte word from memory. +pub fn mload(context: InstructionContext<'_, H, WIRE>) { + gas!(context.interpreter, gas::VERYLOW); + popn_top!([], top, context.interpreter); + let offset = as_usize_or_fail!(context.interpreter, top); + resize_memory!(context.interpreter, offset, 32); + *top = + U256::try_from_be_slice(context.interpreter.memory.slice_len(offset, 32).as_ref()).unwrap() } -pub fn mstore(interpreter: &mut Interpreter, _host: &mut H) { - gas!(interpreter, gas::VERYLOW); - pop!(interpreter, offset, value); - let offset = as_usize_or_fail!(interpreter, offset); - resize_memory!(interpreter, offset, 32); - interpreter.shared_memory.set_u256(offset, value); +/// Implements the MSTORE instruction. +/// +/// Stores a 32-byte word to memory. +pub fn mstore(context: InstructionContext<'_, H, WIRE>) { + gas!(context.interpreter, gas::VERYLOW); + popn!([offset, value], context.interpreter); + let offset = as_usize_or_fail!(context.interpreter, offset); + resize_memory!(context.interpreter, offset, 32); + context + .interpreter + .memory + .set(offset, &value.to_be_bytes::<32>()); } -pub fn mstore8(interpreter: &mut Interpreter, _host: &mut H) { - gas!(interpreter, gas::VERYLOW); - pop!(interpreter, offset, value); - let offset = as_usize_or_fail!(interpreter, offset); - resize_memory!(interpreter, offset, 1); - interpreter.shared_memory.set_byte(offset, value.byte(0)) +/// Implements the MSTORE8 instruction. +/// +/// Stores a single byte to memory. +pub fn mstore8(context: InstructionContext<'_, H, WIRE>) { + gas!(context.interpreter, gas::VERYLOW); + popn!([offset, value], context.interpreter); + let offset = as_usize_or_fail!(context.interpreter, offset); + resize_memory!(context.interpreter, offset, 1); + context.interpreter.memory.set(offset, &[value.byte(0)]); } -pub fn msize(interpreter: &mut Interpreter, _host: &mut H) { - gas!(interpreter, gas::BASE); - push!(interpreter, U256::from(interpreter.shared_memory.len())); +/// Implements the MSIZE instruction. +/// +/// Gets the size of active memory in bytes. +pub fn msize(context: InstructionContext<'_, H, WIRE>) { + gas!(context.interpreter, gas::BASE); + push!( + context.interpreter, + U256::from(context.interpreter.memory.size()) + ); } -// EIP-5656: MCOPY - Memory copying instruction -pub fn mcopy(interpreter: &mut Interpreter, _host: &mut H) { - check!(interpreter, CANCUN); - pop!(interpreter, dst, src, len); +/// Implements the MCOPY instruction. +/// +/// EIP-5656: Memory copying instruction that copies memory from one location to another. +pub fn mcopy(context: InstructionContext<'_, H, WIRE>) { + check!(context.interpreter, CANCUN); + popn!([dst, src, len], context.interpreter); - // into usize or fail - let len = as_usize_or_fail!(interpreter, len); - // deduce gas - gas_or_fail!(interpreter, gas::verylowcopy_cost(len as u64)); + // Into usize or fail + let len = as_usize_or_fail!(context.interpreter, len); + // Deduce gas + gas_or_fail!(context.interpreter, gas::copy_cost_verylow(len)); if len == 0 { return; } - let dst = as_usize_or_fail!(interpreter, dst); - let src = as_usize_or_fail!(interpreter, src); - // resize memory - resize_memory!(interpreter, max(dst, src), len); - // copy memory in place - interpreter.shared_memory.copy(dst, src, len); + let dst = as_usize_or_fail!(context.interpreter, dst); + let src = as_usize_or_fail!(context.interpreter, src); + // Resize memory + resize_memory!(context.interpreter, max(dst, src), len); + // Copy memory in place + context.interpreter.memory.copy(dst, src, len); } diff --git a/crates/interpreter/src/instructions/stack.rs b/crates/interpreter/src/instructions/stack.rs index d75067e1f2..cdfdceccd0 100644 --- a/crates/interpreter/src/instructions/stack.rs +++ b/crates/interpreter/src/instructions/stack.rs @@ -1,159 +1,69 @@ use crate::{ gas, - primitives::{Spec, U256}, - Host, Interpreter, + interpreter_types::{Immediates, InterpreterTypes, Jumps, RuntimeFlag, StackTr}, + InstructionResult, }; +use primitives::U256; -pub fn pop(interpreter: &mut Interpreter, _host: &mut H) { - gas!(interpreter, gas::BASE); - if let Err(result) = interpreter.stack.pop() { - interpreter.instruction_result = result; - } +use crate::InstructionContext; + +/// Implements the POP instruction. +/// +/// Removes the top item from the stack. +pub fn pop(context: InstructionContext<'_, H, WIRE>) { + gas!(context.interpreter, gas::BASE); + // Can ignore return. as relative N jump is safe operation. + popn!([_i], context.interpreter); } /// EIP-3855: PUSH0 instruction /// /// Introduce a new instruction which pushes the constant value 0 onto the stack. -pub fn push0(interpreter: &mut Interpreter, _host: &mut H) { - check!(interpreter, SHANGHAI); - gas!(interpreter, gas::BASE); - if let Err(result) = interpreter.stack.push(U256::ZERO) { - interpreter.instruction_result = result; - } +pub fn push0(context: InstructionContext<'_, H, WIRE>) { + check!(context.interpreter, SHANGHAI); + gas!(context.interpreter, gas::BASE); + push!(context.interpreter, U256::ZERO); } -pub fn push(interpreter: &mut Interpreter, _host: &mut H) { - gas!(interpreter, gas::VERYLOW); - // SAFETY: In analysis we append trailing bytes to the bytecode so that this is safe to do - // without bounds checking. - let ip = interpreter.instruction_pointer; - if let Err(result) = interpreter - .stack - .push_slice(unsafe { core::slice::from_raw_parts(ip, N) }) - { - interpreter.instruction_result = result; +/// Implements the PUSH1-PUSH32 instructions. +/// +/// Pushes N bytes from bytecode onto the stack as a 32-byte value. +pub fn push( + context: InstructionContext<'_, H, WIRE>, +) { + gas!(context.interpreter, gas::VERYLOW); + + let slice = context.interpreter.bytecode.read_slice(N); + if !context.interpreter.stack.push_slice(slice) { + context.interpreter.halt(InstructionResult::StackOverflow); return; } - interpreter.instruction_pointer = unsafe { ip.add(N) }; -} - -pub fn dup(interpreter: &mut Interpreter, _host: &mut H) { - gas!(interpreter, gas::VERYLOW); - if let Err(result) = interpreter.stack.dup(N) { - interpreter.instruction_result = result; - } -} - -pub fn swap(interpreter: &mut Interpreter, _host: &mut H) { - gas!(interpreter, gas::VERYLOW); - if let Err(result) = interpreter.stack.swap(N) { - interpreter.instruction_result = result; - } -} - -pub fn dupn(interpreter: &mut Interpreter, _host: &mut H) { - require_eof!(interpreter); - gas!(interpreter, gas::VERYLOW); - let imm = unsafe { *interpreter.instruction_pointer }; - if let Err(result) = interpreter.stack.dup(imm as usize + 1) { - interpreter.instruction_result = result; - } - interpreter.instruction_pointer = unsafe { interpreter.instruction_pointer.offset(1) }; -} -pub fn swapn(interpreter: &mut Interpreter, _host: &mut H) { - require_eof!(interpreter); - gas!(interpreter, gas::VERYLOW); - let imm = unsafe { *interpreter.instruction_pointer }; - if let Err(result) = interpreter.stack.swap(imm as usize + 1) { - interpreter.instruction_result = result; - } - interpreter.instruction_pointer = unsafe { interpreter.instruction_pointer.offset(1) }; + // Can ignore return. as relative N jump is safe operation + context.interpreter.bytecode.relative_jump(N as isize); } -pub fn exchange(interpreter: &mut Interpreter, _host: &mut H) { - require_eof!(interpreter); - gas!(interpreter, gas::VERYLOW); - let imm = unsafe { *interpreter.instruction_pointer }; - let n = (imm >> 4) + 1; - let m = (imm & 0x0F) + 1; - if let Err(result) = interpreter.stack.exchange(n as usize, m as usize) { - interpreter.instruction_result = result; +/// Implements the DUP1-DUP16 instructions. +/// +/// Duplicates the Nth stack item to the top of the stack. +pub fn dup( + context: InstructionContext<'_, H, WIRE>, +) { + gas!(context.interpreter, gas::VERYLOW); + if !context.interpreter.stack.dup(N) { + context.interpreter.halt(InstructionResult::StackOverflow); } - - interpreter.instruction_pointer = unsafe { interpreter.instruction_pointer.offset(1) }; } -#[cfg(test)] -mod test { - use super::*; - use crate::{ - opcode::{make_instruction_table, DUPN, EXCHANGE, SWAPN}, - primitives::{Bytecode, Bytes, PragueSpec}, - DummyHost, Gas, InstructionResult, - }; - - #[test] - fn dupn() { - let table = make_instruction_table::<_, PragueSpec>(); - let mut host = DummyHost::default(); - let mut interp = Interpreter::new_bytecode(Bytecode::LegacyRaw(Bytes::from([ - DUPN, 0x00, DUPN, 0x01, DUPN, 0x02, - ]))); - interp.is_eof = true; - interp.gas = Gas::new(10000); - - interp.stack.push(U256::from(10)).unwrap(); - interp.stack.push(U256::from(20)).unwrap(); - interp.step(&table, &mut host); - assert_eq!(interp.stack.pop(), Ok(U256::from(20))); - interp.step(&table, &mut host); - assert_eq!(interp.stack.pop(), Ok(U256::from(10))); - interp.step(&table, &mut host); - assert_eq!(interp.instruction_result, InstructionResult::StackUnderflow); - } - - #[test] - fn swapn() { - let table = make_instruction_table::<_, PragueSpec>(); - let mut host = DummyHost::default(); - let mut interp = - Interpreter::new_bytecode(Bytecode::LegacyRaw(Bytes::from([SWAPN, 0x00, SWAPN, 0x01]))); - interp.is_eof = true; - interp.gas = Gas::new(10000); - - interp.stack.push(U256::from(10)).unwrap(); - interp.stack.push(U256::from(20)).unwrap(); - interp.stack.push(U256::from(0)).unwrap(); - interp.step(&table, &mut host); - assert_eq!(interp.stack.peek(0), Ok(U256::from(20))); - assert_eq!(interp.stack.peek(1), Ok(U256::from(0))); - interp.step(&table, &mut host); - assert_eq!(interp.stack.peek(0), Ok(U256::from(10))); - assert_eq!(interp.stack.peek(2), Ok(U256::from(20))); - } - - #[test] - fn exchange() { - let table = make_instruction_table::<_, PragueSpec>(); - let mut host = DummyHost::default(); - let mut interp = Interpreter::new_bytecode(Bytecode::LegacyRaw(Bytes::from([ - EXCHANGE, 0x00, EXCHANGE, 0x11, - ]))); - interp.is_eof = true; - interp.gas = Gas::new(10000); - - interp.stack.push(U256::from(1)).unwrap(); - interp.stack.push(U256::from(5)).unwrap(); - interp.stack.push(U256::from(10)).unwrap(); - interp.stack.push(U256::from(15)).unwrap(); - interp.stack.push(U256::from(0)).unwrap(); - - interp.step(&table, &mut host); - assert_eq!(interp.stack.peek(1), Ok(U256::from(10))); - assert_eq!(interp.stack.peek(2), Ok(U256::from(15))); - interp.step(&table, &mut host); - assert_eq!(interp.stack.peek(2), Ok(U256::from(1))); - assert_eq!(interp.stack.peek(4), Ok(U256::from(15))); +/// Implements the SWAP1-SWAP16 instructions. +/// +/// Swaps the top stack item with the Nth stack item. +pub fn swap( + context: InstructionContext<'_, H, WIRE>, +) { + gas!(context.interpreter, gas::VERYLOW); + assert!(N != 0); + if !context.interpreter.stack.exchange(0, N) { + context.interpreter.halt(InstructionResult::StackOverflow); } } diff --git a/crates/interpreter/src/instructions/system.rs b/crates/interpreter/src/instructions/system.rs index 0887a874f4..6d3ba86570 100644 --- a/crates/interpreter/src/instructions/system.rs +++ b/crates/interpreter/src/instructions/system.rs @@ -1,210 +1,246 @@ use crate::{ gas, - primitives::{Spec, B256, KECCAK_EMPTY, U256}, - Host, InstructionResult, Interpreter, + interpreter::Interpreter, + interpreter_types::{ + InputsTr, InterpreterTypes, LegacyBytecode, MemoryTr, ReturnData, RuntimeFlag, StackTr, + }, + CallInput, InstructionResult, }; use core::ptr; +use primitives::{B256, KECCAK_EMPTY, U256}; -pub fn keccak256(interpreter: &mut Interpreter, _host: &mut H) { - pop_top!(interpreter, offset, len_ptr); - let len = as_usize_or_fail!(interpreter, len_ptr); - gas_or_fail!(interpreter, gas::keccak256_cost(len as u64)); +use crate::InstructionContext; + +/// Implements the KECCAK256 instruction. +/// +/// Computes Keccak-256 hash of memory data. +pub fn keccak256(context: InstructionContext<'_, H, WIRE>) { + popn_top!([offset], top, context.interpreter); + let len = as_usize_or_fail!(context.interpreter, top); + gas_or_fail!(context.interpreter, gas::keccak256_cost(len)); let hash = if len == 0 { KECCAK_EMPTY } else { - let from = as_usize_or_fail!(interpreter, offset); - resize_memory!(interpreter, from, len); - crate::primitives::keccak256(interpreter.shared_memory.slice(from, len)) + let from = as_usize_or_fail!(context.interpreter, offset); + resize_memory!(context.interpreter, from, len); + primitives::keccak256(context.interpreter.memory.slice_len(from, len).as_ref()) }; - *len_ptr = hash.into(); + *top = hash.into(); } -pub fn address(interpreter: &mut Interpreter, _host: &mut H) { - gas!(interpreter, gas::BASE); - push_b256!(interpreter, interpreter.contract.target_address.into_word()); +/// Implements the ADDRESS instruction. +/// +/// Pushes the current contract's address onto the stack. +pub fn address(context: InstructionContext<'_, H, WIRE>) { + gas!(context.interpreter, gas::BASE); + push!( + context.interpreter, + context + .interpreter + .input + .target_address() + .into_word() + .into() + ); } -pub fn caller(interpreter: &mut Interpreter, _host: &mut H) { - gas!(interpreter, gas::BASE); - push_b256!(interpreter, interpreter.contract.caller.into_word()); +/// Implements the CALLER instruction. +/// +/// Pushes the caller's address onto the stack. +pub fn caller(context: InstructionContext<'_, H, WIRE>) { + gas!(context.interpreter, gas::BASE); + push!( + context.interpreter, + context + .interpreter + .input + .caller_address() + .into_word() + .into() + ); } -pub fn codesize(interpreter: &mut Interpreter, _host: &mut H) { - gas!(interpreter, gas::BASE); - // Inform the optimizer that the bytecode cannot be EOF to remove a bounds check. - assume!(!interpreter.contract.bytecode.is_eof()); - push!(interpreter, U256::from(interpreter.contract.bytecode.len())); +/// Implements the CODESIZE instruction. +/// +/// Pushes the size of running contract's bytecode onto the stack. +pub fn codesize(context: InstructionContext<'_, H, WIRE>) { + gas!(context.interpreter, gas::BASE); + push!( + context.interpreter, + U256::from(context.interpreter.bytecode.bytecode_len()) + ); } -pub fn codecopy(interpreter: &mut Interpreter, _host: &mut H) { - pop!(interpreter, memory_offset, code_offset, len); - let len = as_usize_or_fail!(interpreter, len); - gas_or_fail!(interpreter, gas::verylowcopy_cost(len as u64)); - if len == 0 { +/// Implements the CODECOPY instruction. +/// +/// Copies running contract's bytecode to memory. +pub fn codecopy(context: InstructionContext<'_, H, WIRE>) { + popn!([memory_offset, code_offset, len], context.interpreter); + let len = as_usize_or_fail!(context.interpreter, len); + let Some(memory_offset) = memory_resize(context.interpreter, memory_offset, len) else { return; - } - let memory_offset = as_usize_or_fail!(interpreter, memory_offset); + }; let code_offset = as_usize_saturated!(code_offset); - resize_memory!(interpreter, memory_offset, len); - // Inform the optimizer that the bytecode cannot be EOF to remove a bounds check. - assume!(!interpreter.contract.bytecode.is_eof()); - // Note: this can't panic because we resized memory to fit. - interpreter.shared_memory.set_data( + // Note: This can't panic because we resized memory to fit. + context.interpreter.memory.set_data( memory_offset, code_offset, len, - &interpreter.contract.bytecode.original_bytes(), + context.interpreter.bytecode.bytecode_slice(), ); } -pub fn calldataload(interpreter: &mut Interpreter, _host: &mut H) { - gas!(interpreter, gas::VERYLOW); - pop_top!(interpreter, offset_ptr); +/// Implements the CALLDATALOAD instruction. +/// +/// Loads 32 bytes of input data from the specified offset. +pub fn calldataload(context: InstructionContext<'_, H, WIRE>) { + gas!(context.interpreter, gas::VERYLOW); + popn_top!([], offset_ptr, context.interpreter); let mut word = B256::ZERO; let offset = as_usize_saturated!(offset_ptr); - if offset < interpreter.contract.input.len() { - let count = 32.min(interpreter.contract.input.len() - offset); - // SAFETY: count is bounded by the calldata length. + let input = context.interpreter.input.input(); + let input_len = input.len(); + if offset < input_len { + let count = 32.min(input_len - offset); + + // SAFETY: `count` is bounded by the calldata length. // This is `word[..count].copy_from_slice(input[offset..offset + count])`, written using // raw pointers as apparently the compiler cannot optimize the slice version, and using // `get_unchecked` twice is uglier. - debug_assert!(count <= 32 && offset + count <= interpreter.contract.input.len()); - unsafe { - ptr::copy_nonoverlapping( - interpreter.contract.input.as_ptr().add(offset), - word.as_mut_ptr(), - count, - ) - }; + match context.interpreter.input.input() { + CallInput::Bytes(bytes) => { + unsafe { + ptr::copy_nonoverlapping(bytes.as_ptr().add(offset), word.as_mut_ptr(), count) + }; + } + CallInput::SharedBuffer(range) => { + let input_slice = context.interpreter.memory.global_slice(range.clone()); + unsafe { + ptr::copy_nonoverlapping( + input_slice.as_ptr().add(offset), + word.as_mut_ptr(), + count, + ) + }; + } + } } *offset_ptr = word.into(); } -pub fn calldatasize(interpreter: &mut Interpreter, _host: &mut H) { - gas!(interpreter, gas::BASE); - push!(interpreter, U256::from(interpreter.contract.input.len())); +/// Implements the CALLDATASIZE instruction. +/// +/// Pushes the size of input data onto the stack. +pub fn calldatasize(context: InstructionContext<'_, H, WIRE>) { + gas!(context.interpreter, gas::BASE); + push!( + context.interpreter, + U256::from(context.interpreter.input.input().len()) + ); } -pub fn callvalue(interpreter: &mut Interpreter, _host: &mut H) { - gas!(interpreter, gas::BASE); - push!(interpreter, interpreter.contract.call_value); +/// Implements the CALLVALUE instruction. +/// +/// Pushes the value sent with the current call onto the stack. +pub fn callvalue(context: InstructionContext<'_, H, WIRE>) { + gas!(context.interpreter, gas::BASE); + push!(context.interpreter, context.interpreter.input.call_value()); } -pub fn calldatacopy(interpreter: &mut Interpreter, _host: &mut H) { - pop!(interpreter, memory_offset, data_offset, len); - let len = as_usize_or_fail!(interpreter, len); - gas_or_fail!(interpreter, gas::verylowcopy_cost(len as u64)); - if len == 0 { +/// Implements the CALLDATACOPY instruction. +/// +/// Copies input data to memory. +pub fn calldatacopy(context: InstructionContext<'_, H, WIRE>) { + popn!([memory_offset, data_offset, len], context.interpreter); + let len = as_usize_or_fail!(context.interpreter, len); + let Some(memory_offset) = memory_resize(context.interpreter, memory_offset, len) else { return; - } - let memory_offset = as_usize_or_fail!(interpreter, memory_offset); - let data_offset = as_usize_saturated!(data_offset); - resize_memory!(interpreter, memory_offset, len); + }; - // Note: this can't panic because we resized memory to fit. - interpreter.shared_memory.set_data( - memory_offset, - data_offset, - len, - &interpreter.contract.input, - ); + let data_offset = as_usize_saturated!(data_offset); + match context.interpreter.input.input() { + CallInput::Bytes(bytes) => { + context + .interpreter + .memory + .set_data(memory_offset, data_offset, len, bytes.as_ref()); + } + CallInput::SharedBuffer(range) => { + context.interpreter.memory.set_data_from_global( + memory_offset, + data_offset, + len, + range.clone(), + ); + } + } } /// EIP-211: New opcodes: RETURNDATASIZE and RETURNDATACOPY -pub fn returndatasize(interpreter: &mut Interpreter, _host: &mut H) { - check!(interpreter, BYZANTIUM); - gas!(interpreter, gas::BASE); +pub fn returndatasize(context: InstructionContext<'_, H, WIRE>) { + check!(context.interpreter, BYZANTIUM); + gas!(context.interpreter, gas::BASE); push!( - interpreter, - U256::from(interpreter.return_data_buffer.len()) + context.interpreter, + U256::from(context.interpreter.return_data.buffer().len()) ); } /// EIP-211: New opcodes: RETURNDATASIZE and RETURNDATACOPY -pub fn returndatacopy(interpreter: &mut Interpreter, _host: &mut H) { - check!(interpreter, BYZANTIUM); - pop!(interpreter, memory_offset, offset, len); - let len = as_usize_or_fail!(interpreter, len); - gas_or_fail!(interpreter, gas::verylowcopy_cost(len as u64)); +pub fn returndatacopy(context: InstructionContext<'_, H, WIRE>) { + check!(context.interpreter, BYZANTIUM); + popn!([memory_offset, offset, len], context.interpreter); + + let len = as_usize_or_fail!(context.interpreter, len); let data_offset = as_usize_saturated!(offset); + + // Old legacy behavior is to panic if data_end is out of scope of return buffer. let data_end = data_offset.saturating_add(len); - if data_end > interpreter.return_data_buffer.len() { - interpreter.instruction_result = InstructionResult::OutOfOffset; + if data_end > context.interpreter.return_data.buffer().len() { + context.interpreter.halt(InstructionResult::OutOfOffset); return; } - if len != 0 { - let memory_offset = as_usize_or_fail!(interpreter, memory_offset); - resize_memory!(interpreter, memory_offset, len); - interpreter.shared_memory.set( - memory_offset, - &interpreter.return_data_buffer[data_offset..data_end], - ); - } -} -/// Part of EOF ``. -pub fn returndataload(interpreter: &mut Interpreter, _host: &mut H) { - require_eof!(interpreter); - gas!(interpreter, gas::VERYLOW); - pop_top!(interpreter, offset); - let offset_usize = as_usize_or_fail!(interpreter, offset); - if offset_usize.saturating_add(32) > interpreter.return_data_buffer.len() { - // TODO(EOF) proper error. - interpreter.instruction_result = InstructionResult::OutOfOffset; + let Some(memory_offset) = memory_resize(context.interpreter, memory_offset, len) else { return; - } - *offset = - B256::from_slice(&interpreter.return_data_buffer[offset_usize..offset_usize + 32]).into(); -} + }; -pub fn gas(interpreter: &mut Interpreter, _host: &mut H) { - gas!(interpreter, gas::BASE); - push!(interpreter, U256::from(interpreter.gas.remaining())); + // Note: This can't panic because we resized memory to fit. + context.interpreter.memory.set_data( + memory_offset, + data_offset, + len, + context.interpreter.return_data.buffer(), + ); } -#[cfg(test)] -mod test { - use super::*; - use crate::{ - opcode::{make_instruction_table, RETURNDATALOAD}, - primitives::{bytes, Bytecode, PragueSpec}, - DummyHost, Gas, - }; +/// Implements the GAS instruction. +/// +/// Pushes the amount of remaining gas onto the stack. +pub fn gas(context: InstructionContext<'_, H, WIRE>) { + gas!(context.interpreter, gas::BASE); + push!( + context.interpreter, + U256::from(context.interpreter.gas.remaining()) + ); +} - #[test] - fn returndataload() { - let table = make_instruction_table::<_, PragueSpec>(); - let mut host = DummyHost::default(); - - let mut interp = Interpreter::new_bytecode(Bytecode::LegacyRaw( - [RETURNDATALOAD, RETURNDATALOAD, RETURNDATALOAD].into(), - )); - interp.is_eof = true; - interp.gas = Gas::new(10000); - - interp.stack.push(U256::from(0)).unwrap(); - interp.return_data_buffer = - bytes!("000000000000000400000000000000030000000000000002000000000000000100"); - interp.step(&table, &mut host); - assert_eq!( - interp.stack.data(), - &vec![U256::from_limbs([0x01, 0x02, 0x03, 0x04])] - ); - - let _ = interp.stack.pop(); - let _ = interp.stack.push(U256::from(1)); - - interp.step(&table, &mut host); - assert_eq!(interp.instruction_result, InstructionResult::Continue); - assert_eq!( - interp.stack.data(), - &vec![U256::from_limbs([0x0100, 0x0200, 0x0300, 0x0400])] - ); - - let _ = interp.stack.pop(); - let _ = interp.stack.push(U256::from(2)); - interp.step(&table, &mut host); - assert_eq!(interp.instruction_result, InstructionResult::OutOfOffset); +/// Common logic for copying data from a source buffer to the EVM's memory. +/// +/// Handles memory expansion and gas calculation for data copy operations. +pub fn memory_resize( + interpreter: &mut Interpreter, + memory_offset: U256, + len: usize, +) -> Option { + // Safe to cast usize to u64 + gas_or_fail!(interpreter, gas::copy_cost_verylow(len), None); + if len == 0 { + return None; } + let memory_offset = as_usize_or_fail_ret!(interpreter, memory_offset, None); + resize_memory!(interpreter, memory_offset, len, None); + + Some(memory_offset) } diff --git a/crates/interpreter/src/instructions/tx_info.rs b/crates/interpreter/src/instructions/tx_info.rs new file mode 100644 index 0000000000..745c99a6be --- /dev/null +++ b/crates/interpreter/src/instructions/tx_info.rs @@ -0,0 +1,45 @@ +use crate::{ + gas, + interpreter_types::{InterpreterTypes, RuntimeFlag, StackTr}, + Host, +}; +use primitives::U256; + +use crate::InstructionContext; + +/// Implements the GASPRICE instruction. +/// +/// Gets the gas price of the originating transaction. +pub fn gasprice( + context: InstructionContext<'_, H, WIRE>, +) { + gas!(context.interpreter, gas::BASE); + push!( + context.interpreter, + U256::from(context.host.effective_gas_price()) + ); +} + +/// Implements the ORIGIN instruction. +/// +/// Gets the execution origination address. +pub fn origin(context: InstructionContext<'_, H, WIRE>) { + gas!(context.interpreter, gas::BASE); + push!( + context.interpreter, + context.host.caller().into_word().into() + ); +} + +/// Implements the BLOBHASH instruction. +/// +/// EIP-4844: Shard Blob Transactions - gets the hash of a transaction blob. +pub fn blob_hash( + context: InstructionContext<'_, H, WIRE>, +) { + check!(context.interpreter, CANCUN); + gas!(context.interpreter, gas::VERYLOW); + popn_top!([], index, context.interpreter); + let i = as_usize_saturated!(index); + *index = context.host.blob_hash(i).unwrap_or_default(); +} diff --git a/crates/interpreter/src/instructions/utility.rs b/crates/interpreter/src/instructions/utility.rs index 55b1212771..8a51ce9575 100644 --- a/crates/interpreter/src/instructions/utility.rs +++ b/crates/interpreter/src/instructions/utility.rs @@ -1,7 +1,46 @@ -pub(crate) unsafe fn read_i16(ptr: *const u8) -> i16 { - i16::from_be_bytes(core::slice::from_raw_parts(ptr, 2).try_into().unwrap()) +use primitives::{Address, B256, U256}; + +/// Trait for converting types into U256 values. +pub trait IntoU256 { + /// Converts the implementing type into a U256 value. + fn into_u256(self) -> U256; +} + +impl IntoU256 for Address { + fn into_u256(self) -> U256 { + self.into_word().into_u256() + } } -pub(crate) unsafe fn read_u16(ptr: *const u8) -> u16 { - u16::from_be_bytes(core::slice::from_raw_parts(ptr, 2).try_into().unwrap()) +impl IntoU256 for B256 { + fn into_u256(self) -> U256 { + U256::from_be_bytes(self.0) + } +} + +/// Trait for converting types into Address values. +pub trait IntoAddress { + /// Converts the implementing type into an Address value. + fn into_address(self) -> Address; +} + +impl IntoAddress for U256 { + fn into_address(self) -> Address { + Address::from_word(B256::from(self.to_be_bytes())) + } +} + +#[cfg(test)] +mod tests { + use primitives::address; + + use super::*; + + #[test] + fn test_into_u256() { + let addr = address!("0x0000000000000000000000000000000000000001"); + let u256 = addr.into_u256(); + assert_eq!(u256, U256::from(0x01)); + assert_eq!(u256.into_address(), addr); + } } diff --git a/crates/interpreter/src/interpreter.rs b/crates/interpreter/src/interpreter.rs index a27752b2e8..db0ae972f2 100644 --- a/crates/interpreter/src/interpreter.rs +++ b/crates/interpreter/src/interpreter.rs @@ -1,394 +1,299 @@ -pub mod analysis; -mod contract; -#[cfg(feature = "serde")] -pub mod serde; +//! Core interpreter implementation and components. + +/// Extended bytecode functionality. +pub mod ext_bytecode; +mod input; +mod loop_control; +mod return_data; +mod runtime_flags; mod shared_memory; mod stack; -pub use contract::Contract; -pub use shared_memory::{num_words, SharedMemory, EMPTY_SHARED_MEMORY}; +// re-exports +pub use ext_bytecode::ExtBytecode; +pub use input::InputsImpl; +pub use return_data::ReturnDataImpl; +pub use runtime_flags::RuntimeFlags; +pub use shared_memory::{num_words, resize_memory, SharedMemory}; pub use stack::{Stack, STACK_LIMIT}; -use crate::EOFCreateOutcome; +// imports use crate::{ - gas, primitives::Bytes, push, push_b256, return_ok, return_revert, CallOutcome, CreateOutcome, - FunctionStack, Gas, Host, InstructionResult, InterpreterAction, + host::DummyHost, instruction_context::InstructionContext, interpreter_types::*, Gas, Host, + InstructionResult, InstructionTable, InterpreterAction, }; -use core::cmp::min; -use revm_primitives::{Bytecode, Eof, U256}; -use std::borrow::ToOwned; +use bytecode::Bytecode; +use primitives::{hardfork::SpecId, Bytes}; -/// EVM bytecode interpreter. -#[derive(Debug)] -pub struct Interpreter { - /// The current instruction pointer. - pub instruction_pointer: *const u8, - /// The gas state. - pub gas: Gas, - /// Contract information and invoking data - pub contract: Contract, - /// The execution control flag. If this is not set to `Continue`, the interpreter will stop - /// execution. - pub instruction_result: InstructionResult, - /// Currently run Bytecode that instruction result will point to. - /// Bytecode is owned by the contract. - pub bytecode: Bytes, - /// Whether we are Interpreting the Ethereum Object Format (EOF) bytecode. - /// This is local field that is set from `contract.is_eof()`. - pub is_eof: bool, - /// Is init flag for eof create - pub is_eof_init: bool, - /// Shared memory. - /// - /// Note: This field is only set while running the interpreter loop. - /// Otherwise it is taken and replaced with empty shared memory. - pub shared_memory: SharedMemory, - /// Stack. - pub stack: Stack, - /// EOF function stack. - pub function_stack: FunctionStack, - /// The return data buffer for internal calls. - /// It has multi usage: - /// - /// * It contains the output bytes of call sub call. - /// * When this interpreter finishes execution it contains the output bytes of this contract. - pub return_data_buffer: Bytes, - /// Whether the interpreter is in "staticcall" mode, meaning no state changes can happen. - pub is_static: bool, - /// Actions that the EVM should do. - /// - /// Set inside CALL or CREATE instructions and RETURN or REVERT instructions. Additionally those instructions will set - /// InstructionResult to CallOrCreate/Return/Revert so we know the reason. - pub next_action: InterpreterAction, -} - -impl Default for Interpreter { - fn default() -> Self { - Self::new(Contract::default(), 0, false) - } -} - -/// The result of an interpreter operation. -#[derive(Clone, Debug, PartialEq, Eq)] +/// Main interpreter structure that contains all components defined in [`InterpreterTypes`]. +#[derive(Debug, Clone)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -pub struct InterpreterResult { - /// The result of the instruction execution. - pub result: InstructionResult, - /// The output of the instruction execution. - pub output: Bytes, - /// The gas usage information. +pub struct Interpreter { + /// Bytecode being executed. + pub bytecode: WIRE::Bytecode, + /// Gas tracking for execution costs. pub gas: Gas, + /// EVM stack for computation. + pub stack: WIRE::Stack, + /// Buffer for return data from calls. + pub return_data: WIRE::ReturnData, + /// EVM memory for data storage. + pub memory: WIRE::Memory, + /// Input data for current execution context. + pub input: WIRE::Input, + /// Runtime flags controlling execution behavior. + pub runtime_flag: WIRE::RuntimeFlag, + /// Extended functionality and customizations. + pub extend: WIRE::Extend, } -impl Interpreter { +impl Interpreter> { /// Create new interpreter - pub fn new(contract: Contract, gas_limit: u64, is_static: bool) -> Self { - if !contract.bytecode.is_execution_ready() { - panic!("Contract is not execution ready {:?}", contract.bytecode); - } - let is_eof = contract.bytecode.is_eof(); - let bytecode = contract.bytecode.bytecode().clone(); - Self { - instruction_pointer: bytecode.as_ptr(), + pub fn new( + memory: SharedMemory, + bytecode: ExtBytecode, + input: InputsImpl, + is_static: bool, + spec_id: SpecId, + gas_limit: u64, + ) -> Self { + Self::new_inner( + Stack::new(), + memory, bytecode, - contract, - gas: Gas::new(gas_limit), - instruction_result: InstructionResult::Continue, - function_stack: FunctionStack::default(), + input, is_static, - is_eof, - is_eof_init: false, - return_data_buffer: Bytes::new(), - shared_memory: EMPTY_SHARED_MEMORY, - stack: Stack::new(), - next_action: InterpreterAction::None, - } + spec_id, + gas_limit, + ) } - /// Set set is_eof_init to true, this is used to enable `RETURNCONTRACT` opcode. - #[inline] - pub fn set_is_eof_init(&mut self) { - self.is_eof_init = true; + /// Create a new interpreter with default extended functionality. + pub fn default_ext() -> Self { + Self::do_default(Stack::new(), SharedMemory::new()) } - #[inline] - pub fn eof(&self) -> Option<&Eof> { - self.contract.bytecode.eof() + /// Create a new invalid interpreter. + pub fn invalid() -> Self { + Self::do_default(Stack::invalid(), SharedMemory::invalid()) } - /// Test related helper - #[cfg(test)] - pub fn new_bytecode(bytecode: Bytecode) -> Self { - Self::new( - Contract::new( - Bytes::new(), - bytecode, - None, - crate::primitives::Address::default(), - crate::primitives::Address::default(), - U256::ZERO, - ), - 0, + fn do_default(stack: Stack, memory: SharedMemory) -> Self { + Self::new_inner( + stack, + memory, + ExtBytecode::default(), + InputsImpl::default(), false, + SpecId::default(), + u64::MAX, ) } - /// Load EOF code into interpreter. PC is assumed to be correctly set - pub(crate) fn load_eof_code(&mut self, idx: usize, pc: usize) { - // SAFETY: eof flag is true only if bytecode is Eof. - let Bytecode::Eof(eof) = &self.contract.bytecode else { - panic!("Expected EOF code section") - }; - let Some(code) = eof.body.code(idx) else { - panic!("Code not found") - }; - self.bytecode = code.clone(); - self.instruction_pointer = unsafe { self.bytecode.as_ptr().add(pc) }; + #[allow(clippy::too_many_arguments)] + fn new_inner( + stack: Stack, + memory: SharedMemory, + bytecode: ExtBytecode, + input: InputsImpl, + is_static: bool, + spec_id: SpecId, + gas_limit: u64, + ) -> Self { + Self { + bytecode, + gas: Gas::new(gas_limit), + stack, + return_data: Default::default(), + memory, + input, + runtime_flag: RuntimeFlags { is_static, spec_id }, + extend: Default::default(), + } } - /// Inserts the output of a `create` call into the interpreter. - /// - /// This function is used after a `create` call has been executed. It processes the outcome - /// of that call and updates the state of the interpreter accordingly. - /// - /// # Arguments - /// - /// * `create_outcome` - A `CreateOutcome` struct containing the results of the `create` call. - /// - /// # Behavior - /// - /// The function updates the `return_data_buffer` with the data from `create_outcome`. - /// Depending on the `InstructionResult` indicated by `create_outcome`, it performs one of the following: - /// - /// - `Ok`: Pushes the address from `create_outcome` to the stack, updates gas costs, and records any gas refunds. - /// - `Revert`: Pushes `U256::ZERO` to the stack and updates gas costs. - /// - `FatalExternalError`: Sets the `instruction_result` to `InstructionResult::FatalExternalError`. - /// - `Default`: Pushes `U256::ZERO` to the stack. - /// - /// # Side Effects - /// - /// - Updates `return_data_buffer` with the data from `create_outcome`. - /// - Modifies the stack by pushing values depending on the `InstructionResult`. - /// - Updates gas costs and records refunds in the interpreter's `gas` field. - /// - May alter `instruction_result` in case of external errors. - pub fn insert_create_outcome(&mut self, create_outcome: CreateOutcome) { - self.instruction_result = InstructionResult::Continue; - - let instruction_result = create_outcome.instruction_result(); - self.return_data_buffer = if instruction_result.is_revert() { - // Save data to return data buffer if the create reverted - create_outcome.output().to_owned() + /// Clears and reinitializes the interpreter with new parameters. + #[allow(clippy::too_many_arguments)] + pub fn clear( + &mut self, + memory: SharedMemory, + bytecode: ExtBytecode, + input: InputsImpl, + is_static: bool, + spec_id: SpecId, + gas_limit: u64, + ) { + let Self { + bytecode: bytecode_ref, + gas, + stack, + return_data, + memory: memory_ref, + input: input_ref, + runtime_flag, + extend, + } = self; + *bytecode_ref = bytecode; + *gas = Gas::new(gas_limit); + if stack.data().capacity() == 0 { + *stack = Stack::new(); } else { - // Otherwise clear it - Bytes::new() - }; - - match instruction_result { - return_ok!() => { - let address = create_outcome.address; - push_b256!(self, address.unwrap_or_default().into_word()); - self.gas.erase_cost(create_outcome.gas().remaining()); - self.gas.record_refund(create_outcome.gas().refunded()); - } - return_revert!() => { - push!(self, U256::ZERO); - self.gas.erase_cost(create_outcome.gas().remaining()); - } - InstructionResult::FatalExternalError => { - panic!("Fatal external error in insert_create_outcome"); - } - _ => { - push!(self, U256::ZERO); - } + stack.clear(); } + return_data.0.clear(); + *memory_ref = memory; + *input_ref = input; + *runtime_flag = RuntimeFlags { spec_id, is_static }; + *extend = EXT::default(); } - pub fn insert_eofcreate_outcome(&mut self, create_outcome: EOFCreateOutcome) { - let instruction_result = create_outcome.instruction_result(); - - self.return_data_buffer = if *instruction_result == InstructionResult::Revert { - // Save data to return data buffer if the create reverted - create_outcome.output().to_owned() - } else { - // Otherwise clear it. Note that RETURN opcode should abort. - Bytes::new() - }; - - match instruction_result { - InstructionResult::ReturnContract => { - push_b256!(self, create_outcome.address.into_word()); - self.gas.erase_cost(create_outcome.gas().remaining()); - self.gas.record_refund(create_outcome.gas().refunded()); - } - return_revert!() => { - push!(self, U256::ZERO); - self.gas.erase_cost(create_outcome.gas().remaining()); - } - InstructionResult::FatalExternalError => { - panic!("Fatal external error in insert_eofcreate_outcome"); - } - _ => { - push!(self, U256::ZERO); - } - } + /// Sets the bytecode that is going to be executed + pub fn with_bytecode(mut self, bytecode: Bytecode) -> Self { + self.bytecode = ExtBytecode::new(bytecode); + self } - /// Inserts the outcome of a call into the virtual machine's state. - /// - /// This function takes the result of a call, represented by `CallOutcome`, - /// and updates the virtual machine's state accordingly. It involves updating - /// the return data buffer, handling gas accounting, and setting the memory - /// in shared storage based on the outcome of the call. - /// - /// # Arguments - /// - /// * `shared_memory` - A mutable reference to the shared memory used by the virtual machine. - /// * `call_outcome` - The outcome of the call to be processed, containing details such as - /// instruction result, gas information, and output data. - /// - /// # Behavior - /// - /// The function first copies the output data from the call outcome to the virtual machine's - /// return data buffer. It then checks the instruction result from the call outcome: - /// - /// - `return_ok!()`: Processes successful execution, refunds gas, and updates shared memory. - /// - `return_revert!()`: Handles a revert by only updating the gas usage and shared memory. - /// - `InstructionResult::FatalExternalError`: Sets the instruction result to a fatal external error. - /// - Any other result: No specific action is taken. - pub fn insert_call_outcome( - &mut self, - shared_memory: &mut SharedMemory, - call_outcome: CallOutcome, - ) { - self.instruction_result = InstructionResult::Continue; - self.return_data_buffer.clone_from(call_outcome.output()); - - let out_offset = call_outcome.memory_start(); - let out_len = call_outcome.memory_length(); - - let target_len = min(out_len, self.return_data_buffer.len()); - match call_outcome.instruction_result() { - return_ok!() => { - // return unspend gas. - let remaining = call_outcome.gas().remaining(); - let refunded = call_outcome.gas().refunded(); - self.gas.erase_cost(remaining); - self.gas.record_refund(refunded); - shared_memory.set(out_offset, &self.return_data_buffer[..target_len]); - push!(self, U256::from(1)); - } - return_revert!() => { - self.gas.erase_cost(call_outcome.gas().remaining()); - shared_memory.set(out_offset, &self.return_data_buffer[..target_len]); - push!(self, U256::ZERO); - } - InstructionResult::FatalExternalError => { - panic!("Fatal external error in insert_call_outcome"); - } - _ => { - push!(self, U256::ZERO); - } - } + /// Sets the specid for the interpreter. + pub fn set_spec_id(&mut self, spec_id: SpecId) { + self.runtime_flag.spec_id = spec_id; } +} - /// Returns the opcode at the current instruction pointer. - #[inline] - pub fn current_opcode(&self) -> u8 { - unsafe { *self.instruction_pointer } +impl Default for Interpreter { + fn default() -> Self { + Self::default_ext() } +} - /// Returns a reference to the contract. +/// Default types for Ethereum interpreter. +#[derive(Debug)] +pub struct EthInterpreter { + _phantom: core::marker::PhantomData (EXT, MG)>, +} + +impl InterpreterTypes for EthInterpreter { + type Stack = Stack; + type Memory = SharedMemory; + type Bytecode = ExtBytecode; + type ReturnData = ReturnDataImpl; + type Input = InputsImpl; + type RuntimeFlag = RuntimeFlags; + type Extend = EXT; + type Output = InterpreterAction; +} + +impl Interpreter { + /// Performs EVM memory resize. #[inline] - pub fn contract(&self) -> &Contract { - &self.contract + #[must_use] + pub fn resize_memory(&mut self, offset: usize, len: usize) -> bool { + resize_memory(&mut self.gas, &mut self.memory, offset, len) } - /// Returns a reference to the interpreter's gas state. + /// Takes the next action from the control and returns it. #[inline] - pub fn gas(&self) -> &Gas { - &self.gas + pub fn take_next_action(&mut self) -> InterpreterAction { + // Return next action if it is some. + core::mem::take(self.bytecode.action()).expect("Interpreter to set action") } - /// Returns a reference to the interpreter's stack. - #[inline] - pub fn stack(&self) -> &Stack { - &self.stack + /// Halt the interpreter with the given result. + /// + /// This will set the action to [`InterpreterAction::Return`] and set the gas to the current gas. + #[cold] + #[inline(never)] + pub fn halt(&mut self, result: InstructionResult) { + self.bytecode + .set_action(InterpreterAction::new_halt(result, self.gas)); } - /// Returns the current program counter. - #[inline] - pub fn program_counter(&self) -> usize { - // SAFETY: `instruction_pointer` should be at an offset from the start of the bytecode. - // In practice this is always true unless a caller modifies the `instruction_pointer` field manually. - unsafe { self.instruction_pointer.offset_from(self.bytecode.as_ptr()) as usize } + /// Return with the given output. + /// + /// This will set the action to [`InterpreterAction::Return`] and set the gas to the current gas. + pub fn return_with_output(&mut self, output: Bytes) { + self.bytecode.set_action(InterpreterAction::new_return( + InstructionResult::Return, + output, + self.gas, + )); } /// Executes the instruction at the current instruction pointer. /// /// Internally it will increment instruction pointer by one. #[inline] - pub(crate) fn step(&mut self, instruction_table: &[FN; 256], host: &mut H) - where - FN: Fn(&mut Interpreter, &mut H), - { - // Get current opcode. - let opcode = unsafe { *self.instruction_pointer }; - - // SAFETY: In analysis we are doing padding of bytecode so that we are sure that last - // byte instruction is STOP so we are safe to just increment program_counter bcs on last instruction - // it will do noop and just stop execution of this contract - self.instruction_pointer = unsafe { self.instruction_pointer.offset(1) }; - - // execute instruction. - (instruction_table[opcode as usize])(self, host) + pub fn step(&mut self, instruction_table: &InstructionTable, host: &mut H) { + let context = InstructionContext { + interpreter: self, + host, + }; + context.step(instruction_table); } - /// Take memory and replace it with empty memory. - pub fn take_memory(&mut self) -> SharedMemory { - core::mem::replace(&mut self.shared_memory, EMPTY_SHARED_MEMORY) + /// Executes the instruction at the current instruction pointer. + /// + /// Internally it will increment instruction pointer by one. + /// + /// This uses dummy Host. + #[inline] + pub fn step_dummy(&mut self, instruction_table: &InstructionTable) { + let context = InstructionContext { + interpreter: self, + host: &mut DummyHost, + }; + context.step(instruction_table); } /// Executes the interpreter until it returns or stops. - pub fn run( + #[inline] + pub fn run_plain( &mut self, - shared_memory: SharedMemory, - instruction_table: &[FN; 256], + instruction_table: &InstructionTable, host: &mut H, - ) -> InterpreterAction - where - FN: Fn(&mut Interpreter, &mut H), - { - self.next_action = InterpreterAction::None; - self.shared_memory = shared_memory; - // main loop - while self.instruction_result == InstructionResult::Continue { - self.step(instruction_table, host); + ) -> InterpreterAction { + while self.bytecode.is_not_end() { + // Get current opcode. + let opcode = self.bytecode.opcode(); + + // SAFETY: In analysis we are doing padding of bytecode so that we are sure that last + // byte instruction is STOP so we are safe to just increment program_counter bcs on last instruction + // it will do noop and just stop execution of this contract + self.bytecode.relative_jump(1); + let context = InstructionContext { + interpreter: self, + host, + }; + // Execute instruction. + instruction_table[opcode as usize](context); } + self.bytecode.revert_to_previous_pointer(); - // Return next action if it is some. - if self.next_action.is_some() { - return core::mem::take(&mut self.next_action); - } - // If not, return action without output as it is a halt. - InterpreterAction::Return { - result: InterpreterResult { - result: self.instruction_result, - // return empty bytecode - output: Bytes::new(), - gas: self.gas, - }, - } + self.take_next_action() } +} - /// Resize the memory to the new size. Returns whether the gas was enough to resize the memory. - #[inline] - #[must_use] - pub fn resize_memory(&mut self, new_size: usize) -> bool { - resize_memory(&mut self.shared_memory, &mut self.gas, new_size) - } +/// The result of an interpreter operation. +#[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +pub struct InterpreterResult { + /// The result of the instruction execution. + pub result: InstructionResult, + /// The output of the instruction execution. + pub output: Bytes, + /// The gas usage information. + pub gas: Gas, } impl InterpreterResult { + /// Returns a new `InterpreterResult` with the given values. + pub fn new(result: InstructionResult, output: Bytes, gas: Gas) -> Self { + Self { + result, + output, + gas, + } + } + /// Returns whether the instruction result is a success. #[inline] pub const fn is_ok(&self) -> bool { @@ -408,40 +313,59 @@ impl InterpreterResult { } } -/// Resize the memory to the new size. Returns whether the gas was enough to resize the memory. -#[inline(never)] -#[cold] -#[must_use] -pub fn resize_memory(memory: &mut SharedMemory, gas: &mut Gas, new_size: usize) -> bool { - let new_words = num_words(new_size as u64); - let new_cost = gas::memory_gas(new_words); - let current_cost = memory.current_expansion_cost(); - let cost = new_cost - current_cost; - let success = gas.record_cost(cost); - if success { - memory.resize((new_words as usize) * 32); +// Special implementation for types where Output can be created from InterpreterAction +impl Interpreter +where + IW::Output: From, +{ + /// Takes the next action from the control and returns it as the specific Output type. + #[inline] + pub fn take_next_action_as_output(&mut self) -> IW::Output { + From::from(self.take_next_action()) + } + + /// Executes the interpreter until it returns or stops, returning the specific Output type. + #[inline] + pub fn run_plain_as_output( + &mut self, + instruction_table: &InstructionTable, + host: &mut H, + ) -> IW::Output { + From::from(self.run_plain(instruction_table, host)) } - success } #[cfg(test)] mod tests { - use super::*; - use crate::{opcode::InstructionTable, DummyHost}; - use revm_primitives::CancunSpec; - #[test] - fn object_safety() { - let mut interp = Interpreter::new(Contract::default(), u64::MAX, false); - - let mut host = crate::DummyHost::default(); - let table: InstructionTable = - crate::opcode::make_instruction_table::(); - let _ = interp.run(EMPTY_SHARED_MEMORY, &table, &mut host); - - let host: &mut dyn Host = &mut host as &mut dyn Host; - let table: InstructionTable = - crate::opcode::make_instruction_table::(); - let _ = interp.run(EMPTY_SHARED_MEMORY, &table, host); + #[cfg(feature = "serde")] + fn test_interpreter_serde() { + use super::*; + use bytecode::Bytecode; + use primitives::Bytes; + + let bytecode = Bytecode::new_raw(Bytes::from(&[0x60, 0x00, 0x60, 0x00, 0x01][..])); + let interpreter = Interpreter::::new( + SharedMemory::new(), + ExtBytecode::new(bytecode), + InputsImpl::default(), + false, + SpecId::default(), + u64::MAX, + ); + + let serialized = + bincode::serde::encode_to_vec(&interpreter, bincode::config::legacy()).unwrap(); + + let deserialized: Interpreter = + bincode::serde::decode_from_slice(&serialized, bincode::config::legacy()) + .unwrap() + .0; + + assert_eq!( + interpreter.bytecode.pc(), + deserialized.bytecode.pc(), + "Program counter should be preserved" + ); } } diff --git a/crates/interpreter/src/interpreter/analysis.rs b/crates/interpreter/src/interpreter/analysis.rs deleted file mode 100644 index 2b2d89f796..0000000000 --- a/crates/interpreter/src/interpreter/analysis.rs +++ /dev/null @@ -1,592 +0,0 @@ -use revm_primitives::{eof::EofDecodeError, HashSet}; - -use crate::{ - instructions::utility::{read_i16, read_u16}, - opcode, - primitives::{ - bitvec::prelude::{bitvec, BitVec, Lsb0}, - eof::TypesSection, - legacy::JumpTable, - Bytecode, Bytes, Eof, LegacyAnalyzedBytecode, - }, - OPCODE_INFO_JUMPTABLE, STACK_LIMIT, -}; -use std::{sync::Arc, vec, vec::Vec}; - -const EOF_NON_RETURNING_FUNCTION: u8 = 0x80; - -/// Perform bytecode analysis. -/// -/// The analysis finds and caches valid jump destinations for later execution as an optimization step. -/// -/// If the bytecode is already analyzed, it is returned as-is. -#[inline] -pub fn to_analysed(bytecode: Bytecode) -> Bytecode { - let (bytes, len) = match bytecode { - Bytecode::LegacyRaw(bytecode) => { - let len = bytecode.len(); - let mut padded_bytecode = Vec::with_capacity(len + 33); - padded_bytecode.extend_from_slice(&bytecode); - padded_bytecode.resize(len + 33, 0); - (Bytes::from(padded_bytecode), len) - } - n => return n, - }; - let jump_table = analyze(bytes.as_ref()); - - Bytecode::LegacyAnalyzed(LegacyAnalyzedBytecode::new(bytes, len, jump_table)) -} - -/// Analyze bytecode to build a jump map. -fn analyze(code: &[u8]) -> JumpTable { - let mut jumps: BitVec = bitvec![u8, Lsb0; 0; code.len()]; - - let range = code.as_ptr_range(); - let start = range.start; - let mut iterator = start; - let end = range.end; - while iterator < end { - let opcode = unsafe { *iterator }; - if opcode::JUMPDEST == opcode { - // SAFETY: jumps are max length of the code - unsafe { jumps.set_unchecked(iterator.offset_from(start) as usize, true) } - iterator = unsafe { iterator.offset(1) }; - } else { - let push_offset = opcode.wrapping_sub(opcode::PUSH1); - if push_offset < 32 { - // SAFETY: iterator access range is checked in the while loop - iterator = unsafe { iterator.offset((push_offset + 2) as isize) }; - } else { - // SAFETY: iterator access range is checked in the while loop - iterator = unsafe { iterator.offset(1) }; - } - } - } - - JumpTable(Arc::new(jumps)) -} - -pub fn validate_raw_eof(bytecode: Bytes) -> Result { - let eof = Eof::decode(bytecode)?; - validate_eof(&eof)?; - Ok(eof) -} - -/// Validate Eof structures. -pub fn validate_eof(eof: &Eof) -> Result<(), EofError> { - // clone is cheap as it is Bytes and a header. - let mut queue = vec![eof.clone()]; - - while let Some(eof) = queue.pop() { - // iterate over types - validate_eof_codes(&eof)?; - // iterate over containers, convert them to Eof and add to analyze_eof - for container in eof.body.container_section { - queue.push(Eof::decode(container)?); - } - } - - // Eof is valid - Ok(()) -} - -/// Validate EOF -pub fn validate_eof_codes(eof: &Eof) -> Result<(), EofValidationError> { - let mut queued_codes = vec![false; eof.body.code_section.len()]; - if eof.body.code_section.len() != eof.body.types_section.len() { - return Err(EofValidationError::InvalidTypesSection); - } - - if eof.body.code_section.is_empty() { - // no code sections. This should be already checked in decode. - return Err(EofValidationError::NoCodeSections); - } - // first section is default one. - queued_codes[0] = true; - - // the first code section must have a type signature - // (0, 0x80, max_stack_height) (0 inputs non-returning function) - let first_types = &eof.body.types_section[0]; - if first_types.inputs != 0 || first_types.outputs != EOF_NON_RETURNING_FUNCTION { - return Err(EofValidationError::InvalidTypesSection); - } - - // start validation from code section 0. - let mut queue = vec![0]; - while let Some(index) = queue.pop() { - let code = &eof.body.code_section[index]; - let accessed_codes = validate_eof_code( - code, - eof.header.data_size as usize, - index, - eof.body.container_section.len(), - &eof.body.types_section, - )?; - - // queue accessed codes. - accessed_codes.into_iter().for_each(|i| { - if !queued_codes[i] { - queued_codes[i] = true; - queue.push(i); - } - }); - } - // iterate over accessed codes and check if all are accessed. - if queued_codes.into_iter().any(|x| !x) { - return Err(EofValidationError::CodeSectionNotAccessed); - } - - Ok(()) -} - -/// EOF Error. -#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)] -pub enum EofError { - Decode(EofDecodeError), - Validation(EofValidationError), -} - -impl From for EofError { - fn from(err: EofDecodeError) -> Self { - EofError::Decode(err) - } -} - -impl From for EofError { - fn from(err: EofValidationError) -> Self { - EofError::Validation(err) - } -} - -#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)] -pub enum EofValidationError { - FalsePossitive, - /// Opcode is not known. It is not defined in the opcode table. - UnknownOpcode, - /// Opcode is disabled in EOF. For example JUMP, JUMPI, etc. - OpcodeDisabled, - /// Every instruction inside bytecode should be forward accessed. - /// Forward access can be a jump or sequential opcode. - /// In case after terminal opcode there should be a forward jump. - InstructionNotForwardAccessed, - /// Bytecode is too small and is missing immediate bytes for instruction. - MissingImmediateBytes, - /// Similar to [`EofValidationError::MissingImmediateBytes`] but for special case of RJUMPV immediate bytes. - MissingRJUMPVImmediateBytes, - /// Invalid jump into immediate bytes. - JumpToImmediateBytes, - /// Invalid jump into immediate bytes. - BackwardJumpToImmediateBytes, - /// MaxIndex in RJUMPV can't be zero. Zero max index makes it RJUMPI. - RJUMPVZeroMaxIndex, - /// Jump with zero offset would make a jump to next opcode, it does not make sense. - JumpZeroOffset, - /// EOFCREATE points to container out of bounds. - EOFCREATEInvalidIndex, - /// CALLF section out of bounds. - CodeSectionOutOfBounds, - /// CALLF to non returning function is not allowed. - CALLFNonReturningFunction, - /// CALLF stack overflow. - StackOverflow, - /// JUMPF needs to have enough outputs. - JUMPFEnoughOutputs, - /// JUMPF Stack - JUMPFStackHigherThanOutputs, - /// DATA load out of bounds. - DataLoadOutOfBounds, - /// RETF biggest stack num more then outputs. - RETFBiggestStackNumMoreThenOutputs, - /// Stack requirement is more than smallest stack items. - StackUnderflow, - /// Smallest stack items is more than types output. - TypesStackUnderflow, - /// Jump out of bounds. - JumpUnderflow, - /// Jump to out of bounds. - JumpOverflow, - /// Backward jump should have same smallest and biggest stack items. - BackwardJumpBiggestNumMismatch, - /// Backward jump should have same smallest and biggest stack items. - BackwardJumpSmallestNumMismatch, - /// Last instruction should be terminating. - LastInstructionNotTerminating, - /// Code section not accessed. - CodeSectionNotAccessed, - /// Types section invalid - InvalidTypesSection, - /// First types section is invalid. - /// It should have inputs 0 and outputs 0x80. - InvalidFirstTypesSection, - /// Max stack element mismatch. - MaxStackMismatch, - /// No code sections present - NoCodeSections, -} - -/// Validates that: -/// * All instructions are valid. -/// * It ends with a terminating instruction or RJUMP. -/// * All instructions are accessed by forward jumps or . -/// -/// Validate stack requirements and if all codes sections are used. -/// -/// TODO mark accessed Types/Codes -/// -/// Preconditions: -/// * Jump destinations are valid. -/// * All instructions are valid and well formed. -/// * All instruction is accessed by forward jumps. -/// * Bytecode is valid and ends with terminating instruction. -/// -/// Preconditions are checked in `validate_eof_bytecode`. -pub fn validate_eof_code( - code: &[u8], - data_size: usize, - this_types_index: usize, - num_of_containers: usize, - types: &[TypesSection], -) -> Result, EofValidationError> { - let mut accessed_codes = HashSet::::new(); - let this_types = &types[this_types_index]; - - #[derive(Debug, Copy, Clone)] - struct InstructionInfo { - /// Is immediate byte, jumps can't happen on this part of code. - is_immediate: bool, - /// Have forward jump to this opcode. Used to check if opcode - /// after termination is accessed. - is_jumpdest: bool, - /// Smallest number of stack items accessed by jumps or sequential opcodes. - smallest: i32, - /// Biggest number of stack items accessed by jumps or sequential opcodes. - biggest: i32, - } - - impl InstructionInfo { - #[inline] - fn mark_as_immediate(&mut self) -> Result<(), EofValidationError> { - if self.is_jumpdest { - // Jump to immediate bytes. - return Err(EofValidationError::JumpToImmediateBytes); - } - self.is_immediate = true; - Ok(()) - } - } - - impl Default for InstructionInfo { - fn default() -> Self { - Self { - is_immediate: false, - is_jumpdest: false, - smallest: i32::MAX, - biggest: i32::MIN, - } - } - } - - // all bytes that are intermediate. - let mut jumps = vec![InstructionInfo::default(); code.len()]; - let mut is_after_termination = false; - - let mut next_smallest = this_types.inputs as i32; - let mut next_biggest = this_types.inputs as i32; - - let mut i = 0; - // We can check validity and jump destinations in one pass. - while i < code.len() { - let op = code[i]; - let opcode = &OPCODE_INFO_JUMPTABLE[op as usize]; - - let Some(opcode) = opcode else { - // err unknown opcode. - return Err(EofValidationError::UnknownOpcode); - }; - - if opcode.is_disabled_in_eof() { - // Opcode is disabled in EOF - return Err(EofValidationError::OpcodeDisabled); - } - - let this_instruction = &mut jumps[i]; - - // update biggest/smallest values for next instruction only if it is not after termination. - if !is_after_termination { - this_instruction.smallest = core::cmp::min(this_instruction.smallest, next_smallest); - this_instruction.biggest = core::cmp::max(this_instruction.biggest, next_biggest); - } - - let this_instruction = *this_instruction; - - // Opcodes after termination should be accessed by forward jumps. - if is_after_termination && !this_instruction.is_jumpdest { - // opcode after termination was not accessed. - return Err(EofValidationError::InstructionNotForwardAccessed); - } - is_after_termination = opcode.is_terminating(); - - // mark immediate as non-jumpable. RJUMPV is special case covered later. - if opcode.immediate_size() != 0 { - // check if the opcode immediate are within the bounds of the code - if i + opcode.immediate_size() as usize >= code.len() { - // Malfunctional code - return Err(EofValidationError::MissingImmediateBytes); - } - - // mark immediate bytes as non-jumpable. - for imm in 1..opcode.immediate_size() as usize + 1 { - // SAFETY: immediate size is checked above. - jumps[i + imm].mark_as_immediate()?; - } - } - // IO diff used to generate next instruction smallest/biggest value. - let mut stack_io_diff = opcode.io_diff() as i32; - // how many stack items are required for this opcode. - let mut stack_requirement = opcode.inputs() as i32; - // additional immediate bytes for RJUMPV, it has dynamic vtable. - let mut rjumpv_additional_immediates = 0; - // If opcodes is RJUMP, RJUMPI or RJUMPV then this will have absolute jumpdest. - let mut absolute_jumpdest = vec![]; - match op { - opcode::RJUMP | opcode::RJUMPI => { - let offset = unsafe { read_i16(code.as_ptr().add(i + 1)) } as isize; - absolute_jumpdest = vec![offset + 3 + i as isize]; - // RJUMP is considered a terminating opcode. - } - opcode::RJUMPV => { - // code length for RJUMPV is checked with immediate size. - let max_index = code[i + 1] as usize; - let len = max_index + 1; - // and max_index+1 is to get size of vtable as index starts from 0. - rjumpv_additional_immediates = len * 2; - - // +1 is for max_index byte - if i + 1 + rjumpv_additional_immediates >= code.len() { - // Malfunctional code RJUMPV vtable is not complete - return Err(EofValidationError::MissingRJUMPVImmediateBytes); - } - - // Mark vtable as immediate, max_index was already marked. - for imm in 0..rjumpv_additional_immediates { - // SAFETY: immediate size is checked above. - jumps[i + 2 + imm].mark_as_immediate()?; - } - - let mut jumps = Vec::with_capacity(len); - for vtablei in 0..len { - let offset = - unsafe { read_i16(code.as_ptr().add(i + 2 + 2 * vtablei)) } as isize; - jumps.push(offset + i as isize + 2 + rjumpv_additional_immediates as isize); - } - absolute_jumpdest = jumps - } - opcode::CALLF => { - let section_i = unsafe { read_u16(code.as_ptr().add(i + 1)) } as usize; - let Some(target_types) = types.get(section_i) else { - // code section out of bounds. - return Err(EofValidationError::CodeSectionOutOfBounds); - }; - - if target_types.outputs == EOF_NON_RETURNING_FUNCTION { - // callf to non returning function is not allowed - return Err(EofValidationError::CALLFNonReturningFunction); - } - // stack input for this opcode is the input of the called code. - stack_requirement = target_types.inputs as i32; - // stack diff depends on input/output of the called code. - stack_io_diff = target_types.io_diff(); - // mark called code as accessed. - accessed_codes.insert(section_i); - - // we decrement by `types.inputs` as they are considered as send - // to the called code and included in types.max_stack_size. - if this_instruction.biggest - stack_requirement + target_types.max_stack_size as i32 - > STACK_LIMIT as i32 - { - // if stack max items + called code max stack size - return Err(EofValidationError::StackOverflow); - } - } - opcode::JUMPF => { - let target_index = unsafe { read_u16(code.as_ptr().add(i + 1)) } as usize; - // targeted code needs to have zero outputs (be non returning). - let Some(target_types) = types.get(target_index) else { - // code section out of bounds. - return Err(EofValidationError::CodeSectionOutOfBounds); - }; - - // we decrement types.inputs as they are considered send to the called code. - // and included in types.max_stack_size. - if this_instruction.biggest - target_types.inputs as i32 - + target_types.max_stack_size as i32 - > STACK_LIMIT as i32 - { - // stack overflow - return Err(EofValidationError::StackOverflow); - } - accessed_codes.insert(target_index); - - if target_types.outputs == EOF_NON_RETURNING_FUNCTION { - // if it is not returning - stack_requirement = target_types.inputs as i32; - } else { - // check if target code produces enough outputs. - if this_types.outputs < target_types.outputs { - return Err(EofValidationError::JUMPFEnoughOutputs); - } - - stack_requirement = this_types.outputs as i32 + target_types.inputs as i32 - - target_types.outputs as i32; - - // Stack requirement needs to more than this instruction biggest stack number. - if this_instruction.biggest > stack_requirement { - return Err(EofValidationError::JUMPFStackHigherThanOutputs); - } - - // if this instruction max + target_types max is more then stack limit. - if this_instruction.biggest + stack_requirement > STACK_LIMIT as i32 { - return Err(EofValidationError::StackOverflow); - } - } - } - opcode::EOFCREATE => { - let index = code[i + 1] as usize; - if index >= num_of_containers { - // code section out of bounds. - return Err(EofValidationError::EOFCREATEInvalidIndex); - } - } - opcode::DATALOADN => { - let index = unsafe { read_u16(code.as_ptr().add(i + 1)) } as isize; - if data_size < 32 || index > data_size as isize - 32 { - // data load out of bounds. - return Err(EofValidationError::DataLoadOutOfBounds); - } - } - opcode::RETF => { - stack_requirement = this_types.outputs as i32; - if this_instruction.biggest > stack_requirement { - return Err(EofValidationError::RETFBiggestStackNumMoreThenOutputs); - } - } - opcode::DUPN => { - stack_requirement = code[i + 1] as i32 + 1; - } - opcode::SWAPN => { - stack_requirement = code[i + 1] as i32 + 2; - } - opcode::EXCHANGE => { - let imm = code[i + 1]; - let n = (imm >> 4) + 1; - let m = (imm & 0x0F) + 1; - stack_requirement = n as i32 + m as i32 + 1; - } - _ => {} - } - // check if stack requirement is more than smallest stack items. - if stack_requirement > this_instruction.smallest { - // opcode requirement is more than smallest stack items. - return Err(EofValidationError::StackUnderflow); - } - - next_smallest = this_instruction.smallest + stack_io_diff; - next_biggest = this_instruction.biggest + stack_io_diff; - - // check if jumpdest are correct and mark forward jumps. - for absolute_jump in absolute_jumpdest { - if absolute_jump < 0 { - // jump out of bounds. - return Err(EofValidationError::JumpUnderflow); - } - if absolute_jump >= code.len() as isize { - // jump to out of bounds - return Err(EofValidationError::JumpOverflow); - } - // fine to cast as bounds are checked. - let absolute_jump = absolute_jump as usize; - - let target_jump = &mut jumps[absolute_jump]; - if target_jump.is_immediate { - // Jump target is immediate byte. - return Err(EofValidationError::BackwardJumpToImmediateBytes); - } - - // needed to mark forward jumps. It does not do anything for backward jumps. - target_jump.is_jumpdest = true; - - if absolute_jump <= i { - // backward jumps should have same smallest and biggest stack items. - if target_jump.biggest != next_biggest { - // wrong jumpdest. - return Err(EofValidationError::BackwardJumpBiggestNumMismatch); - } - if target_jump.smallest != next_smallest { - // wrong jumpdest. - return Err(EofValidationError::BackwardJumpSmallestNumMismatch); - } - } else { - // forward jumps can make min even smallest size - // while biggest num is needed to check stack overflow - target_jump.smallest = core::cmp::min(target_jump.smallest, next_smallest); - target_jump.biggest = core::cmp::max(target_jump.biggest, next_biggest); - } - } - - // additional immediate are from RJUMPV vtable. - i += 1 + opcode.immediate_size() as usize + rjumpv_additional_immediates; - } - - // last opcode should be terminating - if !is_after_termination { - // wrong termination. - return Err(EofValidationError::LastInstructionNotTerminating); - } - // TODO integrate max so we dont need to iterate again - let mut max_stack_requirement = 0; - for opcode in jumps { - max_stack_requirement = core::cmp::max(opcode.biggest, max_stack_requirement); - } - - if max_stack_requirement != types[this_types_index].max_stack_size as i32 { - // stack overflow - return Err(EofValidationError::MaxStackMismatch); - } - - Ok(accessed_codes) -} - -#[cfg(test)] -mod test { - use super::*; - use revm_primitives::hex; - - #[test] - fn test1() { - // result:Result { result: false, exception: Some("EOF_ConflictingStackHeight") } - let err = - validate_raw_eof(hex!("ef0001010004020001000704000000008000016000e200fffc00").into()); - assert!(err.is_err(), "{err:#?}"); - } - - #[test] - fn test2() { - // result:Result { result: false, exception: Some("EOF_InvalidNumberOfOutputs") } - let err = - validate_raw_eof(hex!("ef000101000c02000300040004000204000000008000020002000100010001e30001005fe500025fe4").into()); - assert!(err.is_ok(), "{err:#?}"); - } - - #[test] - fn test3() { - // result:Result { result: false, exception: Some("EOF_InvalidNumberOfOutputs") } - let err = - validate_raw_eof(hex!("ef000101000c02000300040008000304000000008000020002000503010003e30001005f5f5f5f5fe500025050e4").into()); - assert_eq!( - err, - Err(EofError::Validation( - EofValidationError::JUMPFStackHigherThanOutputs - )) - ); - } -} diff --git a/crates/interpreter/src/interpreter/contract.rs b/crates/interpreter/src/interpreter/contract.rs deleted file mode 100644 index f8625e8533..0000000000 --- a/crates/interpreter/src/interpreter/contract.rs +++ /dev/null @@ -1,92 +0,0 @@ -use super::analysis::to_analysed; -use crate::{ - primitives::{Address, Bytecode, Bytes, Env, TransactTo, B256, U256}, - CallInputs, -}; - -/// EVM contract information. -#[derive(Clone, Debug, Default)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Contract { - /// Contracts data - pub input: Bytes, - /// Bytecode contains contract code, size of original code, analysis with gas block and jump table. - /// Note that current code is extended with push padding and STOP at end. - pub bytecode: Bytecode, - /// Bytecode hash for legacy. For EOF this would be None. - pub hash: Option, - /// Target address of the account. Storage of this address is going to be modified. - pub target_address: Address, - /// Caller of the EVM. - pub caller: Address, - /// Value send to contract from transaction or from CALL opcodes. - pub call_value: U256, -} - -impl Contract { - /// Instantiates a new contract by analyzing the given bytecode. - #[inline] - pub fn new( - input: Bytes, - bytecode: Bytecode, - hash: Option, - target_address: Address, - caller: Address, - call_value: U256, - ) -> Self { - let bytecode = to_analysed(bytecode); - - Self { - input, - bytecode, - hash, - target_address, - caller, - call_value, - } - } - - /// Creates a new contract from the given [`Env`]. - #[inline] - pub fn new_env(env: &Env, bytecode: Bytecode, hash: Option) -> Self { - let contract_address = match env.tx.transact_to { - TransactTo::Call(caller) => caller, - TransactTo::Create => Address::ZERO, - }; - Self::new( - env.tx.data.clone(), - bytecode, - hash, - contract_address, - env.tx.caller, - env.tx.value, - ) - } - - /// Creates a new contract from the given inputs. - #[inline] - pub fn new_with_context( - input: Bytes, - bytecode: Bytecode, - hash: Option, - call_context: &CallInputs, - ) -> Self { - Self::new( - input, - bytecode, - hash, - call_context.target_address, - call_context.caller, - call_context.call_value(), - ) - } - - /// Returns whether the given position is a valid jump destination. - #[inline] - pub fn is_valid_jump(&self, pos: usize) -> bool { - self.bytecode - .legacy_jump_table() - .map(|i| i.is_valid(pos)) - .unwrap_or(false) - } -} diff --git a/crates/interpreter/src/interpreter/ext_bytecode.rs b/crates/interpreter/src/interpreter/ext_bytecode.rs new file mode 100644 index 0000000000..ede6bfcb02 --- /dev/null +++ b/crates/interpreter/src/interpreter/ext_bytecode.rs @@ -0,0 +1,193 @@ +use super::{Immediates, Jumps, LegacyBytecode}; +use crate::{interpreter_types::LoopControl, InterpreterAction}; +use bytecode::{utils::read_u16, Bytecode}; +use core::{ops::Deref, ptr}; +use primitives::B256; + +#[cfg(feature = "serde")] +mod serde; + +/// Extended bytecode structure that wraps base bytecode with additional execution metadata. +#[derive(Debug)] +pub struct ExtBytecode { + bytecode_hash: Option, + /// Actions that the EVM should do. It contains return value of the Interpreter or inputs for `CALL` or `CREATE` instructions. + /// For `RETURN` or `REVERT` instructions it contains the result of the instruction. + pub action: Option, + /// The base bytecode. + base: Bytecode, + /// The previous instruction pointer. + previous_pointer: Option<*const u8>, + /// The current instruction pointer. + instruction_pointer: *const u8, +} + +impl Deref for ExtBytecode { + type Target = Bytecode; + + fn deref(&self) -> &Self::Target { + &self.base + } +} + +impl Default for ExtBytecode { + #[inline] + fn default() -> Self { + Self::new(Bytecode::default()) + } +} + +impl ExtBytecode { + /// Create new extended bytecode and set the instruction pointer to the start of the bytecode. + #[inline] + pub fn new(base: Bytecode) -> Self { + let instruction_pointer = base.bytecode_ptr(); + Self { + base, + instruction_pointer, + bytecode_hash: None, + action: None, + previous_pointer: None, + } + } + + /// Creates new `ExtBytecode` with the given hash. + pub fn new_with_hash(base: Bytecode, hash: B256) -> Self { + let instruction_pointer = base.bytecode_ptr(); + Self { + base, + instruction_pointer, + bytecode_hash: Some(hash), + action: None, + previous_pointer: None, + } + } + + /// Regenerates the bytecode hash. + pub fn regenerate_hash(&mut self) -> B256 { + let hash = self.base.hash_slow(); + self.bytecode_hash = Some(hash); + hash + } + + /// Returns the bytecode hash. + pub fn hash(&mut self) -> Option { + self.bytecode_hash + } +} + +impl LoopControl for ExtBytecode { + #[inline] + fn is_end(&self) -> bool { + self.instruction_pointer.is_null() + } + + #[inline] + fn revert_to_previous_pointer(&mut self) { + if let Some(previous_pointer) = self.previous_pointer { + self.instruction_pointer = previous_pointer; + } + } + + #[inline] + fn set_action(&mut self, action: InterpreterAction) { + self.action = Some(action); + self.previous_pointer = Some(core::mem::replace( + &mut self.instruction_pointer, + ptr::null(), + )); + } + + #[inline] + fn action(&mut self) -> &mut Option { + &mut self.action + } +} + +impl Jumps for ExtBytecode { + #[inline] + fn relative_jump(&mut self, offset: isize) { + self.instruction_pointer = unsafe { self.instruction_pointer.offset(offset) }; + } + + #[inline] + fn absolute_jump(&mut self, offset: usize) { + self.instruction_pointer = unsafe { self.base.bytes_ref().as_ptr().add(offset) }; + } + + #[inline] + fn is_valid_legacy_jump(&mut self, offset: usize) -> bool { + self.base + .legacy_jump_table() + .expect("Panic if not legacy") + .is_valid(offset) + } + + #[inline] + fn opcode(&self) -> u8 { + // SAFETY: `instruction_pointer` always point to bytecode. + unsafe { *self.instruction_pointer } + } + + #[inline] + fn pc(&self) -> usize { + // SAFETY: `instruction_pointer` should be at an offset from the start of the bytes. + // In practice this is always true unless a caller modifies the `instruction_pointer` field manually. + unsafe { + self.instruction_pointer + .offset_from(self.base.bytes_ref().as_ptr()) as usize + } + } +} + +impl Immediates for ExtBytecode { + #[inline] + fn read_u16(&self) -> u16 { + unsafe { read_u16(self.instruction_pointer) } + } + + #[inline] + fn read_u8(&self) -> u8 { + unsafe { *self.instruction_pointer } + } + + #[inline] + fn read_slice(&self, len: usize) -> &[u8] { + unsafe { core::slice::from_raw_parts(self.instruction_pointer, len) } + } + + #[inline] + fn read_offset_u16(&self, offset: isize) -> u16 { + unsafe { + read_u16( + self.instruction_pointer + // Offset for max_index that is one byte + .offset(offset), + ) + } + } +} + +impl LegacyBytecode for ExtBytecode { + fn bytecode_len(&self) -> usize { + self.base.len() + } + + fn bytecode_slice(&self) -> &[u8] { + self.base.original_byte_slice() + } +} + +#[cfg(test)] +mod tests { + use super::*; + use primitives::Bytes; + + #[test] + fn test_with_hash_constructor() { + let bytecode = Bytecode::new_raw(Bytes::from(&[0x60, 0x00][..])); + let hash = bytecode.hash_slow(); + let ext_bytecode = ExtBytecode::new_with_hash(bytecode.clone(), hash); + assert_eq!(ext_bytecode.bytecode_hash, Some(hash)); + } +} diff --git a/crates/interpreter/src/interpreter/ext_bytecode/serde.rs b/crates/interpreter/src/interpreter/ext_bytecode/serde.rs new file mode 100644 index 0000000000..c627200912 --- /dev/null +++ b/crates/interpreter/src/interpreter/ext_bytecode/serde.rs @@ -0,0 +1,50 @@ +use super::ExtBytecode; +use crate::interpreter::Jumps; +use primitives::B256; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; + +#[derive(Serialize, Deserialize)] +struct ExtBytecodeSerde { + base: bytecode::Bytecode, + program_counter: usize, + bytecode_hash: Option, +} + +impl Serialize for ExtBytecode { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + ExtBytecodeSerde { + base: self.base.clone(), + program_counter: self.pc(), + bytecode_hash: self.bytecode_hash, + } + .serialize(serializer) + } +} + +impl<'de> Deserialize<'de> for ExtBytecode { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let ExtBytecodeSerde { + base, + program_counter, + bytecode_hash, + } = ExtBytecodeSerde::deserialize(deserializer)?; + + let mut bytecode = if let Some(hash) = bytecode_hash { + Self::new_with_hash(base, hash) + } else { + Self::new(base) + }; + + if program_counter >= bytecode.base.bytecode().len() { + panic!("serde pc: {program_counter} is greater than or equal to bytecode len"); + } + bytecode.absolute_jump(program_counter); + Ok(bytecode) + } +} diff --git a/crates/interpreter/src/interpreter/input.rs b/crates/interpreter/src/interpreter/input.rs new file mode 100644 index 0000000000..fb28c8252b --- /dev/null +++ b/crates/interpreter/src/interpreter/input.rs @@ -0,0 +1,43 @@ +use crate::{interpreter_types::InputsTr, CallInput}; +use primitives::{Address, U256}; +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; + +/// Inputs for the interpreter that are used for execution of the call. +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Clone, Debug, Default, PartialEq, Eq)] +pub struct InputsImpl { + /// Storage of this account address is being used. + pub target_address: Address, + /// Address of the bytecode that is being executed. This field is not used inside Interpreter but it is used + /// by dependent projects that would need to know the address of the bytecode. + pub bytecode_address: Option
, + /// Address of the caller of the call. + pub caller_address: Address, + /// Input data for the call. + pub input: CallInput, + /// Value of the call. + pub call_value: U256, +} + +impl InputsTr for InputsImpl { + fn target_address(&self) -> Address { + self.target_address + } + + fn caller_address(&self) -> Address { + self.caller_address + } + + fn bytecode_address(&self) -> Option<&Address> { + self.bytecode_address.as_ref() + } + + fn input(&self) -> &CallInput { + &self.input + } + + fn call_value(&self) -> U256 { + self.call_value + } +} diff --git a/crates/interpreter/src/interpreter/loop_control.rs b/crates/interpreter/src/interpreter/loop_control.rs new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/crates/interpreter/src/interpreter/loop_control.rs @@ -0,0 +1 @@ + diff --git a/crates/interpreter/src/interpreter/return_data.rs b/crates/interpreter/src/interpreter/return_data.rs new file mode 100644 index 0000000000..85a302b863 --- /dev/null +++ b/crates/interpreter/src/interpreter/return_data.rs @@ -0,0 +1,19 @@ +use crate::interpreter::ReturnData; +use primitives::Bytes; +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; + +/// Default implementation of return data storage for the interpreter. +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Clone, Debug, Default)] +pub struct ReturnDataImpl(pub Bytes); + +impl ReturnData for ReturnDataImpl { + fn buffer(&self) -> &Bytes { + &self.0 + } + + fn set_buffer(&mut self, bytes: Bytes) { + self.0 = bytes; + } +} diff --git a/crates/interpreter/src/interpreter/runtime_flags.rs b/crates/interpreter/src/interpreter/runtime_flags.rs new file mode 100644 index 0000000000..0fd875b5b9 --- /dev/null +++ b/crates/interpreter/src/interpreter/runtime_flags.rs @@ -0,0 +1,25 @@ +use primitives::hardfork::SpecId; + +use super::RuntimeFlag; +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; + +/// Runtime flags that control interpreter execution behavior. +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct RuntimeFlags { + /// Whether the current execution context is static (read-only). + pub is_static: bool, + /// The current EVM specification ID. + pub spec_id: SpecId, +} + +impl RuntimeFlag for RuntimeFlags { + fn is_static(&self) -> bool { + self.is_static + } + + fn spec_id(&self) -> SpecId { + self.spec_id + } +} diff --git a/crates/interpreter/src/interpreter/serde.rs b/crates/interpreter/src/interpreter/serde.rs deleted file mode 100644 index eb4d8524fc..0000000000 --- a/crates/interpreter/src/interpreter/serde.rs +++ /dev/null @@ -1,242 +0,0 @@ -use crate::{ - Contract, FunctionStack, Gas, InstructionResult, InterpreterAction, SharedMemory, Stack, -}; - -use super::Interpreter; -use revm_primitives::Bytes; -use serde::de::{self, MapAccess, Visitor}; -use serde::ser::SerializeStruct; -use serde::{Deserialize, Deserializer, Serialize, Serializer}; -use std::fmt; - -impl Serialize for Interpreter { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let mut state = serializer.serialize_struct("Interpreter", 8)?; - // Convert the instruction pointer to a usize for serialization - let program_counter = self.program_counter(); - state.serialize_field("program_counter", &program_counter)?; - state.serialize_field("gas", &self.gas)?; - state.serialize_field("contract", &self.contract)?; - state.serialize_field("instruction_result", &self.instruction_result)?; - state.serialize_field("bytecode", &self.bytecode)?; - state.serialize_field("is_eof", &self.is_eof)?; - state.serialize_field("is_eof_init", &self.is_eof_init)?; - state.serialize_field("shared_memory", &self.shared_memory)?; - state.serialize_field("stack", &self.stack)?; - state.serialize_field("function_stack", &self.function_stack)?; - state.serialize_field("return_data_buffer", &self.return_data_buffer)?; - state.serialize_field("is_static", &self.is_static)?; - state.serialize_field("next_action", &self.next_action)?; - state.end() - } -} - -impl<'de> Deserialize<'de> for Interpreter { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - struct InterpreterVisitor; - - #[derive(serde::Deserialize)] - #[serde(field_identifier, rename_all = "lowercase")] - enum InterpreterFields { - ProgramCounter, - Gas, - Contract, - InstructionResult, - Bytecode, - IsEof, - IsEofInit, - SharedMemory, - Stack, - FunctionStack, - ReturnDataBuffer, - IsStatic, - NextAction, - } - - #[allow(clippy::too_many_arguments)] - fn rebuild_interp( - program_counter: isize, - gas: Gas, - contract: Contract, - instruction_result: InstructionResult, - bytecode: Bytes, - is_eof: bool, - is_eof_init: bool, - shared_memory: SharedMemory, - stack: Stack, - function_stack: FunctionStack, - return_data_buffer: Bytes, - is_static: bool, - next_action: InterpreterAction, - ) -> Result { - // Reconstruct the instruction pointer from usize - if program_counter < 0 || program_counter >= bytecode.len() as isize { - return Err("program_counter index out of range"); - } - - // SAFETY: range of program_counter checked above - let instruction_pointer = unsafe { bytecode.as_ptr().offset(program_counter) }; - - // Construct and return the Interpreter instance - Ok(Interpreter { - instruction_pointer, - gas, - contract, - instruction_result, - bytecode, - is_eof, - is_eof_init, - shared_memory, - stack, - function_stack, - return_data_buffer, - is_static, - next_action, - }) - } - - impl<'de> Visitor<'de> for InterpreterVisitor { - type Value = Interpreter; - - fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - formatter.write_str("struct Interpreter") - } - - fn visit_seq(self, mut seq: A) -> Result - where - A: de::SeqAccess<'de>, - { - macro_rules! extract_field { - ($i:ident, $idx:expr) => { - let $i = seq - .next_element()? - .ok_or_else(|| de::Error::invalid_length($idx, &self))?; - }; - } - extract_field!(instruction_pointer, 0); - extract_field!(gas, 1); - extract_field!(contract, 2); - extract_field!(instruction_result, 3); - extract_field!(bytecode, 4); - extract_field!(is_eof, 5); - extract_field!(is_eof_init, 6); - extract_field!(shared_memory, 7); - extract_field!(stack, 8); - extract_field!(function_stack, 9); - extract_field!(return_data_buffer, 10); - extract_field!(is_static, 11); - extract_field!(next_action, 12); - rebuild_interp( - instruction_pointer, - gas, - contract, - instruction_result, - bytecode, - is_eof, - is_eof_init, - shared_memory, - stack, - function_stack, - return_data_buffer, - is_static, - next_action, - ) - .map_err(de::Error::custom) - } - - fn visit_map(self, mut map: V) -> Result - where - V: MapAccess<'de>, - { - macro_rules! parse_map { - ( $(($enum:pat, $var_name:ident)),* ) => { - $( - let mut $var_name = None; - )* - while let Some(key) = map.next_key()? { - match key { - $( - $enum => { - $var_name = Some(map.next_value()?); - } - )* - } - } - $( - let $var_name = $var_name.ok_or_else(|| de::Error::missing_field(stringify!($var_name)))?; - )* - }; - } - parse_map!( - (InterpreterFields::ProgramCounter, program_counter), - (InterpreterFields::Gas, gas), - (InterpreterFields::Contract, contract), - (InterpreterFields::InstructionResult, instruction_result), - (InterpreterFields::Bytecode, bytecode), - (InterpreterFields::IsEof, is_eof), - (InterpreterFields::IsEofInit, is_eof_init), - (InterpreterFields::SharedMemory, shared_memory), - (InterpreterFields::Stack, stack), - (InterpreterFields::FunctionStack, function_stack), - (InterpreterFields::ReturnDataBuffer, return_data_buffer), - (InterpreterFields::IsStatic, is_static), - (InterpreterFields::NextAction, next_action) - ); - - rebuild_interp( - program_counter, - gas, - contract, - instruction_result, - bytecode, - is_eof, - is_eof_init, - shared_memory, - stack, - function_stack, - return_data_buffer, - is_static, - next_action, - ) - .map_err(de::Error::custom) - } - } - - const FIELDS: &[&str] = &[ - "program_counter", - "gas", - "contract", - "instruction_result", - "bytecode", - "is_eof", - "is_eof_init", - "shared_memory", - "stack", - "function_stack", - "return_data_buffer", - "is_static", - "next_action", - ]; - - deserializer.deserialize_struct("Interpreter", FIELDS, InterpreterVisitor) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_serde() { - let interp = Interpreter::new(Contract::default(), u64::MAX, false); - let serialized = bincode::serialize(&interp).unwrap(); - let de: Interpreter = bincode::deserialize(&serialized).unwrap(); - assert_eq!(interp.program_counter(), de.program_counter()); - } -} diff --git a/crates/interpreter/src/interpreter/shared_memory.rs b/crates/interpreter/src/interpreter/shared_memory.rs index cc63e1bf07..8e1b503954 100644 --- a/crates/interpreter/src/interpreter/shared_memory.rs +++ b/crates/interpreter/src/interpreter/shared_memory.rs @@ -1,45 +1,60 @@ -use core::{cmp::min, fmt, ops::Range}; -use revm_primitives::{B256, U256}; -use std::vec::Vec; +use super::MemoryTr; +use core::{ + cell::{Ref, RefCell, RefMut}, + cmp::min, + fmt, + ops::Range, +}; +use primitives::{hex, B256, U256}; +use std::{rc::Rc, vec::Vec}; + +trait RefcellExt { + fn dbg_borrow(&self) -> Ref<'_, T>; + fn dbg_borrow_mut(&self) -> RefMut<'_, T>; +} + +impl RefcellExt for RefCell { + #[inline] + fn dbg_borrow(&self) -> Ref<'_, T> { + match self.try_borrow() { + Ok(b) => b, + Err(e) => debug_unreachable!("{e}"), + } + } + + #[inline] + fn dbg_borrow_mut(&self) -> RefMut<'_, T> { + match self.try_borrow_mut() { + Ok(b) => b, + Err(e) => debug_unreachable!("{e}"), + } + } +} /// A sequential memory shared between calls, which uses /// a `Vec` for internal representation. /// A [SharedMemory] instance should always be obtained using /// the `new` static method to ensure memory safety. -#[derive(Clone, PartialEq, Eq, Hash)] +#[derive(Clone, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct SharedMemory { /// The underlying buffer. - buffer: Vec, + buffer: Option>>>, /// Memory checkpoints for each depth. /// Invariant: these are always in bounds of `data`. - checkpoints: Vec, - /// Invariant: equals `self.checkpoints.last()` - last_checkpoint: usize, - /// Memory limit. See [`CfgEnv`](revm_primitives::CfgEnv). + my_checkpoint: usize, + /// Child checkpoint that we need to free context to. + child_checkpoint: Option, + /// Memory limit. See [`Cfg`](context_interface::Cfg). #[cfg(feature = "memory_limit")] memory_limit: u64, } -/// Empty shared memory. -/// -/// Used as placeholder inside Interpreter when it is not running. -pub const EMPTY_SHARED_MEMORY: SharedMemory = SharedMemory { - buffer: Vec::new(), - checkpoints: Vec::new(), - last_checkpoint: 0, - #[cfg(feature = "memory_limit")] - memory_limit: u64::MAX, -}; - impl fmt::Debug for SharedMemory { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("SharedMemory") .field("current_len", &self.len()) - .field( - "context_memory", - &crate::primitives::hex::encode(self.context_memory()), - ) + .field("context_memory", &hex::encode(&*self.context_memory())) .finish_non_exhaustive() } } @@ -51,6 +66,67 @@ impl Default for SharedMemory { } } +impl MemoryTr for SharedMemory { + fn set_data(&mut self, memory_offset: usize, data_offset: usize, len: usize, data: &[u8]) { + self.set_data(memory_offset, data_offset, len, data); + } + + fn set(&mut self, memory_offset: usize, data: &[u8]) { + self.set(memory_offset, data); + } + + fn size(&self) -> usize { + self.len() + } + + fn copy(&mut self, destination: usize, source: usize, len: usize) { + self.copy(destination, source, len); + } + + fn slice(&self, range: Range) -> Ref<'_, [u8]> { + self.slice_range(range) + } + + fn local_memory_offset(&self) -> usize { + self.my_checkpoint + } + + fn set_data_from_global( + &mut self, + memory_offset: usize, + data_offset: usize, + len: usize, + data_range: Range, + ) { + self.global_to_local_set_data(memory_offset, data_offset, len, data_range); + } + + /// Returns a byte slice of the memory region at the given offset. + /// + /// # Panics + /// + /// Panics on out of bounds access in debug builds only. + /// + /// # Safety + /// + /// In release builds, calling this method with an out-of-bounds range triggers undefined + /// behavior. Callers must ensure that the range is within the bounds of the buffer. + #[inline] + #[cfg_attr(debug_assertions, track_caller)] + fn global_slice(&self, range: Range) -> Ref<'_, [u8]> { + let buffer = self.buffer_ref(); + Ref::map(buffer, |b| match b.get(range) { + Some(slice) => slice, + None => debug_unreachable!("slice OOB: range; len: {}", self.len()), + }) + } + + fn resize(&mut self, new_size: usize) -> bool { + self.resize(new_size); + true + } +} + impl SharedMemory { /// Creates a new memory instance that can be shared between calls. /// @@ -60,13 +136,36 @@ impl SharedMemory { Self::with_capacity(4 * 1024) // from evmone } + /// Creates a new invalid memory instance. + #[inline] + pub fn invalid() -> Self { + Self { + buffer: None, + my_checkpoint: 0, + child_checkpoint: None, + #[cfg(feature = "memory_limit")] + memory_limit: 0, + } + } + + /// Creates a new memory instance with a given shared buffer. + pub fn new_with_buffer(buffer: Rc>>) -> Self { + Self { + buffer: Some(buffer), + my_checkpoint: 0, + child_checkpoint: None, + #[cfg(feature = "memory_limit")] + memory_limit: u64::MAX, + } + } + /// Creates a new memory instance that can be shared between calls with the given `capacity`. #[inline] pub fn with_capacity(capacity: usize) -> Self { Self { - buffer: Vec::with_capacity(capacity), - checkpoints: Vec::with_capacity(32), - last_checkpoint: 0, + buffer: Some(Rc::new(RefCell::new(Vec::with_capacity(capacity)))), + my_checkpoint: 0, + child_checkpoint: None, #[cfg(feature = "memory_limit")] memory_limit: u64::MAX, } @@ -85,36 +184,71 @@ impl SharedMemory { } } + #[inline] + fn buffer(&self) -> &Rc>> { + debug_assert!(self.buffer.is_some(), "cannot use SharedMemory::empty"); + unsafe { self.buffer.as_ref().unwrap_unchecked() } + } + + #[inline] + fn buffer_ref(&self) -> Ref<'_, Vec> { + self.buffer().dbg_borrow() + } + + #[inline] + fn buffer_ref_mut(&self) -> RefMut<'_, Vec> { + self.buffer().dbg_borrow_mut() + } + /// Returns `true` if the `new_size` for the current context memory will /// make the shared buffer length exceed the `memory_limit`. #[cfg(feature = "memory_limit")] #[inline] pub fn limit_reached(&self, new_size: usize) -> bool { - self.last_checkpoint.saturating_add(new_size) as u64 > self.memory_limit + self.my_checkpoint.saturating_add(new_size) as u64 > self.memory_limit } - /// Prepares the shared memory for a new context. + /// Prepares the shared memory for a new child context. + /// + /// # Panics + /// + /// Panics if this function was already called without freeing child context. #[inline] - pub fn new_context(&mut self) { - let new_checkpoint = self.buffer.len(); - self.checkpoints.push(new_checkpoint); - self.last_checkpoint = new_checkpoint; + pub fn new_child_context(&mut self) -> SharedMemory { + if self.child_checkpoint.is_some() { + panic!("new_child_context was already called without freeing child context"); + } + let new_checkpoint = self.full_len(); + self.child_checkpoint = Some(new_checkpoint); + SharedMemory { + buffer: Some(self.buffer().clone()), + my_checkpoint: new_checkpoint, + // child_checkpoint is same as my_checkpoint + child_checkpoint: None, + #[cfg(feature = "memory_limit")] + memory_limit: self.memory_limit, + } } - /// Prepares the shared memory for returning to the previous context. + /// Prepares the shared memory for returning from child context. Do nothing if there is no child context. #[inline] - pub fn free_context(&mut self) { - if let Some(old_checkpoint) = self.checkpoints.pop() { - self.last_checkpoint = self.checkpoints.last().cloned().unwrap_or_default(); - // SAFETY: buffer length is less than or equal `old_checkpoint` - unsafe { self.buffer.set_len(old_checkpoint) }; + pub fn free_child_context(&mut self) { + let Some(child_checkpoint) = self.child_checkpoint.take() else { + return; + }; + unsafe { + self.buffer_ref_mut().set_len(child_checkpoint); } } /// Returns the length of the current memory range. #[inline] pub fn len(&self) -> usize { - self.buffer.len() - self.last_checkpoint + self.full_len() - self.my_checkpoint + } + + fn full_len(&self) -> usize { + self.buffer_ref().len() } /// Returns `true` if the current memory range is empty. @@ -123,16 +257,12 @@ impl SharedMemory { self.len() == 0 } - /// Returns the gas cost for the current memory expansion. - #[inline] - pub fn current_expansion_cost(&self) -> u64 { - crate::gas::memory_gas_for_len(self.len()) - } - /// Resizes the memory in-place so that `len` is equal to `new_len`. #[inline] pub fn resize(&mut self, new_size: usize) { - self.buffer.resize(self.last_checkpoint + new_size, 0); + self.buffer() + .dbg_borrow_mut() + .resize(self.my_checkpoint + new_size, 0); } /// Returns a byte slice of the memory region at the given offset. @@ -142,7 +272,7 @@ impl SharedMemory { /// Panics on out of bounds. #[inline] #[cfg_attr(debug_assertions, track_caller)] - pub fn slice(&self, offset: usize, size: usize) -> &[u8] { + pub fn slice_len(&self, offset: usize, size: usize) -> Ref<'_, [u8]> { self.slice_range(offset..offset + size) } @@ -150,29 +280,66 @@ impl SharedMemory { /// /// # Panics /// - /// Panics on out of bounds. + /// Panics on out of bounds access in debug builds only. + /// + /// # Safety + /// + /// In release builds, calling this method with an out-of-bounds range triggers undefined + /// behavior. Callers must ensure that the range is within the bounds of the memory (i.e., + /// `range.end <= self.len()`). #[inline] #[cfg_attr(debug_assertions, track_caller)] - pub fn slice_range(&self, range @ Range { start, end }: Range) -> &[u8] { - match self.context_memory().get(range) { - Some(slice) => slice, - None => debug_unreachable!("slice OOB: {start}..{end}; len: {}", self.len()), - } + pub fn slice_range(&self, range: Range) -> Ref<'_, [u8]> { + let buffer = self.buffer_ref(); + Ref::map(buffer, |b| { + match b.get(range.start + self.my_checkpoint..range.end + self.my_checkpoint) { + Some(slice) => slice, + None => debug_unreachable!("slice OOB: range; len: {}", self.len()), + } + }) } /// Returns a byte slice of the memory region at the given offset. /// /// # Panics /// - /// Panics on out of bounds. + /// Panics on out of bounds access in debug builds only. + /// + /// # Safety + /// + /// In release builds, calling this method with an out-of-bounds range triggers undefined + /// behavior. Callers must ensure that the range is within the bounds of the buffer. #[inline] #[cfg_attr(debug_assertions, track_caller)] - pub fn slice_mut(&mut self, offset: usize, size: usize) -> &mut [u8] { - let end = offset + size; - match self.context_memory_mut().get_mut(offset..end) { + pub fn global_slice_range(&self, range: Range) -> Ref<'_, [u8]> { + let buffer = self.buffer_ref(); + Ref::map(buffer, |b| match b.get(range) { Some(slice) => slice, - None => debug_unreachable!("slice OOB: {offset}..{end}"), - } + None => debug_unreachable!("slice OOB: range; len: {}", self.len()), + }) + } + + /// Returns a byte slice of the memory region at the given offset. + /// + /// # Panics + /// + /// Panics on out of bounds access in debug builds only. + /// + /// # Safety + /// + /// In release builds, calling this method with out-of-bounds parameters triggers undefined + /// behavior. Callers must ensure that `offset + size` does not exceed the length of the + /// memory. + #[inline] + #[cfg_attr(debug_assertions, track_caller)] + pub fn slice_mut(&mut self, offset: usize, size: usize) -> RefMut<'_, [u8]> { + let buffer = self.buffer_ref_mut(); + RefMut::map(buffer, |b| { + match b.get_mut(self.my_checkpoint + offset..self.my_checkpoint + offset + size) { + Some(slice) => slice, + None => debug_unreachable!("slice OOB: {offset}..{}", offset + size), + } + }) } /// Returns the byte at the given offset. @@ -182,7 +349,7 @@ impl SharedMemory { /// Panics on out of bounds. #[inline] pub fn get_byte(&self, offset: usize) -> u8 { - self.slice(offset, 1)[0] + self.slice_len(offset, 1)[0] } /// Returns a 32-byte slice of the memory region at the given offset. @@ -192,7 +359,7 @@ impl SharedMemory { /// Panics on out of bounds. #[inline] pub fn get_word(&self, offset: usize) -> B256 { - self.slice(offset, 32).try_into().unwrap() + (*self.slice_len(offset, 32)).try_into().unwrap() } /// Returns a U256 of the memory region at the given offset. @@ -256,26 +423,32 @@ impl SharedMemory { /// /// # Panics /// - /// Panics on out of bounds. + /// Panics if memory is out of bounds. #[inline] #[cfg_attr(debug_assertions, track_caller)] pub fn set_data(&mut self, memory_offset: usize, data_offset: usize, len: usize, data: &[u8]) { - if data_offset >= data.len() { - // nullify all memory slots - self.slice_mut(memory_offset, len).fill(0); - return; - } - let data_end = min(data_offset + len, data.len()); - let data_len = data_end - data_offset; - debug_assert!(data_offset < data.len() && data_end <= data.len()); - let data = unsafe { data.get_unchecked(data_offset..data_end) }; - self.slice_mut(memory_offset, data_len) - .copy_from_slice(data); + let mut dst = self.context_memory_mut(); + unsafe { set_data(dst.as_mut(), data, memory_offset, data_offset, len) }; + } - // nullify rest of memory slots - // SAFETY: Memory is assumed to be valid, and it is commented where this assumption is made. - self.slice_mut(memory_offset + data_len, len - data_len) - .fill(0); + /// Set data from global memory to local memory. If global range is smaller than len, zeroes the rest. + #[inline] + #[cfg_attr(debug_assertions, track_caller)] + pub fn global_to_local_set_data( + &mut self, + memory_offset: usize, + data_offset: usize, + len: usize, + data_range: Range, + ) { + let mut buffer = self.buffer_ref_mut(); + let (src, dst) = buffer.split_at_mut(self.my_checkpoint); + let src = if data_range.is_empty() { + &mut [] + } else { + src.get_mut(data_range).unwrap() + }; + unsafe { set_data(dst, src, memory_offset, data_offset, len) }; } /// Copies elements from one part of the memory to another part of itself. @@ -290,31 +463,121 @@ impl SharedMemory { } /// Returns a reference to the memory of the current context, the active memory. + /// + /// # Panics + /// + /// Panics if the checkpoint is invalid in debug builds only. + /// + /// # Safety + /// + /// In release builds, calling this method with an invalid checkpoint triggers undefined + /// behavior. The checkpoint must be within the bounds of the buffer. #[inline] - pub fn context_memory(&self) -> &[u8] { - // SAFETY: access bounded by buffer length - unsafe { - self.buffer - .get_unchecked(self.last_checkpoint..self.buffer.len()) - } + pub fn context_memory(&self) -> Ref<'_, [u8]> { + let buffer = self.buffer_ref(); + Ref::map(buffer, |b| match b.get(self.my_checkpoint..) { + Some(slice) => slice, + None => debug_unreachable!("Context memory should be always valid"), + }) } /// Returns a mutable reference to the memory of the current context. + /// + /// # Panics + /// + /// Panics if the checkpoint is invalid in debug builds only. + /// + /// # Safety + /// + /// In release builds, calling this method with an invalid checkpoint triggers undefined + /// behavior. The checkpoint must be within the bounds of the buffer. #[inline] - pub fn context_memory_mut(&mut self) -> &mut [u8] { - let buf_len = self.buffer.len(); - // SAFETY: access bounded by buffer length - unsafe { self.buffer.get_unchecked_mut(self.last_checkpoint..buf_len) } + pub fn context_memory_mut(&mut self) -> RefMut<'_, [u8]> { + let buffer = self.buffer_ref_mut(); + RefMut::map(buffer, |b| match b.get_mut(self.my_checkpoint..) { + Some(slice) => slice, + None => debug_unreachable!("Context memory should be always valid"), + }) + } +} + +/// Copies data from src to dst taking into account the offsets and len. +/// +/// If src does not have enough data, it nullifies the rest of dst that is not copied. +/// +/// # Safety +/// +/// Assumes that dst has enough space to copy the data. +/// Assumes that src has enough data to copy. +/// Assumes that dst_offset and src_offset are in bounds. +/// Assumes that dst and src are valid. +/// Assumes that dst and src do not overlap. +unsafe fn set_data(dst: &mut [u8], src: &[u8], dst_offset: usize, src_offset: usize, len: usize) { + if src_offset >= src.len() { + // Nullify all memory slots + dst.get_mut(dst_offset..dst_offset + len).unwrap().fill(0); + return; } + let src_end = min(src_offset + len, src.len()); + let src_len = src_end - src_offset; + debug_assert!(src_offset < src.len() && src_end <= src.len()); + let data = unsafe { src.get_unchecked(src_offset..src_end) }; + unsafe { + dst.get_unchecked_mut(dst_offset..dst_offset + src_len) + .copy_from_slice(data) + }; + + // Nullify rest of memory slots + // SAFETY: Memory is assumed to be valid, and it is commented where this assumption is made. + unsafe { + dst.get_unchecked_mut(dst_offset + src_len..dst_offset + len) + .fill(0) + }; } /// Returns number of words what would fit to provided number of bytes, /// i.e. it rounds up the number bytes to number of words. #[inline] -pub const fn num_words(len: u64) -> u64 { +pub const fn num_words(len: usize) -> usize { len.saturating_add(31) / 32 } +/// Performs EVM memory resize. +#[inline] +#[must_use] +pub fn resize_memory( + gas: &mut crate::Gas, + memory: &mut Memory, + offset: usize, + len: usize, +) -> bool { + let new_num_words = num_words(offset.saturating_add(len)); + if new_num_words > gas.memory().words_num { + resize_memory_cold(gas, memory, new_num_words) + } else { + true + } +} + +#[cold] +#[inline(never)] +fn resize_memory_cold( + gas: &mut crate::Gas, + memory: &mut Memory, + new_num_words: usize, +) -> bool { + let cost = unsafe { + gas.memory_mut() + .record_new_len(new_num_words) + .unwrap_unchecked() + }; + if !gas.record_cost(cost) { + return false; + } + memory.resize(new_num_words * 32); + true +} + #[cfg(test)] mod tests { use super::*; @@ -329,79 +592,73 @@ mod tests { assert_eq!(num_words(63), 2); assert_eq!(num_words(64), 2); assert_eq!(num_words(65), 3); - assert_eq!(num_words(u64::MAX), u64::MAX / 32); + assert_eq!(num_words(usize::MAX), usize::MAX / 32); } #[test] - fn new_free_context() { - let mut shared_memory = SharedMemory::new(); - shared_memory.new_context(); - - assert_eq!(shared_memory.buffer.len(), 0); - assert_eq!(shared_memory.checkpoints.len(), 1); - assert_eq!(shared_memory.last_checkpoint, 0); - - unsafe { shared_memory.buffer.set_len(32) }; - assert_eq!(shared_memory.len(), 32); - shared_memory.new_context(); - - assert_eq!(shared_memory.buffer.len(), 32); - assert_eq!(shared_memory.checkpoints.len(), 2); - assert_eq!(shared_memory.last_checkpoint, 32); - assert_eq!(shared_memory.len(), 0); - - unsafe { shared_memory.buffer.set_len(96) }; - assert_eq!(shared_memory.len(), 64); - shared_memory.new_context(); - - assert_eq!(shared_memory.buffer.len(), 96); - assert_eq!(shared_memory.checkpoints.len(), 3); - assert_eq!(shared_memory.last_checkpoint, 96); - assert_eq!(shared_memory.len(), 0); - - // free contexts - shared_memory.free_context(); - assert_eq!(shared_memory.buffer.len(), 96); - assert_eq!(shared_memory.checkpoints.len(), 2); - assert_eq!(shared_memory.last_checkpoint, 32); - assert_eq!(shared_memory.len(), 64); - - shared_memory.free_context(); - assert_eq!(shared_memory.buffer.len(), 32); - assert_eq!(shared_memory.checkpoints.len(), 1); - assert_eq!(shared_memory.last_checkpoint, 0); - assert_eq!(shared_memory.len(), 32); - - shared_memory.free_context(); - assert_eq!(shared_memory.buffer.len(), 0); - assert_eq!(shared_memory.checkpoints.len(), 0); - assert_eq!(shared_memory.last_checkpoint, 0); - assert_eq!(shared_memory.len(), 0); + fn new_free_child_context() { + let mut sm1 = SharedMemory::new(); + + assert_eq!(sm1.buffer_ref().len(), 0); + assert_eq!(sm1.my_checkpoint, 0); + + unsafe { sm1.buffer_ref_mut().set_len(32) }; + assert_eq!(sm1.len(), 32); + let mut sm2 = sm1.new_child_context(); + + assert_eq!(sm2.buffer_ref().len(), 32); + assert_eq!(sm2.my_checkpoint, 32); + assert_eq!(sm2.len(), 0); + + unsafe { sm2.buffer_ref_mut().set_len(96) }; + assert_eq!(sm2.len(), 64); + let mut sm3 = sm2.new_child_context(); + + assert_eq!(sm3.buffer_ref().len(), 96); + assert_eq!(sm3.my_checkpoint, 96); + assert_eq!(sm3.len(), 0); + + unsafe { sm3.buffer_ref_mut().set_len(128) }; + let sm4 = sm3.new_child_context(); + assert_eq!(sm4.buffer_ref().len(), 128); + assert_eq!(sm4.my_checkpoint, 128); + assert_eq!(sm4.len(), 0); + + // Free contexts + drop(sm4); + sm3.free_child_context(); + assert_eq!(sm3.buffer_ref().len(), 128); + assert_eq!(sm3.my_checkpoint, 96); + assert_eq!(sm3.len(), 32); + + sm2.free_child_context(); + assert_eq!(sm2.buffer_ref().len(), 96); + assert_eq!(sm2.my_checkpoint, 32); + assert_eq!(sm2.len(), 64); + + sm1.free_child_context(); + assert_eq!(sm1.buffer_ref().len(), 32); + assert_eq!(sm1.my_checkpoint, 0); + assert_eq!(sm1.len(), 32); } #[test] fn resize() { - let mut shared_memory = SharedMemory::new(); - shared_memory.new_context(); - - shared_memory.resize(32); - assert_eq!(shared_memory.buffer.len(), 32); - assert_eq!(shared_memory.len(), 32); - assert_eq!(shared_memory.buffer.get(0..32), Some(&[0_u8; 32] as &[u8])); - - shared_memory.new_context(); - shared_memory.resize(96); - assert_eq!(shared_memory.buffer.len(), 128); - assert_eq!(shared_memory.len(), 96); - assert_eq!( - shared_memory.buffer.get(32..128), - Some(&[0_u8; 96] as &[u8]) - ); - - shared_memory.free_context(); - shared_memory.resize(64); - assert_eq!(shared_memory.buffer.len(), 64); - assert_eq!(shared_memory.len(), 64); - assert_eq!(shared_memory.buffer.get(0..64), Some(&[0_u8; 64] as &[u8])); + let mut sm1 = SharedMemory::new(); + sm1.resize(32); + assert_eq!(sm1.buffer_ref().len(), 32); + assert_eq!(sm1.len(), 32); + assert_eq!(sm1.buffer_ref().get(0..32), Some(&[0_u8; 32] as &[u8])); + + let mut sm2 = sm1.new_child_context(); + sm2.resize(96); + assert_eq!(sm2.buffer_ref().len(), 128); + assert_eq!(sm2.len(), 96); + assert_eq!(sm2.buffer_ref().get(32..128), Some(&[0_u8; 96] as &[u8])); + + sm1.free_child_context(); + assert_eq!(sm1.buffer_ref().len(), 32); + assert_eq!(sm1.len(), 32); + assert_eq!(sm1.buffer_ref().get(0..32), Some(&[0_u8; 32] as &[u8])); } } diff --git a/crates/interpreter/src/interpreter/stack.rs b/crates/interpreter/src/interpreter/stack.rs index 28b0baf3c1..c835a0202a 100644 --- a/crates/interpreter/src/interpreter/stack.rs +++ b/crates/interpreter/src/interpreter/stack.rs @@ -1,10 +1,10 @@ -use crate::{ - primitives::{B256, U256}, - InstructionResult, -}; +use crate::InstructionResult; use core::{fmt, ptr}; +use primitives::U256; use std::vec::Vec; +use super::StackTr; + /// EVM interpreter stack limit. pub const STACK_LIMIT: usize = 1024; @@ -36,16 +36,83 @@ impl Default for Stack { } } +impl Clone for Stack { + fn clone(&self) -> Self { + // Use `Self::new()` to ensure the cloned Stack maintains the STACK_LIMIT capacity, + // and then copy the data. This preserves the invariant that Stack always has + // STACK_LIMIT capacity, which is crucial for the safety and correctness of other methods. + let mut new_stack = Self::new(); + new_stack.data.extend_from_slice(&self.data); + new_stack + } +} + +impl StackTr for Stack { + #[inline] + fn len(&self) -> usize { + self.len() + } + + #[inline] + fn clear(&mut self) { + self.data.clear(); + } + + #[inline] + fn popn(&mut self) -> Option<[U256; N]> { + if self.len() < N { + return None; + } + // SAFETY: Stack length is checked above. + Some(unsafe { self.popn::() }) + } + + #[inline] + fn popn_top(&mut self) -> Option<([U256; POPN], &mut U256)> { + if self.len() < POPN + 1 { + return None; + } + // SAFETY: Stack length is checked above. + Some(unsafe { self.popn_top::() }) + } + + #[inline] + fn exchange(&mut self, n: usize, m: usize) -> bool { + self.exchange(n, m) + } + + #[inline] + fn dup(&mut self, n: usize) -> bool { + self.dup(n) + } + + #[inline] + fn push(&mut self, value: U256) -> bool { + self.push(value) + } + + #[inline] + fn push_slice(&mut self, slice: &[u8]) -> bool { + self.push_slice_(slice) + } +} + impl Stack { /// Instantiate a new stack with the [default stack limit][STACK_LIMIT]. #[inline] pub fn new() -> Self { Self { - // SAFETY: expansion functions assume that capacity is `STACK_LIMIT`. + // SAFETY: Expansion functions assume that capacity is `STACK_LIMIT`. data: Vec::with_capacity(STACK_LIMIT), } } + /// Instantiate a new invalid Stack. + #[inline] + pub fn invalid() -> Self { + Self { data: Vec::new() } + } + /// Returns the length of the stack in words. #[inline] pub fn len(&self) -> usize { @@ -79,6 +146,7 @@ impl Stack { /// Removes the topmost element from the stack and returns it, or `StackUnderflow` if it is /// empty. #[inline] + #[cfg_attr(debug_assertions, track_caller)] pub fn pop(&mut self) -> Result { self.data.pop().ok_or(InstructionResult::StackUnderflow) } @@ -89,7 +157,9 @@ impl Stack { /// /// The caller is responsible for checking the length of the stack. #[inline] + #[cfg_attr(debug_assertions, track_caller)] pub unsafe fn pop_unsafe(&mut self) -> U256 { + assume!(!self.data.is_empty()); self.data.pop().unwrap_unchecked() } @@ -99,114 +169,52 @@ impl Stack { /// /// The caller is responsible for checking the length of the stack. #[inline] + #[cfg_attr(debug_assertions, track_caller)] pub unsafe fn top_unsafe(&mut self) -> &mut U256 { - let len = self.data.len(); - self.data.get_unchecked_mut(len - 1) + assume!(!self.data.is_empty()); + self.data.last_mut().unwrap_unchecked() } - /// Pop the topmost value, returning the value and the new topmost value. + /// Pops `N` values from the stack. /// /// # Safety /// /// The caller is responsible for checking the length of the stack. #[inline] - pub unsafe fn pop_top_unsafe(&mut self) -> (U256, &mut U256) { - let pop = self.pop_unsafe(); - let top = self.top_unsafe(); - (pop, top) - } - - /// Pops 2 values from the stack. - /// - /// # Safety - /// - /// The caller is responsible for checking the length of the stack. - #[inline] - pub unsafe fn pop2_unsafe(&mut self) -> (U256, U256) { - let pop1 = self.pop_unsafe(); - let pop2 = self.pop_unsafe(); - (pop1, pop2) + #[cfg_attr(debug_assertions, track_caller)] + pub unsafe fn popn(&mut self) -> [U256; N] { + assume!(self.data.len() >= N); + core::array::from_fn(|_| unsafe { self.pop_unsafe() }) } - /// Pops 2 values from the stack and returns them, in addition to the new topmost value. + /// Pops `N` values from the stack and returns the top of the stack. /// /// # Safety /// /// The caller is responsible for checking the length of the stack. #[inline] - pub unsafe fn pop2_top_unsafe(&mut self) -> (U256, U256, &mut U256) { - let pop1 = self.pop_unsafe(); - let pop2 = self.pop_unsafe(); + #[cfg_attr(debug_assertions, track_caller)] + pub unsafe fn popn_top(&mut self) -> ([U256; POPN], &mut U256) { + let result = self.popn::(); let top = self.top_unsafe(); - - (pop1, pop2, top) - } - - /// Pops 3 values from the stack. - /// - /// # Safety - /// - /// The caller is responsible for checking the length of the stack. - #[inline] - pub unsafe fn pop3_unsafe(&mut self) -> (U256, U256, U256) { - let pop1 = self.pop_unsafe(); - let pop2 = self.pop_unsafe(); - let pop3 = self.pop_unsafe(); - - (pop1, pop2, pop3) - } - - /// Pops 4 values from the stack. - /// - /// # Safety - /// - /// The caller is responsible for checking the length of the stack. - #[inline] - pub unsafe fn pop4_unsafe(&mut self) -> (U256, U256, U256, U256) { - let pop1 = self.pop_unsafe(); - let pop2 = self.pop_unsafe(); - let pop3 = self.pop_unsafe(); - let pop4 = self.pop_unsafe(); - - (pop1, pop2, pop3, pop4) - } - - /// Pops 5 values from the stack. - /// - /// # Safety - /// - /// The caller is responsible for checking the length of the stack. - #[inline] - pub unsafe fn pop5_unsafe(&mut self) -> (U256, U256, U256, U256, U256) { - let pop1 = self.pop_unsafe(); - let pop2 = self.pop_unsafe(); - let pop3 = self.pop_unsafe(); - let pop4 = self.pop_unsafe(); - let pop5 = self.pop_unsafe(); - - (pop1, pop2, pop3, pop4, pop5) - } - - /// Push a new value into the stack. If it will exceed the stack limit, - /// returns `StackOverflow` error and leaves the stack unchanged. - #[inline] - pub fn push_b256(&mut self, value: B256) -> Result<(), InstructionResult> { - self.push(value.into()) + (result, top) } /// Push a new value onto the stack. /// - /// If it will exceed the stack limit, returns `StackOverflow` error and leaves the stack + /// If it will exceed the stack limit, returns false and leaves the stack /// unchanged. #[inline] - pub fn push(&mut self, value: U256) -> Result<(), InstructionResult> { + #[must_use] + #[cfg_attr(debug_assertions, track_caller)] + pub fn push(&mut self, value: U256) -> bool { // Allows the compiler to optimize out the `Vec::push` capacity check. assume!(self.data.capacity() == STACK_LIMIT); if self.data.len() == STACK_LIMIT { - return Err(InstructionResult::StackOverflow); + return false; } self.data.push(value); - Ok(()) + true } /// Peek a value at given index for the stack, where the top of @@ -227,22 +235,21 @@ impl Stack { /// /// Panics if `n` is 0. #[inline] + #[must_use] #[cfg_attr(debug_assertions, track_caller)] - pub fn dup(&mut self, n: usize) -> Result<(), InstructionResult> { + pub fn dup(&mut self, n: usize) -> bool { assume!(n > 0, "attempted to dup 0"); let len = self.data.len(); - if len < n { - Err(InstructionResult::StackUnderflow) - } else if len + 1 > STACK_LIMIT { - Err(InstructionResult::StackOverflow) + if len < n || len + 1 > STACK_LIMIT { + false } else { - // SAFETY: check for out of bounds is done above and it makes this safe to do. + // SAFETY: Check for out of bounds is done above and it makes this safe to do. unsafe { let ptr = self.data.as_mut_ptr().add(len); ptr::copy_nonoverlapping(ptr.sub(n), ptr, 1); self.data.set_len(len + 1); } - Ok(()) + true } } @@ -253,7 +260,7 @@ impl Stack { /// Panics if `n` is 0. #[inline(always)] #[cfg_attr(debug_assertions, track_caller)] - pub fn swap(&mut self, n: usize) -> Result<(), InstructionResult> { + pub fn swap(&mut self, n: usize) -> bool { self.exchange(0, n) } @@ -266,51 +273,62 @@ impl Stack { /// Panics if `m` is zero. #[inline] #[cfg_attr(debug_assertions, track_caller)] - pub fn exchange(&mut self, n: usize, m: usize) -> Result<(), InstructionResult> { + pub fn exchange(&mut self, n: usize, m: usize) -> bool { assume!(m > 0, "overlapping exchange"); let len = self.data.len(); let n_m_index = n + m; if n_m_index >= len { - return Err(InstructionResult::StackUnderflow); + return false; } // SAFETY: `n` and `n_m` are checked to be within bounds, and they don't overlap. unsafe { - // NOTE: `ptr::swap_nonoverlapping` is more efficient than `slice::swap` or `ptr::swap` + // Note: `ptr::swap_nonoverlapping` is more efficient than `slice::swap` or `ptr::swap` // because it operates under the assumption that the pointers do not overlap, - // eliminating an intemediate copy, + // eliminating an intermediate copy, // which is a condition we know to be true in this context. let top = self.data.as_mut_ptr().add(len - 1); core::ptr::swap_nonoverlapping(top.sub(n), top.sub(n_m_index), 1); } - Ok(()) + true } /// Pushes an arbitrary length slice of bytes onto the stack, padding the last word with zeros /// if necessary. #[inline] pub fn push_slice(&mut self, slice: &[u8]) -> Result<(), InstructionResult> { + if self.push_slice_(slice) { + Ok(()) + } else { + Err(InstructionResult::StackOverflow) + } + } + + /// Pushes an arbitrary length slice of bytes onto the stack, padding the last word with zeros + /// if necessary. + #[inline] + fn push_slice_(&mut self, slice: &[u8]) -> bool { if slice.is_empty() { - return Ok(()); + return true; } - let n_words = (slice.len() + 31) / 32; + let n_words = slice.len().div_ceil(32); let new_len = self.data.len() + n_words; if new_len > STACK_LIMIT { - return Err(InstructionResult::StackOverflow); + return false; } - // SAFETY: length checked above. + // SAFETY: Length checked above. unsafe { let dst = self.data.as_mut_ptr().add(self.data.len()).cast::(); self.data.set_len(new_len); let mut i = 0; - // write full words + // Write full words let words = slice.chunks_exact(32); let partial_last_word = words.remainder(); for word in words { - // Note: we unroll `U256::from_be_bytes` here to write directly into the buffer, + // Note: We unroll `U256::from_be_bytes` here to write directly into the buffer, // instead of creating a 32 byte array on the stack and then copying it over. for l in word.rchunks_exact(8) { dst.add(i).write(u64::from_be_bytes(l.try_into().unwrap())); @@ -319,10 +337,10 @@ impl Stack { } if partial_last_word.is_empty() { - return Ok(()); + return true; } - // write limbs of partial last word + // Write limbs of partial last word let limbs = partial_last_word.rchunks_exact(8); let partial_last_limb = limbs.remainder(); for l in limbs { @@ -330,7 +348,7 @@ impl Stack { i += 1; } - // write partial last limb by padding with zeros + // Write partial last limb by padding with zeros if !partial_last_limb.is_empty() { let mut tmp = [0u8; 8]; tmp[8 - partial_last_limb.len()..].copy_from_slice(partial_last_limb); @@ -338,16 +356,16 @@ impl Stack { i += 1; } - debug_assert_eq!((i + 3) / 4, n_words, "wrote too much"); + debug_assert_eq!(i.div_ceil(4), n_words, "wrote too much"); - // zero out upper bytes of last word + // Zero out upper bytes of last word let m = i % 4; // 32 / 8 if m != 0 { dst.add(i).write_bytes(0, 4 - m); } } - Ok(()) + true } /// Set a value at given index for the stack, where the top of the @@ -390,7 +408,7 @@ mod tests { fn run(f: impl FnOnce(&mut Stack)) { let mut stack = Stack::new(); - // fill capacity with non-zero values + // Fill capacity with non-zero values unsafe { stack.data.set_len(STACK_LIMIT); stack.data.fill(U256::MAX); @@ -401,13 +419,13 @@ mod tests { #[test] fn push_slices() { - // no-op + // No-op run(|stack| { stack.push_slice(b"").unwrap(); assert_eq!(stack.data, []); }); - // one word + // One word run(|stack| { stack.push_slice(&[42]).unwrap(); assert_eq!(stack.data, [U256::from(42)]); @@ -419,7 +437,7 @@ mod tests { assert_eq!(stack.data, [U256::from(n)]); }); - // more than one word + // More than one word run(|stack| { let b = [U256::from(n).to_be_bytes::<32>(); 2].concat(); stack.push_slice(&b).unwrap(); @@ -444,4 +462,44 @@ mod tests { assert_eq!(stack.data, [U256::ZERO, U256::ZERO, U256::from(n)]); }); } + + #[test] + fn stack_clone() { + // Test cloning an empty stack + let empty_stack = Stack::new(); + let cloned_empty = empty_stack.clone(); + assert_eq!(empty_stack, cloned_empty); + assert_eq!(cloned_empty.len(), 0); + assert_eq!(cloned_empty.data().capacity(), STACK_LIMIT); + + // Test cloning a partially filled stack + let mut partial_stack = Stack::new(); + for i in 0..10 { + assert!(partial_stack.push(U256::from(i))); + } + let mut cloned_partial = partial_stack.clone(); + assert_eq!(partial_stack, cloned_partial); + assert_eq!(cloned_partial.len(), 10); + assert_eq!(cloned_partial.data().capacity(), STACK_LIMIT); + + // Test that modifying the clone doesn't affect the original + assert!(cloned_partial.push(U256::from(100))); + assert_ne!(partial_stack, cloned_partial); + assert_eq!(partial_stack.len(), 10); + assert_eq!(cloned_partial.len(), 11); + + // Test cloning a full stack + let mut full_stack = Stack::new(); + for i in 0..STACK_LIMIT { + assert!(full_stack.push(U256::from(i))); + } + let mut cloned_full = full_stack.clone(); + assert_eq!(full_stack, cloned_full); + assert_eq!(cloned_full.len(), STACK_LIMIT); + assert_eq!(cloned_full.data().capacity(), STACK_LIMIT); + + // Test push to the full original or cloned stack should return StackOverflow + assert!(!full_stack.push(U256::from(100))); + assert!(!cloned_full.push(U256::from(100))); + } } diff --git a/crates/interpreter/src/interpreter/subroutine_stack.rs b/crates/interpreter/src/interpreter/subroutine_stack.rs new file mode 100644 index 0000000000..9c39d5b4ee --- /dev/null +++ b/crates/interpreter/src/interpreter/subroutine_stack.rs @@ -0,0 +1,101 @@ +use std::vec::Vec; + +use crate::interpreter_types::SubRoutineStack; + +/// Function(Sub Routine) return frame in eof +/// +/// Needed information for returning from a function. +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct SubRoutineReturnFrame { + /// The index of the code container that this frame is executing. + pub idx: usize, + /// The program counter where frame execution should continue. + pub pc: usize, +} + +impl SubRoutineReturnFrame { + /// Return new function frame. + pub fn new(idx: usize, pc: usize) -> Self { + Self { idx, pc } + } +} + +/// Function Stack +#[derive(Clone, Debug, Default, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct SubRoutineImpl { + /// Stack of return frames for managing nested subroutine calls + pub return_stack: Vec, + /// Index of the currently executing code section + pub current_code_idx: usize, +} + +impl SubRoutineImpl { + /// Returns new function stack. + pub fn new() -> Self { + Self { + return_stack: Vec::new(), + current_code_idx: 0, + } + } + + /// Clears the function stack. + pub fn clear(&mut self) { + self.return_stack.clear(); + self.current_code_idx = 0; + } + + /// Returns the number of subroutine frames on the stack. + pub fn len(&self) -> usize { + self.return_stack.len() + } + + /// Returns true if the subroutine stack is empty. + pub fn is_empty(&self) -> bool { + self.return_stack.is_empty() + } + + /// Return stack length + pub fn return_stack_len(&self) -> usize { + self.return_stack.len() + } + + /// Sets current_code_idx, this is needed for JUMPF opcode. + pub fn set_current_code_idx(&mut self, idx: usize) { + self.current_code_idx = idx; + } +} + +impl SubRoutineStack for SubRoutineImpl { + fn len(&self) -> usize { + self.return_stack.len() + } + + fn routine_idx(&self) -> usize { + self.current_code_idx + } + + fn push(&mut self, program_counter: usize, new_idx: usize) -> bool { + if self.return_stack.len() >= 1024 { + return false; + } + self.return_stack.push(SubRoutineReturnFrame { + idx: self.current_code_idx, + pc: program_counter, + }); + self.current_code_idx = new_idx; + true + } + + fn pop(&mut self) -> Option { + self.return_stack.pop().map(|i| { + self.current_code_idx = i.idx; + i.pc + }) + } + + fn set_routine_idx(&mut self, idx: usize) { + self.current_code_idx = idx; + } +} diff --git a/crates/interpreter/src/interpreter_action.rs b/crates/interpreter/src/interpreter_action.rs index 0581e220e4..08743e8885 100644 --- a/crates/interpreter/src/interpreter_action.rs +++ b/crates/interpreter/src/interpreter_action.rs @@ -2,67 +2,113 @@ mod call_inputs; mod call_outcome; mod create_inputs; mod create_outcome; -mod eof_create_inputs; -mod eof_create_outcome; -pub use call_inputs::{CallInputs, CallScheme, CallValue}; +pub use call_inputs::{CallInput, CallInputs, CallScheme, CallValue}; pub use call_outcome::CallOutcome; -pub use create_inputs::{CreateInputs, CreateScheme}; +pub use create_inputs::CreateInputs; pub use create_outcome::CreateOutcome; -pub use eof_create_inputs::EOFCreateInput; -pub use eof_create_outcome::EOFCreateOutcome; +use primitives::Bytes; -use crate::InterpreterResult; +use crate::{Gas, InstructionResult, InterpreterResult, SharedMemory}; use std::boxed::Box; -#[derive(Clone, Debug, Default, PartialEq, Eq)] +/// Input data for creating a new execution frame. +#[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub enum FrameInput { + /// No input data (empty frame) + Empty, + /// `CALL`, `CALLCODE`, `DELEGATECALL`, `STATICCALL` instruction called. + Call(Box), + /// `CREATE` or `CREATE2` instruction called. + Create(Box), +} + +/// Initialization data for creating a new execution frame. +#[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct FrameInit { + /// depth of the next frame + pub depth: usize, + /// shared memory set to this shared context + pub memory: SharedMemory, + /// Data needed as input for Interpreter. + pub frame_input: FrameInput, +} + +impl AsMut for FrameInput { + fn as_mut(&mut self) -> &mut Self { + self + } +} + +/// Actions that the interpreter can request from the host environment. +#[derive(Clone, Debug, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum InterpreterAction { - /// CALL, CALLCODE, DELEGATECALL, STATICCALL - /// or EOF EXT instuction called. - Call { inputs: Box }, - /// CREATE or CREATE2 instruction called. - Create { inputs: Box }, - /// EOF CREATE instruction called. - EOFCreate { inputs: Box }, + /// New frame + NewFrame(FrameInput), /// Interpreter finished execution. - Return { result: InterpreterResult }, - /// No action - #[default] - None, + Return(InterpreterResult), } impl InterpreterAction { - /// Returns true if action is call. + /// Returns `true` if action is call. pub fn is_call(&self) -> bool { - matches!(self, InterpreterAction::Call { .. }) + matches!(self, InterpreterAction::NewFrame(FrameInput::Call(..))) } - /// Returns true if action is create. + /// Returns `true` if action is create. pub fn is_create(&self) -> bool { - matches!(self, InterpreterAction::Create { .. }) + matches!(self, InterpreterAction::NewFrame(FrameInput::Create(..))) } - /// Returns true if action is return. + /// Returns `true` if action is return. pub fn is_return(&self) -> bool { matches!(self, InterpreterAction::Return { .. }) } - /// Returns true if action is none. - pub fn is_none(&self) -> bool { - matches!(self, InterpreterAction::None) - } - - /// Returns true if action is some. - pub fn is_some(&self) -> bool { - !self.is_none() + /// Returns [`InterpreterResult`] if action is return. + /// + /// Else it returns [None]. + pub fn into_result_return(self) -> Option { + match self { + InterpreterAction::Return(result) => Some(result), + _ => None, + } } - /// Returns result if action is return. - pub fn into_result_return(self) -> Option { + /// Returns [`InstructionResult`] if action is return. + /// + /// Else it returns [None]. + pub fn instruction_result(&self) -> Option { match self { - InterpreterAction::Return { result } => Some(result), + InterpreterAction::Return(result) => Some(result.result), _ => None, } } + + /// Create new frame action with the given frame input. + pub fn new_frame(frame_input: FrameInput) -> Self { + Self::NewFrame(frame_input) + } + + /// Create new halt action with the given result and gas. + pub fn new_halt(result: InstructionResult, gas: Gas) -> Self { + Self::Return(InterpreterResult::new(result, Bytes::new(), gas)) + } + + /// Create new return action with the given result, output and gas. + pub fn new_return(result: InstructionResult, output: Bytes, gas: Gas) -> Self { + Self::Return(InterpreterResult::new(result, output, gas)) + } + + /// Create new stop action. + pub fn new_stop() -> Self { + Self::Return(InterpreterResult::new( + InstructionResult::Stop, + Bytes::new(), + Gas::new(0), + )) + } } diff --git a/crates/interpreter/src/interpreter_action/call_inputs.rs b/crates/interpreter/src/interpreter_action/call_inputs.rs index 0e51bd5ec6..11865c818f 100644 --- a/crates/interpreter/src/interpreter_action/call_inputs.rs +++ b/crates/interpreter/src/interpreter_action/call_inputs.rs @@ -1,16 +1,76 @@ -use crate::primitives::{Address, Bytes, TransactTo, TxEnv, U256}; +use context_interface::{ContextTr, LocalContextTr}; use core::ops::Range; -use std::boxed::Box; +use primitives::{Address, Bytes, U256}; +/// Input enum for a call. +/// +/// As CallInput uses shared memory buffer it can get overridden if not used directly when call happens. +#[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub enum CallInput { + /// The Range points to the SharedMemory buffer. Buffer can be found in [`context_interface::LocalContextTr::shared_memory_buffer_slice`] function. + /// And can be accessed with `evm.ctx().local().shared_memory_buffer()` + /// + /// # Warning + /// + /// Use it with caution, CallInput shared buffer can be overridden if context from child call is returned so + /// recommendation is to fetch buffer at first Inspector call and clone it from [`context_interface::LocalContextTr::shared_memory_buffer_slice`] function. + SharedBuffer(Range), + /// Bytes of the call data. + Bytes(Bytes), +} + +impl CallInput { + /// Returns the length of the call input. + pub fn len(&self) -> usize { + match self { + Self::Bytes(bytes) => bytes.len(), + Self::SharedBuffer(range) => range.len(), + } + } + + /// Returns `true` if the call input is empty. + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Returns the bytes of the call input. + /// + /// SharedMemory buffer can be shrunked or overwritten if the child call returns the + /// shared memory context to its parent, the range in `CallInput::SharedBuffer` can show unexpected data. + /// + /// # Allocation + /// + /// If this `CallInput` is a `SharedBuffer`, the slice will be copied + /// into a fresh `Bytes` buffer, which can pose a performance penalty. + pub fn bytes(&self, ctx: &mut CTX) -> Bytes + where + CTX: ContextTr, + { + match self { + CallInput::Bytes(bytes) => bytes.clone(), + CallInput::SharedBuffer(range) => ctx + .local() + .shared_memory_buffer_slice(range.clone()) + .map(|b| Bytes::from(b.to_vec())) + .unwrap_or_default(), + } + } +} + +impl Default for CallInput { + #[inline] + fn default() -> Self { + CallInput::SharedBuffer(0..0) + } +} /// Inputs for a call. -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct CallInputs { /// The call data of the call. - pub input: Bytes, + pub input: CallInput, /// The return memory offset where the output of the call is written. - /// - /// In EOF, this range is invalid as EOF calls do not write output to memory. pub return_memory_offset: Range, /// The gas limit of the call. pub gas_limit: u64, @@ -28,7 +88,7 @@ pub struct CallInputs { pub caller: Address, /// Call value. /// - /// NOTE: This value may not necessarily be transferred from caller to callee, see [`CallValue`]. + /// **Note**: This value may not necessarily be transferred from caller to callee, see [`CallValue`]. /// /// Previously `transfer.value` or `context.apparent_value`. pub value: CallValue, @@ -38,39 +98,9 @@ pub struct CallInputs { pub scheme: CallScheme, /// Whether the call is a static call, or is initiated inside a static call. pub is_static: bool, - /// Whether the call is initiated from EOF bytecode. - pub is_eof: bool, } impl CallInputs { - /// Creates new call inputs. - /// - /// Returns `None` if the transaction is not a call. - pub fn new(tx_env: &TxEnv, gas_limit: u64) -> Option { - let TransactTo::Call(target_address) = tx_env.transact_to else { - return None; - }; - Some(CallInputs { - input: tx_env.data.clone(), - gas_limit, - target_address, - bytecode_address: target_address, - caller: tx_env.caller, - value: CallValue::Transfer(tx_env.value), - scheme: CallScheme::Call, - is_static: false, - is_eof: false, - return_memory_offset: 0..0, - }) - } - - /// Creates new boxed call inputs. - /// - /// Returns `None` if the transaction is not a call. - pub fn new_boxed(tx_env: &TxEnv, gas_limit: u64) -> Option> { - Self::new(tx_env, gas_limit).map(Box::new) - } - /// Returns `true` if the call will transfer a non-zero value. #[inline] pub fn transfers_value(&self) -> bool { @@ -111,7 +141,7 @@ impl CallInputs { /// Returns the call value, regardless of the transfer value type. /// - /// NOTE: this value may not necessarily be transferred from caller to callee, see [`CallValue`]. + /// **Note**: This value may not necessarily be transferred from caller to callee, see [`CallValue`]. #[inline] pub const fn call_value(&self) -> U256 { self.value.get() @@ -132,6 +162,28 @@ pub enum CallScheme { StaticCall, } +impl CallScheme { + /// Returns true if it is `CALL`. + pub fn is_call(&self) -> bool { + matches!(self, Self::Call) + } + + /// Returns true if it is `CALLCODE`. + pub fn is_call_code(&self) -> bool { + matches!(self, Self::CallCode) + } + + /// Returns true if it is `DELEGATECALL`. + pub fn is_delegate_call(&self) -> bool { + matches!(self, Self::DelegateCall) + } + + /// Returns true if it is `STATICCALL`. + pub fn is_static_call(&self) -> bool { + matches!(self, Self::StaticCall) + } +} + /// Call value. #[derive(Clone, Debug, PartialEq, Eq, Hash)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] diff --git a/crates/interpreter/src/interpreter_action/call_outcome.rs b/crates/interpreter/src/interpreter_action/call_outcome.rs index f51c01fca7..55a69989f1 100644 --- a/crates/interpreter/src/interpreter_action/call_outcome.rs +++ b/crates/interpreter/src/interpreter_action/call_outcome.rs @@ -1,6 +1,6 @@ use crate::{Gas, InstructionResult, InterpreterResult}; use core::ops::Range; -use revm_primitives::Bytes; +use primitives::Bytes; /// Represents the outcome of a call operation in a virtual machine. /// @@ -14,14 +14,16 @@ use revm_primitives::Bytes; #[derive(Clone, Debug, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct CallOutcome { + /// The result of the interpreter's execution, including output data and gas usage pub result: InterpreterResult, + /// The range in memory where the output data is located pub memory_offset: Range, } impl CallOutcome { - /// Constructs a new `CallOutcome`. + /// Constructs a new [`CallOutcome`]. /// - /// Creates an instance of `CallOutcome` with the given interpreter result and memory offset. + /// Creates an instance of [`CallOutcome`] with the given interpreter result and memory offset. /// /// # Arguments /// @@ -40,7 +42,7 @@ impl CallOutcome { /// /// # Returns /// - /// A reference to the `InstructionResult`. + /// A reference to the [`InstructionResult`]. pub fn instruction_result(&self) -> &InstructionResult { &self.result.result } @@ -51,7 +53,7 @@ impl CallOutcome { /// /// # Returns /// - /// An instance of `Gas` representing the gas usage. + /// An instance of [`Gas`] representing the gas usage. pub fn gas(&self) -> Gas { self.result.gas } @@ -62,7 +64,7 @@ impl CallOutcome { /// /// # Returns /// - /// A reference to the output data as `Bytes`. + /// A reference to the output data as [`Bytes`]. pub fn output(&self) -> &Bytes { &self.result.output } @@ -73,7 +75,7 @@ impl CallOutcome { /// /// # Returns /// - /// The starting index of the memory offset as `usize`. + /// The starting index of the memory offset as [`usize`]. pub fn memory_start(&self) -> usize { self.memory_offset.start } @@ -84,7 +86,7 @@ impl CallOutcome { /// /// # Returns /// - /// The length of the memory range as `usize`. + /// The length of the memory range as [`usize`]. pub fn memory_length(&self) -> usize { self.memory_offset.len() } diff --git a/crates/interpreter/src/interpreter_action/create_inputs.rs b/crates/interpreter/src/interpreter_action/create_inputs.rs index 6db951831a..d44ed3eac8 100644 --- a/crates/interpreter/src/interpreter_action/create_inputs.rs +++ b/crates/interpreter/src/interpreter_action/create_inputs.rs @@ -1,44 +1,23 @@ -pub use crate::primitives::CreateScheme; -use crate::primitives::{Address, Bytes, TransactTo, TxEnv, U256}; -use std::boxed::Box; +use context_interface::CreateScheme; +use primitives::{Address, Bytes, U256}; -/// Inputs for a create call. -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +/// Inputs for a create call +#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct CreateInputs { - /// Caller address of the EVM. + /// Caller address of the EVM pub caller: Address, - /// The create scheme. + /// The create scheme pub scheme: CreateScheme, - /// The value to transfer. + /// The value to transfer pub value: U256, - /// The init code of the contract. + /// The init code of the contract pub init_code: Bytes, - /// The gas limit of the call. + /// The gas limit of the call pub gas_limit: u64, } impl CreateInputs { - /// Creates new create inputs. - pub fn new(tx_env: &TxEnv, gas_limit: u64) -> Option { - let TransactTo::Create = tx_env.transact_to else { - return None; - }; - - Some(CreateInputs { - caller: tx_env.caller, - scheme: CreateScheme::Create, - value: tx_env.value, - init_code: tx_env.data.clone(), - gas_limit, - }) - } - - /// Returns boxed create inputs. - pub fn new_boxed(tx_env: &TxEnv, gas_limit: u64) -> Option> { - Self::new(tx_env, gas_limit).map(Box::new) - } - /// Returns the address that this create call will create. pub fn created_address(&self, nonce: u64) -> Address { match self.scheme { @@ -46,6 +25,7 @@ impl CreateInputs { CreateScheme::Create2 { salt } => self .caller .create2_from_code(salt.to_be_bytes(), &self.init_code), + CreateScheme::Custom { address } => address, } } } diff --git a/crates/interpreter/src/interpreter_action/create_outcome.rs b/crates/interpreter/src/interpreter_action/create_outcome.rs index 5cdfcf41b8..11d7204e66 100644 --- a/crates/interpreter/src/interpreter_action/create_outcome.rs +++ b/crates/interpreter/src/interpreter_action/create_outcome.rs @@ -1,69 +1,74 @@ use crate::{Gas, InstructionResult, InterpreterResult}; -use revm_primitives::{Address, Bytes}; +use primitives::{Address, Bytes}; /// Represents the outcome of a create operation in an interpreter. /// /// This struct holds the result of the operation along with an optional address. +/// /// It provides methods to determine the next action based on the result of the operation. #[derive(Debug, Clone, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct CreateOutcome { - // The result of the interpreter operation. + /// The result of the interpreter operation pub result: InterpreterResult, - // An optional address associated with the create operation. + /// An optional address associated with the create operation pub address: Option
, } impl CreateOutcome { - /// Constructs a new `CreateOutcome`. + /// Constructs a new [`CreateOutcome`]. /// /// # Arguments /// - /// * `result` - An `InterpreterResult` representing the result of the interpreter operation. - /// * `address` - An optional `Address` associated with the create operation. + /// * `result` - An [`InterpreterResult`] representing the result of the interpreter operation. + /// * `address` - An optional [`Address`] associated with the create operation. /// /// # Returns /// - /// A new `CreateOutcome` instance. + /// A new [`CreateOutcome`] instance. pub fn new(result: InterpreterResult, address: Option
) -> Self { Self { result, address } } - /// Retrieves a reference to the `InstructionResult` from the `InterpreterResult`. + /// Retrieves a reference to the [`InstructionResult`] from the [`InterpreterResult`]. + /// + /// This method provides access to the [`InstructionResult`] which represents the + /// outcome of the instruction execution. /// - /// This method provides access to the `InstructionResult` which represents the - /// outcome of the instruction execution. It encapsulates the result information - /// such as whether the instruction was executed successfully, resulted in a revert, - /// or encountered a fatal error. + /// It encapsulates the result information such as whether the instruction was + /// executed successfully, resulted in a revert, or encountered a fatal error. /// /// # Returns /// - /// A reference to the `InstructionResult`. + /// A reference to the [`InstructionResult`]. pub fn instruction_result(&self) -> &InstructionResult { &self.result.result } - /// Retrieves a reference to the output bytes from the `InterpreterResult`. + /// Retrieves a reference to the output bytes from the [`InterpreterResult`]. /// - /// This method returns the output of the interpreted operation. The output is - /// typically used when the operation successfully completes and returns data. + /// This method returns the output of the interpreted operation. + /// + /// The output is typically used when the operation successfully completes and + /// returns data. /// /// # Returns /// - /// A reference to the output `Bytes`. + /// A reference to the output [`Bytes`]. pub fn output(&self) -> &Bytes { &self.result.output } - /// Retrieves a reference to the `Gas` details from the `InterpreterResult`. + /// Retrieves a reference to the [`Gas`] details from the [`InterpreterResult`]. /// /// This method provides access to the gas details of the operation, which includes - /// information about gas used, remaining, and refunded. It is essential for - /// understanding the gas consumption of the operation. + /// information about gas used, remaining, and refunded. + /// + /// It is essential for understanding the gas consumption of the operation. /// /// # Returns /// - /// A reference to the `Gas` details. + /// A reference to the [`Gas`] details. pub fn gas(&self) -> &Gas { &self.result.gas } diff --git a/crates/interpreter/src/interpreter_action/eof_create_inputs.rs b/crates/interpreter/src/interpreter_action/eof_create_inputs.rs deleted file mode 100644 index 25dac1e046..0000000000 --- a/crates/interpreter/src/interpreter_action/eof_create_inputs.rs +++ /dev/null @@ -1,42 +0,0 @@ -use crate::primitives::{Address, Eof, U256}; -use core::ops::Range; - -/// Inputs for EOF create call. -#[derive(Debug, Default, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct EOFCreateInput { - /// Caller of Eof Craate - pub caller: Address, - /// New contract address. - pub created_address: Address, - /// Values of ether transfered - pub value: U256, - /// Init eof code that is going to be executed. - pub eof_init_code: Eof, - /// Gas limit for the create call. - pub gas_limit: u64, - /// Return memory range. If EOF creation Reverts it can return the - /// the memory range. - pub return_memory_range: Range, -} - -impl EOFCreateInput { - /// Returns a new instance of EOFCreateInput. - pub fn new( - caller: Address, - created_address: Address, - value: U256, - eof_init_code: Eof, - gas_limit: u64, - return_memory_range: Range, - ) -> EOFCreateInput { - EOFCreateInput { - caller, - created_address, - value, - eof_init_code, - gas_limit, - return_memory_range, - } - } -} diff --git a/crates/interpreter/src/interpreter_action/eof_create_outcome.rs b/crates/interpreter/src/interpreter_action/eof_create_outcome.rs deleted file mode 100644 index 9ec669a070..0000000000 --- a/crates/interpreter/src/interpreter_action/eof_create_outcome.rs +++ /dev/null @@ -1,88 +0,0 @@ -use core::ops::Range; - -use crate::{Gas, InstructionResult, InterpreterResult}; -use revm_primitives::{Address, Bytes}; - -/// Represents the outcome of a create operation in an interpreter. -/// -/// This struct holds the result of the operation along with an optional address. -/// It provides methods to determine the next action based on the result of the operation. -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct EOFCreateOutcome { - /// The result of the interpreter operation. - pub result: InterpreterResult, - /// An optional address associated with the create operation. - pub address: Address, - /// Return memory range. If EOF creation Reverts it can return bytes from the memory. - pub return_memory_range: Range, -} - -impl EOFCreateOutcome { - /// Constructs a new [`EOFCreateOutcome`]. - /// - /// # Arguments - /// - /// * `result` - An `InterpreterResult` representing the result of the interpreter operation. - /// * `address` - An optional `Address` associated with the create operation. - /// * `return_memory_range` - The memory range that Revert bytes are going to be written. - /// - /// # Returns - /// - /// A new [`EOFCreateOutcome`] instance. - pub fn new( - result: InterpreterResult, - address: Address, - return_memory_range: Range, - ) -> Self { - Self { - result, - address, - return_memory_range, - } - } - - /// Retrieves a reference to the [`InstructionResult`] from the [`InterpreterResult`]. - /// - /// This method provides access to the `InstructionResult` which represents the - /// outcome of the instruction execution. It encapsulates the result information - /// such as whether the instruction was executed successfully, resulted in a revert, - /// or encountered a fatal error. - /// - /// # Returns - /// - /// A reference to the `InstructionResult`. - pub fn instruction_result(&self) -> &InstructionResult { - &self.result.result - } - - /// Retrieves a reference to the output bytes from the `InterpreterResult`. - /// - /// This method returns the output of the interpreted operation. The output is - /// typically used when the operation successfully completes and returns data. - /// - /// # Returns - /// - /// A reference to the output `Bytes`. - pub fn output(&self) -> &Bytes { - &self.result.output - } - - /// Retrieves a reference to the `Gas` details from the `InterpreterResult`. - /// - /// This method provides access to the gas details of the operation, which includes - /// information about gas used, remaining, and refunded. It is essential for - /// understanding the gas consumption of the operation. - /// - /// # Returns - /// - /// A reference to the `Gas` details. - pub fn gas(&self) -> &Gas { - &self.result.gas - } - - /// Returns the memory range that Revert bytes are going to be written. - pub fn return_range(&self) -> Range { - self.return_memory_range.clone() - } -} diff --git a/crates/interpreter/src/interpreter_types.rs b/crates/interpreter/src/interpreter_types.rs new file mode 100644 index 0000000000..810d1eec62 --- /dev/null +++ b/crates/interpreter/src/interpreter_types.rs @@ -0,0 +1,313 @@ +use crate::{CallInput, InstructionResult, InterpreterAction}; +use core::cell::Ref; +use core::ops::{Deref, Range}; +use primitives::{hardfork::SpecId, Address, Bytes, B256, U256}; + +/// Helper function to read immediates data from the bytecode +pub trait Immediates { + /// Reads next 16 bits as signed integer from the bytecode. + #[inline] + fn read_i16(&self) -> i16 { + self.read_u16() as i16 + } + /// Reads next 16 bits as unsigned integer from the bytecode. + fn read_u16(&self) -> u16; + + /// Reads next 8 bits as signed integer from the bytecode. + #[inline] + fn read_i8(&self) -> i8 { + self.read_u8() as i8 + } + + /// Reads next 8 bits as unsigned integer from the bytecode. + fn read_u8(&self) -> u8; + + /// Reads next 16 bits as signed integer from the bytecode at given offset. + #[inline] + fn read_offset_i16(&self, offset: isize) -> i16 { + self.read_offset_u16(offset) as i16 + } + + /// Reads next 16 bits as unsigned integer from the bytecode at given offset. + fn read_offset_u16(&self, offset: isize) -> u16; + + /// Reads next `len` bytes from the bytecode. + /// + /// Used by PUSH opcode. + fn read_slice(&self, len: usize) -> &[u8]; +} + +/// Trait for fetching inputs of the call. +pub trait InputsTr { + /// Returns target address of the call. + fn target_address(&self) -> Address; + /// Returns bytecode address of the call. For DELEGATECALL this address will be different from target address. + /// And if initcode is called this address will be [`None`]. + fn bytecode_address(&self) -> Option<&Address>; + /// Returns caller address of the call. + fn caller_address(&self) -> Address; + /// Returns input of the call. + fn input(&self) -> &CallInput; + /// Returns call value of the call. + fn call_value(&self) -> U256; +} + +/// Trait needed for legacy bytecode. +/// +/// Used in [`bytecode::opcode::CODECOPY`] and [`bytecode::opcode::CODESIZE`] opcodes. +pub trait LegacyBytecode { + /// Returns current bytecode original length. Used in [`bytecode::opcode::CODESIZE`] opcode. + fn bytecode_len(&self) -> usize; + /// Returns current bytecode original slice. Used in [`bytecode::opcode::CODECOPY`] opcode. + fn bytecode_slice(&self) -> &[u8]; +} + +/// Trait for Interpreter to be able to jump +pub trait Jumps { + /// Relative jumps does not require checking for overflow. + fn relative_jump(&mut self, offset: isize); + /// Absolute jumps require checking for overflow and if target is a jump destination + /// from jump table. + fn absolute_jump(&mut self, offset: usize); + /// Check legacy jump destination from jump table. + fn is_valid_legacy_jump(&mut self, offset: usize) -> bool; + /// Returns current program counter. + fn pc(&self) -> usize; + /// Returns instruction opcode. + fn opcode(&self) -> u8; +} + +/// Trait for Interpreter memory operations. +pub trait MemoryTr { + /// Sets memory data at given offset from data with a given data_offset and len. + /// + /// # Panics + /// + /// Panics if range is out of scope of allocated memory. + fn set_data(&mut self, memory_offset: usize, data_offset: usize, len: usize, data: &[u8]); + + /// Inner clone part of memory from global context to local context. + /// This is used to clone calldata to memory. + /// + /// # Panics + /// + /// Panics if range is out of scope of allocated memory. + fn set_data_from_global( + &mut self, + memory_offset: usize, + data_offset: usize, + len: usize, + data_range: Range, + ); + + /// Memory slice with global range. This range + /// + /// # Panics + /// + /// Panics if range is out of scope of allocated memory. + fn global_slice(&self, range: Range) -> Ref<'_, [u8]>; + + /// Offset of local context of memory. + fn local_memory_offset(&self) -> usize; + + /// Sets memory data at given offset. + /// + /// # Panics + /// + /// Panics if range is out of scope of allocated memory. + fn set(&mut self, memory_offset: usize, data: &[u8]); + + /// Returns memory size. + fn size(&self) -> usize; + + /// Copies memory data from source to destination. + /// + /// # Panics + /// Panics if range is out of scope of allocated memory. + fn copy(&mut self, destination: usize, source: usize, len: usize); + + /// Memory slice with range + /// + /// # Panics + /// + /// Panics if range is out of scope of allocated memory. + fn slice(&self, range: Range) -> Ref<'_, [u8]>; + + /// Memory slice len + /// + /// Uses [`slice`][MemoryTr::slice] internally. + fn slice_len(&self, offset: usize, len: usize) -> impl Deref + '_ { + self.slice(offset..offset + len) + } + + /// Resizes memory to new size + /// + /// # Note + /// + /// It checks memory limits. + fn resize(&mut self, new_size: usize) -> bool; +} + +/// Functions needed for Interpreter Stack operations. +pub trait StackTr { + /// Returns stack length. + fn len(&self) -> usize; + + /// Returns `true` if stack is empty. + fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Clears the stack. + fn clear(&mut self); + + /// Pushes values to the stack. + /// + /// Returns `true` if push was successful, `false` if stack overflow. + /// + /// # Note + /// Error is internally set in interpreter. + #[must_use] + fn push(&mut self, value: U256) -> bool; + + /// Pushes slice to the stack. + /// + /// Returns `true` if push was successful, `false` if stack overflow. + /// + /// # Note + /// Error is internally set in interpreter. + fn push_slice(&mut self, slice: &[u8]) -> bool; + + /// Pushes B256 value to the stack. + /// + /// Internally converts B256 to U256 and then calls [`StackTr::push`]. + #[must_use] + fn push_b256(&mut self, value: B256) -> bool { + self.push(value.into()) + } + + /// Pops value from the stack. + #[must_use] + fn popn(&mut self) -> Option<[U256; N]>; + + /// Pop N values from the stack and return top value. + #[must_use] + fn popn_top(&mut self) -> Option<([U256; POPN], &mut U256)>; + + /// Returns top value from the stack. + #[must_use] + fn top(&mut self) -> Option<&mut U256> { + self.popn_top().map(|([], top)| top) + } + + /// Pops one value from the stack. + #[must_use] + fn pop(&mut self) -> Option { + self.popn::<1>().map(|[value]| value) + } + + /// Pops address from the stack. + /// + /// Internally call [`StackTr::pop`] and converts [`U256`] into [`Address`]. + #[must_use] + fn pop_address(&mut self) -> Option
{ + self.pop().map(|value| Address::from(value.to_be_bytes())) + } + + /// Exchanges two values on the stack. + /// + /// Indexes are based from the top of the stack. + /// + /// Returns `true` if swap was successful, `false` if stack underflow. + #[must_use] + fn exchange(&mut self, n: usize, m: usize) -> bool; + + /// Duplicates the `N`th value from the top of the stack. + /// + /// Index is based from the top of the stack. + /// + /// Returns `true` if duplicate was successful, `false` if stack underflow. + #[must_use] + fn dup(&mut self, n: usize) -> bool; +} + +/// Returns return data. +pub trait ReturnData { + /// Returns return data. + fn buffer(&self) -> &Bytes; + + /// Sets return buffer. + fn set_buffer(&mut self, bytes: Bytes); + + /// Clears return buffer. + fn clear(&mut self) { + self.set_buffer(Bytes::new()); + } +} + +/// Trait controls execution of the loop. +pub trait LoopControl { + /// Returns `true` if the loop should continue. + #[inline] + fn is_not_end(&self) -> bool { + !self.is_end() + } + /// Is end of the loop. + fn is_end(&self) -> bool; + /// Reverts to previous instruction pointer. + /// + /// After the loop is finished, the instruction pointer is set to the previous one. + fn revert_to_previous_pointer(&mut self); + /// Set return action and set instruction pointer to null. Preserve previous pointer + /// + /// Previous pointer can be restored by calling [`LoopControl::revert_to_previous_pointer`]. + fn set_action(&mut self, action: InterpreterAction); + /// Takes next action. + fn action(&mut self) -> &mut Option; + /// Returns instruction result + #[inline] + fn instruction_result(&mut self) -> Option { + self.action() + .as_ref() + .and_then(|action| action.instruction_result()) + } +} + +/// Runtime flags that control interpreter execution behavior. +pub trait RuntimeFlag { + /// Returns true if the current execution context is static (read-only). + fn is_static(&self) -> bool; + /// Returns the current EVM specification ID. + fn spec_id(&self) -> SpecId; +} + +/// Trait for interpreter execution. +pub trait Interp { + /// The instruction type. + type Instruction; + /// The action type returned after execution. + type Action; + + /// Runs the interpreter with the given instruction table. + fn run(&mut self, instructions: &[Self::Instruction; 256]) -> Self::Action; +} + +/// Trait defining the component types used by an interpreter implementation. +pub trait InterpreterTypes { + /// Stack implementation type. + type Stack: StackTr; + /// Memory implementation type. + type Memory: MemoryTr; + /// Bytecode implementation type. + type Bytecode: Jumps + Immediates + LoopControl + LegacyBytecode; + /// Return data implementation type. + type ReturnData: ReturnData; + /// Input data implementation type. + type Input: InputsTr; + /// Runtime flags implementation type. + type RuntimeFlag: RuntimeFlag; + /// Extended functionality type. + type Extend; + /// Output type for execution results. + type Output; +} diff --git a/crates/interpreter/src/lib.rs b/crates/interpreter/src/lib.rs index 01db032788..e860126833 100644 --- a/crates/interpreter/src/lib.rs +++ b/crates/interpreter/src/lib.rs @@ -1,6 +1,6 @@ //! # revm-interpreter //! -//! REVM Interpreter. +//! Interpreter is part of the project that executes EVM instructions. #![cfg_attr(not(test), warn(unused_crate_dependencies))] #![cfg_attr(not(feature = "std"), no_std)] @@ -10,37 +10,37 @@ extern crate alloc as std; #[macro_use] mod macros; -// silence lint -#[cfg(test)] -use serde_json as _; - -#[cfg(test)] -use walkdir as _; - -mod function_stack; +/// Gas calculation utilities and constants. pub mod gas; -mod host; +/// Context passed to instruction implementations. +pub mod instruction_context; +/// Instruction execution results and success/error types. mod instruction_result; +/// EVM instruction implementations organized by category. pub mod instructions; +/// Core interpreter implementation for EVM bytecode execution. pub mod interpreter; +/// Types for interpreter actions like calls and contract creation. pub mod interpreter_action; -pub mod opcode; +/// Type traits and definitions for interpreter customization. +pub mod interpreter_types; // Reexport primary types. -pub use function_stack::{FunctionReturnFrame, FunctionStack}; -pub use gas::Gas; -pub use host::{DummyHost, Host, LoadAccountResult, SStoreResult, SelfDestructResult}; +pub use context_interface::{ + context::{SStoreResult, SelfDestructResult, StateLoad}, + CreateScheme, +}; +pub use context_interface::{host, Host}; +pub use gas::{Gas, InitialAndFloorGas}; +pub use instruction_context::InstructionContext; pub use instruction_result::*; +pub use instructions::{instruction_table, Instruction, InstructionTable}; pub use interpreter::{ - analysis, num_words, Contract, Interpreter, InterpreterResult, SharedMemory, Stack, - EMPTY_SHARED_MEMORY, STACK_LIMIT, + num_words, InputsImpl, Interpreter, InterpreterResult, SharedMemory, Stack, STACK_LIMIT, }; pub use interpreter_action::{ - CallInputs, CallOutcome, CallScheme, CallValue, CreateInputs, CreateOutcome, CreateScheme, - EOFCreateInput, EOFCreateOutcome, InterpreterAction, + CallInput, CallInputs, CallOutcome, CallScheme, CallValue, CreateInputs, CreateOutcome, + FrameInput, InterpreterAction, }; -pub use opcode::{Instruction, OpCode, OPCODE_INFO_JUMPTABLE}; -pub use primitives::{MAX_CODE_SIZE, MAX_INITCODE_SIZE}; - -#[doc(hidden)] -pub use revm_primitives as primitives; +pub use interpreter_types::InterpreterTypes; +pub use primitives::{eip7907::MAX_CODE_SIZE, eip7907::MAX_INITCODE_SIZE}; diff --git a/crates/interpreter/src/macros.rs b/crates/interpreter/src/macros.rs index d0c1c6c080..7b28fdefd6 100644 --- a/crates/interpreter/src/macros.rs +++ b/crates/interpreter/src/macros.rs @@ -1,3 +1,6 @@ +/// Macro that triggers `unreachable!` in debug builds but uses unchecked unreachable in release builds. +/// This provides better error messages during development while optimizing for performance in release. +#[macro_export] macro_rules! debug_unreachable { ($($t:tt)*) => { if cfg!(debug_assertions) { @@ -8,6 +11,10 @@ macro_rules! debug_unreachable { }; } +/// Macro for asserting assumptions in debug builds. +/// In debug builds, this will trigger unreachable code if the assumption is false. +/// In release builds, this serves as an optimization hint. +#[macro_export] macro_rules! assume { ($e:expr $(,)?) => { if !$e { diff --git a/crates/interpreter/src/opcode.rs b/crates/interpreter/src/opcode.rs deleted file mode 100644 index b5b6ffd17c..0000000000 --- a/crates/interpreter/src/opcode.rs +++ /dev/null @@ -1,929 +0,0 @@ -//! EVM opcode definitions and utilities. - -pub mod eof_printer; - -use crate::{instructions::*, primitives::Spec, Host, Interpreter}; -use core::{fmt, ptr::NonNull}; -use std::boxed::Box; - -/// EVM opcode function signature. -pub type Instruction = fn(&mut Interpreter, &mut H); - -/// Instruction table is list of instruction function pointers mapped to -/// 256 EVM opcodes. -pub type InstructionTable = [Instruction; 256]; - -/// EVM opcode function signature. -pub type BoxedInstruction<'a, H> = Box; - -/// A table of instructions. -pub type BoxedInstructionTable<'a, H> = [BoxedInstruction<'a, H>; 256]; - -/// Instruction set that contains plain instruction table that contains simple `fn` function pointer. -/// and Boxed `Fn` variant that contains `Box` function pointer that can be used with closured. -/// -/// Note that `Plain` variant gives us 10-20% faster Interpreter execution. -/// -/// Boxed variant can be used to wrap plain function pointer with closure. -pub enum InstructionTables<'a, H> { - Plain(InstructionTable), - Boxed(BoxedInstructionTable<'a, H>), -} - -impl InstructionTables<'_, H> { - /// Creates a plain instruction table for the given spec. - #[inline] - pub const fn new_plain() -> Self { - Self::Plain(make_instruction_table::()) - } -} - -impl<'a, H: Host + 'a> InstructionTables<'a, H> { - /// Inserts a boxed instruction into the table with the specified index. - /// - /// This will convert the table into the [BoxedInstructionTable] variant if it is currently a - /// plain instruction table, before inserting the instruction. - #[inline] - pub fn insert_boxed(&mut self, opcode: u8, instruction: BoxedInstruction<'a, H>) { - // first convert the table to boxed variant - self.convert_boxed(); - - // now we can insert the instruction - match self { - Self::Plain(_) => { - unreachable!("we already converted the table to boxed variant"); - } - Self::Boxed(table) => { - table[opcode as usize] = Box::new(instruction); - } - } - } - - /// Inserts the instruction into the table with the specified index. - #[inline] - pub fn insert(&mut self, opcode: u8, instruction: Instruction) { - match self { - Self::Plain(table) => { - table[opcode as usize] = instruction; - } - Self::Boxed(table) => { - table[opcode as usize] = Box::new(instruction); - } - } - } - - /// Converts the current instruction table to a boxed variant. If the table is already boxed, - /// this is a no-op. - #[inline] - pub fn convert_boxed(&mut self) { - match self { - Self::Plain(table) => { - *self = Self::Boxed(core::array::from_fn(|i| { - let instruction: BoxedInstruction<'a, H> = Box::new(table[i]); - instruction - })); - } - Self::Boxed(_) => {} - }; - } -} - -/// Make instruction table. -#[inline] -pub const fn make_instruction_table() -> InstructionTable { - // Force const-eval of the table creation, making this function trivial. - // TODO: Replace this with a `const {}` block once it is stable. - struct ConstTable { - _host: core::marker::PhantomData, - _spec: core::marker::PhantomData, - } - impl ConstTable { - const NEW: InstructionTable = { - let mut tables: InstructionTable = [control::unknown; 256]; - let mut i = 0; - while i < 256 { - tables[i] = instruction::(i as u8); - i += 1; - } - tables - }; - } - ConstTable::::NEW -} - -/// Make boxed instruction table that calls `outer` closure for every instruction. -#[inline] -pub fn make_boxed_instruction_table<'a, H, SPEC, FN>( - table: InstructionTable, - mut outer: FN, -) -> BoxedInstructionTable<'a, H> -where - H: Host, - SPEC: Spec + 'a, - FN: FnMut(Instruction) -> BoxedInstruction<'a, H>, -{ - core::array::from_fn(|i| outer(table[i])) -} - -/// An error indicating that an opcode is invalid. -#[derive(Debug, PartialEq, Eq)] -#[cfg(feature = "parse")] -pub struct OpCodeError(()); - -#[cfg(feature = "parse")] -impl fmt::Display for OpCodeError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("invalid opcode") - } -} - -#[cfg(all(feature = "std", feature = "parse"))] -impl std::error::Error for OpCodeError {} - -/// An EVM opcode. -/// -/// This is always a valid opcode, as declared in the [`opcode`][self] module or the -/// [`OPCODE_INFO_JUMPTABLE`] constant. -#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[repr(transparent)] -pub struct OpCode(u8); - -impl fmt::Display for OpCode { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let n = self.get(); - if let Some(val) = OPCODE_INFO_JUMPTABLE[n as usize] { - f.write_str(val.name()) - } else { - write!(f, "UNKNOWN(0x{n:02X})") - } - } -} - -#[cfg(feature = "parse")] -impl core::str::FromStr for OpCode { - type Err = OpCodeError; - - #[inline] - fn from_str(s: &str) -> Result { - Self::parse(s).ok_or(OpCodeError(())) - } -} - -impl OpCode { - /// Instantiate a new opcode from a u8. - #[inline] - pub const fn new(opcode: u8) -> Option { - match OPCODE_INFO_JUMPTABLE[opcode as usize] { - Some(_) => Some(Self(opcode)), - None => None, - } - } - - /// Parses an opcode from a string. This is the inverse of [`as_str`](Self::as_str). - #[inline] - #[cfg(feature = "parse")] - pub fn parse(s: &str) -> Option { - NAME_TO_OPCODE.get(s).copied() - } - - /// Returns true if the opcode is a jump destination. - #[inline] - pub const fn is_jumpdest(&self) -> bool { - self.0 == JUMPDEST - } - - /// Takes a u8 and returns true if it is a jump destination. - #[inline] - pub const fn is_jumpdest_by_op(opcode: u8) -> bool { - if let Some(opcode) = Self::new(opcode) { - opcode.is_jumpdest() - } else { - false - } - } - - /// Returns true if the opcode is a legacy jump instruction. - #[inline] - pub const fn is_jump(self) -> bool { - self.0 == JUMP - } - - /// Takes a u8 and returns true if it is a jump instruction. - #[inline] - pub const fn is_jump_by_op(opcode: u8) -> bool { - if let Some(opcode) = Self::new(opcode) { - opcode.is_jump() - } else { - false - } - } - - /// Returns true if the opcode is a `PUSH` instruction. - #[inline] - pub const fn is_push(self) -> bool { - self.0 >= PUSH1 && self.0 <= PUSH32 - } - - /// Takes a u8 and returns true if it is a push instruction. - #[inline] - pub fn is_push_by_op(opcode: u8) -> bool { - if let Some(opcode) = Self::new(opcode) { - opcode.is_push() - } else { - false - } - } - - /// Instantiate a new opcode from a u8 without checking if it is valid. - /// - /// # Safety - /// - /// All code using `Opcode` values assume that they are valid opcodes, so providing an invalid - /// opcode may cause undefined behavior. - #[inline] - pub unsafe fn new_unchecked(opcode: u8) -> Self { - Self(opcode) - } - - /// Returns the opcode as a string. This is the inverse of [`parse`](Self::parse). - #[doc(alias = "name")] - #[inline] - pub const fn as_str(self) -> &'static str { - self.info().name() - } - - /// Returns the opcode name. - #[inline] - pub const fn name_by_op(opcode: u8) -> &'static str { - if let Some(opcode) = Self::new(opcode) { - opcode.as_str() - } else { - "Unknown" - } - } - - /// Returns the number of input stack elements. - #[inline] - pub const fn inputs(&self) -> u8 { - self.info().inputs() - } - - /// Returns the number of output stack elements. - #[inline] - pub const fn outputs(&self) -> u8 { - self.info().outputs() - } - - /// Calculates the difference between the number of input and output stack elements. - #[inline] - pub const fn io_diff(&self) -> i16 { - self.info().io_diff() - } - - /// Returns the opcode information for the given opcode. - #[inline] - pub const fn info_by_op(opcode: u8) -> Option { - if let Some(opcode) = Self::new(opcode) { - Some(opcode.info()) - } else { - None - } - } - - /// Returns the opcode information. - #[inline] - pub const fn info(&self) -> OpCodeInfo { - if let Some(t) = OPCODE_INFO_JUMPTABLE[self.0 as usize] { - t - } else { - panic!("opcode not found") - } - } - - /// Returns the number of both input and output stack elements. - /// - /// Can be slightly faster that calling `inputs` and `outputs` separately. - pub const fn input_output(&self) -> (u8, u8) { - let info = self.info(); - (info.inputs, info.outputs) - } - - /// Returns the opcode as a u8. - #[inline] - pub const fn get(self) -> u8 { - self.0 - } - - /// Returns true if the opcode modifies memory. - /// - /// - #[inline] - pub const fn modifies_memory(&self) -> bool { - matches!( - *self, - OpCode::EXTCODECOPY - | OpCode::MLOAD - | OpCode::MSTORE - | OpCode::MSTORE8 - | OpCode::MCOPY - | OpCode::CODECOPY - | OpCode::CALLDATACOPY - | OpCode::RETURNDATACOPY - | OpCode::CALL - | OpCode::CALLCODE - | OpCode::DELEGATECALL - | OpCode::STATICCALL - ) - } -} - -/// Information about opcode, such as name, and stack inputs and outputs. -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct OpCodeInfo { - /// Invariant: `(name_ptr, name_len)` is a `&'static str`. It is a shorted variant of `str` as - /// the name length is always less than 256 characters. - name_ptr: NonNull, - name_len: u8, - /// Stack inputs. - inputs: u8, - /// Stack outputs. - outputs: u8, - /// Number of intermediate bytes. - /// - /// RJUMPV is a special case where the bytes len depends on bytecode value, - /// for RJUMV size will be set to one byte as it is the minimum immediate size. - immediate_size: u8, - /// Used by EOF verification. All not EOF opcodes are marked false. - not_eof: bool, - /// If the opcode stops execution. aka STOP, RETURN, .. - terminating: bool, -} - -impl fmt::Debug for OpCodeInfo { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("OpCodeInfo") - .field("name", &self.name()) - .field("inputs", &self.inputs()) - .field("outputs", &self.outputs()) - .field("not_eof", &self.is_disabled_in_eof()) - .field("terminating", &self.is_terminating()) - .field("immediate_size", &self.immediate_size()) - .finish() - } -} - -impl OpCodeInfo { - /// Creates a new opcode info with the given name and default values. - pub const fn new(name: &'static str) -> Self { - assert!(name.len() < 256, "opcode name is too long"); - Self { - name_ptr: unsafe { NonNull::new_unchecked(name.as_ptr().cast_mut()) }, - name_len: name.len() as u8, - inputs: 0, - outputs: 0, - not_eof: false, - terminating: false, - immediate_size: 0, - } - } - - /// Returns the opcode name. - #[inline] - pub const fn name(&self) -> &'static str { - // SAFETY: `self.name_*` can only be initialized with a valid `&'static str`. - unsafe { - // TODO: Use `str::from_raw_parts` when it's stable. - let slice = core::slice::from_raw_parts(self.name_ptr.as_ptr(), self.name_len as usize); - core::str::from_utf8_unchecked(slice) - } - } - - /// Calculates the difference between the number of input and output stack elements. - #[inline] - pub const fn io_diff(&self) -> i16 { - self.outputs as i16 - self.inputs as i16 - } - - /// Returns the number of input stack elements. - #[inline] - pub const fn inputs(&self) -> u8 { - self.inputs - } - - /// Returns the number of output stack elements. - #[inline] - pub const fn outputs(&self) -> u8 { - self.outputs - } - - /// Returns whether this opcode is disabled in EOF bytecode. - #[inline] - pub const fn is_disabled_in_eof(&self) -> bool { - self.not_eof - } - - /// Returns whether this opcode terminates execution, e.g. `STOP`, `RETURN`, etc. - #[inline] - pub const fn is_terminating(&self) -> bool { - self.terminating - } - - /// Returns the size of the immediate value in bytes. - #[inline] - pub const fn immediate_size(&self) -> u8 { - self.immediate_size - } -} - -/// Sets the EOF flag to false. -#[inline] -pub const fn not_eof(mut op: OpCodeInfo) -> OpCodeInfo { - op.not_eof = true; - op -} - -/// Sets the immediate bytes number. -/// -/// RJUMPV is special case where the bytes len is depending on bytecode value, -/// for RJUMPV size will be set to one byte while minimum is two. -#[inline] -pub const fn immediate_size(mut op: OpCodeInfo, n: u8) -> OpCodeInfo { - op.immediate_size = n; - op -} - -/// Sets the terminating flag to true. -#[inline] -pub const fn terminating(mut op: OpCodeInfo) -> OpCodeInfo { - op.terminating = true; - op -} - -/// Sets the number of stack inputs and outputs. -#[inline] -pub const fn stack_io(mut op: OpCodeInfo, inputs: u8, outputs: u8) -> OpCodeInfo { - op.inputs = inputs; - op.outputs = outputs; - op -} - -/// Alias for the [`JUMPDEST`] opcode. -pub const NOP: u8 = JUMPDEST; - -/// Callback for creating a [`phf`] map with `stringify_with_cb`. -#[cfg(feature = "parse")] -macro_rules! phf_map_cb { - ($(#[doc = $s:literal] $id:ident)*) => { - phf::phf_map! { - $($s => OpCode::$id),* - } - }; -} - -/// Stringifies identifiers with `paste` so that they are available as literals. -/// This doesn't work with `stringify!` because it cannot be expanded inside of another macro. -#[cfg(feature = "parse")] -macro_rules! stringify_with_cb { - ($callback:ident; $($id:ident)*) => { paste::paste! { - $callback! { $(#[doc = "" $id ""] $id)* } - }}; -} - -macro_rules! opcodes { - ($($val:literal => $name:ident => $f:expr => $($modifier:ident $(( $($modifier_arg:expr),* ))?),*);* $(;)?) => { - // Constants for each opcode. This also takes care of duplicate names. - $( - #[doc = concat!("The `", stringify!($val), "` (\"", stringify!($name),"\") opcode.")] - pub const $name: u8 = $val; - )* - impl OpCode {$( - #[doc = concat!("The `", stringify!($val), "` (\"", stringify!($name),"\") opcode.")] - pub const $name: Self = Self($val); - )*} - - /// Maps each opcode to its info. - pub const OPCODE_INFO_JUMPTABLE: [Option; 256] = { - let mut map = [None; 256]; - let mut prev: u8 = 0; - $( - let val: u8 = $val; - assert!(val == 0 || val > prev, "opcodes must be sorted in ascending order"); - prev = val; - let info = OpCodeInfo::new(stringify!($name)); - $( - let info = $modifier(info, $($($modifier_arg),*)?); - )* - map[$val] = Some(info); - )* - let _ = prev; - map - }; - - /// Maps each name to its opcode. - #[cfg(feature = "parse")] - static NAME_TO_OPCODE: phf::Map<&'static str, OpCode> = stringify_with_cb! { phf_map_cb; $($name)* }; - - /// Returns the instruction function for the given opcode and spec. - pub const fn instruction(opcode: u8) -> Instruction { - match opcode { - $($name => $f,)* - _ => control::unknown, - } - } - }; -} - -// When adding new opcodes: -// 1. add the opcode to the list below; make sure it's sorted by opcode value -// 2. implement the opcode in the corresponding module; -// the function signature must be the exact same as the others -opcodes! { - 0x00 => STOP => control::stop => stack_io(0, 0), terminating; - - 0x01 => ADD => arithmetic::add => stack_io(2, 1); - 0x02 => MUL => arithmetic::mul => stack_io(2, 1); - 0x03 => SUB => arithmetic::sub => stack_io(2, 1); - 0x04 => DIV => arithmetic::div => stack_io(2, 1); - 0x05 => SDIV => arithmetic::sdiv => stack_io(2, 1); - 0x06 => MOD => arithmetic::rem => stack_io(2, 1); - 0x07 => SMOD => arithmetic::smod => stack_io(2, 1); - 0x08 => ADDMOD => arithmetic::addmod => stack_io(3, 1); - 0x09 => MULMOD => arithmetic::mulmod => stack_io(3, 1); - 0x0A => EXP => arithmetic::exp:: => stack_io(2, 1); - 0x0B => SIGNEXTEND => arithmetic::signextend => stack_io(2, 1); - // 0x0C - // 0x0D - // 0x0E - // 0x0F - 0x10 => LT => bitwise::lt => stack_io(2, 1); - 0x11 => GT => bitwise::gt => stack_io(2, 1); - 0x12 => SLT => bitwise::slt => stack_io(2, 1); - 0x13 => SGT => bitwise::sgt => stack_io(2, 1); - 0x14 => EQ => bitwise::eq => stack_io(2, 1); - 0x15 => ISZERO => bitwise::iszero => stack_io(1, 1); - 0x16 => AND => bitwise::bitand => stack_io(2, 1); - 0x17 => OR => bitwise::bitor => stack_io(2, 1); - 0x18 => XOR => bitwise::bitxor => stack_io(2, 1); - 0x19 => NOT => bitwise::not => stack_io(1, 1); - 0x1A => BYTE => bitwise::byte => stack_io(2, 1); - 0x1B => SHL => bitwise::shl:: => stack_io(2, 1); - 0x1C => SHR => bitwise::shr:: => stack_io(2, 1); - 0x1D => SAR => bitwise::sar:: => stack_io(2, 1); - // 0x1E - // 0x1F - 0x20 => KECCAK256 => system::keccak256 => stack_io(2, 1); - // 0x21 - // 0x22 - // 0x23 - // 0x24 - // 0x25 - // 0x26 - // 0x27 - // 0x28 - // 0x29 - // 0x2A - // 0x2B - // 0x2C - // 0x2D - // 0x2E - // 0x2F - 0x30 => ADDRESS => system::address => stack_io(0, 1); - 0x31 => BALANCE => host::balance:: => stack_io(1, 1); - 0x32 => ORIGIN => host_env::origin => stack_io(0, 1); - 0x33 => CALLER => system::caller => stack_io(0, 1); - 0x34 => CALLVALUE => system::callvalue => stack_io(0, 1); - 0x35 => CALLDATALOAD => system::calldataload => stack_io(1, 1); - 0x36 => CALLDATASIZE => system::calldatasize => stack_io(0, 1); - 0x37 => CALLDATACOPY => system::calldatacopy => stack_io(3, 0); - 0x38 => CODESIZE => system::codesize => stack_io(0, 1), not_eof; - 0x39 => CODECOPY => system::codecopy => stack_io(3, 0), not_eof; - - 0x3A => GASPRICE => host_env::gasprice => stack_io(0, 1); - 0x3B => EXTCODESIZE => host::extcodesize:: => stack_io(1, 1), not_eof; - 0x3C => EXTCODECOPY => host::extcodecopy:: => stack_io(4, 0), not_eof; - 0x3D => RETURNDATASIZE => system::returndatasize:: => stack_io(0, 1); - 0x3E => RETURNDATACOPY => system::returndatacopy:: => stack_io(3, 0); - 0x3F => EXTCODEHASH => host::extcodehash:: => stack_io(1, 1), not_eof; - 0x40 => BLOCKHASH => host::blockhash:: => stack_io(1, 1); - 0x41 => COINBASE => host_env::coinbase => stack_io(0, 1); - 0x42 => TIMESTAMP => host_env::timestamp => stack_io(0, 1); - 0x43 => NUMBER => host_env::block_number => stack_io(0, 1); - 0x44 => DIFFICULTY => host_env::difficulty:: => stack_io(0, 1); - 0x45 => GASLIMIT => host_env::gaslimit => stack_io(0, 1); - 0x46 => CHAINID => host_env::chainid:: => stack_io(0, 1); - 0x47 => SELFBALANCE => host::selfbalance:: => stack_io(0, 1); - 0x48 => BASEFEE => host_env::basefee:: => stack_io(0, 1); - 0x49 => BLOBHASH => host_env::blob_hash:: => stack_io(1, 1); - 0x4A => BLOBBASEFEE => host_env::blob_basefee:: => stack_io(0, 1); - // 0x4B - // 0x4C - // 0x4D - // 0x4E - // 0x4F - 0x50 => POP => stack::pop => stack_io(1, 0); - 0x51 => MLOAD => memory::mload => stack_io(1, 1); - 0x52 => MSTORE => memory::mstore => stack_io(2, 0); - 0x53 => MSTORE8 => memory::mstore8 => stack_io(2, 0); - 0x54 => SLOAD => host::sload:: => stack_io(1, 1); - 0x55 => SSTORE => host::sstore:: => stack_io(2, 0); - 0x56 => JUMP => control::jump => stack_io(1, 0), not_eof; - 0x57 => JUMPI => control::jumpi => stack_io(2, 0), not_eof; - 0x58 => PC => control::pc => stack_io(0, 1), not_eof; - 0x59 => MSIZE => memory::msize => stack_io(0, 1); - 0x5A => GAS => system::gas => stack_io(0, 1), not_eof; - 0x5B => JUMPDEST => control::jumpdest_or_nop => stack_io(0, 0); - 0x5C => TLOAD => host::tload:: => stack_io(1, 1); - 0x5D => TSTORE => host::tstore:: => stack_io(2, 0); - 0x5E => MCOPY => memory::mcopy:: => stack_io(3, 0); - - 0x5F => PUSH0 => stack::push0:: => stack_io(0, 1); - 0x60 => PUSH1 => stack::push::<1, H> => stack_io(0, 1), immediate_size(1); - 0x61 => PUSH2 => stack::push::<2, H> => stack_io(0, 1), immediate_size(2); - 0x62 => PUSH3 => stack::push::<3, H> => stack_io(0, 1), immediate_size(3); - 0x63 => PUSH4 => stack::push::<4, H> => stack_io(0, 1), immediate_size(4); - 0x64 => PUSH5 => stack::push::<5, H> => stack_io(0, 1), immediate_size(5); - 0x65 => PUSH6 => stack::push::<6, H> => stack_io(0, 1), immediate_size(6); - 0x66 => PUSH7 => stack::push::<7, H> => stack_io(0, 1), immediate_size(7); - 0x67 => PUSH8 => stack::push::<8, H> => stack_io(0, 1), immediate_size(8); - 0x68 => PUSH9 => stack::push::<9, H> => stack_io(0, 1), immediate_size(9); - 0x69 => PUSH10 => stack::push::<10, H> => stack_io(0, 1), immediate_size(10); - 0x6A => PUSH11 => stack::push::<11, H> => stack_io(0, 1), immediate_size(11); - 0x6B => PUSH12 => stack::push::<12, H> => stack_io(0, 1), immediate_size(12); - 0x6C => PUSH13 => stack::push::<13, H> => stack_io(0, 1), immediate_size(13); - 0x6D => PUSH14 => stack::push::<14, H> => stack_io(0, 1), immediate_size(14); - 0x6E => PUSH15 => stack::push::<15, H> => stack_io(0, 1), immediate_size(15); - 0x6F => PUSH16 => stack::push::<16, H> => stack_io(0, 1), immediate_size(16); - 0x70 => PUSH17 => stack::push::<17, H> => stack_io(0, 1), immediate_size(17); - 0x71 => PUSH18 => stack::push::<18, H> => stack_io(0, 1), immediate_size(18); - 0x72 => PUSH19 => stack::push::<19, H> => stack_io(0, 1), immediate_size(19); - 0x73 => PUSH20 => stack::push::<20, H> => stack_io(0, 1), immediate_size(20); - 0x74 => PUSH21 => stack::push::<21, H> => stack_io(0, 1), immediate_size(21); - 0x75 => PUSH22 => stack::push::<22, H> => stack_io(0, 1), immediate_size(22); - 0x76 => PUSH23 => stack::push::<23, H> => stack_io(0, 1), immediate_size(23); - 0x77 => PUSH24 => stack::push::<24, H> => stack_io(0, 1), immediate_size(24); - 0x78 => PUSH25 => stack::push::<25, H> => stack_io(0, 1), immediate_size(25); - 0x79 => PUSH26 => stack::push::<26, H> => stack_io(0, 1), immediate_size(26); - 0x7A => PUSH27 => stack::push::<27, H> => stack_io(0, 1), immediate_size(27); - 0x7B => PUSH28 => stack::push::<28, H> => stack_io(0, 1), immediate_size(28); - 0x7C => PUSH29 => stack::push::<29, H> => stack_io(0, 1), immediate_size(29); - 0x7D => PUSH30 => stack::push::<30, H> => stack_io(0, 1), immediate_size(30); - 0x7E => PUSH31 => stack::push::<31, H> => stack_io(0, 1), immediate_size(31); - 0x7F => PUSH32 => stack::push::<32, H> => stack_io(0, 1), immediate_size(32); - - 0x80 => DUP1 => stack::dup::<1, H> => stack_io(1, 2); - 0x81 => DUP2 => stack::dup::<2, H> => stack_io(2, 3); - 0x82 => DUP3 => stack::dup::<3, H> => stack_io(3, 4); - 0x83 => DUP4 => stack::dup::<4, H> => stack_io(4, 5); - 0x84 => DUP5 => stack::dup::<5, H> => stack_io(5, 6); - 0x85 => DUP6 => stack::dup::<6, H> => stack_io(6, 7); - 0x86 => DUP7 => stack::dup::<7, H> => stack_io(7, 8); - 0x87 => DUP8 => stack::dup::<8, H> => stack_io(8, 9); - 0x88 => DUP9 => stack::dup::<9, H> => stack_io(9, 10); - 0x89 => DUP10 => stack::dup::<10, H> => stack_io(10, 11); - 0x8A => DUP11 => stack::dup::<11, H> => stack_io(11, 12); - 0x8B => DUP12 => stack::dup::<12, H> => stack_io(12, 13); - 0x8C => DUP13 => stack::dup::<13, H> => stack_io(13, 14); - 0x8D => DUP14 => stack::dup::<14, H> => stack_io(14, 15); - 0x8E => DUP15 => stack::dup::<15, H> => stack_io(15, 16); - 0x8F => DUP16 => stack::dup::<16, H> => stack_io(16, 17); - - 0x90 => SWAP1 => stack::swap::<1, H> => stack_io(2, 2); - 0x91 => SWAP2 => stack::swap::<2, H> => stack_io(3, 3); - 0x92 => SWAP3 => stack::swap::<3, H> => stack_io(4, 4); - 0x93 => SWAP4 => stack::swap::<4, H> => stack_io(5, 5); - 0x94 => SWAP5 => stack::swap::<5, H> => stack_io(6, 6); - 0x95 => SWAP6 => stack::swap::<6, H> => stack_io(7, 7); - 0x96 => SWAP7 => stack::swap::<7, H> => stack_io(8, 8); - 0x97 => SWAP8 => stack::swap::<8, H> => stack_io(9, 9); - 0x98 => SWAP9 => stack::swap::<9, H> => stack_io(10, 10); - 0x99 => SWAP10 => stack::swap::<10, H> => stack_io(11, 11); - 0x9A => SWAP11 => stack::swap::<11, H> => stack_io(12, 12); - 0x9B => SWAP12 => stack::swap::<12, H> => stack_io(13, 13); - 0x9C => SWAP13 => stack::swap::<13, H> => stack_io(14, 14); - 0x9D => SWAP14 => stack::swap::<14, H> => stack_io(15, 15); - 0x9E => SWAP15 => stack::swap::<15, H> => stack_io(16, 16); - 0x9F => SWAP16 => stack::swap::<16, H> => stack_io(17, 17); - - 0xA0 => LOG0 => host::log::<0, H> => stack_io(2, 0); - 0xA1 => LOG1 => host::log::<1, H> => stack_io(3, 0); - 0xA2 => LOG2 => host::log::<2, H> => stack_io(4, 0); - 0xA3 => LOG3 => host::log::<3, H> => stack_io(5, 0); - 0xA4 => LOG4 => host::log::<4, H> => stack_io(6, 0); - // 0xA5 - // 0xA6 - // 0xA7 - // 0xA8 - // 0xA9 - // 0xAA - // 0xAB - // 0xAC - // 0xAD - // 0xAE - // 0xAF - // 0xB0 - // 0xB1 - // 0xB2 - // 0xB3 - // 0xB4 - // 0xB5 - // 0xB6 - // 0xB7 - // 0xB8 - // 0xB9 - // 0xBA - // 0xBB - // 0xBC - // 0xBD - // 0xBE - // 0xBF - // 0xC0 - // 0xC1 - // 0xC2 - // 0xC3 - // 0xC4 - // 0xC5 - // 0xC6 - // 0xC7 - // 0xC8 - // 0xC9 - // 0xCA - // 0xCB - // 0xCC - // 0xCD - // 0xCE - // 0xCF - 0xD0 => DATALOAD => data::data_load => stack_io(1, 1); - 0xD1 => DATALOADN => data::data_loadn => stack_io(0, 1), immediate_size(2); - 0xD2 => DATASIZE => data::data_size => stack_io(0, 1); - 0xD3 => DATACOPY => data::data_copy => stack_io(3, 0); - // 0xD4 - // 0xD5 - // 0xD6 - // 0xD7 - // 0xD8 - // 0xD9 - // 0xDA - // 0xDB - // 0xDC - // 0xDD - // 0xDE - // 0xDF - 0xE0 => RJUMP => control::rjump => stack_io(0, 0), immediate_size(2), terminating; - 0xE1 => RJUMPI => control::rjumpi => stack_io(1, 0), immediate_size(2); - 0xE2 => RJUMPV => control::rjumpv => stack_io(1, 0), immediate_size(1); - 0xE3 => CALLF => control::callf => stack_io(0, 0), immediate_size(2); - 0xE4 => RETF => control::retf => stack_io(0, 0), terminating; - 0xE5 => JUMPF => control::jumpf => stack_io(0, 0), immediate_size(2), terminating; - 0xE6 => DUPN => stack::dupn => stack_io(0, 1), immediate_size(1); - 0xE7 => SWAPN => stack::swapn => stack_io(0, 0), immediate_size(1); - 0xE8 => EXCHANGE => stack::exchange => stack_io(0, 0), immediate_size(1); - // 0xE9 - // 0xEA - // 0xEB - 0xEC => EOFCREATE => contract::eofcreate => stack_io(4, 1), immediate_size(1); - // 0xED - 0xEE => RETURNCONTRACT => contract::return_contract => stack_io(2, 0), immediate_size(1), terminating; - // 0xEF - 0xF0 => CREATE => contract::create:: => stack_io(3, 1), not_eof; - 0xF1 => CALL => contract::call:: => stack_io(7, 1), not_eof; - 0xF2 => CALLCODE => contract::call_code:: => stack_io(7, 1), not_eof; - 0xF3 => RETURN => control::ret => stack_io(2, 0), terminating; - 0xF4 => DELEGATECALL => contract::delegate_call:: => stack_io(6, 1), not_eof; - 0xF5 => CREATE2 => contract::create:: => stack_io(4, 1), not_eof; - // 0xF6 - 0xF7 => RETURNDATALOAD => system::returndataload => stack_io(1, 1); - 0xF8 => EXTCALL => contract::extcall:: => stack_io(4, 1); - 0xF9 => EXTDELEGATECALL => contract::extdelegatecall:: => stack_io(3, 1); - 0xFA => STATICCALL => contract::static_call:: => stack_io(6, 1), not_eof; - 0xFB => EXTSTATICCALL => contract::extstaticcall => stack_io(3, 1); - // 0xFC - 0xFD => REVERT => control::revert:: => stack_io(2, 0), terminating; - 0xFE => INVALID => control::invalid => stack_io(0, 0), terminating; - 0xFF => SELFDESTRUCT => host::selfdestruct:: => stack_io(1, 0), not_eof, terminating; -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_opcode() { - let opcode = OpCode::new(0x00).unwrap(); - assert!(!opcode.is_jumpdest()); - assert!(!opcode.is_jump()); - assert!(!opcode.is_push()); - assert_eq!(opcode.as_str(), "STOP"); - assert_eq!(opcode.get(), 0x00); - } - - #[test] - fn test_eof_disable() { - const REJECTED_IN_EOF: &[u8] = &[ - 0x38, 0x39, 0x3b, 0x3c, 0x3f, 0x5a, 0xf1, 0xf2, 0xf4, 0xfa, 0xff, - ]; - - for opcode in REJECTED_IN_EOF { - let opcode = OpCode::new(*opcode).unwrap(); - assert!( - opcode.info().is_disabled_in_eof(), - "not disabled in EOF: {opcode:#?}", - ); - } - } - - #[test] - fn test_immediate_size() { - let mut expected = [0u8; 256]; - // PUSH opcodes - for push in PUSH1..=PUSH32 { - expected[push as usize] = push - PUSH1 + 1; - } - expected[DATALOADN as usize] = 2; - expected[RJUMP as usize] = 2; - expected[RJUMPI as usize] = 2; - expected[RJUMPV as usize] = 1; - expected[CALLF as usize] = 2; - expected[JUMPF as usize] = 2; - expected[DUPN as usize] = 1; - expected[SWAPN as usize] = 1; - expected[EXCHANGE as usize] = 1; - expected[EOFCREATE as usize] = 1; - expected[RETURNCONTRACT as usize] = 1; - - for (i, opcode) in OPCODE_INFO_JUMPTABLE.iter().enumerate() { - if let Some(opcode) = opcode { - assert_eq!( - opcode.immediate_size(), - expected[i], - "immediate_size check failed for {opcode:#?}", - ); - } - } - } - - #[test] - fn test_enabled_opcodes() { - // List obtained from https://eips.ethereum.org/EIPS/eip-3670 - let opcodes = [ - 0x10..=0x1d, - 0x20..=0x20, - 0x30..=0x3f, - 0x40..=0x48, - 0x50..=0x5b, - 0x54..=0x5f, - 0x60..=0x6f, - 0x70..=0x7f, - 0x80..=0x8f, - 0x90..=0x9f, - 0xa0..=0xa4, - 0xf0..=0xf5, - 0xfa..=0xfa, - 0xfd..=0xfd, - //0xfe, - 0xff..=0xff, - ]; - for i in opcodes { - for opcode in i { - OpCode::new(opcode).expect("Opcode should be valid and enabled"); - } - } - } - - #[test] - fn test_terminating_opcodes() { - let terminating = [ - RETF, - REVERT, - RETURN, - INVALID, - SELFDESTRUCT, - RETURNCONTRACT, - STOP, - RJUMP, - JUMPF, - ]; - let mut opcodes = [false; 256]; - for terminating in terminating.iter() { - opcodes[*terminating as usize] = true; - } - - for (i, opcode) in OPCODE_INFO_JUMPTABLE.into_iter().enumerate() { - assert_eq!( - opcode.map(|opcode| opcode.terminating).unwrap_or_default(), - opcodes[i], - "Opcode {:?} terminating chack failed.", - opcode - ); - } - } - - #[test] - #[cfg(feature = "parse")] - fn test_parsing() { - for i in 0..=u8::MAX { - if let Some(op) = OpCode::new(i) { - assert_eq!(OpCode::parse(op.as_str()), Some(op)); - } - } - } -} diff --git a/crates/interpreter/src/opcode/eof_printer.rs b/crates/interpreter/src/opcode/eof_printer.rs deleted file mode 100644 index dc22688222..0000000000 --- a/crates/interpreter/src/opcode/eof_printer.rs +++ /dev/null @@ -1,67 +0,0 @@ -#[cfg(feature = "std")] -pub fn print_eof_code(code: &[u8]) { - use super::*; - use crate::instructions::utility::read_i16; - use revm_primitives::hex; - - // We can check validity and jump destinations in one pass. - let mut i = 0; - while i < code.len() { - let op = code[i]; - let opcode = &OPCODE_INFO_JUMPTABLE[op as usize]; - - let Some(opcode) = opcode else { - println!("Unknown opcode: 0x{:02X}", op); - i += 1; - continue; - }; - - if opcode.immediate_size() != 0 { - // check if the opcode immediate are within the bounds of the code - if i + opcode.immediate_size() as usize >= code.len() { - println!("Malformed code: immediate out of bounds"); - break; - } - } - - print!("{}", opcode.name()); - if opcode.immediate_size() != 0 { - print!( - " : 0x{:}", - hex::encode(&code[i + 1..i + 1 + opcode.immediate_size() as usize]) - ); - } - - let mut rjumpv_additional_immediates = 0; - if op == RJUMPV { - let max_index = code[i + 1] as usize; - let len = max_index + 1; - // and max_index+1 is to get size of vtable as index starts from 0. - rjumpv_additional_immediates = len * 2; - - // +1 is for max_index byte - if i + 1 + rjumpv_additional_immediates >= code.len() { - println!("Malformed code: immediate out of bounds"); - break; - } - - for vtablei in 0..len { - let offset = unsafe { read_i16(code.as_ptr().add(i + 2 + 2 * vtablei)) } as isize; - println!("RJUMPV[{vtablei}]: 0x{offset:04X}({offset})"); - } - } - - i += 1 + opcode.immediate_size() as usize + rjumpv_additional_immediates; - } -} - -#[cfg(test)] -mod test { - use super::*; - use revm_primitives::hex; - - #[test] - fn sanity_test() { - print_eof_code(&hex!("6001e200ffff00")); - } -} diff --git a/crates/interpreter/tests/EOFTests/EIP3540/validInvalid.json b/crates/interpreter/tests/EOFTests/EIP3540/validInvalid.json deleted file mode 100644 index 21b5f80230..0000000000 --- a/crates/interpreter/tests/EOFTests/EIP3540/validInvalid.json +++ /dev/null @@ -1,489 +0,0 @@ -{ - "validInvalid" : { - "_info" : { - "comment" : "Test various examples to see if they are valid or invalid.\nImplements\n EOF1V3540_0001 (Valid) Deployed code without data section - Data index: 0\n EOF1V3540_0002 (Valid) Deployed code with data section - Data index: 1\n EOF1V3540_0003 (Valid) No data section contents (valid according to relaxed stack validation) - Data index: 2\n EOF1V3540_0004 (Valid) Data section contents incomplete (valid according to relaxed stack validation) - Data index: 3\n EOF1I3540_0001 (Invalid) No magic - Data index: 4\n EOF1I3540_0002 (Invalid) Invalid magic - Data index: 5\n EOF1I3540_0003 - Data index: 6\n EOF1I3540_0004 - Data index: 7\n EOF1I3540_0005 (Invalid) No version - Data index: 8\n EOF1I3540_0006 (Invalid) Invalid version - Data index: 9\n EOF1I3540_0007 - Data index: 10\n EOF1I3540_0008 - Data index: 11\n EOF1I3540_0009 (Invalid) No header - Data index: 12\n EOF1I3540_0010 (Invalid) No type section size - Data index: 13\n EOF1I3540_0011 (Invalid) Type section size incomplete - Data index: 14\n EOF1I3540_0012 (Invalid) Empty code section with non-empty data section - Data index: 15\n EOF1I3540_0013 (Invalid) No total of code sections - Data index: 16\n EOF1I3540_0014 (Invalid) Total of code sections incomplete - Data index: 17\n EOF1I3540_0015 (Invalid) No code section size - Data index: 18\n EOF1I3540_0016 (Invalid) Code section size incomplete - Data index: 19\n EOF1I3540_0017 (Invalid) No data section after code section size - Data index: 20\n EOF1I3540_0018 (Invalid) No data size - Data index: 21\n EOF1I3540_0019 (Invalid) Data size incomplete - Data index: 22\n EOF1I3540_0020 (Invalid) No section terminator after data section size - Data index: 23\n EOF1I3540_0021 (Invalid) No type section contents - Data index: 24\n EOF1I3540_0022 (Invalid) Type section contents (no outputs and max stack) - Data index: 25\n EOF1I3540_0023 (Invalid) Type section contents (no max stack) - Data index: 26\n EOF1I3540_0024 (Invalid) Type section contents (max stack incomplete) - Data index: 27\n EOF1I3540_0025 (Invalid) No code section contents - Data index: 28\n EOF1I3540_0026 (Invalid) Code section contents incomplete - Data index: 29\n EOF1I3540_0027 (Invalid) Trailing bytes after code section - Data index: 30\n EOF1I3540_0028 (Invalid) Empty code section - Data index: 31\n EOF1I3540_0029 (Invalid) Empty code section with non-empty data section - Data index: 32\n EOF1I3540_0030 (Invalid) Code section preceding type section - Data index: 33\n EOF1I3540_0031 (Invalid) Data section preceding type section - Data index: 34\n EOF1I3540_0032 (Invalid) Data section preceding code section - Data index: 35\n EOF1I3540_0033 (Invalid) Data section without code section - Data index: 36\n EOF1I3540_0034 (Invalid) No data section - Data index: 37\n EOF1I3540_0035 (Invalid) Trailing bytes after data section - Data index: 38\n EOF1I3540_0036 (Invalid) Multiple data sections - Data index: 39\n EOF1I3540_0037 (Invalid) Multiple code and data sections - Data index: 40\n EOF1I3540_0038 (Invalid) Unknown section IDs (at the beginning) - Data index: 41\n EOF1I3540_0039 - Data index: 42\n EOF1I3540_0040 - Data index: 43\n EOF1I3540_0041 (Invalid) Unknown section IDs (after types section) - Data index: 44\n EOF1I3540_0042 - Data index: 45\n EOF1I3540_0043 - Data index: 46\n EOF1I3540_0044 (Invalid) Unknown section IDs (after code section) - Data index: 47\n EOF1I3540_0045 - Data index: 48\n EOF1I3540_0046 - Data index: 49\n EOF1I3540_0047 (Invalid) Unknown section IDs (after data section) - Data index: 50\n EOF1I3540_0048 - Data index: 51\n EOF1I3540_0049 - Data index: 52\n", - "filling-rpc-server" : "evmone-t8n 0.12.0-dev+commit.14ba7529", - "filling-tool-version" : "retesteth-0.3.2-cancun+commit.9d793abd.Linux.g++", - "generatedTestHash" : "70f1c847a164c49063ecd1387e723bcecfdad88b8f833bc5be85c24c98c35b44", - "lllcversion" : "Version: 0.5.14-develop.2022.4.6+commit.401d5358.Linux.g++", - "solidity" : "Version: 0.8.18-develop.2023.1.16+commit.469d6d4d.Linux.g++", - "source" : "src/EOFTestsFiller/EIP3540/validInvalidFiller.yml", - "sourceHash" : "4625c63a66a8d034619df01985568a2e17850ed4100d04ab877c769ca9105f60" - }, - "vectors" : { - "validInvalid_0" : { - "code" : "0xef00010100040200010004040000000080000160005000", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_1" : { - "code" : "0xef00010100040200010004040004000080000160005000aabbccdd", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_10" : { - "code" : "0xef000201000402000100010400000000000000fe", - "results" : { - "Prague" : { - "exception" : "EOF_UnknownVersion", - "result" : false - } - } - }, - "validInvalid_11" : { - "code" : "0xef00ff01000402000100010400000000000000fe", - "results" : { - "Prague" : { - "exception" : "EOF_UnknownVersion", - "result" : false - } - } - }, - "validInvalid_12" : { - "code" : "0xef0001", - "results" : { - "Prague" : { - "exception" : "EOF_SectionHeadersNotTerminated", - "result" : false - } - } - }, - "validInvalid_13" : { - "code" : "0xef000101", - "results" : { - "Prague" : { - "exception" : "EOF_SectionHeadersNotTerminated", - "result" : false - } - } - }, - "validInvalid_14" : { - "code" : "0xef00010100", - "results" : { - "Prague" : { - "exception" : "EOF_IncompleteSectionSize", - "result" : false - } - } - }, - "validInvalid_15" : { - "code" : "0xef000101000402000100000400020000000000aabb", - "results" : { - "Prague" : { - "exception" : "EOF_ZeroSectionSize", - "result" : false - } - } - }, - "validInvalid_16" : { - "code" : "0xef000101000402", - "results" : { - "Prague" : { - "exception" : "EOF_IncompleteSectionNumber", - "result" : false - } - } - }, - "validInvalid_17" : { - "code" : "0xef00010100040200", - "results" : { - "Prague" : { - "exception" : "EOF_IncompleteSectionNumber", - "result" : false - } - } - }, - "validInvalid_18" : { - "code" : "0xef0001010004020001", - "results" : { - "Prague" : { - "exception" : "EOF_SectionHeadersNotTerminated", - "result" : false - } - } - }, - "validInvalid_19" : { - "code" : "0xef000101000402000100", - "results" : { - "Prague" : { - "exception" : "EOF_IncompleteSectionSize", - "result" : false - } - } - }, - "validInvalid_2" : { - "code" : "0xef000101000402000100010400020000800000fe", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_20" : { - "code" : "0xef00010100040200010001", - "results" : { - "Prague" : { - "exception" : "EOF_SectionHeadersNotTerminated", - "result" : false - } - } - }, - "validInvalid_21" : { - "code" : "0xef0001010004020001000104", - "results" : { - "Prague" : { - "exception" : "EOF_SectionHeadersNotTerminated", - "result" : false - } - } - }, - "validInvalid_22" : { - "code" : "0xef000101000402000100010400", - "results" : { - "Prague" : { - "exception" : "EOF_IncompleteSectionSize", - "result" : false - } - } - }, - "validInvalid_23" : { - "code" : "0xef00010100040200010001040002", - "results" : { - "Prague" : { - "exception" : "EOF_SectionHeadersNotTerminated", - "result" : false - } - } - }, - "validInvalid_24" : { - "code" : "0xef0001010004020001000104000200", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidSectionBodiesSize", - "result" : false - } - } - }, - "validInvalid_25" : { - "code" : "0xef000101000402000100010400020000", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidSectionBodiesSize", - "result" : false - } - } - }, - "validInvalid_26" : { - "code" : "0xef00010100040200010001040002000000", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidSectionBodiesSize", - "result" : false - } - } - }, - "validInvalid_27" : { - "code" : "0xef0001010004020001000104000200000000", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidSectionBodiesSize", - "result" : false - } - } - }, - "validInvalid_28" : { - "code" : "0xef000101000402000100010400020000000000", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidSectionBodiesSize", - "result" : false - } - } - }, - "validInvalid_29" : { - "code" : "0xef0001010004020001002904000000000000027f", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidSectionBodiesSize", - "result" : false - } - } - }, - "validInvalid_3" : { - "code" : "0xef000101000402000100010400020000800000feaa", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_30" : { - "code" : "0xef000101000402000100010400000000000000feaabbcc", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidSectionBodiesSize", - "result" : false - } - } - }, - "validInvalid_31" : { - "code" : "0xef000101000402000100000400000000000000", - "results" : { - "Prague" : { - "exception" : "EOF_ZeroSectionSize", - "result" : false - } - } - }, - "validInvalid_32" : { - "code" : "0xef000101000402000100000400020000000000aabb", - "results" : { - "Prague" : { - "exception" : "EOF_ZeroSectionSize", - "result" : false - } - } - }, - "validInvalid_33" : { - "code" : "0xef000102000100010100040400020000000000feaabb", - "results" : { - "Prague" : { - "exception" : "EOF_TypeSectionMissing", - "result" : false - } - } - }, - "validInvalid_34" : { - "code" : "0xef000104000201000402000100010000000000feaabb", - "results" : { - "Prague" : { - "exception" : "EOF_TypeSectionMissing", - "result" : false - } - } - }, - "validInvalid_35" : { - "code" : "0xef000101000404000202000100010000000000feaabb", - "results" : { - "Prague" : { - "exception" : "EOF_CodeSectionMissing", - "result" : false - } - } - }, - "validInvalid_36" : { - "code" : "0xef00010100040400020000000000aabb", - "results" : { - "Prague" : { - "exception" : "EOF_CodeSectionMissing", - "result" : false - } - } - }, - "validInvalid_37" : { - "code" : "0xef000101000402000100010000000000fe", - "results" : { - "Prague" : { - "exception" : "EOF_DataSectionMissing", - "result" : false - } - } - }, - "validInvalid_38" : { - "code" : "0xef000101000402000100010400020000000000feaabbccdd", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidSectionBodiesSize", - "result" : false - } - } - }, - "validInvalid_39" : { - "code" : "0xef000101000402000100010400020400020000000000feaabbaabb", - "results" : { - "Prague" : { - "exception" : "EOF_HeaderTerminatorMissing", - "result" : false - } - } - }, - "validInvalid_4" : { - "code" : "0xef", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidPrefix", - "result" : false - } - } - }, - "validInvalid_40" : { - "code" : "0xef000101000802000200010001040002040002000000000000000000fefeaabbaabb", - "results" : { - "Prague" : { - "exception" : "EOF_HeaderTerminatorMissing", - "result" : false - } - } - }, - "validInvalid_41" : { - "code" : "0xef000105000101000402000100010400000000000000fe", - "results" : { - "Prague" : { - "exception" : "EOF_TypeSectionMissing", - "result" : false - } - } - }, - "validInvalid_42" : { - "code" : "0xef000106000101000402000100010400000000000000fe", - "results" : { - "Prague" : { - "exception" : "EOF_TypeSectionMissing", - "result" : false - } - } - }, - "validInvalid_43" : { - "code" : "0xef0001ff000101000402000100010400000000000000fe", - "results" : { - "Prague" : { - "exception" : "EOF_TypeSectionMissing", - "result" : false - } - } - }, - "validInvalid_44" : { - "code" : "0xef000101000405000102000100010400000000000000fe", - "results" : { - "Prague" : { - "exception" : "EOF_CodeSectionMissing", - "result" : false - } - } - }, - "validInvalid_45" : { - "code" : "0xef000101000406000102000100010400000000000000fe", - "results" : { - "Prague" : { - "exception" : "EOF_CodeSectionMissing", - "result" : false - } - } - }, - "validInvalid_46" : { - "code" : "0xef0001010004ff000102000100010400000000000000fe", - "results" : { - "Prague" : { - "exception" : "EOF_CodeSectionMissing", - "result" : false - } - } - }, - "validInvalid_47" : { - "code" : "0xef000101000402000100010500010400000000000000fe", - "results" : { - "Prague" : { - "exception" : "EOF_DataSectionMissing", - "result" : false - } - } - }, - "validInvalid_48" : { - "code" : "0xef000101000402000100010600010400000000000000fe", - "results" : { - "Prague" : { - "exception" : "EOF_DataSectionMissing", - "result" : false - } - } - }, - "validInvalid_49" : { - "code" : "0xef00010100040200010001ff00010400000000000000fe", - "results" : { - "Prague" : { - "exception" : "EOF_DataSectionMissing", - "result" : false - } - } - }, - "validInvalid_5" : { - "code" : "0xef010101000402000100010400000000000000fe", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidPrefix", - "result" : false - } - } - }, - "validInvalid_50" : { - "code" : "0xef000101000402000100010400000500010000000000fe", - "results" : { - "Prague" : { - "exception" : "EOF_HeaderTerminatorMissing", - "result" : false - } - } - }, - "validInvalid_51" : { - "code" : "0xef000101000402000100010400000600010000000000fe", - "results" : { - "Prague" : { - "exception" : "EOF_HeaderTerminatorMissing", - "result" : false - } - } - }, - "validInvalid_52" : { - "code" : "0xef00010100040200010001040000ff00010000000000fe", - "results" : { - "Prague" : { - "exception" : "EOF_HeaderTerminatorMissing", - "result" : false - } - } - }, - "validInvalid_6" : { - "code" : "0xef020101000402000100010400000000000000fe", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidPrefix", - "result" : false - } - } - }, - "validInvalid_7" : { - "code" : "0xefff0101000402000100010400000000000000fe", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidPrefix", - "result" : false - } - } - }, - "validInvalid_8" : { - "code" : "0xef00", - "results" : { - "Prague" : { - "exception" : "EOF_UnknownVersion", - "result" : false - } - } - }, - "validInvalid_9" : { - "code" : "0xef000001000402000100010400000000000000fe", - "results" : { - "Prague" : { - "exception" : "EOF_UnknownVersion", - "result" : false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/EIP3670/validInvalid.json b/crates/interpreter/tests/EOFTests/EIP3670/validInvalid.json deleted file mode 100644 index aa31614039..0000000000 --- a/crates/interpreter/tests/EOFTests/EIP3670/validInvalid.json +++ /dev/null @@ -1,2568 +0,0 @@ -{ - "validInvalid" : { - "_info" : { - "comment" : "Test valid and invalid EOF code\n Implements\n EOFV3670_0001 (Valid) Code containing the STOP opcode - Data Section 0\n EOFV3670_0002 (Valid) Code containing the ADD opcode - Data Section 1\n EOFV3670_0003 (Valid) Code containing the MUL opcode - Data Section 2\n EOFV3670_0004 (Valid) Code containing the SUB opcode - Data Section 3\n EOFV3670_0005 (Valid) Code containing the DIV opcode - Data Section 4\n EOFV3670_0006 (Valid) Code containing the SDIV opcode - Data Section 5\n EOFV3670_0007 (Valid) Code containing the MOD opcode - Data Section 6\n EOFV3670_0008 (Valid) Code containing the SMOD opcode - Data Section 7\n EOFV3670_0009 (Valid) Code containing the ADDMOD opcode - Data Section 8\n EOFV3670_0010 (Valid) Code containing the MULMOD opcode - Data Section 9\n EOFV3670_0011 (Valid) Code containing the EXP opcode - Data Section 10\n EOFV3670_0012 (Valid) Code containing the SIGNEXTEND opcode - Data Section 11\n EOFV3670_0013 (Valid) Code containing the LT opcode - Data Section 12\n EOFV3670_0014 (Valid) Code containing the GT opcode - Data Section 13\n EOFV3670_0015 (Valid) Code containing the SLT opcode - Data Section 14\n EOFV3670_0016 (Valid) Code containing the SGT opcode - Data Section 15\n EOFV3670_0017 (Valid) Code containing the EQ opcode - Data Section 16\n EOFV3670_0018 (Valid) Code containing the ISZERO opcode - Data Section 17\n EOFV3670_0019 (Valid) Code containing the AND opcode - Data Section 18\n EOFV3670_0020 (Valid) Code containing the OR opcode - Data Section 19\n EOFV3670_0021 (Valid) Code containing the XOR opcode - Data Section 20\n EOFV3670_0022 (Valid) Code containing the NOT opcode - Data Section 21\n EOFV3670_0023 (Valid) Code containing the BYTE opcode - Data Section 22\n EOFV3670_0024 (Valid) Code containing the SHL opcode - Data Section 23\n EOFV3670_0025 (Valid) Code containing the SHR opcode - Data Section 24\n EOFV3670_0026 (Valid) Code containing the SAR opcode - Data Section 25\n EOFV3670_0027 (Valid) Code containing the SHA3 opcode - Data Section 26\n EOFV3670_0028 (Valid) Code containing the ADDRESS opcode - Data Section 27\n EOFV3670_0029 (Valid) Code containing the BALANCE opcode - Data Section 28\n EOFV3670_0030 (Valid) Code containing the ORIGIN opcode - Data Section 29\n EOFV3670_0031 (Valid) Code containing the CALLER opcode - Data Section 30\n EOFV3670_0032 (Valid) Code containing the CALLVALUE opcode - Data Section 31\n EOFV3670_0033 (Valid) Code containing the CALLDATALOAD opcode - Data Section 32\n EOFV3670_0034 (Valid) Code containing the CALLDATASIZE opcode - Data Section 33\n EOFV3670_0035 (Valid) Code containing the CALLDATACOPY opcode - Data Section 34\n EOFV3670_0036 (Valid) Code containing the CODESIZE opcode - Data Section 35\n EOFV3670_0037 (Valid) Code containing the CODECOPY opcode - Data Section 36\n EOFV3670_0038 (Valid) Code containing the GASPRICE opcode - Data Section 37\n EOFV3670_0039 (Valid) Code containing the EXTCODESIZE opcode - Data Section 38\n EOFV3670_0040 (Valid) Code containing the EXTCODECOPY opcode - Data Section 39\n EOFV3670_0041 (Valid) Code containing the RETURNDATASIZE opcode - Data Section 40\n EOFV3670_0042 (Valid) Code containing the RETURNDATACOPY opcode - Data Section 41\n EOFV3670_0043 (Valid) Code containing the EXTCODEHASH opcode - Data Section 42\n EOFV3670_0044 (Valid) Code containing the BLOCKHASH opcode - Data Section 43\n EOFV3670_0045 (Valid) Code containing the COINBASE opcode - Data Section 44\n EOFV3670_0046 (Valid) Code containing the TIMESTAMP opcode - Data Section 45\n EOFV3670_0047 (Valid) Code containing the NUMBER opcode - Data Section 46\n EOFV3670_0048 (Valid) Code containing the DIFFICULTY opcode - Data Section 47\n EOFV3670_0049 (Valid) Code containing the GASLIMIT opcode - Data Section 48\n EOFV3670_0050 (Valid) Code containing the CHAINID opcode - Data Section 49\n EOFV3670_0051 (Valid) Code containing the SELFBALANCE opcode - Data Section 50\n EOFV3670_0052 (Valid) Code containing the BASEFEE opcode - Data Section 51\n EOFV3670_0053 (Valid) Code containing the BLOBHASH opcode - Data Section 52\n EOFV3670_0054 (Valid) Code containing the BLOBBASEFEE opcode - Data Section 53\n EOFV3670_0055 (Valid) Code containing the POP opcode - Data Section 54\n EOFV3670_0056 (Valid) Code containing the MLOAD opcode - Data Section 55\n EOFV3670_0057 (Valid) Code containing the MSTORE8 opcode - Data Section 56\n EOFV3670_0058 (Valid) Code containing the SLOAD opcode - Data Section 57\n EOFV3670_0059 (Valid) Code containing the SSTORE opcode - Data Section 58\n EOFV3670_0060 (Valid) Code containing the MSIZE opcode - Data Section 59\n EOFV3670_0061 (Valid) Code containing the GAS opcode - Data Section 60\n EOFV3670_0062 (Valid) Code containing the NOP opcode - Data Section 61\n EOFV3670_0063 (Valid) Code containing the MCOPY opcode - Data Section 62\n EOFV3670_0064 (Valid) Code containing the PUSH0 opcode - Data Section 63\n EOFV3670_0065 (Valid) Code containing the PUSH1 opcode - Data Section 64\n EOFV3670_0066 (Valid) Code containing the PUSH2 opcode - Data Section 65\n EOFV3670_0067 (Valid) Code containing the PUSH3 opcode - Data Section 66\n EOFV3670_0068 (Valid) Code containing the PUSH4 opcode - Data Section 67\n EOFV3670_0069 (Valid) Code containing the PUSH5 opcode - Data Section 68\n EOFV3670_0070 (Valid) Code containing the PUSH6 opcode - Data Section 69\n EOFV3670_0071 (Valid) Code containing the PUSH7 opcode - Data Section 70\n EOFV3670_0072 (Valid) Code containing the PUSH8 opcode - Data Section 71\n EOFV3670_0073 (Valid) Code containing the PUSH9 opcode - Data Section 72\n EOFV3670_0074 (Valid) Code containing the PUSH10 opcode - Data Section 73\n EOFV3670_0075 (Valid) Code containing the PUSH11 opcode - Data Section 74\n EOFV3670_0076 (Valid) Code containing the PUSH12 opcode - Data Section 75\n EOFV3670_0077 (Valid) Code containing the PUSH13 opcode - Data Section 76\n EOFV3670_0078 (Valid) Code containing the PUSH14 opcode - Data Section 77\n EOFV3670_0079 (Valid) Code containing the PUSH15 opcode - Data Section 78\n EOFV3670_0080 (Valid) Code containing the PUSH16 opcode - Data Section 79\n EOFV3670_0081 (Valid) Code containing the PUSH17 opcode - Data Section 80\n EOFV3670_0082 (Valid) Code containing the PUSH18 opcode - Data Section 81\n EOFV3670_0083 (Valid) Code containing the PUSH19 opcode - Data Section 82\n EOFV3670_0084 (Valid) Code containing the PUSH20 opcode - Data Section 83\n EOFV3670_0085 (Valid) Code containing the PUSH21 opcode - Data Section 84\n EOFV3670_0086 (Valid) Code containing the PUSH22 opcode - Data Section 85\n EOFV3670_0087 (Valid) Code containing the PUSH23 opcode - Data Section 86\n EOFV3670_0088 (Valid) Code containing the PUSH24 opcode - Data Section 87\n EOFV3670_0089 (Valid) Code containing the PUSH25 opcode - Data Section 88\n EOFV3670_0090 (Valid) Code containing the PUSH26 opcode - Data Section 89\n EOFV3670_0091 (Valid) Code containing the PUSH27 opcode - Data Section 90\n EOFV3670_0092 (Valid) Code containing the PUSH28 opcode - Data Section 91\n EOFV3670_0093 (Valid) Code containing the PUSH29 opcode - Data Section 92\n EOFV3670_0094 (Valid) Code containing the PUSH30 opcode - Data Section 93\n EOFV3670_0095 (Valid) Code containing the PUSH31 opcode - Data Section 94\n EOFV3670_0096 (Valid) Code containing the PUSH32 opcode - Data Section 95\n EOFV3670_0097 (Valid) Code containing the DUP1 opcode - Data Section 96\n EOFV3670_0098 (Valid) Code containing the DUP2 opcode - Data Section 97\n EOFV3670_0099 (Valid) Code containing the DUP3 opcode - Data Section 98\n EOFV3670_0100 (Valid) Code containing the DUP4 opcode - Data Section 99\n EOFV3670_0101 (Valid) Code containing the DUP5 opcode - Data Section 100\n EOFV3670_0102 (Valid) Code containing the DUP6 opcode - Data Section 101\n EOFV3670_0103 (Valid) Code containing the DUP7 opcode - Data Section 102\n EOFV3670_0104 (Valid) Code containing the DUP8 opcode - Data Section 103\n EOFV3670_0105 (Valid) Code containing the DUP9 opcode - Data Section 104\n EOFV3670_0106 (Valid) Code containing the DUP10 opcode - Data Section 105\n EOFV3670_0107 (Valid) Code containing the DUP11 opcode - Data Section 106\n EOFV3670_0108 (Valid) Code containing the DUP12 opcode - Data Section 107\n EOFV3670_0109 (Valid) Code containing the DUP13 opcode - Data Section 108\n EOFV3670_0110 (Valid) Code containing the DUP14 opcode - Data Section 109\n EOFV3670_0111 (Valid) Code containing the DUP15 opcode - Data Section 110\n EOFV3670_0112 (Valid) Code containing the DUP16 opcode - Data Section 111\n EOFV3670_0113 (Valid) Code containing the SWAP1 opcode - Data Section 112\n EOFV3670_0114 (Valid) Code containing the SWAP2 opcode - Data Section 113\n EOFV3670_0115 (Valid) Code containing the SWAP3 opcode - Data Section 114\n EOFV3670_0116 (Valid) Code containing the SWAP4 opcode - Data Section 115\n EOFV3670_0117 (Valid) Code containing the SWAP5 opcode - Data Section 116\n EOFV3670_0118 (Valid) Code containing the SWAP6 opcode - Data Section 117\n EOFV3670_0119 (Valid) Code containing the SWAP7 opcode - Data Section 118\n EOFV3670_0120 (Valid) Code containing the SWAP8 opcode - Data Section 119\n EOFV3670_0121 (Valid) Code containing the SWAP9 opcode - Data Section 120\n EOFV3670_0122 (Valid) Code containing the SWAP10 opcode - Data Section 121\n EOFV3670_0123 (Valid) Code containing the SWAP11 opcode - Data Section 122\n EOFV3670_0124 (Valid) Code containing the SWAP12 opcode - Data Section 123\n EOFV3670_0125 (Valid) Code containing the SWAP13 opcode - Data Section 124\n EOFV3670_0126 (Valid) Code containing the SWAP14 opcode - Data Section 125\n EOFV3670_0127 (Valid) Code containing the SWAP15 opcode - Data Section 126\n EOFV3670_0128 (Valid) Code containing the SWAP16 opcode - Data Section 127\n EOFV3670_0129 (Valid) Code containing the LOG0 opcode - Data Section 128\n EOFV3670_0130 (Valid) Code containing the LOG1 opcode - Data Section 129\n EOFV3670_0131 (Valid) Code containing the LOG2 opcode - Data Section 130\n EOFV3670_0132 (Valid) Code containing the LOG3 opcode - Data Section 131\n EOFV3670_0133 (Valid) Code containing the LOG4 opcode - Data Section 132\n EOFV3670_0134 (Valid) Code containing the CALL opcode - Data Section 133\n EOFV3670_0135 (Valid) Code containing the RETURN opcode - Data Section 134\n EOFV3670_0136 (Valid) Code containing the DELEGATECALL opcode - Data Section 135\n EOFV3670_0137 (Valid) Code containing the STATICCALL opcode - Data Section 136\n EOFV3670_0138 (Valid) Code containing the REVERT opcode - Data Section 137\n EOFV3670_0139 (Valid) Code containing the INVALID opcode - Data Section 138\n EOFI3670_0140 (Invalid) Code containing undefined instruction 0x0c - Data Section 139\n EOFI3670_0141 (Invalid) Code containing undefined instruction 0x0d - Data Section 140\n EOFI3670_0142 (Invalid) Code containing undefined instruction 0x0e - Data Section 141\n EOFI3670_0143 (Invalid) Code containing undefined instruction 0x0f - Data Section 142\n EOFI3670_0144 (Invalid) Code containing undefined instruction 0x1e - Data Section 143\n EOFI3670_0145 (Invalid) Code containing undefined instruction 0x1f - Data Section 144\n EOFI3670_0146 (Invalid) Code containing undefined instruction 0x21 - Data Section 145\n EOFI3670_0147 (Invalid) Code containing undefined instruction 0x22 - Data Section 146\n EOFI3670_0148 (Invalid) Code containing undefined instruction 0x23 - Data Section 147\n EOFI3670_0149 (Invalid) Code containing undefined instruction 0x24 - Data Section 148\n EOFI3670_0150 (Invalid) Code containing undefined instruction 0x25 - Data Section 149\n EOFI3670_0151 (Invalid) Code containing undefined instruction 0x26 - Data Section 150\n EOFI3670_0152 (Invalid) Code containing undefined instruction 0x27 - Data Section 151\n EOFI3670_0153 (Invalid) Code containing undefined instruction 0x28 - Data Section 152\n EOFI3670_0154 (Invalid) Code containing undefined instruction 0x29 - Data Section 153\n EOFI3670_0155 (Invalid) Code containing undefined instruction 0x2a - Data Section 154\n EOFI3670_0156 (Invalid) Code containing undefined instruction 0x2b - Data Section 155\n EOFI3670_0157 (Invalid) Code containing undefined instruction 0x2c - Data Section 156\n EOFI3670_0158 (Invalid) Code containing undefined instruction 0x2d - Data Section 157\n EOFI3670_0159 (Invalid) Code containing undefined instruction 0x2e - Data Section 158\n EOFI3670_0160 (Invalid) Code containing undefined instruction 0x2f - Data Section 159\n EOFI3670_0161 (Invalid) Code containing undefined instruction 0x4b - Data Section 160\n EOFI3670_0162 (Invalid) Code containing undefined instruction 0x4c - Data Section 161\n EOFI3670_0163 (Invalid) Code containing undefined instruction 0x4d - Data Section 162\n EOFI3670_0164 (Invalid) Code containing undefined instruction 0x4e - Data Section 163\n EOFI3670_0165 (Invalid) Code containing undefined instruction 0x4f - Data Section 164\n EOFI3670_0166 (Invalid) Code containing undefined instruction 0x56 - Data Section 165\n EOFI3670_0167 (Invalid) Code containing undefined instruction 0x57 - Data Section 166\n EOFI3670_0168 (Invalid) Code containing undefined instruction 0x58 - Data Section 167\n EOFI3670_0169 (Invalid) Code containing undefined instruction 0xa5 - Data Section 168\n EOFI3670_0170 (Invalid) Code containing undefined instruction 0xa6 - Data Section 169\n EOFI3670_0171 (Invalid) Code containing undefined instruction 0xa7 - Data Section 170\n EOFI3670_0172 (Invalid) Code containing undefined instruction 0xa8 - Data Section 171\n EOFI3670_0173 (Invalid) Code containing undefined instruction 0xa9 - Data Section 172\n EOFI3670_0174 (Invalid) Code containing undefined instruction 0xaa - Data Section 173\n EOFI3670_0175 (Invalid) Code containing undefined instruction 0xab - Data Section 174\n EOFI3670_0176 (Invalid) Code containing undefined instruction 0xac - Data Section 175\n EOFI3670_0177 (Invalid) Code containing undefined instruction 0xad - Data Section 176\n EOFI3670_0178 (Invalid) Code containing undefined instruction 0xae - Data Section 177\n EOFI3670_0179 (Invalid) Code containing undefined instruction 0xaf - Data Section 178\n EOFI3670_0180 (Invalid) Code containing undefined instruction 0xb2 - Data Section 179\n EOFI3670_0181 (Invalid) Code containing undefined instruction 0xb3 - Data Section 180\n EOFI3670_0182 (Invalid) Code containing undefined instruction 0xb4 - Data Section 181\n EOFI3670_0183 (Invalid) Code containing undefined instruction 0xb5 - Data Section 182\n EOFI3670_0184 (Invalid) Code containing undefined instruction 0xb6 - Data Section 183\n EOFI3670_0185 (Invalid) Code containing undefined instruction 0xb7 - Data Section 184\n EOFI3670_0186 (Invalid) Code containing undefined instruction 0xb8 - Data Section 185\n EOFI3670_0187 (Invalid) Code containing undefined instruction 0xb9 - Data Section 186\n EOFI3670_0188 (Invalid) Code containing undefined instruction 0xba - Data Section 187\n EOFI3670_0189 (Invalid) Code containing undefined instruction 0xbb - Data Section 188\n EOFI3670_0190 (Invalid) Code containing undefined instruction 0xbc - Data Section 189\n EOFI3670_0191 (Invalid) Code containing undefined instruction 0xbd - Data Section 190\n EOFI3670_0192 (Invalid) Code containing undefined instruction 0xbe - Data Section 191\n EOFI3670_0193 (Invalid) Code containing undefined instruction 0xbf - Data Section 192\n EOFI3670_0194 (Invalid) Code containing undefined instruction 0xc0 - Data Section 193\n EOFI3670_0195 (Invalid) Code containing undefined instruction 0xc1 - Data Section 194\n EOFI3670_0196 (Invalid) Code containing undefined instruction 0xc2 - Data Section 195\n EOFI3670_0197 (Invalid) Code containing undefined instruction 0xc3 - Data Section 196\n EOFI3670_0198 (Invalid) Code containing undefined instruction 0xc4 - Data Section 197\n EOFI3670_0199 (Invalid) Code containing undefined instruction 0xc5 - Data Section 198\n EOFI3670_0200 (Invalid) Code containing undefined instruction 0xc6 - Data Section 199\n EOFI3670_0201 (Invalid) Code containing undefined instruction 0xc7 - Data Section 200\n EOFI3670_0202 (Invalid) Code containing undefined instruction 0xc8 - Data Section 201\n EOFI3670_0203 (Invalid) Code containing undefined instruction 0xc9 - Data Section 202\n EOFI3670_0204 (Invalid) Code containing undefined instruction 0xca - Data Section 203\n EOFI3670_0205 (Invalid) Code containing undefined instruction 0xcb - Data Section 204\n EOFI3670_0206 (Invalid) Code containing undefined instruction 0xcc - Data Section 205\n EOFI3670_0207 (Invalid) Code containing undefined instruction 0xcd - Data Section 206\n EOFI3670_0208 (Invalid) Code containing undefined instruction 0xce - Data Section 207\n EOFI3670_0209 (Invalid) Code containing undefined instruction 0xcf - Data Section 208\n EOFI3670_0210 (Invalid) Code containing undefined instruction 0xd4 - Data Section 209\n EOFI3670_0211 (Invalid) Code containing undefined instruction 0xd5 - Data Section 210\n EOFI3670_0212 (Invalid) Code containing undefined instruction 0xd6 - Data Section 211\n EOFI3670_0213 (Invalid) Code containing undefined instruction 0xd7 - Data Section 212\n EOFI3670_0214 (Invalid) Code containing undefined instruction 0xd8 - Data Section 213\n EOFI3670_0215 (Invalid) Code containing undefined instruction 0xd9 - Data Section 214\n EOFI3670_0216 (Invalid) Code containing undefined instruction 0xda - Data Section 215\n EOFI3670_0217 (Invalid) Code containing undefined instruction 0xdb - Data Section 216\n EOFI3670_0218 (Invalid) Code containing undefined instruction 0xdc - Data Section 217\n EOFI3670_0219 (Invalid) Code containing undefined instruction 0xdd - Data Section 218\n EOFI3670_0220 (Invalid) Code containing undefined instruction 0xde - Data Section 219\n EOFI3670_0221 (Invalid) Code containing undefined instruction 0xdf - Data Section 220\n EOFI3670_0222 (Invalid) Code containing undefined instruction 0xe8 - Data Section 221\n EOFI3670_0223 (Invalid) Code containing undefined instruction 0xe9 - Data Section 222\n EOFI3670_0224 (Invalid) Code containing undefined instruction 0xea - Data Section 223\n EOFI3670_0225 (Invalid) Code containing undefined instruction 0xeb - Data Section 224\n EOFI3670_0226 (Invalid) Code containing undefined instruction 0xef - Data Section 225\n EOFI3670_0227 (Invalid) Code containing undefined instruction 0xf0 - Data Section 226\n EOFI3670_0228 (Invalid) Code containing undefined instruction 0xf2 - Data Section 227\n EOFI3670_0229 (Invalid) Code containing undefined instruction 0xf5 - Data Section 228\n EOFI3670_0230 (Invalid) Code containing undefined instruction 0xf6 - Data Section 229\n EOFI3670_0231 (Invalid) Code containing undefined instruction 0xf8 - Data Section 230\n EOFI3670_0232 (Invalid) Code containing undefined instruction 0xf9 - Data Section 231\n EOFI3670_0233 (Invalid) Code containing undefined instruction 0xfb - Data Section 232\n EOFI3670_0234 (Invalid) Code containing undefined instruction 0xfc - Data Section 233\n EOFI3670_0235 (Invalid) Code containing undefined instruction 0xff - Data Section 234\n EOFI3670_0236 (Invalid) Truncated PUSH1 (no immediates) - Data Section 235\n EOFI3670_0237 (Invalid) Truncated PUSH2 (no immediates) - Data Section 236\n EOFI3670_0238 (Invalid) Truncated PUSH2 (truncated immediates) - Data Section 237\n EOFI3670_0239 (Invalid) Truncated PUSH3 (no immediates) - Data Section 238\n EOFI3670_0240 (Invalid) Truncated PUSH3 (truncated immediates) - Data Section 239\n EOFI3670_0241 (Invalid) Truncated PUSH4 (no immediates) - Data Section 240\n EOFI3670_0242 (Invalid) Truncated PUSH4 (truncated immediates) - Data Section 241\n EOFI3670_0243 (Invalid) Truncated PUSH5 (no immediates) - Data Section 242\n EOFI3670_0244 (Invalid) Truncated PUSH5 (truncated immediates) - Data Section 243\n EOFI3670_0245 (Invalid) Truncated PUSH6 (no immediates) - Data Section 244\n EOFI3670_0246 (Invalid) Truncated PUSH6 (truncated immediates) - Data Section 245\n EOFI3670_0247 (Invalid) Truncated PUSH7 (no immediates) - Data Section 246\n EOFI3670_0248 (Invalid) Truncated PUSH7 (truncated immediates) - Data Section 247\n EOFI3670_0249 (Invalid) Truncated PUSH8 (no immediates) - Data Section 248\n EOFI3670_0250 (Invalid) Truncated PUSH8 (truncated immediates) - Data Section 249\n EOFI3670_0251 (Invalid) Truncated PUSH9 (no immediates) - Data Section 250\n EOFI3670_0252 (Invalid) Truncated PUSH9 (truncated immediates) - Data Section 251\n EOFI3670_0253 (Invalid) Truncated PUSH10 (no immediates) - Data Section 252\n EOFI3670_0254 (Invalid) Truncated PUSH10 (truncated immediates) - Data Section 253\n EOFI3670_0255 (Invalid) Truncated PUSH11 (no immediates) - Data Section 254\n EOFI3670_0256 (Invalid) Truncated PUSH11 (truncated immediates) - Data Section 255\n EOFI3670_0257 (Invalid) Truncated PUSH12 (no immediates) - Data Section 256\n EOFI3670_0258 (Invalid) Truncated PUSH12 (truncated immediates) - Data Section 257\n EOFI3670_0259 (Invalid) Truncated PUSH13 (no immediates) - Data Section 258\n EOFI3670_0260 (Invalid) Truncated PUSH13 (truncated immediates) - Data Section 259\n EOFI3670_0261 (Invalid) Truncated PUSH14 (no immediates) - Data Section 260\n EOFI3670_0262 (Invalid) Truncated PUSH14 (truncated immediates) - Data Section 261\n EOFI3670_0263 (Invalid) Truncated PUSH15 (no immediates) - Data Section 262\n EOFI3670_0264 (Invalid) Truncated PUSH15 (truncated immediates) - Data Section 263\n EOFI3670_0265 (Invalid) Truncated PUSH16 (no immediates) - Data Section 264\n EOFI3670_0266 (Invalid) Truncated PUSH16 (truncated immediates) - Data Section 265\n EOFI3670_0267 (Invalid) Truncated PUSH17 (no immediates) - Data Section 266\n EOFI3670_0268 (Invalid) Truncated PUSH17 (truncated immediates) - Data Section 267\n EOFI3670_0269 (Invalid) Truncated PUSH18 (no immediates) - Data Section 268\n EOFI3670_0270 (Invalid) Truncated PUSH18 (truncated immediates) - Data Section 269\n EOFI3670_0271 (Invalid) Truncated PUSH19 (no immediates) - Data Section 270\n EOFI3670_0272 (Invalid) Truncated PUSH19 (truncated immediates) - Data Section 271\n EOFI3670_0273 (Invalid) Truncated PUSH20 (no immediates) - Data Section 272\n EOFI3670_0274 (Invalid) Truncated PUSH20 (truncated immediates) - Data Section 273\n EOFI3670_0275 (Invalid) Truncated PUSH21 (no immediates) - Data Section 274\n EOFI3670_0276 (Invalid) Truncated PUSH21 (truncated immediates) - Data Section 275\n EOFI3670_0277 (Invalid) Truncated PUSH22 (no immediates) - Data Section 276\n EOFI3670_0278 (Invalid) Truncated PUSH22 (truncated immediates) - Data Section 277\n EOFI3670_0279 (Invalid) Truncated PUSH23 (no immediates) - Data Section 278\n EOFI3670_0280 (Invalid) Truncated PUSH23 (truncated immediates) - Data Section 279\n EOFI3670_0281 (Invalid) Truncated PUSH24 (no immediates) - Data Section 280\n EOFI3670_0282 (Invalid) Truncated PUSH24 (truncated immediates) - Data Section 281\n EOFI3670_0283 (Invalid) Truncated PUSH25 (no immediates) - Data Section 282\n EOFI3670_0284 (Invalid) Truncated PUSH25 (truncated immediates) - Data Section 283\n EOFI3670_0285 (Invalid) Truncated PUSH26 (no immediates) - Data Section 284\n EOFI3670_0286 (Invalid) Truncated PUSH26 (truncated immediates) - Data Section 285\n EOFI3670_0287 (Invalid) Truncated PUSH27 (no immediates) - Data Section 286\n EOFI3670_0288 (Invalid) Truncated PUSH27 (truncated immediates) - Data Section 287\n EOFI3670_0289 (Invalid) Truncated PUSH28 (no immediates) - Data Section 288\n EOFI3670_0290 (Invalid) Truncated PUSH28 (truncated immediates) - Data Section 289\n EOFI3670_0291 (Invalid) Truncated PUSH29 (no immediates) - Data Section 290\n EOFI3670_0292 (Invalid) Truncated PUSH29 (truncated immediates) - Data Section 291\n EOFI3670_0293 (Invalid) Truncated PUSH30 (no immediates) - Data Section 292\n EOFI3670_0294 (Invalid) Truncated PUSH30 (truncated immediates) - Data Section 293\n EOFI3670_0295 (Invalid) Truncated PUSH31 (no immediates) - Data Section 294\n EOFI3670_0296 (Invalid) Truncated PUSH31 (truncated immediates) - Data Section 295\n EOFI3670_0297 (Invalid) Truncated PUSH32 (no immediates) - Data Section 296\n EOFI3670_0298 (Invalid) Truncated PUSH32 (truncated immediates) - Data Section 297\n EOFI3670_0299 (Invalid) Containing undefined instruction (0xfb) after STOP - Data Section 298\n", - "filling-rpc-server" : "evmone-t8n 0.12.0-dev+commit.14ba7529", - "filling-tool-version" : "retesteth-0.3.2-cancun+commit.9d793abd.Linux.g++", - "generatedTestHash" : "b2305be6aaf4c98bf09b5892455f61697aff8cd555895837c8df7324ed7bf9e6", - "lllcversion" : "Version: 0.5.14-develop.2022.4.6+commit.401d5358.Linux.g++", - "solidity" : "Version: 0.8.18-develop.2023.1.16+commit.469d6d4d.Linux.g++", - "source" : "src/EOFTestsFiller/EIP3670/validInvalidFiller.yml", - "sourceHash" : "513e8e83276305366c781c549bb70abeacd865e219b9adfa7aacdc619765ea67" - }, - "vectors" : { - "validInvalid_0" : { - "code" : "0xef00010100040200010001040000000080000000", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_1" : { - "code" : "0xef0001010004020001000504000000008000026001800100", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_10" : { - "code" : "0xef0001010004020001000504000000008000026001800a00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_100" : { - "code" : "0xef0001010004020001000804000000008000066001808080808400", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_101" : { - "code" : "0xef000101000402000100090400000000800007600180808080808500", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_102" : { - "code" : "0xef0001010004020001000a040000000080000860018080808080808600", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_103" : { - "code" : "0xef0001010004020001000b04000000008000096001808080808080808700", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_104" : { - "code" : "0xef0001010004020001000c040000000080000a600180808080808080808800", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_105" : { - "code" : "0xef0001010004020001000d040000000080000b60018080808080808080808900", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_106" : { - "code" : "0xef0001010004020001000e040000000080000c6001808080808080808080808a00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_107" : { - "code" : "0xef0001010004020001000f040000000080000d600180808080808080808080808b00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_108" : { - "code" : "0xef00010100040200010010040000000080000e60018080808080808080808080808c00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_109" : { - "code" : "0xef00010100040200010011040000000080000f6001808080808080808080808080808d00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_11" : { - "code" : "0xef0001010004020001000504000000008000026001800b00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_110" : { - "code" : "0xef000101000402000100120400000000800010600180808080808080808080808080808e00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_111" : { - "code" : "0xef00010100040200010013040000000080001160018080808080808080808080808080808f00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_112" : { - "code" : "0xef0001010004020001000504000000008000026001809000", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_113" : { - "code" : "0xef000101000402000100060400000000800003600180809100", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_114" : { - "code" : "0xef00010100040200010007040000000080000460018080809200", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_115" : { - "code" : "0xef0001010004020001000804000000008000056001808080809300", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_116" : { - "code" : "0xef000101000402000100090400000000800006600180808080809400", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_117" : { - "code" : "0xef0001010004020001000a040000000080000760018080808080809500", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_118" : { - "code" : "0xef0001010004020001000b04000000008000086001808080808080809600", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_119" : { - "code" : "0xef0001010004020001000c0400000000800009600180808080808080809700", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_12" : { - "code" : "0xef0001010004020001000504000000008000026001801000", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_120" : { - "code" : "0xef0001010004020001000d040000000080000a60018080808080808080809800", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_121" : { - "code" : "0xef0001010004020001000e040000000080000b6001808080808080808080809900", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_122" : { - "code" : "0xef0001010004020001000f040000000080000c600180808080808080808080809a00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_123" : { - "code" : "0xef00010100040200010010040000000080000d60018080808080808080808080809b00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_124" : { - "code" : "0xef00010100040200010011040000000080000e6001808080808080808080808080809c00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_125" : { - "code" : "0xef00010100040200010012040000000080000f600180808080808080808080808080809d00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_126" : { - "code" : "0xef00010100040200010013040000000080001060018080808080808080808080808080809e00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_127" : { - "code" : "0xef0001010004020001001404000000008000116001808080808080808080808080808080809f00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_128" : { - "code" : "0xef000101000402000100050400000000800002600180a000", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_129" : { - "code" : "0xef00010100040200010006040000000080000360018080a100", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_13" : { - "code" : "0xef0001010004020001000504000000008000026001801100", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_130" : { - "code" : "0xef0001010004020001000704000000008000046001808080a200", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_131" : { - "code" : "0xef000101000402000100080400000000800005600180808080a300", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_132" : { - "code" : "0xef00010100040200010009040000000080000660018080808080a400", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_133" : { - "code" : "0xef0001010004020001000a04000000008000076001808080808080f100", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_134" : { - "code" : "0xef000101000402000100040400000000800002600180f3", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_135" : { - "code" : "0xef00010100040200010009040000000080000660018080808080f400", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_136" : { - "code" : "0xef00010100040200010009040000000080000660018080808080fa00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_137" : { - "code" : "0xef000101000402000100040400000000800002600180fd", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_138" : { - "code" : "0xef000101000402000100010400000000800000fe", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_139" : { - "code" : "0xef0001010004020001000204000000008000000c00", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_14" : { - "code" : "0xef0001010004020001000504000000008000026001801200", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_140" : { - "code" : "0xef0001010004020001000204000000008000000d00", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_141" : { - "code" : "0xef0001010004020001000204000000008000000e00", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_142" : { - "code" : "0xef0001010004020001000204000000008000000f00", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_143" : { - "code" : "0xef0001010004020001000204000000008000001e00", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_144" : { - "code" : "0xef0001010004020001000204000000008000001f00", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_145" : { - "code" : "0xef0001010004020001000204000000008000002100", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_146" : { - "code" : "0xef0001010004020001000204000000008000002200", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_147" : { - "code" : "0xef0001010004020001000204000000008000002300", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_148" : { - "code" : "0xef0001010004020001000204000000008000002400", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_149" : { - "code" : "0xef0001010004020001000204000000008000002500", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_15" : { - "code" : "0xef0001010004020001000504000000008000026001801300", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_150" : { - "code" : "0xef0001010004020001000204000000008000002600", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_151" : { - "code" : "0xef0001010004020001000204000000008000002700", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_152" : { - "code" : "0xef0001010004020001000204000000008000002800", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_153" : { - "code" : "0xef0001010004020001000204000000008000002900", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_154" : { - "code" : "0xef0001010004020001000204000000008000002a00", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_155" : { - "code" : "0xef0001010004020001000204000000008000002b00", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_156" : { - "code" : "0xef0001010004020001000204000000008000002c00", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_157" : { - "code" : "0xef0001010004020001000204000000008000002d00", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_158" : { - "code" : "0xef0001010004020001000204000000008000002e00", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_159" : { - "code" : "0xef0001010004020001000204000000008000002f00", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_16" : { - "code" : "0xef0001010004020001000504000000008000026001801400", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_160" : { - "code" : "0xef0001010004020001000204000000008000004b00", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_161" : { - "code" : "0xef0001010004020001000204000000008000004c00", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_162" : { - "code" : "0xef0001010004020001000204000000008000004d00", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_163" : { - "code" : "0xef0001010004020001000204000000008000004e00", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_164" : { - "code" : "0xef0001010004020001000204000000008000004f00", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_165" : { - "code" : "0xef0001010004020001000204000000008000005600", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_166" : { - "code" : "0xef0001010004020001000204000000008000005700", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_167" : { - "code" : "0xef0001010004020001000204000000008000015800", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_168" : { - "code" : "0xef000101000402000100020400000000800000a500", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_169" : { - "code" : "0xef000101000402000100020400000000800000a600", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_17" : { - "code" : "0xef00010100040200010004040000000080000160011500", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_170" : { - "code" : "0xef000101000402000100020400000000800000a700", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_171" : { - "code" : "0xef000101000402000100020400000000800000a800", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_172" : { - "code" : "0xef000101000402000100020400000000800000a900", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_173" : { - "code" : "0xef000101000402000100020400000000800000aa00", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_174" : { - "code" : "0xef000101000402000100020400000000800000ab00", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_175" : { - "code" : "0xef000101000402000100020400000000800000ac00", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_176" : { - "code" : "0xef000101000402000100020400000000800000ad00", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_177" : { - "code" : "0xef000101000402000100020400000000800000ae00", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_178" : { - "code" : "0xef000101000402000100020400000000800000af00", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_179" : { - "code" : "0xef000101000402000100020400000000800000b200", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_18" : { - "code" : "0xef0001010004020001000504000000008000026001801600", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_180" : { - "code" : "0xef000101000402000100020400000000800000b300", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_181" : { - "code" : "0xef000101000402000100020400000000800000b400", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_182" : { - "code" : "0xef000101000402000100020400000000800000b500", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_183" : { - "code" : "0xef000101000402000100020400000000800000b600", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_184" : { - "code" : "0xef000101000402000100020400000000800000b700", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_185" : { - "code" : "0xef000101000402000100020400000000800000b800", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_186" : { - "code" : "0xef000101000402000100020400000000800000b900", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_187" : { - "code" : "0xef000101000402000100020400000000800000ba00", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_188" : { - "code" : "0xef000101000402000100020400000000800000bb00", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_189" : { - "code" : "0xef000101000402000100020400000000800000bc00", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_19" : { - "code" : "0xef0001010004020001000504000000008000026001801700", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_190" : { - "code" : "0xef000101000402000100020400000000800000bd00", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_191" : { - "code" : "0xef000101000402000100020400000000800000be00", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_192" : { - "code" : "0xef000101000402000100020400000000800000bf00", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_193" : { - "code" : "0xef000101000402000100020400000000800000c000", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_194" : { - "code" : "0xef000101000402000100020400000000800000c100", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_195" : { - "code" : "0xef000101000402000100020400000000800000c200", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_196" : { - "code" : "0xef000101000402000100020400000000800000c300", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_197" : { - "code" : "0xef000101000402000100020400000000800000c400", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_198" : { - "code" : "0xef000101000402000100020400000000800000c500", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_199" : { - "code" : "0xef000101000402000100020400000000800000c600", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_2" : { - "code" : "0xef0001010004020001000504000000008000026001800200", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_20" : { - "code" : "0xef0001010004020001000504000000008000026001801800", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_200" : { - "code" : "0xef000101000402000100020400000000800000c700", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_201" : { - "code" : "0xef000101000402000100020400000000800000c800", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_202" : { - "code" : "0xef000101000402000100020400000000800000c900", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_203" : { - "code" : "0xef000101000402000100020400000000800000ca00", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_204" : { - "code" : "0xef000101000402000100020400000000800000cb00", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_205" : { - "code" : "0xef000101000402000100020400000000800000cc00", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_206" : { - "code" : "0xef000101000402000100020400000000800000cd00", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_207" : { - "code" : "0xef000101000402000100020400000000800000ce00", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_208" : { - "code" : "0xef000101000402000100020400000000800000cf00", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_209" : { - "code" : "0xef000101000402000100020400000000800000d400", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_21" : { - "code" : "0xef00010100040200010004040000000080000160011900", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_210" : { - "code" : "0xef000101000402000100020400000000800000d500", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_211" : { - "code" : "0xef000101000402000100020400000000800000d600", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_212" : { - "code" : "0xef000101000402000100020400000000800000d700", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_213" : { - "code" : "0xef000101000402000100020400000000800000d800", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_214" : { - "code" : "0xef000101000402000100020400000000800000d900", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_215" : { - "code" : "0xef000101000402000100020400000000800000da00", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_216" : { - "code" : "0xef000101000402000100020400000000800000db00", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_217" : { - "code" : "0xef000101000402000100020400000000800000dc00", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_218" : { - "code" : "0xef000101000402000100020400000000800000dd00", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_219" : { - "code" : "0xef000101000402000100020400000000800000de00", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_22" : { - "code" : "0xef0001010004020001000504000000008000026001801a00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_220" : { - "code" : "0xef000101000402000100020400000000800000df00", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_221" : { - "code" : "0xef000101000402000100020400000000800000e800", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_222" : { - "code" : "0xef000101000402000100020400000000800000e900", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_223" : { - "code" : "0xef000101000402000100020400000000800000ea00", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_224" : { - "code" : "0xef000101000402000100020400000000800000eb00", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_225" : { - "code" : "0xef000101000402000100020400000000800000ef00", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_226" : { - "code" : "0xef000101000402000100020400000000800000f000", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_227" : { - "code" : "0xef000101000402000100020400000000800000f200", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_228" : { - "code" : "0xef000101000402000100020400000000800000f500", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_229" : { - "code" : "0xef000101000402000100020400000000800000f600", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_23" : { - "code" : "0xef0001010004020001000504000000008000026001801b00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_230" : { - "code" : "0xef000101000402000100020400000000800000f800", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_231" : { - "code" : "0xef000101000402000100020400000000800000f900", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_232" : { - "code" : "0xef000101000402000100020400000000800000fb00", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_233" : { - "code" : "0xef000101000402000100020400000000800000fc00", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_234" : { - "code" : "0xef000101000402000100020400000000800000ff00", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_235" : { - "code" : "0xef0001010004020001000b04000000008000026001600155600260025560", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_236" : { - "code" : "0xef0001010004020001000b04000000008000026001600155600260025561", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_237" : { - "code" : "0xef0001010004020001000b04000000008000026001600155600260025561", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_238" : { - "code" : "0xef0001010004020001000b04000000008000026001600155600260025562", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_239" : { - "code" : "0xef0001010004020001000b04000000008000026001600155600260025562", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_24" : { - "code" : "0xef0001010004020001000504000000008000026001801c00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_240" : { - "code" : "0xef0001010004020001000b04000000008000026001600155600260025563", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_241" : { - "code" : "0xef0001010004020001000b04000000008000026001600155600260025563", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_242" : { - "code" : "0xef0001010004020001000b04000000008000026001600155600260025564", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_243" : { - "code" : "0xef0001010004020001000b04000000008000026001600155600260025564", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_244" : { - "code" : "0xef0001010004020001000b04000000008000026001600155600260025565", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_245" : { - "code" : "0xef0001010004020001000b04000000008000026001600155600260025565", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_246" : { - "code" : "0xef0001010004020001000b04000000008000026001600155600260025566", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_247" : { - "code" : "0xef0001010004020001000b04000000008000026001600155600260025566", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_248" : { - "code" : "0xef0001010004020001000b04000000008000026001600155600260025567", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_249" : { - "code" : "0xef0001010004020001000b04000000008000026001600155600260025567", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_25" : { - "code" : "0xef0001010004020001000504000000008000026001801d00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_250" : { - "code" : "0xef0001010004020001000b04000000008000026001600155600260025568", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_251" : { - "code" : "0xef0001010004020001000b04000000008000026001600155600260025568", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_252" : { - "code" : "0xef0001010004020001000b04000000008000026001600155600260025569", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_253" : { - "code" : "0xef0001010004020001000b04000000008000026001600155600260025569", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_254" : { - "code" : "0xef0001010004020001000b0400000000800002600160015560026002556a", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_255" : { - "code" : "0xef0001010004020001000b0400000000800002600160015560026002556a", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_256" : { - "code" : "0xef0001010004020001000b0400000000800002600160015560026002556b", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_257" : { - "code" : "0xef0001010004020001000b0400000000800002600160015560026002556b", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_258" : { - "code" : "0xef0001010004020001000b0400000000800002600160015560026002556c", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_259" : { - "code" : "0xef0001010004020001000b0400000000800002600160015560026002556c", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_26" : { - "code" : "0xef0001010004020001000504000000008000026001802000", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_260" : { - "code" : "0xef0001010004020001000b0400000000800002600160015560026002556d", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_261" : { - "code" : "0xef0001010004020001000b0400000000800002600160015560026002556d", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_262" : { - "code" : "0xef0001010004020001000b0400000000800002600160015560026002556e", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_263" : { - "code" : "0xef0001010004020001000b0400000000800002600160015560026002556e", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_264" : { - "code" : "0xef0001010004020001000b0400000000800002600160015560026002556f", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_265" : { - "code" : "0xef0001010004020001000b0400000000800002600160015560026002556f", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_266" : { - "code" : "0xef0001010004020001000b04000000008000026001600155600260025570", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_267" : { - "code" : "0xef0001010004020001000b04000000008000026001600155600260025570", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_268" : { - "code" : "0xef0001010004020001000b04000000008000026001600155600260025571", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_269" : { - "code" : "0xef0001010004020001000b04000000008000026001600155600260025571", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_27" : { - "code" : "0xef0001010004020001000204000000008000013000", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_270" : { - "code" : "0xef0001010004020001000b04000000008000026001600155600260025572", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_271" : { - "code" : "0xef0001010004020001000b04000000008000026001600155600260025572", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_272" : { - "code" : "0xef0001010004020001000b04000000008000026001600155600260025573", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_273" : { - "code" : "0xef0001010004020001000b04000000008000026001600155600260025573", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_274" : { - "code" : "0xef0001010004020001000b04000000008000026001600155600260025574", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_275" : { - "code" : "0xef0001010004020001000b04000000008000026001600155600260025574", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_276" : { - "code" : "0xef0001010004020001000b04000000008000026001600155600260025575", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_277" : { - "code" : "0xef0001010004020001000b04000000008000026001600155600260025575", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_278" : { - "code" : "0xef0001010004020001000b04000000008000026001600155600260025576", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_279" : { - "code" : "0xef0001010004020001000b04000000008000026001600155600260025576", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_28" : { - "code" : "0xef00010100040200010004040000000080000160013100", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_280" : { - "code" : "0xef0001010004020001000b04000000008000026001600155600260025577", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_281" : { - "code" : "0xef0001010004020001000b04000000008000026001600155600260025577", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_282" : { - "code" : "0xef0001010004020001000b04000000008000026001600155600260025578", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_283" : { - "code" : "0xef0001010004020001000b04000000008000026001600155600260025578", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_284" : { - "code" : "0xef0001010004020001000b04000000008000026001600155600260025579", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_285" : { - "code" : "0xef0001010004020001000b04000000008000026001600155600260025579", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_286" : { - "code" : "0xef0001010004020001000b0400000000800002600160015560026002557a", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_287" : { - "code" : "0xef0001010004020001000b0400000000800002600160015560026002557a", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_288" : { - "code" : "0xef0001010004020001000b0400000000800002600160015560026002557b", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_289" : { - "code" : "0xef0001010004020001000b0400000000800002600160015560026002557b", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_29" : { - "code" : "0xef0001010004020001000204000000008000013200", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_290" : { - "code" : "0xef0001010004020001000b0400000000800002600160015560026002557c", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_291" : { - "code" : "0xef0001010004020001000b0400000000800002600160015560026002557c", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_292" : { - "code" : "0xef0001010004020001000b0400000000800002600160015560026002557d", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_293" : { - "code" : "0xef0001010004020001000b0400000000800002600160015560026002557d", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_294" : { - "code" : "0xef0001010004020001000b0400000000800002600160015560026002557e", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_295" : { - "code" : "0xef0001010004020001000b0400000000800002600160015560026002557e", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_296" : { - "code" : "0xef0001010004020001000b0400000000800002600160015560026002557f", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_297" : { - "code" : "0xef0001010004020001000b0400000000800002600160015560026002557f", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_298" : { - "code" : "0xef0001010004020001000c04000000008000026001600155600260025500fb", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_3" : { - "code" : "0xef0001010004020001000504000000008000026001800300", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_30" : { - "code" : "0xef0001010004020001000204000000008000013300", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_31" : { - "code" : "0xef0001010004020001000204000000008000013400", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_32" : { - "code" : "0xef00010100040200010004040000000080000160013500", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_33" : { - "code" : "0xef0001010004020001000204000000008000013600", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_34" : { - "code" : "0xef000101000402000100060400000000800003600180803700", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_35" : { - "code" : "0xef0001010004020001000204000000008000013800", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_36" : { - "code" : "0xef000101000402000100060400000000800003600180803900", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_37" : { - "code" : "0xef0001010004020001000204000000008000013a00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_38" : { - "code" : "0xef00010100040200010004040000000080000160013b00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_39" : { - "code" : "0xef00010100040200010007040000000080000460018080803c00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_4" : { - "code" : "0xef0001010004020001000504000000008000026001800400", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_40" : { - "code" : "0xef0001010004020001000204000000008000013d00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_41" : { - "code" : "0xef000101000402000100060400000000800003600180803e00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_42" : { - "code" : "0xef00010100040200010004040000000080000160013f00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_43" : { - "code" : "0xef00010100040200010004040000000080000160014000", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_44" : { - "code" : "0xef0001010004020001000204000000008000014100", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_45" : { - "code" : "0xef0001010004020001000204000000008000014200", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_46" : { - "code" : "0xef0001010004020001000204000000008000014300", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_47" : { - "code" : "0xef0001010004020001000204000000008000014400", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_48" : { - "code" : "0xef0001010004020001000204000000008000014500", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_49" : { - "code" : "0xef0001010004020001000204000000008000014600", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_5" : { - "code" : "0xef0001010004020001000504000000008000026001800500", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_50" : { - "code" : "0xef0001010004020001000204000000008000014700", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_51" : { - "code" : "0xef0001010004020001000204000000008000014800", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_52" : { - "code" : "0xef00010100040200010004040000000080000160014900", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_53" : { - "code" : "0xef0001010004020001000204000000008000014a00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_54" : { - "code" : "0xef00010100040200010004040000000080000160015000", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_55" : { - "code" : "0xef00010100040200010004040000000080000160015100", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_56" : { - "code" : "0xef0001010004020001000504000000008000026001805300", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_57" : { - "code" : "0xef00010100040200010004040000000080000160015400", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_58" : { - "code" : "0xef0001010004020001000504000000008000026001805500", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_59" : { - "code" : "0xef0001010004020001000204000000008000015900", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_6" : { - "code" : "0xef0001010004020001000504000000008000026001800600", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_60" : { - "code" : "0xef0001010004020001000204000000008000015a00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_61" : { - "code" : "0xef0001010004020001000204000000008000005b00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_62" : { - "code" : "0xef000101000402000100060400000000800003600180805e00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_63" : { - "code" : "0xef0001010004020001000204000000008000015f00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_64" : { - "code" : "0xef000101000402000100030400000000800001600100", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_65" : { - "code" : "0xef00010100040200010004040000000080000161ffff00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_66" : { - "code" : "0xef00010100040200010005040000000080000162ffffff00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_67" : { - "code" : "0xef00010100040200010006040000000080000163ffffffff00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_68" : { - "code" : "0xef00010100040200010007040000000080000164ffffffffff00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_69" : { - "code" : "0xef00010100040200010008040000000080000165ffffffffffff00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_7" : { - "code" : "0xef0001010004020001000504000000008000026001800700", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_70" : { - "code" : "0xef00010100040200010009040000000080000166ffffffffffffff00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_71" : { - "code" : "0xef0001010004020001000a040000000080000167ffffffffffffffff00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_72" : { - "code" : "0xef0001010004020001000b040000000080000168ffffffffffffffffff00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_73" : { - "code" : "0xef0001010004020001000c040000000080000169ffffffffffffffffffff00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_74" : { - "code" : "0xef0001010004020001000d04000000008000016affffffffffffffffffffff00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_75" : { - "code" : "0xef0001010004020001000e04000000008000016bffffffffffffffffffffffff00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_76" : { - "code" : "0xef0001010004020001000f04000000008000016cffffffffffffffffffffffffff00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_77" : { - "code" : "0xef0001010004020001001004000000008000016dffffffffffffffffffffffffffff00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_78" : { - "code" : "0xef0001010004020001001104000000008000016effffffffffffffffffffffffffffff00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_79" : { - "code" : "0xef0001010004020001001204000000008000016fffffffffffffffffffffffffffffffff00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_8" : { - "code" : "0xef000101000402000100060400000000800003600180800800", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_80" : { - "code" : "0xef00010100040200010013040000000080000170ffffffffffffffffffffffffffffffffff00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_81" : { - "code" : "0xef00010100040200010014040000000080000171ffffffffffffffffffffffffffffffffffff00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_82" : { - "code" : "0xef00010100040200010015040000000080000172ffffffffffffffffffffffffffffffffffffff00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_83" : { - "code" : "0xef00010100040200010016040000000080000173ffffffffffffffffffffffffffffffffffffffff00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_84" : { - "code" : "0xef00010100040200010017040000000080000174ffffffffffffffffffffffffffffffffffffffffff00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_85" : { - "code" : "0xef00010100040200010018040000000080000175ffffffffffffffffffffffffffffffffffffffffffff00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_86" : { - "code" : "0xef00010100040200010019040000000080000176ffffffffffffffffffffffffffffffffffffffffffffff00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_87" : { - "code" : "0xef0001010004020001001a040000000080000177ffffffffffffffffffffffffffffffffffffffffffffffff00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_88" : { - "code" : "0xef0001010004020001001b040000000080000178ffffffffffffffffffffffffffffffffffffffffffffffffff00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_89" : { - "code" : "0xef0001010004020001001c040000000080000179ffffffffffffffffffffffffffffffffffffffffffffffffffff00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_9" : { - "code" : "0xef000101000402000100060400000000800003600180800900", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_90" : { - "code" : "0xef0001010004020001001d04000000008000017affffffffffffffffffffffffffffffffffffffffffffffffffffff00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_91" : { - "code" : "0xef0001010004020001001e04000000008000017bffffffffffffffffffffffffffffffffffffffffffffffffffffffff00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_92" : { - "code" : "0xef0001010004020001001f04000000008000017cffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_93" : { - "code" : "0xef0001010004020001002004000000008000017dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_94" : { - "code" : "0xef0001010004020001002104000000008000017effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_95" : { - "code" : "0xef0001010004020001002204000000008000017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_96" : { - "code" : "0xef00010100040200010004040000000080000260018000", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_97" : { - "code" : "0xef0001010004020001000504000000008000036001808100", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_98" : { - "code" : "0xef000101000402000100060400000000800004600180808200", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_99" : { - "code" : "0xef00010100040200010007040000000080000560018080808300", - "results" : { - "Prague" : { - "result" : true - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/EIP4200/validInvalid.json b/crates/interpreter/tests/EOFTests/EIP4200/validInvalid.json deleted file mode 100644 index 4d78c6442b..0000000000 --- a/crates/interpreter/tests/EOFTests/EIP4200/validInvalid.json +++ /dev/null @@ -1,513 +0,0 @@ -{ - "validInvalid" : { - "_info" : { - "comment" : "Test various examples to see if they are valid or invalid.\nImplements\n EOF1V4200_0001 (Valid) EOF code containing RJUMP (Positive, Negative) - Data index: 0\n EOF1V4200_0002 (Valid) EOF code containing RJUMP (Zero) - Data index: 1\n EOF1V4200_0003 (Valid) EOF with RJUMP containing the maximum offset (32767) - Data index: 2\n EOF1V4200_0004 (Valid) EOF code containing RJUMPI (Positive) - Data index: 3\n EOF1V4200_0005 (Valid) EOF code containing RJUMPI (Negative) - Data index: 4\n EOF1V4200_0006 (Valid) EOF code containing RJUMPI (Zero) - Data index: 5\n EOF1V4200_0007 (Valid) EOF with RJUMPI containing the maximum offset (32767) - Data index: 6\n EOF1V4200_0008 (Valid) EOF with RJUMPV table size 1 (Positive) - Data index: 7\n EOF1V4200_0009 (Valid) EOF with RJUMPV table size 1 (Negative) - Data index: 8\n EOF1V4200_0010 (Valid) EOF with RJUMPV table size 1 (Zero) - Data index: 9\n EOF1V4200_0011 (Valid) EOF with RJUMPV table size 3 - Data index: 10\n EOF1V4200_0012 (Valid) EOF with RJUMPV table size 256 (Target 0) - Data index: 11\n EOF1V4200_0013 (Valid) EOF with RJUMPV table size 256 (Target 100) - Data index: 12\n EOF1V4200_0014 (Valid) EOF with RJUMPV table size 256 (Target 254) - Data index: 13\n EOF1V4200_0015 (Valid) EOF with RJUMPV table size 256 (Target 256) - Data index: 14\n EOF1V4200_0016 (Valid) EOF with RJUMPV containing the maximum offset (32767) - Data index: 15\n EOF1I4200_0001 (Invalid) EOF code containing truncated RJUMP - Data index: 16\n EOF1I4200_0002 (Invalid) EOF code containing truncated RJUMP - Data index: 17\n EOF1I4200_0003 (Invalid) EOF code containing RJUMP with target outside code bounds (Jumping into header) - Data index: 18\n EOF1I4200_0004 (Invalid) EOF code containing RJUMP with target outside code bounds (Jumping before code begin) - Data index: 19\n EOF1I4200_0005 (Invalid) EOF code containing RJUMP with target outside code bounds (Jumping into data section) - Data index: 20\n EOF1I4200_0006 (Invalid) EOF code containing RJUMP with target outside code bounds (Jumping after code end) - Data index: 21\n EOF1I4200_0007 (Invalid) EOF code containing RJUMP with target outside code bounds (Jumping to code end) - Data index: 22\n EOF1I4200_0008 (Invalid) EOF code containing RJUMP with target self RJUMP immediate - Data index: 23\n EOF1I4200_0009 (Invalid) EOF code containing RJUMP with target other RJUMP immediate - Data index: 24\n EOF1I4200_0010 (Invalid) EOF code containing RJUMP with target RJUMPI immediate - Data index: 25\n EOF1I4200_0011 (Invalid) EOF code containing RJUMP with target PUSH immediate - Data index: 26\n EOF1I4200_0012 (Invalid) EOF code containing RJUMP with target RJUMPV immediate - Data index: 27\n EOF1I4200_0013 (Invalid) EOF code containing RJUMP with target CALLF immediate - Data index: 28\n EOF1I4200_0014 (Invalid) EOF code containing truncated RJUMPI - Data index: 29\n EOF1I4200_0015 (Invalid) EOF code containing truncated RJUMPI - Data index: 30\n EOF1I4200_0016 (Invalid) EOF code containing RJUMPI with target outside code bounds (Jumping into header) - Data index: 31\n EOF1I4200_0017 (Invalid) EOF code containing RJUMPI with target outside code bounds (Jumping to before code begin) - Data index: 32\n EOF1I4200_0018 (Invalid) EOF code containing RJUMPI with target outside code bounds (Jumping into data section) - Data index: 33\n EOF1I4200_0019 (Invalid) EOF code containing RJUMPI with target outside code bounds (Jumping to after code end) - Data index: 34\n EOF1I4200_0020 (Invalid) EOF code containing RJUMPI with target outside code bounds (Jumping to code end) - Data index: 35\n EOF1I4200_0021 (Invalid) EOF code containing RJUMPI with target same RJUMPI immediate - Data index: 36\n EOF1I4200_0022 (Invalid) EOF code containing RJUMPI with target other RJUMPI immediate - Data index: 37\n EOF1I4200_0023 (Invalid) EOF code containing RJUMPI with target RJUMP immediate - Data index: 38\n EOF1I4200_0024 (Invalid) EOF code containing RJUMPI with target PUSH immediate - Data index: 39\n EOF1I4200_0025 (Invalid) EOF code containing RJUMPI with target RJUMPV immediate - Data index: 40\n EOF1I4200_0026 (Invalid) EOF code containing RJUMPI with target CALLF immediate - Data index: 41\n EOF1I4200_0027 (Invalid) EOF code containing RJUMPV with max_index 0 but no immediates - Data index: 42\n EOF1I4200_0028 (Invalid) EOF code containing truncated RJUMPV - Data index: 43\n EOF1I4200_0029 (Invalid) EOF code containing truncated RJUMPV - Data index: 44\n EOF1I4200_0030 (Invalid) EOF code containing truncated RJUMPV - Data index: 45\n EOF1I4200_0031 (Invalid) EOF code containing RJUMPV with target outside code bounds (Jumping into header) - Data index: 46\n EOF1I4200_0032 (Invalid) EOF code containing RJUMPV with target outside code bounds (Jumping to before code begin) - Data index: 47\n EOF1I4200_0033 (Invalid) EOF code containing RJUMPV with target outside code bounds (Jumping into data section) - Data index: 48\n EOF1I4200_0034 (Invalid) EOF code containing RJUMPV with target outside code bounds (Jumping to after code end) - Data index: 49\n EOF1I4200_0035 (Invalid) EOF code containing RJUMPV with target outside code bounds (Jumping to code end) - Data index: 50\n EOF1I4200_0036 (Invalid) EOF code containing RJUMPV with target same RJUMPV immediate - Data index: 51\n EOF1I4200_0037 (Invalid) EOF code containing RJUMPV with target RJUMP immediate - Data index: 52\n EOF1I4200_0038 (Invalid) EOF code containing RJUMPV with target RJUMPI immediate - Data index: 53\n EOF1I4200_0039 (Invalid) EOF code containing RJUMPV with target PUSH immediate - Data index: 54\n EOF1I4200_0040 (Invalid) EOF code containing RJUMPV with target other RJUMPV immediate - Data index: 55\n EOF1I4200_0041 (Invalid) EOF code containing RJUMPV with target CALLF immediate - Data index: 56\n", - "filling-rpc-server" : "evmone-t8n 0.12.0-dev+commit.14ba7529", - "filling-tool-version" : "retesteth-0.3.2-cancun+commit.9d793abd.Linux.g++", - "generatedTestHash" : "6f6a515834f257803a49a1074b4a996638d699c74fddf6103d21e3d7f02f33c4", - "lllcversion" : "Version: 0.5.14-develop.2022.4.6+commit.401d5358.Linux.g++", - "solidity" : "Version: 0.8.18-develop.2023.1.16+commit.469d6d4d.Linux.g++", - "source" : "src/EOFTestsFiller/EIP4200/validInvalidFiller.yml", - "sourceHash" : "06fd1b57a7e0d80ade8000683de4e77b85a02306e9e4b6b66d42cc0f3b5ee2b8" - }, - "vectors" : { - "validInvalid_0" : { - "code" : "0xef0001010004020001001004000000008000025fe10003e00006600160015500e0fff7", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_1" : { - "code" : "0xef000101000402000100090400000000800002e00000600160015500", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_10" : { - "code" : "0xef0001010004020001001304000000008000026000e20200030000fff65b5b00600160015500", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_11" : { - "code" : "0xef0001010004020001030a04000000008000026000e2ff010000c600690073005100ff004a00ec002900cd00ba00ab00f200fb00e30046007c00c2005400f8001b00e800e7008d0076005a002e00630033009f00c9009a00660032000d00b70031005800a3005a0025005d00050017005800e9005e00d400ab00b200cd00c6009b00b400540011000e0082007400410021003d00dc0087007000e9003e00a1004100e100fc0067003e0001007e009700ea00dc006b0096008f0038005c002a00ec00b0003b00fb003200af003c005400ec001800db005c0002001a00fe004300fb00fa00aa003a00fb002900d100e60005003c007c0094007500d800be0061008900f9005c00bb00a80099000f009500b100eb00f100b3000500ef00f7000000e900a1003a00e500ca000b00cb00d000480047006400bd001f0023001e00a8001c007b006400c500140073005a00c5005e004b00790063003b0070006400240011009e000900dc00aa00d400ac00f2001b001000af003b003300cd00e30050004800470015005c00bb006f0022001900ba009b007d00f5000b00e1001a001c007f002300f8002900f800a4001b001300b500ca004e00e800980032003800e00079004d003d003400bc005f004e007700fa00cb006c000500ac00860021002b00aa001a005500a200be007000b50073003b0004005c00d30036009400b300af00e200f000e4009e004f00320015004900fd008200c500ff5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b00600160015500", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_12" : { - "code" : "0xef0001010004020001030a04000000008000026064e2ff006700c600690073005100ff004a00ec002900cd00ba00ab00f200fb00e30046007c00c2005400f8001b00e800e7008d0076005a002e00630033009f00c9009a00660032000d00b70031005800a3005a0025005d00050017005800e9005e00d400ab00b200cd00c6009b00b400540011000e0082007400410021003d00dc0087007000e9003e00a1004100e100fc0067003e0001007e009700ea00dc006b0096008f0038005c002a00ec00b0003b00fb003200af003c005400ec001800db005c0002001a00fe0043010000fa00aa003a00fb002900d100e60005003c007c0094007500d800be0061008900f9005c00bb00a80099000f009500b100eb00f100b3000500ef00f7000000e900a1003a00e500ca000b00cb00d000480047006400bd001f0023001e00a8001c007b006400c500140073005a00c5005e004b00790063003b0070006400240011009e000900dc00aa00d400ac00f2001b001000af003b003300cd00e30050004800470015005c00bb006f0022001900ba009b007d00f5000b00e1001a001c007f002300f8002900f800a4001b001300b500ca004e00e800980032003800e00079004d003d003400bc005f004e007700fa00cb006c000500ac00860021002b00aa001a005500a200be007000b50073003b0004005c00d30036009400b300af00e200f000e4009e004f00320015004900fd008200c500ff5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b00600160015500", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_13" : { - "code" : "0xef0001010004020001030a040000000080000260fee2ff006700c600690073005100ff004a00ec002900cd00ba00ab00f200fb00e30046007c00c2005400f8001b00e800e7008d0076005a002e00630033009f00c9009a00660032000d00b70031005800a3005a0025005d00050017005800e9005e00d400ab00b200cd00c6009b00b400540011000e0082007400410021003d00dc0087007000e9003e00a1004100e100fc0067003e0001007e009700ea00dc006b0096008f0038005c002a00ec00b0003b00fb003200af003c005400ec001800db005c0002001a00fe004300fb00fa00aa003a00fb002900d100e60005003c007c0094007500d800be0061008900f9005c00bb00a80099000f009500b100eb00f100b3000500ef00f7000000e900a1003a00e500ca000b00cb00d000480047006400bd001f0023001e00a8001c007b006400c500140073005a00c5005e004b00790063003b0070006400240011009e000900dc00aa00d400ac00f2001b001000af003b003300cd00e30050004800470015005c00bb006f0022001900ba009b007d00f5000b00e1001a001c007f002300f8002900f800a4001b001300b500ca004e00e800980032003800e00079004d003d003400bc005f004e007700fa00cb006c000500ac00860021002b00aa001a005500a200be007000b50073003b0004005c00d30036009400b300af00e200f000e4009e004f00320015004900fd0082010000c55b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b00600160015500", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_14" : { - "code" : "0xef0001010004020001030a0400000000800002610100e2ff006700c600690073005100ff004a00ec002900cd00ba00ab00f200fb00e30046007c00c2005400f8001b00e800e7008d0076005a002e00630033009f00c9009a00660032000d00b70031005800a3005a0025005d00050017005800e9005e00d400ab00b200cd00c6009b00b400540011000e0082007400410021003d00dc0087007000e9003e00a1004100e100fc0067003e0001007e009700ea00dc006b0096008f0038005c002a00ec00b0003b00fb003200af003c005400ec001800db005c0002001a00fe004300fb00fa00aa003a00fb002900d100e60005003c007c0094007500d800be0061008900f9005c00bb00a80099000f009500b100eb00f100b3000500ef00f7000000e900a1003a00e500ca000b00cb00d000480047006400bd001f0023001e00a8001c007b006400c500140073005a00c5005e004b00790063003b0070006400240011009e000900dc00aa00d400ac00f2001b001000af003b003300cd00e30050004800470015005c00bb006f0022001900ba009b007d00f5000b00e1001a001c007f002300f8002900f800a4001b001300b500ca004e00e800980032003800e00079004d003d003400bc005f004e007700fa00cb006c000500ac00860021002b00aa001a005500a200be007000b50073003b0004005c00d30036009400b300af00e200f000e4009e004f00320015004900fd008200ff00c55b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b600160015500", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_15" : { - "code" : "0xef0001010004020001800b04000000008000026001e2007fff5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b6001600100", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_16" : { - "code" : "0xef000101000402000100010400000000800000e0", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_17" : { - "code" : "0xef000101000402000100020400000000800000e000", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_18" : { - "code" : "0xef000101000402000100030400000000800000e0fffb", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidJumpDestination", - "result" : false - } - } - }, - "validInvalid_19" : { - "code" : "0xef000101000402000100030400000000800000e0ffe9", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidJumpDestination", - "result" : false - } - } - }, - "validInvalid_2" : { - "code" : "0xef0001010004020001800d04000000008000026000e10003e07fff5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b600160015500", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_20" : { - "code" : "0xef000101000402000100030400040000800000e00002aabbccdd", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidJumpDestination", - "result" : false - } - } - }, - "validInvalid_21" : { - "code" : "0xef000101000402000100030400000000800000e00002", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidJumpDestination", - "result" : false - } - } - }, - "validInvalid_22" : { - "code" : "0xef000101000402000100040400000000800000e0000100", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidJumpDestination", - "result" : false - } - } - }, - "validInvalid_23" : { - "code" : "0xef000101000402000100030400000000800000e0ffff", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidJumpDestination", - "result" : false - } - } - }, - "validInvalid_24" : { - "code" : "0xef000101000402000100070400000000800000e0000300e0fffc", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidJumpDestination", - "result" : false - } - } - }, - "validInvalid_25" : { - "code" : "0xef0001010004020001000a0400000000800000e00005006001e1fffa00", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidJumpDestination", - "result" : false - } - } - }, - "validInvalid_26" : { - "code" : "0xef0001010004020001000a0400000000800000e000025b600160015500", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidJumpDestination", - "result" : false - } - } - }, - "validInvalid_27" : { - "code" : "0xef0001010004020001000b0400000000800000e00005006001e200000000", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidJumpDestination", - "result" : false - } - } - }, - "validInvalid_28" : { - "code" : "0xef000101000802000200070006040000000080000000000002e00002e30001006001600155e4", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidJumpDestination", - "result" : false - } - } - }, - "validInvalid_29" : { - "code" : "0xef0001010004020001000304000000008000016000e1", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_3" : { - "code" : "0xef0001010004020001000e04000000008000026001e100035b5b00600160015500", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_30" : { - "code" : "0xef0001010004020001000404000000008000016000e100", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_31" : { - "code" : "0xef0001010004020001000604000000008000016001e1fff900", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidJumpDestination", - "result" : false - } - } - }, - "validInvalid_32" : { - "code" : "0xef0001010004020001000604000000008000016001e1ffe700", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidJumpDestination", - "result" : false - } - } - }, - "validInvalid_33" : { - "code" : "0xef0001010004020001000604000400008000016001e1000200aabbccdd", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidJumpDestination", - "result" : false - } - } - }, - "validInvalid_34" : { - "code" : "0xef0001010004020001000604000000008000016001e1000200", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidJumpDestination", - "result" : false - } - } - }, - "validInvalid_35" : { - "code" : "0xef0001010004020001000604000000008000016001e1000100", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidJumpDestination", - "result" : false - } - } - }, - "validInvalid_36" : { - "code" : "0xef0001010004020001000604000000008000016001e1ffff00", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidJumpDestination", - "result" : false - } - } - }, - "validInvalid_37" : { - "code" : "0xef0001010004020001000c04000000008000016001e10005006001e1fff500", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidJumpDestination", - "result" : false - } - } - }, - "validInvalid_38" : { - "code" : "0xef0001010004020001000904000000008000016001e1000300e0fff7", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidJumpDestination", - "result" : false - } - } - }, - "validInvalid_39" : { - "code" : "0xef0001010004020001000604000000008000016001e1fffc00", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidJumpDestination", - "result" : false - } - } - }, - "validInvalid_4" : { - "code" : "0xef0001010004020001001104000000008000026001e100066001600155006001e1fff500", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_40" : { - "code" : "0xef0001010004020001000d04000000008000016001e10005006001e200000000", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidJumpDestination", - "result" : false - } - } - }, - "validInvalid_41" : { - "code" : "0xef0001010008020002000900060400000000800001000000026001e10002e30001006001600155e4", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidJumpDestination", - "result" : false - } - } - }, - "validInvalid_42" : { - "code" : "0xef0001010004020001000404000000008000016001e200", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_43" : { - "code" : "0xef0001010004020001000304000000008000016001e2", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_44" : { - "code" : "0xef0001010004020001000404000000008000016001e200", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_45" : { - "code" : "0xef0001010004020001000504000000008000016001e20000", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_46" : { - "code" : "0xef0001010004020001000704000000008000016001e200fff900", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidJumpDestination", - "result" : false - } - } - }, - "validInvalid_47" : { - "code" : "0xef0001010004020001000704000000008000016001e200fff100", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidJumpDestination", - "result" : false - } - } - }, - "validInvalid_48" : { - "code" : "0xef0001010004020001000704000400008000016001e200000200aabbccdd", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidJumpDestination", - "result" : false - } - } - }, - "validInvalid_49" : { - "code" : "0xef0001010004020001000704000000008000016001e200000200", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidJumpDestination", - "result" : false - } - } - }, - "validInvalid_5" : { - "code" : "0xef0001010004020001000b04000000008000026001e10000600160015500", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_50" : { - "code" : "0xef0001010004020001000704000000008000016001e200000100", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidJumpDestination", - "result" : false - } - } - }, - "validInvalid_51" : { - "code" : "0xef0001010004020001000704000000008000016001e200ffff00", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidJumpDestination", - "result" : false - } - } - }, - "validInvalid_52" : { - "code" : "0xef0001010004020001000d04000000008000016001e2000005006001e0fff700", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidJumpDestination", - "result" : false - } - } - }, - "validInvalid_53" : { - "code" : "0xef0001010004020001000d04000000008000016001e2000005006001e1fff700", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidJumpDestination", - "result" : false - } - } - }, - "validInvalid_54" : { - "code" : "0xef0001010004020001000d04000000008000016001e200000200600160015500", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidJumpDestination", - "result" : false - } - } - }, - "validInvalid_55" : { - "code" : "0xef0001010004020001000e04000000008000016001e2000005006001e200000000", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidJumpDestination", - "result" : false - } - } - }, - "validInvalid_56" : { - "code" : "0xef0001010008020002000a00060400000000800001000000026000e2000002e30001006001600155e4", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidJumpDestination", - "result" : false - } - } - }, - "validInvalid_6" : { - "code" : "0xef0001010004020001800b04000000008000026001e17fff5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b600160015500", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_7" : { - "code" : "0xef0001010004020001000f04000000008000026000e20000035b5b00600160015500", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_8" : { - "code" : "0xef0001010004020001001204000000008000026001e100066001600155006000e200fff400", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_9" : { - "code" : "0xef0001010004020001000c04000000008000026000e2000000600160015500", - "results" : { - "Prague" : { - "result" : true - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/EIP4750/validInvalid.json b/crates/interpreter/tests/EOFTests/EIP4750/validInvalid.json deleted file mode 100644 index 0e07dd4823..0000000000 --- a/crates/interpreter/tests/EOFTests/EIP4750/validInvalid.json +++ /dev/null @@ -1,323 +0,0 @@ -{ - "validInvalid" : { - "_info" : { - "comment" : "Test various examples to see if they are valid or invalid.\nImplements\n EOF1V4750_0001 (Valid) EOF code containing single type section - Data index: 0\n EOF1V4750_0002 (Valid) EOF code containing single type section and data section - Data index: 1\n EOF1V4750_0003 (Valid) EOF code containing multiple type/code sections - Data index: 2\n EOF1V4750_0004 (Valid) EOF code containing multiple type/code sections and data section - Data index: 3\n EOF1V4750_0005 (Valid) EOF code containing multiple type/code sections, no void I/O types - Data index: 4\n EOF1V4750_0006 (Valid) EOF code containing multiple type/code sections, no void I/O types, containing data section - Data index: 5\n EOF1V4750_0007 (Valid) EOF code containing the maximum number of code sections - Data index: 6\n EOF1V4750_0008 (Valid) EOF code containing the maximum number of code sections and data section - Data index: 7\n EOF1I4750_0001 (Invalid) EOF code missing mandatory type section - Data index: 8\n EOF1I4750_0002 (Invalid) EOF code containing multiple type headers - Data index: 9\n EOF1I4750_0003 (Invalid) EOF code containing type section size (Size 1) - Data index: 10\n EOF1I4750_0004 (Invalid) EOF code containing type section size (Size 8 - 1 Code section) - Data index: 11\n EOF1I4750_0005 (Invalid) EOF code containing type section size (Size 8 - 3 Code sections) - Data index: 12\n EOF1I4750_0006 (Invalid) EOF code containing invalid section type (1,0) (First section having a type different than (0,0x80)) - Data index: 13\n EOF1I4750_0007 (Invalid) EOF code containing invalid section type (0,1) (First section having a type different than (0,0x80)) - Data index: 14\n EOF1I4750_0008 (Invalid) EOF code containing invalid section type (2,3) (First section having a type different than (0,0x80)) - Data index: 15\n EOF1I4750_0009 (Invalid) EOF code containing too many code sections - Data index: 16\n EOF1I4750_0010 (Invalid) EOF code containing CALLF to a non existing code section - Data index: 17\n EOF1I4750_0011 (Invalid) EOF code containing truncated CALLF - Data index: 18\n EOF1I4750_0012 (Invalid) EOF code containing deprecated instruction (JUMP) - Data index: 19\n EOF1I4750_0013 (Invalid) EOF code containing deprecated instruction (JUMPI) - Data index: 20\n EOF1I4750_0014 (Invalid) EOF code containing deprecated instruction (PC) - Data index: 21\n EOF1I4750_0015 (Invalid) EOF code containing deprecated instruction (SELFDESTRUCT) - Data index: 22\n EOF1I4750_0016 (Invalid) EOF code containing deprecated instruction (CALLCODE) - Data index: 23\n EOF1I4750_0017 (Invalid) EOF code containing deprecated instruction (CREATE) - Data index: 24\n EOF1I4750_0018 (Invalid) EOF code containing deprecated instruction (CREATE2) - Data index: 25\n EOF1I4750_0019 (Invalid) EOF code containing call to functions without required stack specified in type section - Data index: 26\n EOF1I4750_0020 (Invalid) EOF code containing call to functions without required stack NOT specified in type section - Data index: 27\n EOF1I4750_0021 (Invalid) EOF code containing function trying to return more items than specified in type section - Data index: 28\n EOF1I4750_0022 (Invalid) EOF code containing function exceeding max stack items - Data index: 29\n EOF1I4750_0023 (Invalid) EOF code containing function which max stack height causes to exceed max stack items (stack overflow) - Data index: 30\n EOF1I4750_0024 (Invalid) EOF code containing RETF as terminating instruction in first code section (a) Marking first section as returning - Data index: 31\n EOF1I4750_0025 (Invalid) EOF code containing RETF as terminating instruction in first code section (b) Marking first section as non-returning - Data index: 32\n EOF1I4750_0026 (Invalid) EOF code containing RETF as terminating instruction in first code section, containing data section (a) Marking first section as returning - Data index: 33\n EOF1I4750_0027 (Invalid) EOF code containing RETF as terminating instruction in first code section, containing data section (b) Marking first section as non-returning - Data index: 34\n", - "filling-rpc-server" : "evmone-t8n 0.12.0-dev+commit.14ba7529", - "filling-tool-version" : "retesteth-0.3.2-cancun+commit.9d793abd.Linux.g++", - "generatedTestHash" : "c52f3b975197f1d77a471f473a590881508b5388acdbd60f6c7b5b7f8af2ffb5", - "lllcversion" : "Version: 0.5.14-develop.2022.4.6+commit.401d5358.Linux.g++", - "solidity" : "Version: 0.8.18-develop.2023.1.16+commit.469d6d4d.Linux.g++", - "source" : "src/EOFTestsFiller/EIP4750/validInvalidFiller.yml", - "sourceHash" : "40e46dcbdfd6e64cfb79154c4cf88a0fb32571e29cffb6e1bb1ef744e464744b" - }, - "vectors" : { - "validInvalid_0" : { - "code" : "0xef000101000402000100010400000000800000fe", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_1" : { - "code" : "0xef000101000402000100010400010000800000feda", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_10" : { - "code" : "0xef000101000102000100010400000000800000fe", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidSectionBodiesSize", - "result" : false - } - } - }, - "validInvalid_11" : { - "code" : "0xef000101000802000100010400000000800000fe", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidSectionBodiesSize", - "result" : false - } - } - }, - "validInvalid_12" : { - "code" : "0xef0001010008020003000100010001040000000080000000800000fefefe", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidTypeSectionSize", - "result" : false - } - } - }, - "validInvalid_13" : { - "code" : "0xef000101000402000100010400000001000000fe", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidFirstSectionType", - "result" : false - } - } - }, - "validInvalid_14" : { - "code" : "0xef000101000402000100010400000000010000fe", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidFirstSectionType", - "result" : false - } - } - }, - "validInvalid_15" : { - "code" : "0xef000101000402000100010400000002030000fe", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidFirstSectionType", - "result" : false - } - } - }, - "validInvalid_16" : { - "code" : "0xef000101100402040100040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040001040000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e3000100e30002e4e30003e4e30004e4e30005e4e30006e4e30007e4e30008e4e30009e4e3000ae4e3000be4e3000ce4e3000de4e3000ee4e3000fe4e30010e4e30011e4e30012e4e30013e4e30014e4e30015e4e30016e4e30017e4e30018e4e30019e4e3001ae4e3001be4e3001ce4e3001de4e3001ee4e3001fe4e30020e4e30021e4e30022e4e30023e4e30024e4e30025e4e30026e4e30027e4e30028e4e30029e4e3002ae4e3002be4e3002ce4e3002de4e3002ee4e3002fe4e30030e4e30031e4e30032e4e30033e4e30034e4e30035e4e30036e4e30037e4e30038e4e30039e4e3003ae4e3003be4e3003ce4e3003de4e3003ee4e3003fe4e30040e4e30041e4e30042e4e30043e4e30044e4e30045e4e30046e4e30047e4e30048e4e30049e4e3004ae4e3004be4e3004ce4e3004de4e3004ee4e3004fe4e30050e4e30051e4e30052e4e30053e4e30054e4e30055e4e30056e4e30057e4e30058e4e30059e4e3005ae4e3005be4e3005ce4e3005de4e3005ee4e3005fe4e30060e4e30061e4e30062e4e30063e4e30064e4e30065e4e30066e4e30067e4e30068e4e30069e4e3006ae4e3006be4e3006ce4e3006de4e3006ee4e3006fe4e30070e4e30071e4e30072e4e30073e4e30074e4e30075e4e30076e4e30077e4e30078e4e30079e4e3007ae4e3007be4e3007ce4e3007de4e3007ee4e3007fe4e30080e4e30081e4e30082e4e30083e4e30084e4e30085e4e30086e4e30087e4e30088e4e30089e4e3008ae4e3008be4e3008ce4e3008de4e3008ee4e3008fe4e30090e4e30091e4e30092e4e30093e4e30094e4e30095e4e30096e4e30097e4e30098e4e30099e4e3009ae4e3009be4e3009ce4e3009de4e3009ee4e3009fe4e300a0e4e300a1e4e300a2e4e300a3e4e300a4e4e300a5e4e300a6e4e300a7e4e300a8e4e300a9e4e300aae4e300abe4e300ace4e300ade4e300aee4e300afe4e300b0e4e300b1e4e300b2e4e300b3e4e300b4e4e300b5e4e300b6e4e300b7e4e300b8e4e300b9e4e300bae4e300bbe4e300bce4e300bde4e300bee4e300bfe4e300c0e4e300c1e4e300c2e4e300c3e4e300c4e4e300c5e4e300c6e4e300c7e4e300c8e4e300c9e4e300cae4e300cbe4e300cce4e300cde4e300cee4e300cfe4e300d0e4e300d1e4e300d2e4e300d3e4e300d4e4e300d5e4e300d6e4e300d7e4e300d8e4e300d9e4e300dae4e300dbe4e300dce4e300dde4e300dee4e300dfe4e300e0e4e300e1e4e300e2e4e300e3e4e300e4e4e300e5e4e300e6e4e300e7e4e300e8e4e300e9e4e300eae4e300ebe4e300ece4e300ede4e300eee4e300efe4e300f0e4e300f1e4e300f2e4e300f3e4e300f4e4e300f5e4e300f6e4e300f7e4e300f8e4e300f9e4e300fae4e300fbe4e300fce4e300fde4e300fee4e300ffe4e30100e4e30101e4e30102e4e30103e4e30104e4e30105e4e30106e4e30107e4e30108e4e30109e4e3010ae4e3010be4e3010ce4e3010de4e3010ee4e3010fe4e30110e4e30111e4e30112e4e30113e4e30114e4e30115e4e30116e4e30117e4e30118e4e30119e4e3011ae4e3011be4e3011ce4e3011de4e3011ee4e3011fe4e30120e4e30121e4e30122e4e30123e4e30124e4e30125e4e30126e4e30127e4e30128e4e30129e4e3012ae4e3012be4e3012ce4e3012de4e3012ee4e3012fe4e30130e4e30131e4e30132e4e30133e4e30134e4e30135e4e30136e4e30137e4e30138e4e30139e4e3013ae4e3013be4e3013ce4e3013de4e3013ee4e3013fe4e30140e4e30141e4e30142e4e30143e4e30144e4e30145e4e30146e4e30147e4e30148e4e30149e4e3014ae4e3014be4e3014ce4e3014de4e3014ee4e3014fe4e30150e4e30151e4e30152e4e30153e4e30154e4e30155e4e30156e4e30157e4e30158e4e30159e4e3015ae4e3015be4e3015ce4e3015de4e3015ee4e3015fe4e30160e4e30161e4e30162e4e30163e4e30164e4e30165e4e30166e4e30167e4e30168e4e30169e4e3016ae4e3016be4e3016ce4e3016de4e3016ee4e3016fe4e30170e4e30171e4e30172e4e30173e4e30174e4e30175e4e30176e4e30177e4e30178e4e30179e4e3017ae4e3017be4e3017ce4e3017de4e3017ee4e3017fe4e30180e4e30181e4e30182e4e30183e4e30184e4e30185e4e30186e4e30187e4e30188e4e30189e4e3018ae4e3018be4e3018ce4e3018de4e3018ee4e3018fe4e30190e4e30191e4e30192e4e30193e4e30194e4e30195e4e30196e4e30197e4e30198e4e30199e4e3019ae4e3019be4e3019ce4e3019de4e3019ee4e3019fe4e301a0e4e301a1e4e301a2e4e301a3e4e301a4e4e301a5e4e301a6e4e301a7e4e301a8e4e301a9e4e301aae4e301abe4e301ace4e301ade4e301aee4e301afe4e301b0e4e301b1e4e301b2e4e301b3e4e301b4e4e301b5e4e301b6e4e301b7e4e301b8e4e301b9e4e301bae4e301bbe4e301bce4e301bde4e301bee4e301bfe4e301c0e4e301c1e4e301c2e4e301c3e4e301c4e4e301c5e4e301c6e4e301c7e4e301c8e4e301c9e4e301cae4e301cbe4e301cce4e301cde4e301cee4e301cfe4e301d0e4e301d1e4e301d2e4e301d3e4e301d4e4e301d5e4e301d6e4e301d7e4e301d8e4e301d9e4e301dae4e301dbe4e301dce4e301dde4e301dee4e301dfe4e301e0e4e301e1e4e301e2e4e301e3e4e301e4e4e301e5e4e301e6e4e301e7e4e301e8e4e301e9e4e301eae4e301ebe4e301ece4e301ede4e301eee4e301efe4e301f0e4e301f1e4e301f2e4e301f3e4e301f4e4e301f5e4e301f6e4e301f7e4e301f8e4e301f9e4e301fae4e301fbe4e301fce4e301fde4e301fee4e301ffe4e30200e4e30201e4e30202e4e30203e4e30204e4e30205e4e30206e4e30207e4e30208e4e30209e4e3020ae4e3020be4e3020ce4e3020de4e3020ee4e3020fe4e30210e4e30211e4e30212e4e30213e4e30214e4e30215e4e30216e4e30217e4e30218e4e30219e4e3021ae4e3021be4e3021ce4e3021de4e3021ee4e3021fe4e30220e4e30221e4e30222e4e30223e4e30224e4e30225e4e30226e4e30227e4e30228e4e30229e4e3022ae4e3022be4e3022ce4e3022de4e3022ee4e3022fe4e30230e4e30231e4e30232e4e30233e4e30234e4e30235e4e30236e4e30237e4e30238e4e30239e4e3023ae4e3023be4e3023ce4e3023de4e3023ee4e3023fe4e30240e4e30241e4e30242e4e30243e4e30244e4e30245e4e30246e4e30247e4e30248e4e30249e4e3024ae4e3024be4e3024ce4e3024de4e3024ee4e3024fe4e30250e4e30251e4e30252e4e30253e4e30254e4e30255e4e30256e4e30257e4e30258e4e30259e4e3025ae4e3025be4e3025ce4e3025de4e3025ee4e3025fe4e30260e4e30261e4e30262e4e30263e4e30264e4e30265e4e30266e4e30267e4e30268e4e30269e4e3026ae4e3026be4e3026ce4e3026de4e3026ee4e3026fe4e30270e4e30271e4e30272e4e30273e4e30274e4e30275e4e30276e4e30277e4e30278e4e30279e4e3027ae4e3027be4e3027ce4e3027de4e3027ee4e3027fe4e30280e4e30281e4e30282e4e30283e4e30284e4e30285e4e30286e4e30287e4e30288e4e30289e4e3028ae4e3028be4e3028ce4e3028de4e3028ee4e3028fe4e30290e4e30291e4e30292e4e30293e4e30294e4e30295e4e30296e4e30297e4e30298e4e30299e4e3029ae4e3029be4e3029ce4e3029de4e3029ee4e3029fe4e302a0e4e302a1e4e302a2e4e302a3e4e302a4e4e302a5e4e302a6e4e302a7e4e302a8e4e302a9e4e302aae4e302abe4e302ace4e302ade4e302aee4e302afe4e302b0e4e302b1e4e302b2e4e302b3e4e302b4e4e302b5e4e302b6e4e302b7e4e302b8e4e302b9e4e302bae4e302bbe4e302bce4e302bde4e302bee4e302bfe4e302c0e4e302c1e4e302c2e4e302c3e4e302c4e4e302c5e4e302c6e4e302c7e4e302c8e4e302c9e4e302cae4e302cbe4e302cce4e302cde4e302cee4e302cfe4e302d0e4e302d1e4e302d2e4e302d3e4e302d4e4e302d5e4e302d6e4e302d7e4e302d8e4e302d9e4e302dae4e302dbe4e302dce4e302dde4e302dee4e302dfe4e302e0e4e302e1e4e302e2e4e302e3e4e302e4e4e302e5e4e302e6e4e302e7e4e302e8e4e302e9e4e302eae4e302ebe4e302ece4e302ede4e302eee4e302efe4e302f0e4e302f1e4e302f2e4e302f3e4e302f4e4e302f5e4e302f6e4e302f7e4e302f8e4e302f9e4e302fae4e302fbe4e302fce4e302fde4e302fee4e302ffe4e30300e4e30301e4e30302e4e30303e4e30304e4e30305e4e30306e4e30307e4e30308e4e30309e4e3030ae4e3030be4e3030ce4e3030de4e3030ee4e3030fe4e30310e4e30311e4e30312e4e30313e4e30314e4e30315e4e30316e4e30317e4e30318e4e30319e4e3031ae4e3031be4e3031ce4e3031de4e3031ee4e3031fe4e30320e4e30321e4e30322e4e30323e4e30324e4e30325e4e30326e4e30327e4e30328e4e30329e4e3032ae4e3032be4e3032ce4e3032de4e3032ee4e3032fe4e30330e4e30331e4e30332e4e30333e4e30334e4e30335e4e30336e4e30337e4e30338e4e30339e4e3033ae4e3033be4e3033ce4e3033de4e3033ee4e3033fe4e30340e4e30341e4e30342e4e30343e4e30344e4e30345e4e30346e4e30347e4e30348e4e30349e4e3034ae4e3034be4e3034ce4e3034de4e3034ee4e3034fe4e30350e4e30351e4e30352e4e30353e4e30354e4e30355e4e30356e4e30357e4e30358e4e30359e4e3035ae4e3035be4e3035ce4e3035de4e3035ee4e3035fe4e30360e4e30361e4e30362e4e30363e4e30364e4e30365e4e30366e4e30367e4e30368e4e30369e4e3036ae4e3036be4e3036ce4e3036de4e3036ee4e3036fe4e30370e4e30371e4e30372e4e30373e4e30374e4e30375e4e30376e4e30377e4e30378e4e30379e4e3037ae4e3037be4e3037ce4e3037de4e3037ee4e3037fe4e30380e4e30381e4e30382e4e30383e4e30384e4e30385e4e30386e4e30387e4e30388e4e30389e4e3038ae4e3038be4e3038ce4e3038de4e3038ee4e3038fe4e30390e4e30391e4e30392e4e30393e4e30394e4e30395e4e30396e4e30397e4e30398e4e30399e4e3039ae4e3039be4e3039ce4e3039de4e3039ee4e3039fe4e303a0e4e303a1e4e303a2e4e303a3e4e303a4e4e303a5e4e303a6e4e303a7e4e303a8e4e303a9e4e303aae4e303abe4e303ace4e303ade4e303aee4e303afe4e303b0e4e303b1e4e303b2e4e303b3e4e303b4e4e303b5e4e303b6e4e303b7e4e303b8e4e303b9e4e303bae4e303bbe4e303bce4e303bde4e303bee4e303bfe4e303c0e4e303c1e4e303c2e4e303c3e4e303c4e4e303c5e4e303c6e4e303c7e4e303c8e4e303c9e4e303cae4e303cbe4e303cce4e303cde4e303cee4e303cfe4e303d0e4e303d1e4e303d2e4e303d3e4e303d4e4e303d5e4e303d6e4e303d7e4e303d8e4e303d9e4e303dae4e303dbe4e303dce4e303dde4e303dee4e303dfe4e303e0e4e303e1e4e303e2e4e303e3e4e303e4e4e303e5e4e303e6e4e303e7e4e303e8e4e303e9e4e303eae4e303ebe4e303ece4e303ede4e303eee4e303efe4e303f0e4e303f1e4e303f2e4e303f3e4e303f4e4e303f5e4e303f6e4e303f7e4e303f8e4e303f9e4e303fae4e303fbe4e303fce4e303fde4e303fee4e303ffe4e30400e4e4", - "results" : { - "Prague" : { - "exception" : "EOF_TooManyCodeSections", - "result" : false - } - } - }, - "validInvalid_17" : { - "code" : "0xef000101000402000100040400000000800000e3000100", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidCodeSectionIndex", - "result" : false - } - } - }, - "validInvalid_18" : { - "code" : "0xef000101000402000100020400000000800000e300", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_19" : { - "code" : "0xef0001010004020001000b0400000000800001600456fe5b600160015500", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_2" : { - "code" : "0xef000101000802000200040001040000000080000000000000e3000100e4", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_20" : { - "code" : "0xef0001010004020001000d04000000008000026006600157fe5b600160015500", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_21" : { - "code" : "0xef0001010004020001000504000000008000025860015500", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_22" : { - "code" : "0xef0001010004020001000304000000008000016001ff", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_23" : { - "code" : "0xef0001010004020001000a04000000008000076001808080808080f200", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_24" : { - "code" : "0xef00010100040200010006040000000080000360018080f000", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_25" : { - "code" : "0xef0001010004020001000704000000008000046001808080f500", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_26" : { - "code" : "0xef000101000802000200040002040000000080000002010002e300010001e4", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_27" : { - "code" : "0xef00010100080200020008000204000000008000020000000060016001e300010001e4", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_28" : { - "code" : "0xef000101000802000200040003040000000080000000000001e30001006001e4", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidNumberOfOutputs", - "result" : false - } - } - }, - "validInvalid_29" : { - "code" : "0xef00010100080200020404000504000000008004020003000360018080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080e300010060028080e4", - "results" : { - "Prague" : { - "exception" : "EOF_MaxStackHeightExceeded", - "result" : false - } - } - }, - "validInvalid_3" : { - "code" : "0xef000101000802000200040001040001000080000000000000e3000100e4da", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_30" : { - "code" : "0xef00010100080200020404000804000000008003ff0000000360018080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080e300010060018080505050e4", - "results" : { - "Prague" : { - "exception" : "EOF_StackOverflow", - "result" : false - } - } - }, - "validInvalid_31" : { - "code" : "0xef000101000402000100010400000000000000e4", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidFirstSectionType", - "result" : false - } - } - }, - "validInvalid_32" : { - "code" : "0xef000101000402000100010400000000800000e4", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidNonReturningFlag", - "result" : false - } - } - }, - "validInvalid_33" : { - "code" : "0xef000101000402000100010400010000000000e4da", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidFirstSectionType", - "result" : false - } - } - }, - "validInvalid_34" : { - "code" : "0xef000101000402000100010400000000800000e4", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidNonReturningFlag", - "result" : false - } - } - }, - "validInvalid_4" : { - "code" : "0xef0001010010020004000f00020002000204000000008000030100000100010001020300035fe30001e300025fe300035050500050e430e480e4", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_5" : { - "code" : "0xef0001010010020004000f00020002000204000100008000030100000100010001020300035fe30001e300025fe300035050500050e430e480e4da", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_6" : { - "code" : "0xef000101100002040000040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400010400000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e3000100e30002e4e30003e4e30004e4e30005e4e30006e4e30007e4e30008e4e30009e4e3000ae4e3000be4e3000ce4e3000de4e3000ee4e3000fe4e30010e4e30011e4e30012e4e30013e4e30014e4e30015e4e30016e4e30017e4e30018e4e30019e4e3001ae4e3001be4e3001ce4e3001de4e3001ee4e3001fe4e30020e4e30021e4e30022e4e30023e4e30024e4e30025e4e30026e4e30027e4e30028e4e30029e4e3002ae4e3002be4e3002ce4e3002de4e3002ee4e3002fe4e30030e4e30031e4e30032e4e30033e4e30034e4e30035e4e30036e4e30037e4e30038e4e30039e4e3003ae4e3003be4e3003ce4e3003de4e3003ee4e3003fe4e30040e4e30041e4e30042e4e30043e4e30044e4e30045e4e30046e4e30047e4e30048e4e30049e4e3004ae4e3004be4e3004ce4e3004de4e3004ee4e3004fe4e30050e4e30051e4e30052e4e30053e4e30054e4e30055e4e30056e4e30057e4e30058e4e30059e4e3005ae4e3005be4e3005ce4e3005de4e3005ee4e3005fe4e30060e4e30061e4e30062e4e30063e4e30064e4e30065e4e30066e4e30067e4e30068e4e30069e4e3006ae4e3006be4e3006ce4e3006de4e3006ee4e3006fe4e30070e4e30071e4e30072e4e30073e4e30074e4e30075e4e30076e4e30077e4e30078e4e30079e4e3007ae4e3007be4e3007ce4e3007de4e3007ee4e3007fe4e30080e4e30081e4e30082e4e30083e4e30084e4e30085e4e30086e4e30087e4e30088e4e30089e4e3008ae4e3008be4e3008ce4e3008de4e3008ee4e3008fe4e30090e4e30091e4e30092e4e30093e4e30094e4e30095e4e30096e4e30097e4e30098e4e30099e4e3009ae4e3009be4e3009ce4e3009de4e3009ee4e3009fe4e300a0e4e300a1e4e300a2e4e300a3e4e300a4e4e300a5e4e300a6e4e300a7e4e300a8e4e300a9e4e300aae4e300abe4e300ace4e300ade4e300aee4e300afe4e300b0e4e300b1e4e300b2e4e300b3e4e300b4e4e300b5e4e300b6e4e300b7e4e300b8e4e300b9e4e300bae4e300bbe4e300bce4e300bde4e300bee4e300bfe4e300c0e4e300c1e4e300c2e4e300c3e4e300c4e4e300c5e4e300c6e4e300c7e4e300c8e4e300c9e4e300cae4e300cbe4e300cce4e300cde4e300cee4e300cfe4e300d0e4e300d1e4e300d2e4e300d3e4e300d4e4e300d5e4e300d6e4e300d7e4e300d8e4e300d9e4e300dae4e300dbe4e300dce4e300dde4e300dee4e300dfe4e300e0e4e300e1e4e300e2e4e300e3e4e300e4e4e300e5e4e300e6e4e300e7e4e300e8e4e300e9e4e300eae4e300ebe4e300ece4e300ede4e300eee4e300efe4e300f0e4e300f1e4e300f2e4e300f3e4e300f4e4e300f5e4e300f6e4e300f7e4e300f8e4e300f9e4e300fae4e300fbe4e300fce4e300fde4e300fee4e300ffe4e30100e4e30101e4e30102e4e30103e4e30104e4e30105e4e30106e4e30107e4e30108e4e30109e4e3010ae4e3010be4e3010ce4e3010de4e3010ee4e3010fe4e30110e4e30111e4e30112e4e30113e4e30114e4e30115e4e30116e4e30117e4e30118e4e30119e4e3011ae4e3011be4e3011ce4e3011de4e3011ee4e3011fe4e30120e4e30121e4e30122e4e30123e4e30124e4e30125e4e30126e4e30127e4e30128e4e30129e4e3012ae4e3012be4e3012ce4e3012de4e3012ee4e3012fe4e30130e4e30131e4e30132e4e30133e4e30134e4e30135e4e30136e4e30137e4e30138e4e30139e4e3013ae4e3013be4e3013ce4e3013de4e3013ee4e3013fe4e30140e4e30141e4e30142e4e30143e4e30144e4e30145e4e30146e4e30147e4e30148e4e30149e4e3014ae4e3014be4e3014ce4e3014de4e3014ee4e3014fe4e30150e4e30151e4e30152e4e30153e4e30154e4e30155e4e30156e4e30157e4e30158e4e30159e4e3015ae4e3015be4e3015ce4e3015de4e3015ee4e3015fe4e30160e4e30161e4e30162e4e30163e4e30164e4e30165e4e30166e4e30167e4e30168e4e30169e4e3016ae4e3016be4e3016ce4e3016de4e3016ee4e3016fe4e30170e4e30171e4e30172e4e30173e4e30174e4e30175e4e30176e4e30177e4e30178e4e30179e4e3017ae4e3017be4e3017ce4e3017de4e3017ee4e3017fe4e30180e4e30181e4e30182e4e30183e4e30184e4e30185e4e30186e4e30187e4e30188e4e30189e4e3018ae4e3018be4e3018ce4e3018de4e3018ee4e3018fe4e30190e4e30191e4e30192e4e30193e4e30194e4e30195e4e30196e4e30197e4e30198e4e30199e4e3019ae4e3019be4e3019ce4e3019de4e3019ee4e3019fe4e301a0e4e301a1e4e301a2e4e301a3e4e301a4e4e301a5e4e301a6e4e301a7e4e301a8e4e301a9e4e301aae4e301abe4e301ace4e301ade4e301aee4e301afe4e301b0e4e301b1e4e301b2e4e301b3e4e301b4e4e301b5e4e301b6e4e301b7e4e301b8e4e301b9e4e301bae4e301bbe4e301bce4e301bde4e301bee4e301bfe4e301c0e4e301c1e4e301c2e4e301c3e4e301c4e4e301c5e4e301c6e4e301c7e4e301c8e4e301c9e4e301cae4e301cbe4e301cce4e301cde4e301cee4e301cfe4e301d0e4e301d1e4e301d2e4e301d3e4e301d4e4e301d5e4e301d6e4e301d7e4e301d8e4e301d9e4e301dae4e301dbe4e301dce4e301dde4e301dee4e301dfe4e301e0e4e301e1e4e301e2e4e301e3e4e301e4e4e301e5e4e301e6e4e301e7e4e301e8e4e301e9e4e301eae4e301ebe4e301ece4e301ede4e301eee4e301efe4e301f0e4e301f1e4e301f2e4e301f3e4e301f4e4e301f5e4e301f6e4e301f7e4e301f8e4e301f9e4e301fae4e301fbe4e301fce4e301fde4e301fee4e301ffe4e30200e4e30201e4e30202e4e30203e4e30204e4e30205e4e30206e4e30207e4e30208e4e30209e4e3020ae4e3020be4e3020ce4e3020de4e3020ee4e3020fe4e30210e4e30211e4e30212e4e30213e4e30214e4e30215e4e30216e4e30217e4e30218e4e30219e4e3021ae4e3021be4e3021ce4e3021de4e3021ee4e3021fe4e30220e4e30221e4e30222e4e30223e4e30224e4e30225e4e30226e4e30227e4e30228e4e30229e4e3022ae4e3022be4e3022ce4e3022de4e3022ee4e3022fe4e30230e4e30231e4e30232e4e30233e4e30234e4e30235e4e30236e4e30237e4e30238e4e30239e4e3023ae4e3023be4e3023ce4e3023de4e3023ee4e3023fe4e30240e4e30241e4e30242e4e30243e4e30244e4e30245e4e30246e4e30247e4e30248e4e30249e4e3024ae4e3024be4e3024ce4e3024de4e3024ee4e3024fe4e30250e4e30251e4e30252e4e30253e4e30254e4e30255e4e30256e4e30257e4e30258e4e30259e4e3025ae4e3025be4e3025ce4e3025de4e3025ee4e3025fe4e30260e4e30261e4e30262e4e30263e4e30264e4e30265e4e30266e4e30267e4e30268e4e30269e4e3026ae4e3026be4e3026ce4e3026de4e3026ee4e3026fe4e30270e4e30271e4e30272e4e30273e4e30274e4e30275e4e30276e4e30277e4e30278e4e30279e4e3027ae4e3027be4e3027ce4e3027de4e3027ee4e3027fe4e30280e4e30281e4e30282e4e30283e4e30284e4e30285e4e30286e4e30287e4e30288e4e30289e4e3028ae4e3028be4e3028ce4e3028de4e3028ee4e3028fe4e30290e4e30291e4e30292e4e30293e4e30294e4e30295e4e30296e4e30297e4e30298e4e30299e4e3029ae4e3029be4e3029ce4e3029de4e3029ee4e3029fe4e302a0e4e302a1e4e302a2e4e302a3e4e302a4e4e302a5e4e302a6e4e302a7e4e302a8e4e302a9e4e302aae4e302abe4e302ace4e302ade4e302aee4e302afe4e302b0e4e302b1e4e302b2e4e302b3e4e302b4e4e302b5e4e302b6e4e302b7e4e302b8e4e302b9e4e302bae4e302bbe4e302bce4e302bde4e302bee4e302bfe4e302c0e4e302c1e4e302c2e4e302c3e4e302c4e4e302c5e4e302c6e4e302c7e4e302c8e4e302c9e4e302cae4e302cbe4e302cce4e302cde4e302cee4e302cfe4e302d0e4e302d1e4e302d2e4e302d3e4e302d4e4e302d5e4e302d6e4e302d7e4e302d8e4e302d9e4e302dae4e302dbe4e302dce4e302dde4e302dee4e302dfe4e302e0e4e302e1e4e302e2e4e302e3e4e302e4e4e302e5e4e302e6e4e302e7e4e302e8e4e302e9e4e302eae4e302ebe4e302ece4e302ede4e302eee4e302efe4e302f0e4e302f1e4e302f2e4e302f3e4e302f4e4e302f5e4e302f6e4e302f7e4e302f8e4e302f9e4e302fae4e302fbe4e302fce4e302fde4e302fee4e302ffe4e30300e4e30301e4e30302e4e30303e4e30304e4e30305e4e30306e4e30307e4e30308e4e30309e4e3030ae4e3030be4e3030ce4e3030de4e3030ee4e3030fe4e30310e4e30311e4e30312e4e30313e4e30314e4e30315e4e30316e4e30317e4e30318e4e30319e4e3031ae4e3031be4e3031ce4e3031de4e3031ee4e3031fe4e30320e4e30321e4e30322e4e30323e4e30324e4e30325e4e30326e4e30327e4e30328e4e30329e4e3032ae4e3032be4e3032ce4e3032de4e3032ee4e3032fe4e30330e4e30331e4e30332e4e30333e4e30334e4e30335e4e30336e4e30337e4e30338e4e30339e4e3033ae4e3033be4e3033ce4e3033de4e3033ee4e3033fe4e30340e4e30341e4e30342e4e30343e4e30344e4e30345e4e30346e4e30347e4e30348e4e30349e4e3034ae4e3034be4e3034ce4e3034de4e3034ee4e3034fe4e30350e4e30351e4e30352e4e30353e4e30354e4e30355e4e30356e4e30357e4e30358e4e30359e4e3035ae4e3035be4e3035ce4e3035de4e3035ee4e3035fe4e30360e4e30361e4e30362e4e30363e4e30364e4e30365e4e30366e4e30367e4e30368e4e30369e4e3036ae4e3036be4e3036ce4e3036de4e3036ee4e3036fe4e30370e4e30371e4e30372e4e30373e4e30374e4e30375e4e30376e4e30377e4e30378e4e30379e4e3037ae4e3037be4e3037ce4e3037de4e3037ee4e3037fe4e30380e4e30381e4e30382e4e30383e4e30384e4e30385e4e30386e4e30387e4e30388e4e30389e4e3038ae4e3038be4e3038ce4e3038de4e3038ee4e3038fe4e30390e4e30391e4e30392e4e30393e4e30394e4e30395e4e30396e4e30397e4e30398e4e30399e4e3039ae4e3039be4e3039ce4e3039de4e3039ee4e3039fe4e303a0e4e303a1e4e303a2e4e303a3e4e303a4e4e303a5e4e303a6e4e303a7e4e303a8e4e303a9e4e303aae4e303abe4e303ace4e303ade4e303aee4e303afe4e303b0e4e303b1e4e303b2e4e303b3e4e303b4e4e303b5e4e303b6e4e303b7e4e303b8e4e303b9e4e303bae4e303bbe4e303bce4e303bde4e303bee4e303bfe4e303c0e4e303c1e4e303c2e4e303c3e4e303c4e4e303c5e4e303c6e4e303c7e4e303c8e4e303c9e4e303cae4e303cbe4e303cce4e303cde4e303cee4e303cfe4e303d0e4e303d1e4e303d2e4e303d3e4e303d4e4e303d5e4e303d6e4e303d7e4e303d8e4e303d9e4e303dae4e303dbe4e303dce4e303dde4e303dee4e303dfe4e303e0e4e303e1e4e303e2e4e303e3e4e303e4e4e303e5e4e303e6e4e303e7e4e303e8e4e303e9e4e303eae4e303ebe4e303ece4e303ede4e303eee4e303efe4e303f0e4e303f1e4e303f2e4e303f3e4e303f4e4e303f5e4e303f6e4e303f7e4e303f8e4e303f9e4e303fae4e303fbe4e303fce4e303fde4e303fee4e303ffe4e4", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_7" : { - "code" : "0xef000101100002040000040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400040004000400010400010000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e3000100e30002e4e30003e4e30004e4e30005e4e30006e4e30007e4e30008e4e30009e4e3000ae4e3000be4e3000ce4e3000de4e3000ee4e3000fe4e30010e4e30011e4e30012e4e30013e4e30014e4e30015e4e30016e4e30017e4e30018e4e30019e4e3001ae4e3001be4e3001ce4e3001de4e3001ee4e3001fe4e30020e4e30021e4e30022e4e30023e4e30024e4e30025e4e30026e4e30027e4e30028e4e30029e4e3002ae4e3002be4e3002ce4e3002de4e3002ee4e3002fe4e30030e4e30031e4e30032e4e30033e4e30034e4e30035e4e30036e4e30037e4e30038e4e30039e4e3003ae4e3003be4e3003ce4e3003de4e3003ee4e3003fe4e30040e4e30041e4e30042e4e30043e4e30044e4e30045e4e30046e4e30047e4e30048e4e30049e4e3004ae4e3004be4e3004ce4e3004de4e3004ee4e3004fe4e30050e4e30051e4e30052e4e30053e4e30054e4e30055e4e30056e4e30057e4e30058e4e30059e4e3005ae4e3005be4e3005ce4e3005de4e3005ee4e3005fe4e30060e4e30061e4e30062e4e30063e4e30064e4e30065e4e30066e4e30067e4e30068e4e30069e4e3006ae4e3006be4e3006ce4e3006de4e3006ee4e3006fe4e30070e4e30071e4e30072e4e30073e4e30074e4e30075e4e30076e4e30077e4e30078e4e30079e4e3007ae4e3007be4e3007ce4e3007de4e3007ee4e3007fe4e30080e4e30081e4e30082e4e30083e4e30084e4e30085e4e30086e4e30087e4e30088e4e30089e4e3008ae4e3008be4e3008ce4e3008de4e3008ee4e3008fe4e30090e4e30091e4e30092e4e30093e4e30094e4e30095e4e30096e4e30097e4e30098e4e30099e4e3009ae4e3009be4e3009ce4e3009de4e3009ee4e3009fe4e300a0e4e300a1e4e300a2e4e300a3e4e300a4e4e300a5e4e300a6e4e300a7e4e300a8e4e300a9e4e300aae4e300abe4e300ace4e300ade4e300aee4e300afe4e300b0e4e300b1e4e300b2e4e300b3e4e300b4e4e300b5e4e300b6e4e300b7e4e300b8e4e300b9e4e300bae4e300bbe4e300bce4e300bde4e300bee4e300bfe4e300c0e4e300c1e4e300c2e4e300c3e4e300c4e4e300c5e4e300c6e4e300c7e4e300c8e4e300c9e4e300cae4e300cbe4e300cce4e300cde4e300cee4e300cfe4e300d0e4e300d1e4e300d2e4e300d3e4e300d4e4e300d5e4e300d6e4e300d7e4e300d8e4e300d9e4e300dae4e300dbe4e300dce4e300dde4e300dee4e300dfe4e300e0e4e300e1e4e300e2e4e300e3e4e300e4e4e300e5e4e300e6e4e300e7e4e300e8e4e300e9e4e300eae4e300ebe4e300ece4e300ede4e300eee4e300efe4e300f0e4e300f1e4e300f2e4e300f3e4e300f4e4e300f5e4e300f6e4e300f7e4e300f8e4e300f9e4e300fae4e300fbe4e300fce4e300fde4e300fee4e300ffe4e30100e4e30101e4e30102e4e30103e4e30104e4e30105e4e30106e4e30107e4e30108e4e30109e4e3010ae4e3010be4e3010ce4e3010de4e3010ee4e3010fe4e30110e4e30111e4e30112e4e30113e4e30114e4e30115e4e30116e4e30117e4e30118e4e30119e4e3011ae4e3011be4e3011ce4e3011de4e3011ee4e3011fe4e30120e4e30121e4e30122e4e30123e4e30124e4e30125e4e30126e4e30127e4e30128e4e30129e4e3012ae4e3012be4e3012ce4e3012de4e3012ee4e3012fe4e30130e4e30131e4e30132e4e30133e4e30134e4e30135e4e30136e4e30137e4e30138e4e30139e4e3013ae4e3013be4e3013ce4e3013de4e3013ee4e3013fe4e30140e4e30141e4e30142e4e30143e4e30144e4e30145e4e30146e4e30147e4e30148e4e30149e4e3014ae4e3014be4e3014ce4e3014de4e3014ee4e3014fe4e30150e4e30151e4e30152e4e30153e4e30154e4e30155e4e30156e4e30157e4e30158e4e30159e4e3015ae4e3015be4e3015ce4e3015de4e3015ee4e3015fe4e30160e4e30161e4e30162e4e30163e4e30164e4e30165e4e30166e4e30167e4e30168e4e30169e4e3016ae4e3016be4e3016ce4e3016de4e3016ee4e3016fe4e30170e4e30171e4e30172e4e30173e4e30174e4e30175e4e30176e4e30177e4e30178e4e30179e4e3017ae4e3017be4e3017ce4e3017de4e3017ee4e3017fe4e30180e4e30181e4e30182e4e30183e4e30184e4e30185e4e30186e4e30187e4e30188e4e30189e4e3018ae4e3018be4e3018ce4e3018de4e3018ee4e3018fe4e30190e4e30191e4e30192e4e30193e4e30194e4e30195e4e30196e4e30197e4e30198e4e30199e4e3019ae4e3019be4e3019ce4e3019de4e3019ee4e3019fe4e301a0e4e301a1e4e301a2e4e301a3e4e301a4e4e301a5e4e301a6e4e301a7e4e301a8e4e301a9e4e301aae4e301abe4e301ace4e301ade4e301aee4e301afe4e301b0e4e301b1e4e301b2e4e301b3e4e301b4e4e301b5e4e301b6e4e301b7e4e301b8e4e301b9e4e301bae4e301bbe4e301bce4e301bde4e301bee4e301bfe4e301c0e4e301c1e4e301c2e4e301c3e4e301c4e4e301c5e4e301c6e4e301c7e4e301c8e4e301c9e4e301cae4e301cbe4e301cce4e301cde4e301cee4e301cfe4e301d0e4e301d1e4e301d2e4e301d3e4e301d4e4e301d5e4e301d6e4e301d7e4e301d8e4e301d9e4e301dae4e301dbe4e301dce4e301dde4e301dee4e301dfe4e301e0e4e301e1e4e301e2e4e301e3e4e301e4e4e301e5e4e301e6e4e301e7e4e301e8e4e301e9e4e301eae4e301ebe4e301ece4e301ede4e301eee4e301efe4e301f0e4e301f1e4e301f2e4e301f3e4e301f4e4e301f5e4e301f6e4e301f7e4e301f8e4e301f9e4e301fae4e301fbe4e301fce4e301fde4e301fee4e301ffe4e30200e4e30201e4e30202e4e30203e4e30204e4e30205e4e30206e4e30207e4e30208e4e30209e4e3020ae4e3020be4e3020ce4e3020de4e3020ee4e3020fe4e30210e4e30211e4e30212e4e30213e4e30214e4e30215e4e30216e4e30217e4e30218e4e30219e4e3021ae4e3021be4e3021ce4e3021de4e3021ee4e3021fe4e30220e4e30221e4e30222e4e30223e4e30224e4e30225e4e30226e4e30227e4e30228e4e30229e4e3022ae4e3022be4e3022ce4e3022de4e3022ee4e3022fe4e30230e4e30231e4e30232e4e30233e4e30234e4e30235e4e30236e4e30237e4e30238e4e30239e4e3023ae4e3023be4e3023ce4e3023de4e3023ee4e3023fe4e30240e4e30241e4e30242e4e30243e4e30244e4e30245e4e30246e4e30247e4e30248e4e30249e4e3024ae4e3024be4e3024ce4e3024de4e3024ee4e3024fe4e30250e4e30251e4e30252e4e30253e4e30254e4e30255e4e30256e4e30257e4e30258e4e30259e4e3025ae4e3025be4e3025ce4e3025de4e3025ee4e3025fe4e30260e4e30261e4e30262e4e30263e4e30264e4e30265e4e30266e4e30267e4e30268e4e30269e4e3026ae4e3026be4e3026ce4e3026de4e3026ee4e3026fe4e30270e4e30271e4e30272e4e30273e4e30274e4e30275e4e30276e4e30277e4e30278e4e30279e4e3027ae4e3027be4e3027ce4e3027de4e3027ee4e3027fe4e30280e4e30281e4e30282e4e30283e4e30284e4e30285e4e30286e4e30287e4e30288e4e30289e4e3028ae4e3028be4e3028ce4e3028de4e3028ee4e3028fe4e30290e4e30291e4e30292e4e30293e4e30294e4e30295e4e30296e4e30297e4e30298e4e30299e4e3029ae4e3029be4e3029ce4e3029de4e3029ee4e3029fe4e302a0e4e302a1e4e302a2e4e302a3e4e302a4e4e302a5e4e302a6e4e302a7e4e302a8e4e302a9e4e302aae4e302abe4e302ace4e302ade4e302aee4e302afe4e302b0e4e302b1e4e302b2e4e302b3e4e302b4e4e302b5e4e302b6e4e302b7e4e302b8e4e302b9e4e302bae4e302bbe4e302bce4e302bde4e302bee4e302bfe4e302c0e4e302c1e4e302c2e4e302c3e4e302c4e4e302c5e4e302c6e4e302c7e4e302c8e4e302c9e4e302cae4e302cbe4e302cce4e302cde4e302cee4e302cfe4e302d0e4e302d1e4e302d2e4e302d3e4e302d4e4e302d5e4e302d6e4e302d7e4e302d8e4e302d9e4e302dae4e302dbe4e302dce4e302dde4e302dee4e302dfe4e302e0e4e302e1e4e302e2e4e302e3e4e302e4e4e302e5e4e302e6e4e302e7e4e302e8e4e302e9e4e302eae4e302ebe4e302ece4e302ede4e302eee4e302efe4e302f0e4e302f1e4e302f2e4e302f3e4e302f4e4e302f5e4e302f6e4e302f7e4e302f8e4e302f9e4e302fae4e302fbe4e302fce4e302fde4e302fee4e302ffe4e30300e4e30301e4e30302e4e30303e4e30304e4e30305e4e30306e4e30307e4e30308e4e30309e4e3030ae4e3030be4e3030ce4e3030de4e3030ee4e3030fe4e30310e4e30311e4e30312e4e30313e4e30314e4e30315e4e30316e4e30317e4e30318e4e30319e4e3031ae4e3031be4e3031ce4e3031de4e3031ee4e3031fe4e30320e4e30321e4e30322e4e30323e4e30324e4e30325e4e30326e4e30327e4e30328e4e30329e4e3032ae4e3032be4e3032ce4e3032de4e3032ee4e3032fe4e30330e4e30331e4e30332e4e30333e4e30334e4e30335e4e30336e4e30337e4e30338e4e30339e4e3033ae4e3033be4e3033ce4e3033de4e3033ee4e3033fe4e30340e4e30341e4e30342e4e30343e4e30344e4e30345e4e30346e4e30347e4e30348e4e30349e4e3034ae4e3034be4e3034ce4e3034de4e3034ee4e3034fe4e30350e4e30351e4e30352e4e30353e4e30354e4e30355e4e30356e4e30357e4e30358e4e30359e4e3035ae4e3035be4e3035ce4e3035de4e3035ee4e3035fe4e30360e4e30361e4e30362e4e30363e4e30364e4e30365e4e30366e4e30367e4e30368e4e30369e4e3036ae4e3036be4e3036ce4e3036de4e3036ee4e3036fe4e30370e4e30371e4e30372e4e30373e4e30374e4e30375e4e30376e4e30377e4e30378e4e30379e4e3037ae4e3037be4e3037ce4e3037de4e3037ee4e3037fe4e30380e4e30381e4e30382e4e30383e4e30384e4e30385e4e30386e4e30387e4e30388e4e30389e4e3038ae4e3038be4e3038ce4e3038de4e3038ee4e3038fe4e30390e4e30391e4e30392e4e30393e4e30394e4e30395e4e30396e4e30397e4e30398e4e30399e4e3039ae4e3039be4e3039ce4e3039de4e3039ee4e3039fe4e303a0e4e303a1e4e303a2e4e303a3e4e303a4e4e303a5e4e303a6e4e303a7e4e303a8e4e303a9e4e303aae4e303abe4e303ace4e303ade4e303aee4e303afe4e303b0e4e303b1e4e303b2e4e303b3e4e303b4e4e303b5e4e303b6e4e303b7e4e303b8e4e303b9e4e303bae4e303bbe4e303bce4e303bde4e303bee4e303bfe4e303c0e4e303c1e4e303c2e4e303c3e4e303c4e4e303c5e4e303c6e4e303c7e4e303c8e4e303c9e4e303cae4e303cbe4e303cce4e303cde4e303cee4e303cfe4e303d0e4e303d1e4e303d2e4e303d3e4e303d4e4e303d5e4e303d6e4e303d7e4e303d8e4e303d9e4e303dae4e303dbe4e303dce4e303dde4e303dee4e303dfe4e303e0e4e303e1e4e303e2e4e303e3e4e303e4e4e303e5e4e303e6e4e303e7e4e303e8e4e303e9e4e303eae4e303ebe4e303ece4e303ede4e303eee4e303efe4e303f0e4e303f1e4e303f2e4e303f3e4e303f4e4e303f5e4e303f6e4e303f7e4e303f8e4e303f9e4e303fae4e303fbe4e303fce4e303fde4e303fee4e303ffe4e4da", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_8" : { - "code" : "0xef000102000100010400000000800000fe", - "results" : { - "Prague" : { - "exception" : "EOF_TypeSectionMissing", - "result" : false - } - } - }, - "validInvalid_9" : { - "code" : "0xef00010100040100040400000000800000fe", - "results" : { - "Prague" : { - "exception" : "EOF_CodeSectionMissing", - "result" : false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/EIP5450/validInvalid.json b/crates/interpreter/tests/EOFTests/EIP5450/validInvalid.json deleted file mode 100644 index 684a03c852..0000000000 --- a/crates/interpreter/tests/EOFTests/EIP5450/validInvalid.json +++ /dev/null @@ -1,1730 +0,0 @@ -{ - "validInvalid" : { - "_info" : { - "comment" : "Test various examples to see if they are valid or invalid.\nImplements\n EOF1V5450_0001 (Valid) Code with branches having the same stack height - Data index: 0\n EOF1V5450_0002 (Valid) Jump table - Data index: 1\n EOF1V5450_0003 (Valid) Infinite loop - Data index: 2\n EOF1V5450_0004 (Valid) Infinite loop using RJUMPV - Data index: 3\n EOF1V5450_0005 (Valid) CALLF branches with the same total of outputs - Data index: 4\n EOF1V5450_0006 (Valid) CALLF inputs - Data index: 5\n EOF1V5450_0007 (Valid) Validate input for ADD opcode - Data index: 6\n EOF1V5450_0008 (Valid) Validate input for MUL opcode - Data index: 7\n EOF1V5450_0009 (Valid) Validate input for SUB opcode - Data index: 8\n EOF1V5450_0010 (Valid) Validate input for DIV opcode - Data index: 9\n EOF1V5450_0011 (Valid) Validate input for SDIV opcode - Data index: 10\n EOF1V5450_0012 (Valid) Validate input for MOD opcode - Data index: 11\n EOF1V5450_0013 (Valid) Validate input for SMOD opcode - Data index: 12\n EOF1V5450_0014 (Valid) Validate input for ADDMOD opcode - Data index: 13\n EOF1V5450_0015 (Valid) Validate input for MULMOD opcode - Data index: 14\n EOF1V5450_0016 (Valid) Validate input for EXP opcode - Data index: 15\n EOF1V5450_0017 (Valid) Validate input for SIGNEXTEND opcode - Data index: 16\n EOF1V5450_0018 (Valid) Validate input for LT opcode - Data index: 17\n EOF1V5450_0019 (Valid) Validate input for GT opcode - Data index: 18\n EOF1V5450_0020 (Valid) Validate input for SLT opcode - Data index: 19\n EOF1V5450_0021 (Valid) Validate input for SGT opcode - Data index: 20\n EOF1V5450_0022 (Valid) Validate input for EQ opcode - Data index: 21\n EOF1V5450_0023 (Valid) Validate input for ISZERO opcode - Data index: 22\n EOF1V5450_0024 (Valid) Validate input for AND opcode - Data index: 23\n EOF1V5450_0025 (Valid) Validate input for OR opcode - Data index: 24\n EOF1V5450_0026 (Valid) Validate input for XOR opcode - Data index: 25\n EOF1V5450_0027 (Valid) Validate input for NOT opcode - Data index: 26\n EOF1V5450_0028 (Valid) Validate input for BYTE opcode - Data index: 27\n EOF1V5450_0029 (Valid) Validate input for SHL opcode - Data index: 28\n EOF1V5450_0030 (Valid) Validate input for SHR opcode - Data index: 29\n EOF1V5450_0031 (Valid) Validate input for SAR opcode - Data index: 30\n EOF1V5450_0032 (Valid) Validate input for SHA3 opcode - Data index: 31\n EOF1V5450_0033 (Valid) Validate input for BALANCE opcode - Data index: 32\n EOF1V5450_0034 (Valid) Validate input for CALLDATALOAD opcode - Data index: 33\n EOF1V5450_0035 (Valid) Validate input for CALLDATACOPY opcode - Data index: 34\n EOF1V5450_0036 (Valid) Validate input for CODECOPY opcode - Data index: 35\n EOF1V5450_0037 (Valid) Validate input for EXTCODESIZE opcode - Data index: 36\n EOF1V5450_0038 (Valid) Validate input for EXTCODECOPY opcode - Data index: 37\n EOF1V5450_0039 (Valid) Validate input for RETURNDATACOPY opcode - Data index: 38\n EOF1V5450_0040 (Valid) Validate input for EXTCODEHASH opcode - Data index: 39\n EOF1V5450_0041 (Valid) Validate input for BLOCKHASH opcode - Data index: 40\n EOF1V5450_0042 (Valid) Validate input for BLOBHASH opcode - Data index: 41\n EOF1V5450_0043 (Valid) Validate input for POP opcode - Data index: 42\n EOF1V5450_0044 (Valid) Validate input for MLOAD opcode - Data index: 43\n EOF1V5450_0045 (Valid) Validate input for MSTORE opcode - Data index: 44\n EOF1V5450_0046 (Valid) Validate input for MSTORE8 opcode - Data index: 45\n EOF1V5450_0047 (Valid) Validate input for SLOAD opcode - Data index: 46\n EOF1V5450_0048 (Valid) Validate input for SSTORE opcode - Data index: 47\n EOF1V5450_0049 (Valid) Validate input for MCOPY opcode - Data index: 48\n EOF1V5450_0050 (Valid) Validate input for DUP1 opcode - Data index: 49\n EOF1V5450_0051 (Valid) Validate input for DUP2 opcode - Data index: 50\n EOF1V5450_0052 (Valid) Validate input for DUP3 opcode - Data index: 51\n EOF1V5450_0053 (Valid) Validate input for DUP4 opcode - Data index: 52\n EOF1V5450_0054 (Valid) Validate input for DUP5 opcode - Data index: 53\n EOF1V5450_0055 (Valid) Validate input for DUP6 opcode - Data index: 54\n EOF1V5450_0056 (Valid) Validate input for DUP7 opcode - Data index: 55\n EOF1V5450_0057 (Valid) Validate input for DUP8 opcode - Data index: 56\n EOF1V5450_0058 (Valid) Validate input for DUP9 opcode - Data index: 57\n EOF1V5450_0059 (Valid) Validate input for DUP10 opcode - Data index: 58\n EOF1V5450_0060 (Valid) Validate input for DUP11 opcode - Data index: 59\n EOF1V5450_0061 (Valid) Validate input for DUP12 opcode - Data index: 60\n EOF1V5450_0062 (Valid) Validate input for DUP13 opcode - Data index: 61\n EOF1V5450_0063 (Valid) Validate input for DUP14 opcode - Data index: 62\n EOF1V5450_0064 (Valid) Validate input for DUP15 opcode - Data index: 63\n EOF1V5450_0065 (Valid) Validate input for DUP16 opcode - Data index: 64\n EOF1V5450_0066 (Valid) Validate input for SWAP1 opcode - Data index: 65\n EOF1V5450_0067 (Valid) Validate input for SWAP2 opcode - Data index: 66\n EOF1V5450_0068 (Valid) Validate input for SWAP3 opcode - Data index: 67\n EOF1V5450_0069 (Valid) Validate input for SWAP4 opcode - Data index: 68\n EOF1V5450_0070 (Valid) Validate input for SWAP5 opcode - Data index: 69\n EOF1V5450_0071 (Valid) Validate input for SWAP6 opcode - Data index: 70\n EOF1V5450_0072 (Valid) Validate input for SWAP7 opcode - Data index: 71\n EOF1V5450_0073 (Valid) Validate input for SWAP8 opcode - Data index: 72\n EOF1V5450_0074 (Valid) Validate input for SWAP9 opcode - Data index: 73\n EOF1V5450_0075 (Valid) Validate input for SWAP10 opcode - Data index: 74\n EOF1V5450_0076 (Valid) Validate input for SWAP11 opcode - Data index: 75\n EOF1V5450_0077 (Valid) Validate input for SWAP12 opcode - Data index: 76\n EOF1V5450_0078 (Valid) Validate input for SWAP13 opcode - Data index: 77\n EOF1V5450_0079 (Valid) Validate input for SWAP14 opcode - Data index: 78\n EOF1V5450_0080 (Valid) Validate input for SWAP15 opcode - Data index: 79\n EOF1V5450_0081 (Valid) Validate input for SWAP16 opcode - Data index: 80\n EOF1V5450_0082 (Valid) Validate input for LOG0 opcode - Data index: 81\n EOF1V5450_0083 (Valid) Validate input for LOG1 opcode - Data index: 82\n EOF1V5450_0084 (Valid) Validate input for LOG2 opcode - Data index: 83\n EOF1V5450_0085 (Valid) Validate input for LOG3 opcode - Data index: 84\n EOF1V5450_0086 (Valid) Validate input for LOG4 opcode - Data index: 85\n EOF1V5450_0087 (Valid) Validate input for CALL opcode - Data index: 86\n EOF1V5450_0088 (Valid) Validate input for RETURN opcode - Data index: 87\n EOF1V5450_0089 (Valid) Validate input for DELEGATECALL opcode - Data index: 88\n EOF1V5450_0090 (Valid) Validate input for STATICCALL opcode - Data index: 89\n EOF1V5450_0091 (Valid) Validate input for REVERT opcode - Data index: 90\n EOF1V5450_0092 (Valid) Containing terminating opcode RETURN at the end - Data index: 91\n EOF1V5450_0093 (Valid) Containing terminating opcode REVERT at the end - Data index: 92\n EOF1V5450_0094 (Valid) Loop ending with unconditional RJUMP (a) - Data index: 93\n EOF1V5450_0095 (Valid) Loop ending with unconditional RJUMP (b) - Data index: 94\n EOF1V5450_0096 (Valid) Functions ending with RETF - Data index: 95\n EOF1V5450_0097 (Valid) Stack is not required to be empty on terminating instruction RETURN - Data index: 96\n EOF1V5450_0098 (Valid) Stack is not required to be empty on terminating instruction REVERT - Data index: 97\n EOF1V5450_0099 (Valid) RETF returning maximum number of outputs (127) - Data index: 98\n EOF1V5450_0100 (Valid) Calling function with enough stack items: Function 1 calls Function 2 with enough parameters - Data index: 99\n EOF1V5450_0101 (Valid) Stack height mismatch for different paths valid according to relaxed stack validation - Data index: 100\n EOF1V5450_0102 (Valid) Stack height mismatch for different paths valid according to relaxed stack validation - Data index: 101\n EOF1V5450_0103 (Valid) Calls returning different number of outputs valid according to relaxed stack validation - Data index: 102\n EOF1V5450_0104 (Valid) Jump table with different stack heights valid according to relaxed stack validation - Data index: 103\n EOF1I5450_0001 (Invalid) Pushing loop - Data index: 104\n EOF1I5450_0002 (Invalid) Popping loop - Data index: 105\n EOF1I5450_0003 (Invalid) Stack underflow for opcode ADD - Data index: 106\n EOF1I5450_0004 (Invalid) Stack underflow for opcode MUL - Data index: 107\n EOF1I5450_0005 (Invalid) Stack underflow for opcode SUB - Data index: 108\n EOF1I5450_0006 (Invalid) Stack underflow for opcode DIV - Data index: 109\n EOF1I5450_0007 (Invalid) Stack underflow for opcode SDIV - Data index: 110\n EOF1I5450_0008 (Invalid) Stack underflow for opcode MOD - Data index: 111\n EOF1I5450_0009 (Invalid) Stack underflow for opcode SMOD - Data index: 112\n EOF1I5450_0010 (Invalid) Stack underflow for opcode ADDMOD - Data index: 113\n EOF1I5450_0011 (Invalid) Stack underflow for opcode MULMOD - Data index: 114\n EOF1I5450_0012 (Invalid) Stack underflow for opcode EXP - Data index: 115\n EOF1I5450_0013 (Invalid) Stack underflow for opcode SIGNEXTEND - Data index: 116\n EOF1I5450_0014 (Invalid) Stack underflow for opcode LT - Data index: 117\n EOF1I5450_0015 (Invalid) Stack underflow for opcode GT - Data index: 118\n EOF1I5450_0016 (Invalid) Stack underflow for opcode SLT - Data index: 119\n EOF1I5450_0017 (Invalid) Stack underflow for opcode SGT - Data index: 120\n EOF1I5450_0018 (Invalid) Stack underflow for opcode EQ - Data index: 121\n EOF1I5450_0019 (Invalid) Stack underflow for opcode ISZERO - Data index: 122\n EOF1I5450_0020 (Invalid) Stack underflow for opcode AND - Data index: 123\n EOF1I5450_0021 (Invalid) Stack underflow for opcode OR - Data index: 124\n EOF1I5450_0022 (Invalid) Stack underflow for opcode XOR - Data index: 125\n EOF1I5450_0023 (Invalid) Stack underflow for opcode NOT - Data index: 126\n EOF1I5450_0024 (Invalid) Stack underflow for opcode BYTE - Data index: 127\n EOF1I5450_0025 (Invalid) Stack underflow for opcode SHL - Data index: 128\n EOF1I5450_0026 (Invalid) Stack underflow for opcode SHR - Data index: 129\n EOF1I5450_0027 (Invalid) Stack underflow for opcode SAR - Data index: 130\n EOF1I5450_0028 (Invalid) Stack underflow for opcode SHA3 - Data index: 131\n EOF1I5450_0029 (Invalid) Stack underflow for opcode BALANCE - Data index: 132\n EOF1I5450_0030 (Invalid) Stack underflow for opcode CALLDATALOAD - Data index: 133\n EOF1I5450_0031 (Invalid) Stack underflow for opcode CALLDATACOPY - Data index: 134\n EOF1I5450_0032 (Invalid) Stack underflow for opcode CODECOPY - Data index: 135\n EOF1I5450_0033 (Invalid) Stack underflow for opcode EXTCODESIZE - Data index: 136\n EOF1I5450_0034 (Invalid) Stack underflow for opcode EXTCODECOPY - Data index: 137\n EOF1I5450_0035 (Invalid) Stack underflow for opcode RETURNDATACOPY - Data index: 138\n EOF1I5450_0036 (Invalid) Stack underflow for opcode EXTCODEHASH - Data index: 139\n EOF1I5450_0037 (Invalid) Stack underflow for opcode BLOCKHASH - Data index: 140\n EOF1I5450_0038 (Invalid) Stack underflow for opcode BLOBHASH - Data index: 141\n EOF1I5450_0039 (Invalid) Stack underflow for opcode POP - Data index: 142\n EOF1I5450_0040 (Invalid) Stack underflow for opcode MLOAD - Data index: 143\n EOF1I5450_0041 (Invalid) Stack underflow for opcode MSTORE - Data index: 144\n EOF1I5450_0042 (Invalid) Stack underflow for opcode MSTORE8 - Data index: 145\n EOF1I5450_0043 (Invalid) Stack underflow for opcode SLOAD - Data index: 146\n EOF1I5450_0044 (Invalid) Stack underflow for opcode SSTORE - Data index: 147\n EOF1I5450_0045 (Invalid) Stack underflow for opcode MCOPY - Data index: 148\n EOF1I5450_0046 (Invalid) Stack underflow for opcode DUP1 - Data index: 149\n EOF1I5450_0047 (Invalid) Stack underflow for opcode DUP2 - Data index: 150\n EOF1I5450_0048 (Invalid) Stack underflow for opcode DUP3 - Data index: 151\n EOF1I5450_0049 (Invalid) Stack underflow for opcode DUP4 - Data index: 152\n EOF1I5450_0050 (Invalid) Stack underflow for opcode DUP5 - Data index: 153\n EOF1I5450_0051 (Invalid) Stack underflow for opcode DUP6 - Data index: 154\n EOF1I5450_0052 (Invalid) Stack underflow for opcode DUP7 - Data index: 155\n EOF1I5450_0053 (Invalid) Stack underflow for opcode DUP8 - Data index: 156\n EOF1I5450_0054 (Invalid) Stack underflow for opcode DUP9 - Data index: 157\n EOF1I5450_0055 (Invalid) Stack underflow for opcode DUP10 - Data index: 158\n EOF1I5450_0056 (Invalid) Stack underflow for opcode DUP11 - Data index: 159\n EOF1I5450_0057 (Invalid) Stack underflow for opcode DUP12 - Data index: 160\n EOF1I5450_0058 (Invalid) Stack underflow for opcode DUP13 - Data index: 161\n EOF1I5450_0059 (Invalid) Stack underflow for opcode DUP14 - Data index: 162\n EOF1I5450_0060 (Invalid) Stack underflow for opcode DUP15 - Data index: 163\n EOF1I5450_0061 (Invalid) Stack underflow for opcode DUP16 - Data index: 164\n EOF1I5450_0062 (Invalid) Stack underflow for opcode SWAP1 - Data index: 165\n EOF1I5450_0063 (Invalid) Stack underflow for opcode SWAP2 - Data index: 166\n EOF1I5450_0064 (Invalid) Stack underflow for opcode SWAP3 - Data index: 167\n EOF1I5450_0065 (Invalid) Stack underflow for opcode SWAP4 - Data index: 168\n EOF1I5450_0066 (Invalid) Stack underflow for opcode SWAP5 - Data index: 169\n EOF1I5450_0067 (Invalid) Stack underflow for opcode SWAP6 - Data index: 170\n EOF1I5450_0068 (Invalid) Stack underflow for opcode SWAP7 - Data index: 171\n EOF1I5450_0069 (Invalid) Stack underflow for opcode SWAP8 - Data index: 172\n EOF1I5450_0070 (Invalid) Stack underflow for opcode SWAP9 - Data index: 173\n EOF1I5450_0071 (Invalid) Stack underflow for opcode SWAP10 - Data index: 174\n EOF1I5450_0072 (Invalid) Stack underflow for opcode SWAP11 - Data index: 175\n EOF1I5450_0073 (Invalid) Stack underflow for opcode SWAP12 - Data index: 176\n EOF1I5450_0074 (Invalid) Stack underflow for opcode SWAP13 - Data index: 177\n EOF1I5450_0075 (Invalid) Stack underflow for opcode SWAP14 - Data index: 178\n EOF1I5450_0076 (Invalid) Stack underflow for opcode SWAP15 - Data index: 179\n EOF1I5450_0077 (Invalid) Stack underflow for opcode SWAP16 - Data index: 180\n EOF1I5450_0078 (Invalid) Stack underflow for opcode LOG0 - Data index: 181\n EOF1I5450_0079 (Invalid) Stack underflow for opcode LOG1 - Data index: 182\n EOF1I5450_0080 (Invalid) Stack underflow for opcode LOG2 - Data index: 183\n EOF1I5450_0081 (Invalid) Stack underflow for opcode LOG3 - Data index: 184\n EOF1I5450_0082 (Invalid) Stack underflow for opcode LOG4 - Data index: 185\n EOF1I5450_0083 (Invalid) Stack underflow for opcode CALL - Data index: 186\n EOF1I5450_0084 (Invalid) Stack underflow for opcode RETURN - Data index: 187\n EOF1I5450_0085 (Invalid) Stack underflow for opcode DELEGATECALL - Data index: 188\n EOF1I5450_0086 (Invalid) Stack underflow for opcode STATICCALL - Data index: 189\n EOF1I5450_0087 (Invalid) Stack underflow for opcode REVERT - Data index: 190\n EOF1I5450_0088 (Invalid) Calling function without enough stack items: Function 0 calls Function 1 without enough parameters - Data index: 191\n EOF1I5450_0089 (Invalid) Calling function without enough stack items: Function 0 calls Function 1 without enought parameters, Function 1 calls Function 2 without enough parameers - Data index: 192\n EOF1I5450_0090 (Invalid) Stack Overflow: Function pushing more than 1024 items to the stack - Data index: 193\n EOF1I5450_0091 (Invalid) Stack Overflow: Function 1 when called by Function 0 pushes more than 1024 items to the stack - Data index: 194\n EOF1I5450_0092 (Invalid) Function ending with non-terminating instruction (a) - Data index: 195\n EOF1I5450_0093 (Invalid) Function ending with non-terminating instruction (b) - Data index: 196\n EOF1I5450_0094 (Invalid) Function ending with non-terminating instruction (c) - Data index: 197\n EOF1I5450_0095 (Invalid) Function containing unreachable code after RETURN - Data index: 198\n EOF1I5450_0096 (Invalid) Function containing unreachable code after REVERT - Data index: 199\n EOF1I5450_0097 (Invalid) Unreachable code after RJUMP - Data index: 200\n EOF1I5450_0098 (Invalid) Unreachable code after infinite loop - Data index: 201\n", - "filling-rpc-server" : "evmone-t8n 0.12.0-dev+commit.14ba7529", - "filling-tool-version" : "retesteth-0.3.2-cancun+commit.9d793abd.Linux.g++", - "generatedTestHash" : "5fe8f95c5397e77caa07f7e5f6d2c78d06a72b1f77bf2af91e4a281eeb1ee612", - "lllcversion" : "Version: 0.5.14-develop.2022.4.6+commit.401d5358.Linux.g++", - "solidity" : "Version: 0.8.18-develop.2023.1.16+commit.469d6d4d.Linux.g++", - "source" : "src/EOFTestsFiller/EIP5450/validInvalidFiller.yml", - "sourceHash" : "10f981cd7e7564f42a8d3ab4dd1cf401a95e06d254c75b4903a189553c1e4ad4" - }, - "vectors" : { - "validInvalid_0" : { - "code" : "0xef0001010004020001001104000000008000026000e1000760016002e000046003600400", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_1" : { - "code" : "0xef0001010004020001001b04000000008000026000e2010007000e60016002e0000b60036004e000046005600600", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_10" : { - "code" : "0xef0001010004020001000504000000008000026001800500", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_100" : { - "code" : "0xef0001010004020001000a04000000008000026000e100026001600200", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_101" : { - "code" : "0xef0001010004020001000f04000000008000026000e100056001e000046002600300", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_102" : { - "code" : "0xef000101000c020003000f00030004040000000080000200010001000200026000e10006e30001e00003e30002006001e4600180e4", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_103" : { - "code" : "0xef0001010004020001001b04000000008000036000e2010005000c6001e0000d60026003e0000660036004600500", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_104" : { - "code" : "0xef0001010004020001000504000000008000016000e0fffb", - "results" : { - "Prague" : { - "exception" : "EOF_ConflictingStackHeight", - "result" : false - } - } - }, - "validInvalid_105" : { - "code" : "0xef0001010004020001000804000000008000036000808050e0fffc", - "results" : { - "Prague" : { - "exception" : "EOF_ConflictingStackHeight", - "result" : false - } - } - }, - "validInvalid_106" : { - "code" : "0xef00010100040200010004040000000080000160010100", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_107" : { - "code" : "0xef00010100040200010004040000000080000160010200", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_108" : { - "code" : "0xef00010100040200010004040000000080000160010300", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_109" : { - "code" : "0xef00010100040200010004040000000080000160010400", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_11" : { - "code" : "0xef0001010004020001000504000000008000026001800600", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_110" : { - "code" : "0xef00010100040200010004040000000080000160010500", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_111" : { - "code" : "0xef00010100040200010004040000000080000160010600", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_112" : { - "code" : "0xef00010100040200010004040000000080000160010700", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_113" : { - "code" : "0xef000101000402000100060400000000800002600160010800", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_114" : { - "code" : "0xef000101000402000100060400000000800002600160010900", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_115" : { - "code" : "0xef00010100040200010004040000000080000160010a00", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_116" : { - "code" : "0xef00010100040200010004040000000080000160010b00", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_117" : { - "code" : "0xef00010100040200010004040000000080000160011000", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_118" : { - "code" : "0xef00010100040200010004040000000080000160011100", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_119" : { - "code" : "0xef00010100040200010004040000000080000160011200", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_12" : { - "code" : "0xef0001010004020001000504000000008000026001800700", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_120" : { - "code" : "0xef00010100040200010004040000000080000160011300", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_121" : { - "code" : "0xef00010100040200010004040000000080000160011400", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_122" : { - "code" : "0xef0001010004020001000204000000008000001500", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_123" : { - "code" : "0xef00010100040200010004040000000080000160011600", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_124" : { - "code" : "0xef00010100040200010004040000000080000160011700", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_125" : { - "code" : "0xef00010100040200010004040000000080000160011800", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_126" : { - "code" : "0xef0001010004020001000204000000008000001900", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_127" : { - "code" : "0xef00010100040200010004040000000080000160011a00", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_128" : { - "code" : "0xef00010100040200010004040000000080000160011b00", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_129" : { - "code" : "0xef00010100040200010004040000000080000160011c00", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_13" : { - "code" : "0xef000101000402000100060400000000800003600180800800", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_130" : { - "code" : "0xef00010100040200010004040000000080000160011d00", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_131" : { - "code" : "0xef00010100040200010004040000000080000160012000", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_132" : { - "code" : "0xef0001010004020001000204000000008000003100", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_133" : { - "code" : "0xef0001010004020001000204000000008000003500", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_134" : { - "code" : "0xef000101000402000100060400000000800002600160013700", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_135" : { - "code" : "0xef000101000402000100060400000000800002600160013900", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_136" : { - "code" : "0xef0001010004020001000204000000008000003b00", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_137" : { - "code" : "0xef0001010004020001000804000000008000036001600160013c00", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_138" : { - "code" : "0xef000101000402000100060400000000800002600160013e00", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_139" : { - "code" : "0xef0001010004020001000204000000008000003f00", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_14" : { - "code" : "0xef000101000402000100060400000000800003600180800900", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_140" : { - "code" : "0xef0001010004020001000204000000008000004000", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_141" : { - "code" : "0xef0001010004020001000204000000008000004900", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_142" : { - "code" : "0xef0001010004020001000204000000008000005000", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_143" : { - "code" : "0xef0001010004020001000204000000008000005100", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_144" : { - "code" : "0xef00010100040200010004040000000080000160015200", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_145" : { - "code" : "0xef00010100040200010004040000000080000160015300", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_146" : { - "code" : "0xef0001010004020001000204000000008000005400", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_147" : { - "code" : "0xef00010100040200010004040000000080000160015500", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_148" : { - "code" : "0xef000101000402000100060400000000800002600160015e00", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_149" : { - "code" : "0xef0001010004020001000204000000008000018000", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_15" : { - "code" : "0xef0001010004020001000504000000008000026001800a00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_150" : { - "code" : "0xef00010100040200010004040000000080000260018100", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_151" : { - "code" : "0xef000101000402000100060400000000800003600160018200", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_152" : { - "code" : "0xef0001010004020001000804000000008000046001600160018300", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_153" : { - "code" : "0xef0001010004020001000a040000000080000560016001600160018400", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_154" : { - "code" : "0xef0001010004020001000c0400000000800006600160016001600160018500", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_155" : { - "code" : "0xef0001010004020001000e04000000008000076001600160016001600160018600", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_156" : { - "code" : "0xef00010100040200010010040000000080000860016001600160016001600160018700", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_157" : { - "code" : "0xef000101000402000100120400000000800009600160016001600160016001600160018800", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_158" : { - "code" : "0xef00010100040200010014040000000080000a6001600160016001600160016001600160018900", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_159" : { - "code" : "0xef00010100040200010016040000000080000b60016001600160016001600160016001600160018a00", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_16" : { - "code" : "0xef0001010004020001000504000000008000026001800b00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_160" : { - "code" : "0xef00010100040200010018040000000080000c600160016001600160016001600160016001600160018b00", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_161" : { - "code" : "0xef0001010004020001001a040000000080000d6001600160016001600160016001600160016001600160018c00", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_162" : { - "code" : "0xef0001010004020001001c040000000080000e60016001600160016001600160016001600160016001600160018d00", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_163" : { - "code" : "0xef0001010004020001001e040000000080000f600160016001600160016001600160016001600160016001600160018e00", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_164" : { - "code" : "0xef0001010004020001002004000000008000106001600160016001600160016001600160016001600160016001600160018f00", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_165" : { - "code" : "0xef00010100040200010004040000000080000160019000", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_166" : { - "code" : "0xef000101000402000100060400000000800002600160019100", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_167" : { - "code" : "0xef0001010004020001000804000000008000036001600160019200", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_168" : { - "code" : "0xef0001010004020001000a040000000080000460016001600160019300", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_169" : { - "code" : "0xef0001010004020001000c0400000000800005600160016001600160019400", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_17" : { - "code" : "0xef0001010004020001000504000000008000026001801000", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_170" : { - "code" : "0xef0001010004020001000e04000000008000066001600160016001600160019500", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_171" : { - "code" : "0xef00010100040200010010040000000080000760016001600160016001600160019600", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_172" : { - "code" : "0xef000101000402000100120400000000800008600160016001600160016001600160019700", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_173" : { - "code" : "0xef0001010004020001001404000000008000096001600160016001600160016001600160019800", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_174" : { - "code" : "0xef00010100040200010016040000000080000a60016001600160016001600160016001600160019900", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_175" : { - "code" : "0xef00010100040200010018040000000080000b600160016001600160016001600160016001600160019a00", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_176" : { - "code" : "0xef0001010004020001001a040000000080000c6001600160016001600160016001600160016001600160019b00", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_177" : { - "code" : "0xef0001010004020001001c040000000080000d60016001600160016001600160016001600160016001600160019c00", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_178" : { - "code" : "0xef0001010004020001001e040000000080000e600160016001600160016001600160016001600160016001600160019d00", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_179" : { - "code" : "0xef00010100040200010020040000000080000f6001600160016001600160016001600160016001600160016001600160019e00", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_18" : { - "code" : "0xef0001010004020001000504000000008000026001801100", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_180" : { - "code" : "0xef00010100040200010022040000000080001060016001600160016001600160016001600160016001600160016001600160019f00", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_181" : { - "code" : "0xef0001010004020001000404000000008000016001a000", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_182" : { - "code" : "0xef00010100040200010006040000000080000260016001a100", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_183" : { - "code" : "0xef000101000402000100080400000000800003600160016001a200", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_184" : { - "code" : "0xef0001010004020001000a04000000008000046001600160016001a300", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_185" : { - "code" : "0xef0001010004020001000c040000000080000560016001600160016001a400", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_186" : { - "code" : "0xef0001010004020001000e0400000000800006600160016001600160016001f100", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_187" : { - "code" : "0xef0001010004020001000304000000008000016001f3", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_188" : { - "code" : "0xef0001010004020001000c040000000080000560016001600160016001f400", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_189" : { - "code" : "0xef0001010004020001000c040000000080000560016001600160016001fa00", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_19" : { - "code" : "0xef0001010004020001000504000000008000026001801200", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_190" : { - "code" : "0xef0001010004020001000304000000008000016001fd", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_191" : { - "code" : "0xef000101000c02000300040007000304000000008000000100000302000002e3000100600080e30002e45050e4", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_192" : { - "code" : "0xef000101000c02000300040006000604000000008000000100000202800002e30001006000e30002e45050e30003e4", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_193" : { - "code" : "0xef0001010004020001080004000000008004006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000", - "results" : { - "Prague" : { - "exception" : "EOF_MaxStackHeightExceeded", - "result" : false - } - } - }, - "validInvalid_194" : { - "code" : "0xef000101000802000207fb000b040000000080040100050005600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000e3000160006000600060006000e4", - "results" : { - "Prague" : { - "exception" : "EOF_MaxStackHeightExceeded", - "result" : false - } - } - }, - "validInvalid_195" : { - "code" : "0xef0001010004020001000204000000008000016000", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidCodeTermination", - "result" : false - } - } - }, - "validInvalid_196" : { - "code" : "0xef0001010004020001000704000000008000016000e10001005b", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidCodeTermination", - "result" : false - } - } - }, - "validInvalid_197" : { - "code" : "0xef0001010004020001000b04000000008000016000e20100010002fe005b", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidCodeTermination", - "result" : false - } - } - }, - "validInvalid_198" : { - "code" : "0xef00010100040200010006040000000080000260006000f300", - "results" : { - "Prague" : { - "exception" : "EOF_UnreachableCode", - "result" : false - } - } - }, - "validInvalid_199" : { - "code" : "0xef00010100040200010006040000000080000260006000fd00", - "results" : { - "Prague" : { - "exception" : "EOF_UnreachableCode", - "result" : false - } - } - }, - "validInvalid_2" : { - "code" : "0xef000101000402000100090400000000800002600060015050e0fff7", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_20" : { - "code" : "0xef0001010004020001000504000000008000026001801300", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_200" : { - "code" : "0xef000101000402000100080400000000800001e000026000600000", - "results" : { - "Prague" : { - "exception" : "EOF_UnreachableCode", - "result" : false - } - } - }, - "validInvalid_201" : { - "code" : "0xef0001010004020001000c0400000000800001e000026000600050e0fffa00", - "results" : { - "Prague" : { - "exception" : "EOF_UnreachableCode", - "result" : false - } - } - }, - "validInvalid_21" : { - "code" : "0xef0001010004020001000504000000008000026001801400", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_22" : { - "code" : "0xef00010100040200010004040000000080000160011500", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_23" : { - "code" : "0xef0001010004020001000504000000008000026001801600", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_24" : { - "code" : "0xef0001010004020001000504000000008000026001801700", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_25" : { - "code" : "0xef0001010004020001000504000000008000026001801800", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_26" : { - "code" : "0xef00010100040200010004040000000080000160011900", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_27" : { - "code" : "0xef0001010004020001000504000000008000026001801a00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_28" : { - "code" : "0xef0001010004020001000504000000008000026001801b00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_29" : { - "code" : "0xef0001010004020001000504000000008000026001801c00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_3" : { - "code" : "0xef00010100040200010199040000000080000160c9e2c9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fe6800", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_30" : { - "code" : "0xef0001010004020001000504000000008000026001801d00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_31" : { - "code" : "0xef0001010004020001000504000000008000026001802000", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_32" : { - "code" : "0xef00010100040200010004040000000080000160013100", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_33" : { - "code" : "0xef00010100040200010004040000000080000160013500", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_34" : { - "code" : "0xef000101000402000100060400000000800003600180803700", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_35" : { - "code" : "0xef000101000402000100060400000000800003600180803900", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_36" : { - "code" : "0xef00010100040200010004040000000080000160013b00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_37" : { - "code" : "0xef00010100040200010007040000000080000460018080803c00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_38" : { - "code" : "0xef000101000402000100060400000000800003600180803e00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_39" : { - "code" : "0xef00010100040200010004040000000080000160013f00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_4" : { - "code" : "0xef000101000c020003000f00020002040000000080000100010001000100016000e10006e30001e00003e300020030e438e4", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_40" : { - "code" : "0xef00010100040200010004040000000080000160014000", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_41" : { - "code" : "0xef00010100040200010004040000000080000160014900", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_42" : { - "code" : "0xef00010100040200010004040000000080000160015000", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_43" : { - "code" : "0xef00010100040200010004040000000080000160015100", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_44" : { - "code" : "0xef0001010004020001000504000000008000026001805200", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_45" : { - "code" : "0xef0001010004020001000504000000008000026001805300", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_46" : { - "code" : "0xef00010100040200010004040000000080000160015400", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_47" : { - "code" : "0xef0001010004020001000504000000008000026001805500", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_48" : { - "code" : "0xef000101000402000100060400000000800003600180805e00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_49" : { - "code" : "0xef00010100040200010004040000000080000260018000", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_5" : { - "code" : "0xef000101001002000400050005008100800400000000800001010000020200007f7f00007f5fe30001005fe30002e48080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080e30003e450505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050e4", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_50" : { - "code" : "0xef0001010004020001000504000000008000036001808100", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_51" : { - "code" : "0xef000101000402000100060400000000800004600180808200", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_52" : { - "code" : "0xef00010100040200010007040000000080000560018080808300", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_53" : { - "code" : "0xef0001010004020001000804000000008000066001808080808400", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_54" : { - "code" : "0xef000101000402000100090400000000800007600180808080808500", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_55" : { - "code" : "0xef0001010004020001000a040000000080000860018080808080808600", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_56" : { - "code" : "0xef0001010004020001000b04000000008000096001808080808080808700", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_57" : { - "code" : "0xef0001010004020001000c040000000080000a600180808080808080808800", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_58" : { - "code" : "0xef0001010004020001000d040000000080000b60018080808080808080808900", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_59" : { - "code" : "0xef0001010004020001000e040000000080000c6001808080808080808080808a00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_6" : { - "code" : "0xef0001010004020001000504000000008000026001800100", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_60" : { - "code" : "0xef0001010004020001000f040000000080000d600180808080808080808080808b00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_61" : { - "code" : "0xef00010100040200010010040000000080000e60018080808080808080808080808c00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_62" : { - "code" : "0xef00010100040200010011040000000080000f6001808080808080808080808080808d00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_63" : { - "code" : "0xef000101000402000100120400000000800010600180808080808080808080808080808e00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_64" : { - "code" : "0xef00010100040200010013040000000080001160018080808080808080808080808080808f00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_65" : { - "code" : "0xef0001010004020001000504000000008000026001809000", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_66" : { - "code" : "0xef000101000402000100060400000000800003600180809100", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_67" : { - "code" : "0xef00010100040200010007040000000080000460018080809200", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_68" : { - "code" : "0xef0001010004020001000804000000008000056001808080809300", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_69" : { - "code" : "0xef000101000402000100090400000000800006600180808080809400", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_7" : { - "code" : "0xef0001010004020001000504000000008000026001800200", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_70" : { - "code" : "0xef0001010004020001000a040000000080000760018080808080809500", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_71" : { - "code" : "0xef0001010004020001000b04000000008000086001808080808080809600", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_72" : { - "code" : "0xef0001010004020001000c0400000000800009600180808080808080809700", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_73" : { - "code" : "0xef0001010004020001000d040000000080000a60018080808080808080809800", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_74" : { - "code" : "0xef0001010004020001000e040000000080000b6001808080808080808080809900", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_75" : { - "code" : "0xef0001010004020001000f040000000080000c600180808080808080808080809a00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_76" : { - "code" : "0xef00010100040200010010040000000080000d60018080808080808080808080809b00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_77" : { - "code" : "0xef00010100040200010011040000000080000e6001808080808080808080808080809c00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_78" : { - "code" : "0xef00010100040200010012040000000080000f600180808080808080808080808080809d00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_79" : { - "code" : "0xef00010100040200010013040000000080001060018080808080808080808080808080809e00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_8" : { - "code" : "0xef0001010004020001000504000000008000026001800300", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_80" : { - "code" : "0xef0001010004020001001404000000008000116001808080808080808080808080808080809f00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_81" : { - "code" : "0xef000101000402000100050400000000800002600180a000", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_82" : { - "code" : "0xef00010100040200010006040000000080000360018080a100", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_83" : { - "code" : "0xef0001010004020001000704000000008000046001808080a200", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_84" : { - "code" : "0xef000101000402000100080400000000800005600180808080a300", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_85" : { - "code" : "0xef00010100040200010009040000000080000660018080808080a400", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_86" : { - "code" : "0xef0001010004020001000a04000000008000076001808080808080f100", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_87" : { - "code" : "0xef000101000402000100040400000000800002600180f3", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_88" : { - "code" : "0xef00010100040200010009040000000080000660018080808080f400", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_89" : { - "code" : "0xef00010100040200010009040000000080000660018080808080fa00", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_9" : { - "code" : "0xef0001010004020001000504000000008000026001800400", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_90" : { - "code" : "0xef000101000402000100040400000000800002600180fd", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_91" : { - "code" : "0xef000101000402000100070400000000800002600150600080f3", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_92" : { - "code" : "0xef000101000402000100070400000000800002600150600080fd", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_93" : { - "code" : "0xef000101000402000100030400000000800000e0fffd", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_94" : { - "code" : "0xef0001010004020001000e0400000000800002600a6001900380e1000100e0fff4", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_95" : { - "code" : "0xef000101000c020003000600060006040000000080000101010002000200026000e300010050e3000250e46000610000e4", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_96" : { - "code" : "0xef000101000402000100070400000000800005600080808080f3", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_97" : { - "code" : "0xef000101000402000100070400000000800005600080808080fd", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_98" : { - "code" : "0xef000101000802000200040081040000000080007f007f007fe30001006000808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080e4", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_99" : { - "code" : "0xef000101000c020003000600060003040000000080000101000002020000026000e30001006000e30002e45050e4", - "results" : { - "Prague" : { - "result" : true - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/efExample/validInvalid.json b/crates/interpreter/tests/EOFTests/efExample/validInvalid.json deleted file mode 100644 index 497cbd18f6..0000000000 --- a/crates/interpreter/tests/EOFTests/efExample/validInvalid.json +++ /dev/null @@ -1,485 +0,0 @@ -{ - "validInvalid" : { - "_info" : { - "comment" : "Test various examples to see if they are valid or invalid.\nImplements\n EOF1I0001 check that EOF1 with a bad magic number fails\n EOF1I0002 check that EOF1 with a bad version number fails\n EOF1I0003 check that EOF1 with a bad section order fails\n EOF1I0004 check that EOF1 missing a section fails\n EOF1I0005 check that EOF1 with a bad end of sections number fails\n EOF1I0006 check that EOF1 with too many or too few bytes fails\n EOF1I0007 check that EOF1 with a malformed code section fails\n EOF1I0008 check that EOF1 with an illegal opcode fails\n EOF1I0009 check that EOF1 with the wrong maxStackDepth fails\n EOF1I0010 check that return values are not allowed on section 0\n EOF1I0011 check that function calls to code sections that don't exist fail\n EOF1I0012 check that code sections that cause stack underflow fail\n EOF1I0013 check that we can't return more values than we declare\n EOF1I0014 check that code that looks deeper in the stack than the parameters fails\n EOF1I0015 check that code that uses removed opcodes fails\n EOF1I0016 check that code that uses new relative jumps to outside the section fails\n EOF1I0017 check that parameters are not allowed on section 0\n EOF1I0018 inconsistent number of code sections (between types and code)\n EOF1I0019 check that jumps into the middle on an opcode are not allowed\n EOF1I0020 check that you can't get to the same opcode with two different stack heights\n EOF1I0022 stack underflow caused by a function call\n EOF1I0023 sections with unreachable code fail\n EOF1I0024 sections that end with a non-terminator opcode fail\n EOF1I0025 data stack height of 1024 is invalid\n EOF1V0001 check that simple valid EOF1 deploys\n EOF1V0002 check that valid EOF1 with two code sections deploys\n EOF1V0003 check that valid EOF1 with four code sections deploys\n EOF1V0004 check that valid EOF1 can include 0xFE, the designated invalid opcode\n EOF1V0005 check that EOF1 with the right maxStackDepth deploys\n EOF1V0006 check that return values are allowed on code sections that aren't zero\n EOF1V0007 check that function calls to code sections that exist are allowed\n EOF1V0008 check that code that uses a new style relative jump (5C) succeeds\n EOF1V0009 check that parameters are allowed on code sections that aren't zero\n EOF1V0010 parameters are part of the max stack height\n EOF1V0011 check that code that uses a new style conditional jump (5D) succeeds\n EOF1V0012 return values on code sections affect maxStackHeight of the caller\n EOF1V0013 jump tables work\n EOF1V0014 sections that end with a legit terminating opcode are OK\n EOF1V0015 data stack height of 1023 is valid\n EOF1V0016 check that data section size can be less than the declared size\n", - "filling-rpc-server" : "evmone-t8n 0.12.0-dev+commit.14ba7529", - "filling-tool-version" : "retesteth-0.3.2-cancun+commit.9d793abd.Linux.g++", - "generatedTestHash" : "8be48064c85661c6125e29eba56ec2ea604ba480d22410eedb125978ed173d2e", - "lllcversion" : "Version: 0.5.14-develop.2022.4.6+commit.401d5358.Linux.g++", - "solidity" : "Version: 0.8.18-develop.2023.1.16+commit.469d6d4d.Linux.g++", - "source" : "src/EOFTestsFiller/efExample/validInvalidFiller.yml", - "sourceHash" : "3e743bba1e9bffbfcc2bf398913470701329e100ed6a31bc155fb323f4910c7b" - }, - "vectors" : { - "validInvalid_0" : { - "code" : "0xef000101000402000100030400010000800001305000ef", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_1" : { - "code" : "0xef0001010004020001000304000400008000013050000bad", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_10" : { - "code" : "0xef0001010014020005001900030003000100010400040000800001008000020080000200800000000000005f35e2030000000300060009e50001e50002e50003e30004005f5ff35f5ffdfee40bad60a7", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_11" : { - "code" : "0xef0001010004020001000d04000400008000016001e2010002000030503050000bad60a7", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_12" : { - "code" : "0xef0001010004020001000d04000400008000016001e2020002ffff30503050000bad60a7", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidJumpDestination", - "result" : false - } - } - }, - "validInvalid_13" : { - "code" : "0xef0001010004020001000804000400008000016001e10001305b000bad60a7", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_14" : { - "code" : "0xef0001010004020001000a0400040000800000e00003e00002e0fffa000bad60a7", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidJumpDestination", - "result" : false - } - } - }, - "validInvalid_15" : { - "code" : "0xef000101000402000100100400040000800003600060006000e10003e10002e1fffa000bad60a7", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidJumpDestination", - "result" : false - } - } - }, - "validInvalid_16" : { - "code" : "0xef000101000802000100030400040000800001000000003050000bad60a7", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidTypeSectionSize", - "result" : false - } - } - }, - "validInvalid_17" : { - "code" : "0xef0001010008020001000304000400008000013050000bad60a7", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidTypeSectionSize", - "result" : false - } - } - }, - "validInvalid_18" : { - "code" : "0xef0001010004020001000504000100008000016003565b00ef", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_19" : { - "code" : "0xef00010100040200010007040001000080000160016003575b00ef", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_2" : { - "code" : "0xef0001010004020001000304000400008000013050000bad60a70bad", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidSectionBodiesSize", - "result" : false - } - } - }, - "validInvalid_20" : { - "code" : "0xef0001010004020001000404000100008000016001ff00ef", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_21" : { - "code" : "0xef000101000402000100040400010000800007", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidSectionBodiesSize", - "result" : false - } - } - }, - "validInvalid_22" : { - "code" : "0xef0001010004020001001004000100008000016001600260036004600560066007f200ef", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_23" : { - "code" : "0xef0001010004020001000504000100008000016003565b00ef", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_24" : { - "code" : "0xef00010100080200020006000304000400008000010101000130e3000150005030e40bad60a7", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_25" : { - "code" : "0xef000101000802000200040002040004000080000100010001e300010030e40bad60a7", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_26" : { - "code" : "0xef000101000802000200030001040004000080000100010001e30001300bad60a7", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidCodeTermination", - "result" : false - } - } - }, - "validInvalid_27" : { - "code" : "0xef000101000802000200040002040004000080000101000001e300010050e40bad60a7", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_28" : { - "code" : "0xef000101000c0200030028000b001f04000400008003ff000a000a00640064e30002e30002e30002e30002e30002e30002e30002e30002e30002e30002e30001e300013030300030303030303030303030e4e30001e30001e30001e30001e30001e30001e30001e30001e30001e30001e40bad60a7", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_29" : { - "code" : "0xef000101000c0200030029000b001f0400040000800400000a000a00640064e30002e30002e30002e30002e30002e30002e30002e30002e30002e30002e30001e30001303030300030303030303030303030e4e30001e30001e30001e30001e30001e30001e30001e30001e30001e30001e40bad60a7", - "results" : { - "Prague" : { - "exception" : "EOF_MaxStackHeightExceeded", - "result" : false - } - } - }, - "validInvalid_3" : { - "code" : "0xef0001010004020001000304000400008000013050000bad60a7", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_30" : { - "code" : "0xef0001010010020004000b000300030003040004000080000101010001000000010101000130e30001e30003e30002005030e43050e45030e40bad60a7", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_31" : { - "code" : "0xef00010100100200040015000500070007040004000080000100800002008000030080000130505f35e202000000030006e50001e50002e50003303050500030303050505000305030503050000bad60a7", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_32" : { - "code" : "0xef00010100100200040010000300070007040004000080000100800000008000030080000130505f35e20100000003e50001e50003e5000230303050505000305030503050000bad60a7", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_33" : { - "code" : "0xef00010100100200040015000300070007040004000080000100800000008000030080000130505f35e202000000030006e50001e50002e50003e5000f30303050505000305030503050000bad60a7", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidCodeSectionIndex", - "result" : false - } - } - }, - "validInvalid_34" : { - "code" : "0xef0001010008020002000600030400040000800001028000023050e50001005050000bad60a7", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_35" : { - "code" : "0xef0001010008020002000600030400040000800001000100023050e30001003030e40bad60a7", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidNumberOfOutputs", - "result" : false - } - } - }, - "validInvalid_36" : { - "code" : "0xef0001010008020002000600030400040000800001010100023050e30001003091e40bad60a7", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_37" : { - "code" : "0xef0001010004020001000304000400000100013050fe0bad60a7", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidFirstSectionType", - "result" : false - } - } - }, - "validInvalid_38" : { - "code" : "0xef000101000802000200050003040004000080000202800002305fe500015050000bad60a7", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_39" : { - "code" : "0xef0001010004020001000304000400018000013050fe0bad60a7", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidFirstSectionType", - "result" : false - } - } - }, - "validInvalid_4" : { - "code" : "0xef00010100040200010003040004000080000130ef000bad60a7", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_40" : { - "code" : "0xef0001010004020001000304000400008000033050000bad60a7", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidMaxStackHeight", - "result" : false - } - } - }, - "validInvalid_41" : { - "code" : "0xef00010100040200010001040004000080000530503050000bad60a7", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidSectionBodiesSize", - "result" : false - } - } - }, - "validInvalid_42" : { - "code" : "0xef0001010004020001000304000400008000013050620bad60a7", - "results" : { - "Prague" : { - "exception" : "EOF_TruncatedImmediate", - "result" : false - } - } - }, - "validInvalid_43" : { - "code" : "0xef00010100040200010003040001ff00800001305000ef", - "results" : { - "Prague" : { - "exception" : "EOF_HeaderTerminatorMissing", - "result" : false - } - } - }, - "validInvalid_44" : { - "code" : "0xef020101000402000100030400010000800001305000ef", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidMagic", - "result" : false - } - } - }, - "validInvalid_45" : { - "code" : "0xef000001000402000100030400010000800001305000ef", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidVersion", - "result" : false - } - } - }, - "validInvalid_46" : { - "code" : "0xef000201000402000100030400010000800001305000ef", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidVersion", - "result" : false - } - } - }, - "validInvalid_47" : { - "code" : "0xef000102000100030100040400010000800001305000ef", - "results" : { - "Prague" : { - "exception" : "EOF_TypeSectionMissing", - "result" : false - } - } - }, - "validInvalid_48" : { - "code" : "0xef000102000100030400010100040000800001305000ef", - "results" : { - "Prague" : { - "exception" : "EOF_TypeSectionMissing", - "result" : false - } - } - }, - "validInvalid_49" : { - "code" : "0xef000102000100030400010000800001305000ef", - "results" : { - "Prague" : { - "exception" : "EOF_TypeSectionMissing", - "result" : false - } - } - }, - "validInvalid_5" : { - "code" : "0xef0001010004020001000304000400008000013050fe0bad60a7", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_50" : { - "code" : "0xef00010100040400010000800001305000ef", - "results" : { - "Prague" : { - "exception" : "EOF_CodeSectionMissing", - "result" : false - } - } - }, - "validInvalid_51" : { - "code" : "0xef000101000402000100030000800001305000ef", - "results" : { - "Prague" : { - "exception" : "EOF_DataSectionMissing", - "result" : false - } - } - }, - "validInvalid_52" : { - "code" : "0xef0001010004020001000a040016000080000338600060003938601df3ef0001010004020001000304001d0000000001385000", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_53" : { - "code" : "0x610badfe", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidMagic", - "result" : false - } - } - }, - "validInvalid_6" : { - "code" : "0xef00010100040200010003040001ff00800001305000ef", - "results" : { - "Prague" : { - "exception" : "EOF_HeaderTerminatorMissing", - "result" : false - } - } - }, - "validInvalid_7" : { - "code" : "0xef0001010004020001000e04000400008000015fe10003e00003e00003e0fffa000bad60a7", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_8" : { - "code" : "0xef000101000402000100050400040000800000e000015b000bad60a7", - "results" : { - "Prague" : { - "exception" : "EOF_UnreachableCode", - "result" : false - } - } - }, - "validInvalid_9" : { - "code" : "0xef0001010004020001000704000400008000016001e100015b000bad60a7", - "results" : { - "Prague" : { - "result" : true - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/efExample/ymlExample.json b/crates/interpreter/tests/EOFTests/efExample/ymlExample.json deleted file mode 100644 index 36505b9187..0000000000 --- a/crates/interpreter/tests/EOFTests/efExample/ymlExample.json +++ /dev/null @@ -1,51 +0,0 @@ -{ - "ymlExample" : { - "_info" : { - "comment" : "EOF example test", - "filling-rpc-server" : "evmone-t8n 0.12.0-dev+commit.14ba7529", - "filling-tool-version" : "retesteth-0.3.2-cancun+commit.9d793abd.Linux.g++", - "generatedTestHash" : "acafd37d166881fa1a015acb1d6ff88f0f698e14a7db9098952065aaa90e78e5", - "lllcversion" : "Version: 0.5.14-develop.2022.4.6+commit.401d5358.Linux.g++", - "solidity" : "Version: 0.8.18-develop.2023.1.16+commit.469d6d4d.Linux.g++", - "source" : "src/EOFTestsFiller/efExample/ymlExampleFiller.yml", - "sourceHash" : "3eb098795ee0f651ae94dab0674f1a6f2e9dd5d6210cf6719508d9f301b4b71d" - }, - "vectors" : { - "ymlExample_0" : { - "code" : "0x60016000f3", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidPrefix", - "result" : false - } - } - }, - "ymlExample_1" : { - "code" : "0xef0001010004020001000a040016000080000338600060003938601df3ef0001010004020001000304001d0000800001385000", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "ymlExample_2" : { - "code" : "0xefffff", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidPrefix", - "result" : false - } - } - }, - "ymlExample_3" : { - "code" : "0x610badfe", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidPrefix", - "result" : false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_callf_truncated.json b/crates/interpreter/tests/EOFTests/eof_validation/EOF1_callf_truncated.json deleted file mode 100644 index 4a160d1954..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_callf_truncated.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "EOF1_callf_truncated": { - "vectors": { - "EOF1_callf_truncated_0": { - "code": "0xef000101000402000100010400000000800000e3", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_callf_truncated_1": { - "code": "0xef000101000402000100020400000000800000e300", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_code_section_0_size.json b/crates/interpreter/tests/EOFTests/eof_validation/EOF1_code_section_0_size.json deleted file mode 100644 index 8ca3ca3cf6..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_code_section_0_size.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "EOF1_code_section_0_size": { - "vectors": { - "EOF1_code_section_0_size_0": { - "code": "0xef000101000402000000", - "results": { - "Prague": { - "exception": "EOF_ZeroSectionSize", - "result": false - } - } - }, - "EOF1_code_section_0_size_1": { - "code": "0xef000101000402000004000100da", - "results": { - "Prague": { - "exception": "EOF_ZeroSectionSize", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_code_section_missing.json b/crates/interpreter/tests/EOFTests/eof_validation/EOF1_code_section_missing.json deleted file mode 100644 index 275c6a9cf3..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_code_section_missing.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "EOF1_code_section_missing": { - "vectors": { - "EOF1_code_section_missing_0": { - "code": "0xef000101000400", - "results": { - "Prague": { - "exception": "EOF_CodeSectionMissing", - "result": false - } - } - }, - "EOF1_code_section_missing_1": { - "code": "0xef00010100040400010000800000da", - "results": { - "Prague": { - "exception": "EOF_CodeSectionMissing", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_code_section_offset.json b/crates/interpreter/tests/EOFTests/eof_validation/EOF1_code_section_offset.json deleted file mode 100644 index d150cbac85..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_code_section_offset.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "EOF1_code_section_offset": { - "vectors": { - "EOF1_code_section_offset_0": { - "code": "0xef000101000802000200030001040004000080000000800000e50001fe00000000", - "results": { - "Prague": { - "result": true - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_data_section_0_size.json b/crates/interpreter/tests/EOFTests/eof_validation/EOF1_data_section_0_size.json deleted file mode 100644 index 8e10968c99..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_data_section_0_size.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "EOF1_data_section_0_size": { - "vectors": { - "EOF1_data_section_0_size_0": { - "code": "0xef000101000402000100010400000000800000fe", - "results": { - "Prague": { - "result": true - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_data_section_before_code_section.json b/crates/interpreter/tests/EOFTests/eof_validation/EOF1_data_section_before_code_section.json deleted file mode 100644 index eb96abcffe..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_data_section_before_code_section.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "EOF1_data_section_before_code_section": { - "vectors": { - "EOF1_data_section_before_code_section_0": { - "code": "0xef000101000403000102000100010000800000aafe", - "results": { - "Prague": { - "exception": "EOF_CodeSectionMissing", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_data_section_before_types_section.json b/crates/interpreter/tests/EOFTests/eof_validation/EOF1_data_section_before_types_section.json deleted file mode 100644 index 8f6595f4cb..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_data_section_before_types_section.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "EOF1_data_section_before_types_section": { - "vectors": { - "EOF1_data_section_before_types_section_0": { - "code": "0xef0001040001010004020001000100aa00800000fe", - "results": { - "Prague": { - "exception": "EOF_TypeSectionMissing", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_dataloadn_truncated.json b/crates/interpreter/tests/EOFTests/eof_validation/EOF1_dataloadn_truncated.json deleted file mode 100644 index c5a120807e..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_dataloadn_truncated.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "EOF1_dataloadn_truncated": { - "vectors": { - "EOF1_dataloadn_truncated_0": { - "code": "0xef000101000402000100010400000000800000d1", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_dataloadn_truncated_1": { - "code": "0xef000101000402000100020400000000800000d100", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_embedded_container.json b/crates/interpreter/tests/EOFTests/eof_validation/EOF1_embedded_container.json deleted file mode 100644 index 37748c14ee..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_embedded_container.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "EOF1_embedded_container": { - "vectors": { - "EOF1_embedded_container_0": { - "code": "0xef00010100040200010006030001001404000000008000016000e0000000ef000101000402000100010400000000800000fe", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_embedded_container_1": { - "code": "0xef00010100040200010006030001001404000200008000016000e0000000ef000101000402000100010400000000800000fe", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_embedded_container_2": { - "code": "0xef00010100040200010006030001001404000200008000016000e0000000ef000101000402000100010400000000800000feaabb", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_embedded_container_3": { - "code": "0xef00010100040200010006030001000604000000008000016000e0000000aabbccddeeff", - "results": { - "Prague": { - "exception": "EOF_InvalidPrefix", - "result": false - } - } - }, - "EOF1_embedded_container_4": { - "code": "0xef000101000402000100060300020014001604000000008000016000e0000000ef000101000402000100010400000000800000feef0001010004020001000304000000008000025f5ff3", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_embedded_container_5": { - "code": "0xef00010100040200010006030100001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001404000000008000016000e0000000ef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000fe", - "results": { - "Prague": { - "result": true - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_embedded_container_invalid.json b/crates/interpreter/tests/EOFTests/eof_validation/EOF1_embedded_container_invalid.json deleted file mode 100644 index b394324a18..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_embedded_container_invalid.json +++ /dev/null @@ -1,87 +0,0 @@ -{ - "EOF1_embedded_container_invalid": { - "vectors": { - "EOF1_embedded_container_invalid_0": { - "code": "0xef0001010004020001000603", - "results": { - "Prague": { - "exception": "EOF_IncompleteSectionNumber", - "result": false - } - } - }, - "EOF1_embedded_container_invalid_1": { - "code": "0xef000101000402000100060300", - "results": { - "Prague": { - "exception": "EOF_IncompleteSectionNumber", - "result": false - } - } - }, - "EOF1_embedded_container_invalid_2": { - "code": "0xef00010100040200010006030001", - "results": { - "Prague": { - "exception": "EOF_SectionHeadersNotTerminated", - "result": false - } - } - }, - "EOF1_embedded_container_invalid_3": { - "code": "0xef0001010004020001000603000100", - "results": { - "Prague": { - "exception": "EOF_IncompleteSectionSize", - "result": false - } - } - }, - "EOF1_embedded_container_invalid_4": { - "code": "0xef000101000402000100060300010014", - "results": { - "Prague": { - "exception": "EOF_SectionHeadersNotTerminated", - "result": false - } - } - }, - "EOF1_embedded_container_invalid_5": { - "code": "0xef00010100040200010006030000040000000080000160005d000000", - "results": { - "Prague": { - "exception": "EOF_ZeroSectionSize", - "result": false - } - } - }, - "EOF1_embedded_container_invalid_6": { - "code": "0xef000101000402000100060300010000040000000080000160005d000000", - "results": { - "Prague": { - "exception": "EOF_ZeroSectionSize", - "result": false - } - } - }, - "EOF1_embedded_container_invalid_7": { - "code": "0xef000101000402000100060300010014040000000080000160005d000000", - "results": { - "Prague": { - "exception": "EOF_InvalidSectionBodiesSize", - "result": false - } - } - }, - "EOF1_embedded_container_invalid_8": { - "code": "0xef0001010004020001000603010100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001040000000080000160005d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TooManyContainerSections", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_eofcreate_invalid.json b/crates/interpreter/tests/EOFTests/eof_validation/EOF1_eofcreate_invalid.json deleted file mode 100644 index 2940c81713..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_eofcreate_invalid.json +++ /dev/null @@ -1,51 +0,0 @@ -{ - "EOF1_eofcreate_invalid": { - "vectors": { - "EOF1_eofcreate_invalid_0": { - "code": "0xef0001010004020001000903000100140400000000800004600060ff60006000ecef000101000402000100010400000000800000fe", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_eofcreate_invalid_1": { - "code": "0xef0001010004020001000a03000100140400000000800004600060ff60006000ec00ef000101000402000100010400000000800000fe", - "results": { - "Prague": { - "exception": "EOF_InvalidCodeTermination", - "result": false - } - } - }, - "EOF1_eofcreate_invalid_2": { - "code": "0xef0001010004020001000c03000100140400000000800004600060ff60006000ec015000ef000101000402000100010400000000800000fe", - "results": { - "Prague": { - "exception": "EOF_InvalidContainerSectionIndex", - "result": false - } - } - }, - "EOF1_eofcreate_invalid_3": { - "code": "0xef0001010004020001000c03000100140400000000800004600060ff60006000ecff5000ef000101000402000100010400000000800000fe", - "results": { - "Prague": { - "exception": "EOF_InvalidContainerSectionIndex", - "result": false - } - } - }, - "EOF1_eofcreate_invalid_4": { - "code": "0xef0001010004020001000c03000100160400000000800004600060ff60006000ec005000ef000101000402000100010400030000800000feaabb", - "results": { - "Prague": { - "exception": "EOF_EofCreateWithTruncatedContainer", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_eofcreate_valid.json b/crates/interpreter/tests/EOFTests/eof_validation/EOF1_eofcreate_valid.json deleted file mode 100644 index 0d8513f604..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_eofcreate_valid.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "EOF1_eofcreate_valid": { - "vectors": { - "EOF1_eofcreate_valid_0": { - "code": "0xef0001010004020001000b0300010014040000000080000436600060ff6000ec005000ef000101000402000100010400000000800000fe", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_eofcreate_valid_1": { - "code": "0xef0001010004020001000b03000200140014040000000080000436600060ff6000ec015000ef000101000402000100010400000000800000feef000101000402000100010400000000800000fe", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_eofcreate_valid_2": { - "code": "0xef0001010004020001000b0301000014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014040000000080000436600060ff6000ecff5000ef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000fe", - "results": { - "Prague": { - "result": true - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_header_not_terminated.json b/crates/interpreter/tests/EOFTests/eof_validation/EOF1_header_not_terminated.json deleted file mode 100644 index 38c7abe293..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_header_not_terminated.json +++ /dev/null @@ -1,78 +0,0 @@ -{ - "EOF1_header_not_terminated": { - "vectors": { - "EOF1_header_not_terminated_0": { - "code": "0xef000101", - "results": { - "Prague": { - "exception": "EOF_SectionHeadersNotTerminated", - "result": false - } - } - }, - "EOF1_header_not_terminated_1": { - "code": "0xef0001010004", - "results": { - "Prague": { - "exception": "EOF_SectionHeadersNotTerminated", - "result": false - } - } - }, - "EOF1_header_not_terminated_2": { - "code": "0xef0001010004fe", - "results": { - "Prague": { - "exception": "EOF_CodeSectionMissing", - "result": false - } - } - }, - "EOF1_header_not_terminated_3": { - "code": "0xef000101000402", - "results": { - "Prague": { - "exception": "EOF_IncompleteSectionNumber", - "result": false - } - } - }, - "EOF1_header_not_terminated_4": { - "code": "0xef00010100040200", - "results": { - "Prague": { - "exception": "EOF_IncompleteSectionNumber", - "result": false - } - } - }, - "EOF1_header_not_terminated_5": { - "code": "0xef0001010004020001", - "results": { - "Prague": { - "exception": "EOF_SectionHeadersNotTerminated", - "result": false - } - } - }, - "EOF1_header_not_terminated_6": { - "code": "0xef00010100040200010001040001", - "results": { - "Prague": { - "exception": "EOF_SectionHeadersNotTerminated", - "result": false - } - } - }, - "EOF1_header_not_terminated_7": { - "code": "0xef00010100040200010001040001feaa", - "results": { - "Prague": { - "exception": "EOF_HeaderTerminatorMissing", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_incomplete_section_size.json b/crates/interpreter/tests/EOFTests/eof_validation/EOF1_incomplete_section_size.json deleted file mode 100644 index 928b771d26..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_incomplete_section_size.json +++ /dev/null @@ -1,69 +0,0 @@ -{ - "EOF1_incomplete_section_size": { - "vectors": { - "EOF1_incomplete_section_size_0": { - "code": "0xef000101", - "results": { - "Prague": { - "exception": "EOF_SectionHeadersNotTerminated", - "result": false - } - } - }, - "EOF1_incomplete_section_size_1": { - "code": "0xef00010100", - "results": { - "Prague": { - "exception": "EOF_IncompleteSectionSize", - "result": false - } - } - }, - "EOF1_incomplete_section_size_2": { - "code": "0xef00010100040200", - "results": { - "Prague": { - "exception": "EOF_IncompleteSectionNumber", - "result": false - } - } - }, - "EOF1_incomplete_section_size_3": { - "code": "0xef000101000402000100", - "results": { - "Prague": { - "exception": "EOF_IncompleteSectionSize", - "result": false - } - } - }, - "EOF1_incomplete_section_size_4": { - "code": "0xef00010100040200010001", - "results": { - "Prague": { - "exception": "EOF_SectionHeadersNotTerminated", - "result": false - } - } - }, - "EOF1_incomplete_section_size_5": { - "code": "0xef0001010004020001000104", - "results": { - "Prague": { - "exception": "EOF_SectionHeadersNotTerminated", - "result": false - } - } - }, - "EOF1_incomplete_section_size_6": { - "code": "0xef000101000402000100010400", - "results": { - "Prague": { - "exception": "EOF_IncompleteSectionSize", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_invalid_section_0_type.json b/crates/interpreter/tests/EOFTests/eof_validation/EOF1_invalid_section_0_type.json deleted file mode 100644 index 0afe03ba0a..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_invalid_section_0_type.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "EOF1_invalid_section_0_type": { - "vectors": { - "EOF1_invalid_section_0_type_0": { - "code": "0xef00010100040200010001040000000000000000", - "results": { - "Prague": { - "exception": "EOF_InvalidFirstSectionType", - "result": false - } - } - }, - "EOF1_invalid_section_0_type_1": { - "code": "0xef00010100040200010003040000000001000060005c", - "results": { - "Prague": { - "exception": "EOF_InvalidFirstSectionType", - "result": false - } - } - }, - "EOF1_invalid_section_0_type_2": { - "code": "0xef000101000402000100010400000001800000fe", - "results": { - "Prague": { - "exception": "EOF_InvalidFirstSectionType", - "result": false - } - } - }, - "EOF1_invalid_section_0_type_3": { - "code": "0xef00010100040200010003040000000203000060005c", - "results": { - "Prague": { - "exception": "EOF_InvalidFirstSectionType", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_invalid_type_section_size.json b/crates/interpreter/tests/EOFTests/eof_validation/EOF1_invalid_type_section_size.json deleted file mode 100644 index 698bf85665..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_invalid_type_section_size.json +++ /dev/null @@ -1,51 +0,0 @@ -{ - "EOF1_invalid_type_section_size": { - "vectors": { - "EOF1_invalid_type_section_size_0": { - "code": "0xef000101000102000100010400000000fe", - "results": { - "Prague": { - "exception": "EOF_InvalidTypeSectionSize", - "result": false - } - } - }, - "EOF1_invalid_type_section_size_1": { - "code": "0xef00010100020200010001040000000080fe", - "results": { - "Prague": { - "exception": "EOF_InvalidTypeSectionSize", - "result": false - } - } - }, - "EOF1_invalid_type_section_size_2": { - "code": "0xef00010100080200010001040000000080000000000000fe", - "results": { - "Prague": { - "exception": "EOF_InvalidTypeSectionSize", - "result": false - } - } - }, - "EOF1_invalid_type_section_size_3": { - "code": "0xef0001010008020003000100010001040000000080000000800000fefefe", - "results": { - "Prague": { - "exception": "EOF_InvalidTypeSectionSize", - "result": false - } - } - }, - "EOF1_invalid_type_section_size_4": { - "code": "0xef00010100100200030001000100010400000000800000008000000080000000800000fefefe", - "results": { - "Prague": { - "exception": "EOF_InvalidTypeSectionSize", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_multiple_data_sections.json b/crates/interpreter/tests/EOFTests/eof_validation/EOF1_multiple_data_sections.json deleted file mode 100644 index 17cb8a34f9..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_multiple_data_sections.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "EOF1_multiple_data_sections": { - "vectors": { - "EOF1_multiple_data_sections_0": { - "code": "0xef000101000402000100010400010400010000800000fedada", - "results": { - "Prague": { - "exception": "EOF_HeaderTerminatorMissing", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_multiple_type_sections.json b/crates/interpreter/tests/EOFTests/eof_validation/EOF1_multiple_type_sections.json deleted file mode 100644 index 6a83b1a98c..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_multiple_type_sections.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "EOF1_multiple_type_sections": { - "vectors": { - "EOF1_multiple_type_sections_0": { - "code": "0xef000101000401000402000200010001000080000000800000fefe", - "results": { - "Prague": { - "exception": "EOF_CodeSectionMissing", - "result": false - } - } - }, - "EOF1_multiple_type_sections_1": { - "code": "0xef0001030002010001010001040002000000fefe0000", - "results": { - "Prague": { - "exception": "EOF_TypeSectionMissing", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_no_type_section.json b/crates/interpreter/tests/EOFTests/eof_validation/EOF1_no_type_section.json deleted file mode 100644 index 2d046aa7a7..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_no_type_section.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "EOF1_no_type_section": { - "vectors": { - "EOF1_no_type_section_0": { - "code": "0xef0001020001000100fe", - "results": { - "Prague": { - "exception": "EOF_TypeSectionMissing", - "result": false - } - } - }, - "EOF1_no_type_section_1": { - "code": "0xef00010200020001000100fefe", - "results": { - "Prague": { - "exception": "EOF_TypeSectionMissing", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_returncontract_invalid.json b/crates/interpreter/tests/EOFTests/eof_validation/EOF1_returncontract_invalid.json deleted file mode 100644 index be7ee59297..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_returncontract_invalid.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "EOF1_returncontract_invalid": { - "vectors": { - "EOF1_returncontract_invalid_0": { - "code": "0xef000101000402000100050300010014040000000080000460006000eeef000101000402000100010400000000800000fe", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_returncontract_invalid_1": { - "code": "0xef000101000402000100060300010014040000000080000460006000ee01ef000101000402000100010400000000800000fe", - "results": { - "Prague": { - "exception": "EOF_InvalidContainerSectionIndex", - "result": false - } - } - }, - "EOF1_returncontract_invalid_2": { - "code": "0xef000101000402000100060300010014040000000080000460006000eeffef000101000402000100010400000000800000fe", - "results": { - "Prague": { - "exception": "EOF_InvalidContainerSectionIndex", - "result": false - } - } - }, - "EOF1_returncontract_invalid_3": { - "code": "0xef000101000402000100070300010014040000000080000260006000ee0000ef000101000402000100010400000000800000fe", - "results": { - "Prague": { - "exception": "EOF_UnreachableCode", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_returncontract_valid.json b/crates/interpreter/tests/EOFTests/eof_validation/EOF1_returncontract_valid.json deleted file mode 100644 index 60252e7d33..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_returncontract_valid.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "EOF1_returncontract_valid": { - "vectors": { - "EOF1_returncontract_valid_0": { - "code": "0xef000101000402000100060300010014040000000080000260006000ee00ef000101000402000100010400000000800000fe", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_returncontract_valid_1": { - "code": "0xef0001010004020001000603000200140014040000000080000260006000ee01ef000101000402000100010400000000800000feef000101000402000100010400000000800000fe", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_returncontract_valid_2": { - "code": "0xef000101000402000100060301000014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014001400140014040000000080000260006000eeffef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000feef000101000402000100010400000000800000fe", - "results": { - "Prague": { - "result": true - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_rjump_invalid_destination.json b/crates/interpreter/tests/EOFTests/eof_validation/EOF1_rjump_invalid_destination.json deleted file mode 100644 index 1ae65f3ec4..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_rjump_invalid_destination.json +++ /dev/null @@ -1,78 +0,0 @@ -{ - "EOF1_rjump_invalid_destination": { - "vectors": { - "EOF1_rjump_invalid_destination_0": { - "code": "0xef000101000402000100040400000000800000e0fffb00", - "results": { - "Prague": { - "exception": "EOF_InvalidJumpDestination", - "result": false - } - } - }, - "EOF1_rjump_invalid_destination_1": { - "code": "0xef000101000402000100040400000000800000e0fff300", - "results": { - "Prague": { - "exception": "EOF_InvalidJumpDestination", - "result": false - } - } - }, - "EOF1_rjump_invalid_destination_2": { - "code": "0xef000101000402000100040400000000800000e0000200", - "results": { - "Prague": { - "exception": "EOF_InvalidJumpDestination", - "result": false - } - } - }, - "EOF1_rjump_invalid_destination_3": { - "code": "0xef000101000402000100040400000000800000e0000100", - "results": { - "Prague": { - "exception": "EOF_InvalidJumpDestination", - "result": false - } - } - }, - "EOF1_rjump_invalid_destination_4": { - "code": "0xef000101000402000100040400000000800000e0ffff00", - "results": { - "Prague": { - "exception": "EOF_InvalidJumpDestination", - "result": false - } - } - }, - "EOF1_rjump_invalid_destination_5": { - "code": "0xef0001010004020001000604000000008000006000e0fffc00", - "results": { - "Prague": { - "exception": "EOF_InvalidJumpDestination", - "result": false - } - } - }, - "EOF1_rjump_invalid_destination_6": { - "code": "0xef0001010004020001000f03000100140400000000800004e00009600060ff60006000ec005000ef000101000402000100010400000000800000fe", - "results": { - "Prague": { - "exception": "EOF_InvalidJumpDestination", - "result": false - } - } - }, - "EOF1_rjump_invalid_destination_7": { - "code": "0xef0001010004020001000903000100140400000000800002e0000560006000ee00ef000101000402000100010400000000800000fe", - "results": { - "Prague": { - "exception": "EOF_InvalidJumpDestination", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_rjump_truncated.json b/crates/interpreter/tests/EOFTests/eof_validation/EOF1_rjump_truncated.json deleted file mode 100644 index 8f2d5863d0..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_rjump_truncated.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "EOF1_rjump_truncated": { - "vectors": { - "EOF1_rjump_truncated_0": { - "code": "0xef000101000402000100010400000000800000e0", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_rjump_truncated_1": { - "code": "0xef000101000402000100020400000000800000e000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_rjumpi_invalid_destination.json b/crates/interpreter/tests/EOFTests/eof_validation/EOF1_rjumpi_invalid_destination.json deleted file mode 100644 index b119e62e70..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_rjumpi_invalid_destination.json +++ /dev/null @@ -1,78 +0,0 @@ -{ - "EOF1_rjumpi_invalid_destination": { - "vectors": { - "EOF1_rjumpi_invalid_destination_0": { - "code": "0xef0001010004020001000604000000008000006000e1fff900", - "results": { - "Prague": { - "exception": "EOF_InvalidJumpDestination", - "result": false - } - } - }, - "EOF1_rjumpi_invalid_destination_1": { - "code": "0xef0001010004020001000604000000008000006000e1fff100", - "results": { - "Prague": { - "exception": "EOF_InvalidJumpDestination", - "result": false - } - } - }, - "EOF1_rjumpi_invalid_destination_2": { - "code": "0xef0001010004020001000604000000008000006000e1000200", - "results": { - "Prague": { - "exception": "EOF_InvalidJumpDestination", - "result": false - } - } - }, - "EOF1_rjumpi_invalid_destination_3": { - "code": "0xef0001010004020001000604000000008000006000e1000100", - "results": { - "Prague": { - "exception": "EOF_InvalidJumpDestination", - "result": false - } - } - }, - "EOF1_rjumpi_invalid_destination_4": { - "code": "0xef0001010004020001000604000000008000006000e1ffff00", - "results": { - "Prague": { - "exception": "EOF_InvalidJumpDestination", - "result": false - } - } - }, - "EOF1_rjumpi_invalid_destination_5": { - "code": "0xef0001010004020001000604000000008000006000e1fffc00", - "results": { - "Prague": { - "exception": "EOF_InvalidJumpDestination", - "result": false - } - } - }, - "EOF1_rjumpi_invalid_destination_6": { - "code": "0xef00010100040200010011030001001404000000008000046000e10009600060ff60006000ec005000ef000101000402000100010400000000800000fe", - "results": { - "Prague": { - "exception": "EOF_InvalidJumpDestination", - "result": false - } - } - }, - "EOF1_rjumpi_invalid_destination_7": { - "code": "0xef0001010004020001000b030001001404000000008000026000e1000560006000ee00ef000101000402000100010400000000800000fe", - "results": { - "Prague": { - "exception": "EOF_InvalidJumpDestination", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_rjumpi_truncated.json b/crates/interpreter/tests/EOFTests/eof_validation/EOF1_rjumpi_truncated.json deleted file mode 100644 index 1eab63f429..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_rjumpi_truncated.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "EOF1_rjumpi_truncated": { - "vectors": { - "EOF1_rjumpi_truncated_0": { - "code": "0xef0001010004020001000304000000008000006000e1", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_rjumpi_truncated_1": { - "code": "0xef0001010004020001000404000000008000006000e100", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_rjumpv_invalid_destination.json b/crates/interpreter/tests/EOFTests/eof_validation/EOF1_rjumpv_invalid_destination.json deleted file mode 100644 index adf48163a2..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_rjumpv_invalid_destination.json +++ /dev/null @@ -1,114 +0,0 @@ -{ - "EOF1_rjumpv_invalid_destination": { - "vectors": { - "EOF1_rjumpv_invalid_destination_0": { - "code": "0xef0001010004020001000804000000008000006000e200ffe96001", - "results": { - "Prague": { - "exception": "EOF_InvalidJumpDestination", - "result": false - } - } - }, - "EOF1_rjumpv_invalid_destination_1": { - "code": "0xef0001010004020001000804000000008000006000e200fff86001", - "results": { - "Prague": { - "exception": "EOF_InvalidJumpDestination", - "result": false - } - } - }, - "EOF1_rjumpv_invalid_destination_10": { - "code": "0xef00010100040200010012030001001404000000008000046000e2000009600060ff60006000ec005000ef000101000402000100010400000000800000fe", - "results": { - "Prague": { - "exception": "EOF_InvalidJumpDestination", - "result": false - } - } - }, - "EOF1_rjumpv_invalid_destination_11": { - "code": "0xef0001010004020001000c030001001404000000008000026000e200000560006000ee00ef000101000402000100010400000000800000fe", - "results": { - "Prague": { - "exception": "EOF_InvalidJumpDestination", - "result": false - } - } - }, - "EOF1_rjumpv_invalid_destination_2": { - "code": "0xef0001010004020001000804000000008000006000e200ffff6001", - "results": { - "Prague": { - "exception": "EOF_InvalidJumpDestination", - "result": false - } - } - }, - "EOF1_rjumpv_invalid_destination_3": { - "code": "0xef0001010004020001000804000000008000006000e20000026001", - "results": { - "Prague": { - "exception": "EOF_InvalidJumpDestination", - "result": false - } - } - }, - "EOF1_rjumpv_invalid_destination_4": { - "code": "0xef0001010004020001000804000000008000006000e20000036001", - "results": { - "Prague": { - "exception": "EOF_InvalidJumpDestination", - "result": false - } - } - }, - "EOF1_rjumpv_invalid_destination_5": { - "code": "0xef0001010004020001000f04000000008000006002e20200000003ffe56001006002", - "results": { - "Prague": { - "exception": "EOF_InvalidJumpDestination", - "result": false - } - } - }, - "EOF1_rjumpv_invalid_destination_6": { - "code": "0xef0001010004020001000f04000000008000006002e20200000003fff46001006002", - "results": { - "Prague": { - "exception": "EOF_InvalidJumpDestination", - "result": false - } - } - }, - "EOF1_rjumpv_invalid_destination_7": { - "code": "0xef0001010004020001000f04000000008000006002e20200000003ffff6001006002", - "results": { - "Prague": { - "exception": "EOF_InvalidJumpDestination", - "result": false - } - } - }, - "EOF1_rjumpv_invalid_destination_8": { - "code": "0xef0001010004020001000f04000000008000006002e2020000000300056001006002", - "results": { - "Prague": { - "exception": "EOF_InvalidJumpDestination", - "result": false - } - } - }, - "EOF1_rjumpv_invalid_destination_9": { - "code": "0xef0001010004020001000f04000000008000006002e2020000000300066001006002", - "results": { - "Prague": { - "exception": "EOF_InvalidJumpDestination", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_rjumpv_truncated.json b/crates/interpreter/tests/EOFTests/eof_validation/EOF1_rjumpv_truncated.json deleted file mode 100644 index 17c521a9e8..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_rjumpv_truncated.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "EOF1_rjumpv_truncated": { - "vectors": { - "EOF1_rjumpv_truncated_0": { - "code": "0xef0001010004020001000504000000008000006000e20000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_rjumpv_truncated_1": { - "code": "0xef0001010004020001000704000000008000006000e201000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_rjumpv_truncated_2": { - "code": "0xef0001010004020001000604000000008000006002e2010000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_rjumpv_truncated_3": { - "code": "0xef0001010004020001000904000000008000006002e20200000003ff", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_section_order.json b/crates/interpreter/tests/EOFTests/eof_validation/EOF1_section_order.json deleted file mode 100644 index 5bb7cf0c34..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_section_order.json +++ /dev/null @@ -1,94 +0,0 @@ -{ - "EOF1_section_order": { - "vectors": { - "EOF1_section_order_0": { - "code": "0xef0001010004020001000604000200008000016000e0000000aabb", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_section_order_1": { - "code": "0xef000101000404000202000100060000800000aabb6000e0000000", - "results": { - "Prague": { - "exception": "EOF_CodeSectionMissing", - "result": false - } - } - }, - "EOF1_section_order_2": { - "code": "0xef00010200010006010004040002006000e000000000800000aabb", - "results": { - "Prague": { - "exception": "EOF_TypeSectionMissing", - "result": false - } - } - }, - "EOF1_section_order_3": { - "code": "0xef00010200010006040002010004006000e0000000aabb00800000", - "results": { - "Prague": { - "exception": "EOF_TypeSectionMissing", - "result": false - } - } - }, - "EOF1_section_order_4": { - "code": "0xef0001040002010004020001000600aabb008000006000e0000000", - "results": { - "Prague": { - "exception": "EOF_TypeSectionMissing", - "result": false - } - } - }, - "EOF1_section_order_5": { - "code": "0xef0001040002020001000601000400aabb6000e000000000800000", - "results": { - "Prague": { - "exception": "EOF_TypeSectionMissing", - "result": false - } - } - }, - "EOF1_section_order_6": { - "code": "0xef00010100040200010006030001001404000200008000016000e0000000ef000101000402000100010400000000800000feaabb", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_section_order_7": { - "code": "0xef00010300010014010004020001000604000200ef000101000402000100010400000000800000fe008000016000e0000000aabb", - "results": { - "Prague": { - "exception": "EOF_TypeSectionMissing", - "result": false - } - } - }, - "EOF1_section_order_8": { - "code": "0xef0001010004030001001402000100060400020000800001ef000101000402000100010400000000800000fe6000e0000000aabb", - "results": { - "Prague": { - "exception": "EOF_CodeSectionMissing", - "result": false - } - } - }, - "EOF1_section_order_9": { - "code": "0xef00010100040200010006040002030001001400008000016000e0000000aabbef000101000402000100010400000000800000fe", - "results": { - "Prague": { - "exception": "EOF_HeaderTerminatorMissing", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_too_many_code_sections.json b/crates/interpreter/tests/EOFTests/eof_validation/EOF1_too_many_code_sections.json deleted file mode 100644 index 8fc104acfe..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_too_many_code_sections.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "EOF1_too_many_code_sections": { - "vectors": { - "invalid": { - "code": "0xef000101100202040100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001040000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000e50001e50002e50003e50004e50005e50006e50007e50008e50009e5000ae5000be5000ce5000de5000ee5000fe50010e50011e50012e50013e50014e50015e50016e50017e50018e50019e5001ae5001be5001ce5001de5001ee5001fe50020e50021e50022e50023e50024e50025e50026e50027e50028e50029e5002ae5002be5002ce5002de5002ee5002fe50030e50031e50032e50033e50034e50035e50036e50037e50038e50039e5003ae5003be5003ce5003de5003ee5003fe50040e50041e50042e50043e50044e50045e50046e50047e50048e50049e5004ae5004be5004ce5004de5004ee5004fe50050e50051e50052e50053e50054e50055e50056e50057e50058e50059e5005ae5005be5005ce5005de5005ee5005fe50060e50061e50062e50063e50064e50065e50066e50067e50068e50069e5006ae5006be5006ce5006de5006ee5006fe50070e50071e50072e50073e50074e50075e50076e50077e50078e50079e5007ae5007be5007ce5007de5007ee5007fe50080e50081e50082e50083e50084e50085e50086e50087e50088e50089e5008ae5008be5008ce5008de5008ee5008fe50090e50091e50092e50093e50094e50095e50096e50097e50098e50099e5009ae5009be5009ce5009de5009ee5009fe500a0e500a1e500a2e500a3e500a4e500a5e500a6e500a7e500a8e500a9e500aae500abe500ace500ade500aee500afe500b0e500b1e500b2e500b3e500b4e500b5e500b6e500b7e500b8e500b9e500bae500bbe500bce500bde500bee500bfe500c0e500c1e500c2e500c3e500c4e500c5e500c6e500c7e500c8e500c9e500cae500cbe500cce500cde500cee500cfe500d0e500d1e500d2e500d3e500d4e500d5e500d6e500d7e500d8e500d9e500dae500dbe500dce500dde500dee500dfe500e0e500e1e500e2e500e3e500e4e500e5e500e6e500e7e500e8e500e9e500eae500ebe500ece500ede500eee500efe500f0e500f1e500f2e500f3e500f4e500f5e500f6e500f7e500f8e500f9e500fae500fbe500fce500fde500fee500ffe50100e50101e50102e50103e50104e50105e50106e50107e50108e50109e5010ae5010be5010ce5010de5010ee5010fe50110e50111e50112e50113e50114e50115e50116e50117e50118e50119e5011ae5011be5011ce5011de5011ee5011fe50120e50121e50122e50123e50124e50125e50126e50127e50128e50129e5012ae5012be5012ce5012de5012ee5012fe50130e50131e50132e50133e50134e50135e50136e50137e50138e50139e5013ae5013be5013ce5013de5013ee5013fe50140e50141e50142e50143e50144e50145e50146e50147e50148e50149e5014ae5014be5014ce5014de5014ee5014fe50150e50151e50152e50153e50154e50155e50156e50157e50158e50159e5015ae5015be5015ce5015de5015ee5015fe50160e50161e50162e50163e50164e50165e50166e50167e50168e50169e5016ae5016be5016ce5016de5016ee5016fe50170e50171e50172e50173e50174e50175e50176e50177e50178e50179e5017ae5017be5017ce5017de5017ee5017fe50180e50181e50182e50183e50184e50185e50186e50187e50188e50189e5018ae5018be5018ce5018de5018ee5018fe50190e50191e50192e50193e50194e50195e50196e50197e50198e50199e5019ae5019be5019ce5019de5019ee5019fe501a0e501a1e501a2e501a3e501a4e501a5e501a6e501a7e501a8e501a9e501aae501abe501ace501ade501aee501afe501b0e501b1e501b2e501b3e501b4e501b5e501b6e501b7e501b8e501b9e501bae501bbe501bce501bde501bee501bfe501c0e501c1e501c2e501c3e501c4e501c5e501c6e501c7e501c8e501c9e501cae501cbe501cce501cde501cee501cfe501d0e501d1e501d2e501d3e501d4e501d5e501d6e501d7e501d8e501d9e501dae501dbe501dce501dde501dee501dfe501e0e501e1e501e2e501e3e501e4e501e5e501e6e501e7e501e8e501e9e501eae501ebe501ece501ede501eee501efe501f0e501f1e501f2e501f3e501f4e501f5e501f6e501f7e501f8e501f9e501fae501fbe501fce501fde501fee501ffe50200e50201e50202e50203e50204e50205e50206e50207e50208e50209e5020ae5020be5020ce5020de5020ee5020fe50210e50211e50212e50213e50214e50215e50216e50217e50218e50219e5021ae5021be5021ce5021de5021ee5021fe50220e50221e50222e50223e50224e50225e50226e50227e50228e50229e5022ae5022be5022ce5022de5022ee5022fe50230e50231e50232e50233e50234e50235e50236e50237e50238e50239e5023ae5023be5023ce5023de5023ee5023fe50240e50241e50242e50243e50244e50245e50246e50247e50248e50249e5024ae5024be5024ce5024de5024ee5024fe50250e50251e50252e50253e50254e50255e50256e50257e50258e50259e5025ae5025be5025ce5025de5025ee5025fe50260e50261e50262e50263e50264e50265e50266e50267e50268e50269e5026ae5026be5026ce5026de5026ee5026fe50270e50271e50272e50273e50274e50275e50276e50277e50278e50279e5027ae5027be5027ce5027de5027ee5027fe50280e50281e50282e50283e50284e50285e50286e50287e50288e50289e5028ae5028be5028ce5028de5028ee5028fe50290e50291e50292e50293e50294e50295e50296e50297e50298e50299e5029ae5029be5029ce5029de5029ee5029fe502a0e502a1e502a2e502a3e502a4e502a5e502a6e502a7e502a8e502a9e502aae502abe502ace502ade502aee502afe502b0e502b1e502b2e502b3e502b4e502b5e502b6e502b7e502b8e502b9e502bae502bbe502bce502bde502bee502bfe502c0e502c1e502c2e502c3e502c4e502c5e502c6e502c7e502c8e502c9e502cae502cbe502cce502cde502cee502cfe502d0e502d1e502d2e502d3e502d4e502d5e502d6e502d7e502d8e502d9e502dae502dbe502dce502dde502dee502dfe502e0e502e1e502e2e502e3e502e4e502e5e502e6e502e7e502e8e502e9e502eae502ebe502ece502ede502eee502efe502f0e502f1e502f2e502f3e502f4e502f5e502f6e502f7e502f8e502f9e502fae502fbe502fce502fde502fee502ffe50300e50301e50302e50303e50304e50305e50306e50307e50308e50309e5030ae5030be5030ce5030de5030ee5030fe50310e50311e50312e50313e50314e50315e50316e50317e50318e50319e5031ae5031be5031ce5031de5031ee5031fe50320e50321e50322e50323e50324e50325e50326e50327e50328e50329e5032ae5032be5032ce5032de5032ee5032fe50330e50331e50332e50333e50334e50335e50336e50337e50338e50339e5033ae5033be5033ce5033de5033ee5033fe50340e50341e50342e50343e50344e50345e50346e50347e50348e50349e5034ae5034be5034ce5034de5034ee5034fe50350e50351e50352e50353e50354e50355e50356e50357e50358e50359e5035ae5035be5035ce5035de5035ee5035fe50360e50361e50362e50363e50364e50365e50366e50367e50368e50369e5036ae5036be5036ce5036de5036ee5036fe50370e50371e50372e50373e50374e50375e50376e50377e50378e50379e5037ae5037be5037ce5037de5037ee5037fe50380e50381e50382e50383e50384e50385e50386e50387e50388e50389e5038ae5038be5038ce5038de5038ee5038fe50390e50391e50392e50393e50394e50395e50396e50397e50398e50399e5039ae5039be5039ce5039de5039ee5039fe503a0e503a1e503a2e503a3e503a4e503a5e503a6e503a7e503a8e503a9e503aae503abe503ace503ade503aee503afe503b0e503b1e503b2e503b3e503b4e503b5e503b6e503b7e503b8e503b9e503bae503bbe503bce503bde503bee503bfe503c0e503c1e503c2e503c3e503c4e503c5e503c6e503c7e503c8e503c9e503cae503cbe503cce503cde503cee503cfe503d0e503d1e503d2e503d3e503d4e503d5e503d6e503d7e503d8e503d9e503dae503dbe503dce503dde503dee503dfe503e0e503e1e503e2e503e3e503e4e503e5e503e6e503e7e503e8e503e9e503eae503ebe503ece503ede503eee503efe503f0e503f1e503f2e503f3e503f4e503f5e503f6e503f7e503f8e503f9e503fae503fbe503fce503fde503fee503ffe504005b5b00", - "results": { - "Prague": { - "exception": "EOF_TooManyCodeSections", - "result": false - } - } - }, - "valid": { - "code": "0xef000101100002040000030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030400000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000e50001e50002e50003e50004e50005e50006e50007e50008e50009e5000ae5000be5000ce5000de5000ee5000fe50010e50011e50012e50013e50014e50015e50016e50017e50018e50019e5001ae5001be5001ce5001de5001ee5001fe50020e50021e50022e50023e50024e50025e50026e50027e50028e50029e5002ae5002be5002ce5002de5002ee5002fe50030e50031e50032e50033e50034e50035e50036e50037e50038e50039e5003ae5003be5003ce5003de5003ee5003fe50040e50041e50042e50043e50044e50045e50046e50047e50048e50049e5004ae5004be5004ce5004de5004ee5004fe50050e50051e50052e50053e50054e50055e50056e50057e50058e50059e5005ae5005be5005ce5005de5005ee5005fe50060e50061e50062e50063e50064e50065e50066e50067e50068e50069e5006ae5006be5006ce5006de5006ee5006fe50070e50071e50072e50073e50074e50075e50076e50077e50078e50079e5007ae5007be5007ce5007de5007ee5007fe50080e50081e50082e50083e50084e50085e50086e50087e50088e50089e5008ae5008be5008ce5008de5008ee5008fe50090e50091e50092e50093e50094e50095e50096e50097e50098e50099e5009ae5009be5009ce5009de5009ee5009fe500a0e500a1e500a2e500a3e500a4e500a5e500a6e500a7e500a8e500a9e500aae500abe500ace500ade500aee500afe500b0e500b1e500b2e500b3e500b4e500b5e500b6e500b7e500b8e500b9e500bae500bbe500bce500bde500bee500bfe500c0e500c1e500c2e500c3e500c4e500c5e500c6e500c7e500c8e500c9e500cae500cbe500cce500cde500cee500cfe500d0e500d1e500d2e500d3e500d4e500d5e500d6e500d7e500d8e500d9e500dae500dbe500dce500dde500dee500dfe500e0e500e1e500e2e500e3e500e4e500e5e500e6e500e7e500e8e500e9e500eae500ebe500ece500ede500eee500efe500f0e500f1e500f2e500f3e500f4e500f5e500f6e500f7e500f8e500f9e500fae500fbe500fce500fde500fee500ffe50100e50101e50102e50103e50104e50105e50106e50107e50108e50109e5010ae5010be5010ce5010de5010ee5010fe50110e50111e50112e50113e50114e50115e50116e50117e50118e50119e5011ae5011be5011ce5011de5011ee5011fe50120e50121e50122e50123e50124e50125e50126e50127e50128e50129e5012ae5012be5012ce5012de5012ee5012fe50130e50131e50132e50133e50134e50135e50136e50137e50138e50139e5013ae5013be5013ce5013de5013ee5013fe50140e50141e50142e50143e50144e50145e50146e50147e50148e50149e5014ae5014be5014ce5014de5014ee5014fe50150e50151e50152e50153e50154e50155e50156e50157e50158e50159e5015ae5015be5015ce5015de5015ee5015fe50160e50161e50162e50163e50164e50165e50166e50167e50168e50169e5016ae5016be5016ce5016de5016ee5016fe50170e50171e50172e50173e50174e50175e50176e50177e50178e50179e5017ae5017be5017ce5017de5017ee5017fe50180e50181e50182e50183e50184e50185e50186e50187e50188e50189e5018ae5018be5018ce5018de5018ee5018fe50190e50191e50192e50193e50194e50195e50196e50197e50198e50199e5019ae5019be5019ce5019de5019ee5019fe501a0e501a1e501a2e501a3e501a4e501a5e501a6e501a7e501a8e501a9e501aae501abe501ace501ade501aee501afe501b0e501b1e501b2e501b3e501b4e501b5e501b6e501b7e501b8e501b9e501bae501bbe501bce501bde501bee501bfe501c0e501c1e501c2e501c3e501c4e501c5e501c6e501c7e501c8e501c9e501cae501cbe501cce501cde501cee501cfe501d0e501d1e501d2e501d3e501d4e501d5e501d6e501d7e501d8e501d9e501dae501dbe501dce501dde501dee501dfe501e0e501e1e501e2e501e3e501e4e501e5e501e6e501e7e501e8e501e9e501eae501ebe501ece501ede501eee501efe501f0e501f1e501f2e501f3e501f4e501f5e501f6e501f7e501f8e501f9e501fae501fbe501fce501fde501fee501ffe50200e50201e50202e50203e50204e50205e50206e50207e50208e50209e5020ae5020be5020ce5020de5020ee5020fe50210e50211e50212e50213e50214e50215e50216e50217e50218e50219e5021ae5021be5021ce5021de5021ee5021fe50220e50221e50222e50223e50224e50225e50226e50227e50228e50229e5022ae5022be5022ce5022de5022ee5022fe50230e50231e50232e50233e50234e50235e50236e50237e50238e50239e5023ae5023be5023ce5023de5023ee5023fe50240e50241e50242e50243e50244e50245e50246e50247e50248e50249e5024ae5024be5024ce5024de5024ee5024fe50250e50251e50252e50253e50254e50255e50256e50257e50258e50259e5025ae5025be5025ce5025de5025ee5025fe50260e50261e50262e50263e50264e50265e50266e50267e50268e50269e5026ae5026be5026ce5026de5026ee5026fe50270e50271e50272e50273e50274e50275e50276e50277e50278e50279e5027ae5027be5027ce5027de5027ee5027fe50280e50281e50282e50283e50284e50285e50286e50287e50288e50289e5028ae5028be5028ce5028de5028ee5028fe50290e50291e50292e50293e50294e50295e50296e50297e50298e50299e5029ae5029be5029ce5029de5029ee5029fe502a0e502a1e502a2e502a3e502a4e502a5e502a6e502a7e502a8e502a9e502aae502abe502ace502ade502aee502afe502b0e502b1e502b2e502b3e502b4e502b5e502b6e502b7e502b8e502b9e502bae502bbe502bce502bde502bee502bfe502c0e502c1e502c2e502c3e502c4e502c5e502c6e502c7e502c8e502c9e502cae502cbe502cce502cde502cee502cfe502d0e502d1e502d2e502d3e502d4e502d5e502d6e502d7e502d8e502d9e502dae502dbe502dce502dde502dee502dfe502e0e502e1e502e2e502e3e502e4e502e5e502e6e502e7e502e8e502e9e502eae502ebe502ece502ede502eee502efe502f0e502f1e502f2e502f3e502f4e502f5e502f6e502f7e502f8e502f9e502fae502fbe502fce502fde502fee502ffe50300e50301e50302e50303e50304e50305e50306e50307e50308e50309e5030ae5030be5030ce5030de5030ee5030fe50310e50311e50312e50313e50314e50315e50316e50317e50318e50319e5031ae5031be5031ce5031de5031ee5031fe50320e50321e50322e50323e50324e50325e50326e50327e50328e50329e5032ae5032be5032ce5032de5032ee5032fe50330e50331e50332e50333e50334e50335e50336e50337e50338e50339e5033ae5033be5033ce5033de5033ee5033fe50340e50341e50342e50343e50344e50345e50346e50347e50348e50349e5034ae5034be5034ce5034de5034ee5034fe50350e50351e50352e50353e50354e50355e50356e50357e50358e50359e5035ae5035be5035ce5035de5035ee5035fe50360e50361e50362e50363e50364e50365e50366e50367e50368e50369e5036ae5036be5036ce5036de5036ee5036fe50370e50371e50372e50373e50374e50375e50376e50377e50378e50379e5037ae5037be5037ce5037de5037ee5037fe50380e50381e50382e50383e50384e50385e50386e50387e50388e50389e5038ae5038be5038ce5038de5038ee5038fe50390e50391e50392e50393e50394e50395e50396e50397e50398e50399e5039ae5039be5039ce5039de5039ee5039fe503a0e503a1e503a2e503a3e503a4e503a5e503a6e503a7e503a8e503a9e503aae503abe503ace503ade503aee503afe503b0e503b1e503b2e503b3e503b4e503b5e503b6e503b7e503b8e503b9e503bae503bbe503bce503bde503bee503bfe503c0e503c1e503c2e503c3e503c4e503c5e503c6e503c7e503c8e503c9e503cae503cbe503cce503cde503cee503cfe503d0e503d1e503d2e503d3e503d4e503d5e503d6e503d7e503d8e503d9e503dae503dbe503dce503dde503dee503dfe503e0e503e1e503e2e503e3e503e4e503e5e503e6e503e7e503e8e503e9e503eae503ebe503ece503ede503eee503efe503f0e503f1e503f2e503f3e503f4e503f5e503f6e503f7e503f8e503f9e503fae503fbe503fce503fde503fee503ff5b5b00", - "results": { - "Prague": { - "result": true - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_trailing_bytes.json b/crates/interpreter/tests/EOFTests/eof_validation/EOF1_trailing_bytes.json deleted file mode 100644 index 1c77f0921a..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_trailing_bytes.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "EOF1_trailing_bytes": { - "vectors": { - "EOF1_trailing_bytes_0": { - "code": "0xef000101000402000100010400000000800000fedeadbeef", - "results": { - "Prague": { - "exception": "EOF_InvalidSectionBodiesSize", - "result": false - } - } - }, - "EOF1_trailing_bytes_1": { - "code": "0xef000101000402000100010400020000800000feaabbdeadbeef", - "results": { - "Prague": { - "exception": "EOF_InvalidSectionBodiesSize", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_truncated_push.json b/crates/interpreter/tests/EOFTests/eof_validation/EOF1_truncated_push.json deleted file mode 100644 index 893f226fee..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_truncated_push.json +++ /dev/null @@ -1,5014 +0,0 @@ -{ - "EOF1_truncated_push": { - "vectors": { - "EOF1_truncated_push_0": { - "code": "0xef00010100040200010001040000000080000060", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_1": { - "code": "0xef000101000402000100030400000000800001600000", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_truncated_push_10": { - "code": "0xef0001010004020001000204000000008000016300", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_100": { - "code": "0xef0001010004020001000b04000000008000016c00000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_101": { - "code": "0xef0001010004020001000c04000000008000016c0000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_102": { - "code": "0xef0001010004020001000d04000000008000016c000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_103": { - "code": "0xef0001010004020001000f04000000008000016c0000000000000000000000000000", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_truncated_push_104": { - "code": "0xef0001010004020001000104000000008000016d", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_105": { - "code": "0xef0001010004020001000204000000008000016d00", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_106": { - "code": "0xef0001010004020001000304000000008000016d0000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_107": { - "code": "0xef0001010004020001000404000000008000016d000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_108": { - "code": "0xef0001010004020001000504000000008000016d00000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_109": { - "code": "0xef0001010004020001000604000000008000016d0000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_11": { - "code": "0xef000101000402000100030400000000800001630000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_110": { - "code": "0xef0001010004020001000704000000008000016d000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_111": { - "code": "0xef0001010004020001000804000000008000016d00000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_112": { - "code": "0xef0001010004020001000904000000008000016d0000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_113": { - "code": "0xef0001010004020001000a04000000008000016d000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_114": { - "code": "0xef0001010004020001000b04000000008000016d00000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_115": { - "code": "0xef0001010004020001000c04000000008000016d0000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_116": { - "code": "0xef0001010004020001000d04000000008000016d000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_117": { - "code": "0xef0001010004020001000e04000000008000016d00000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_118": { - "code": "0xef0001010004020001001004000000008000016d000000000000000000000000000000", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_truncated_push_119": { - "code": "0xef0001010004020001000104000000008000016e", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_12": { - "code": "0xef00010100040200010004040000000080000163000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_120": { - "code": "0xef0001010004020001000204000000008000016e00", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_121": { - "code": "0xef0001010004020001000304000000008000016e0000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_122": { - "code": "0xef0001010004020001000404000000008000016e000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_123": { - "code": "0xef0001010004020001000504000000008000016e00000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_124": { - "code": "0xef0001010004020001000604000000008000016e0000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_125": { - "code": "0xef0001010004020001000704000000008000016e000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_126": { - "code": "0xef0001010004020001000804000000008000016e00000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_127": { - "code": "0xef0001010004020001000904000000008000016e0000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_128": { - "code": "0xef0001010004020001000a04000000008000016e000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_129": { - "code": "0xef0001010004020001000b04000000008000016e00000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_13": { - "code": "0xef000101000402000100060400000000800001630000000000", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_truncated_push_130": { - "code": "0xef0001010004020001000c04000000008000016e0000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_131": { - "code": "0xef0001010004020001000d04000000008000016e000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_132": { - "code": "0xef0001010004020001000e04000000008000016e00000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_133": { - "code": "0xef0001010004020001000f04000000008000016e0000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_134": { - "code": "0xef0001010004020001001104000000008000016e00000000000000000000000000000000", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_truncated_push_135": { - "code": "0xef0001010004020001000104000000008000016f", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_136": { - "code": "0xef0001010004020001000204000000008000016f00", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_137": { - "code": "0xef0001010004020001000304000000008000016f0000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_138": { - "code": "0xef0001010004020001000404000000008000016f000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_139": { - "code": "0xef0001010004020001000504000000008000016f00000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_14": { - "code": "0xef00010100040200010001040000000080000164", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_140": { - "code": "0xef0001010004020001000604000000008000016f0000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_141": { - "code": "0xef0001010004020001000704000000008000016f000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_142": { - "code": "0xef0001010004020001000804000000008000016f00000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_143": { - "code": "0xef0001010004020001000904000000008000016f0000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_144": { - "code": "0xef0001010004020001000a04000000008000016f000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_145": { - "code": "0xef0001010004020001000b04000000008000016f00000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_146": { - "code": "0xef0001010004020001000c04000000008000016f0000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_147": { - "code": "0xef0001010004020001000d04000000008000016f000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_148": { - "code": "0xef0001010004020001000e04000000008000016f00000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_149": { - "code": "0xef0001010004020001000f04000000008000016f0000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_15": { - "code": "0xef0001010004020001000204000000008000016400", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_150": { - "code": "0xef0001010004020001001004000000008000016f000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_151": { - "code": "0xef0001010004020001001204000000008000016f0000000000000000000000000000000000", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_truncated_push_152": { - "code": "0xef00010100040200010001040000000080000170", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_153": { - "code": "0xef0001010004020001000204000000008000017000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_154": { - "code": "0xef000101000402000100030400000000800001700000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_155": { - "code": "0xef00010100040200010004040000000080000170000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_156": { - "code": "0xef0001010004020001000504000000008000017000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_157": { - "code": "0xef000101000402000100060400000000800001700000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_158": { - "code": "0xef00010100040200010007040000000080000170000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_159": { - "code": "0xef0001010004020001000804000000008000017000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_16": { - "code": "0xef000101000402000100030400000000800001640000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_160": { - "code": "0xef000101000402000100090400000000800001700000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_161": { - "code": "0xef0001010004020001000a040000000080000170000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_162": { - "code": "0xef0001010004020001000b04000000008000017000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_163": { - "code": "0xef0001010004020001000c0400000000800001700000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_164": { - "code": "0xef0001010004020001000d040000000080000170000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_165": { - "code": "0xef0001010004020001000e04000000008000017000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_166": { - "code": "0xef0001010004020001000f0400000000800001700000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_167": { - "code": "0xef00010100040200010010040000000080000170000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_168": { - "code": "0xef0001010004020001001104000000008000017000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_169": { - "code": "0xef00010100040200010013040000000080000170000000000000000000000000000000000000", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_truncated_push_17": { - "code": "0xef00010100040200010004040000000080000164000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_170": { - "code": "0xef00010100040200010001040000000080000171", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_171": { - "code": "0xef0001010004020001000204000000008000017100", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_172": { - "code": "0xef000101000402000100030400000000800001710000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_173": { - "code": "0xef00010100040200010004040000000080000171000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_174": { - "code": "0xef0001010004020001000504000000008000017100000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_175": { - "code": "0xef000101000402000100060400000000800001710000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_176": { - "code": "0xef00010100040200010007040000000080000171000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_177": { - "code": "0xef0001010004020001000804000000008000017100000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_178": { - "code": "0xef000101000402000100090400000000800001710000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_179": { - "code": "0xef0001010004020001000a040000000080000171000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_18": { - "code": "0xef0001010004020001000504000000008000016400000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_180": { - "code": "0xef0001010004020001000b04000000008000017100000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_181": { - "code": "0xef0001010004020001000c0400000000800001710000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_182": { - "code": "0xef0001010004020001000d040000000080000171000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_183": { - "code": "0xef0001010004020001000e04000000008000017100000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_184": { - "code": "0xef0001010004020001000f0400000000800001710000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_185": { - "code": "0xef00010100040200010010040000000080000171000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_186": { - "code": "0xef0001010004020001001104000000008000017100000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_187": { - "code": "0xef000101000402000100120400000000800001710000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_188": { - "code": "0xef0001010004020001001404000000008000017100000000000000000000000000000000000000", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_truncated_push_189": { - "code": "0xef00010100040200010001040000000080000172", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_19": { - "code": "0xef00010100040200010007040000000080000164000000000000", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_truncated_push_190": { - "code": "0xef0001010004020001000204000000008000017200", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_191": { - "code": "0xef000101000402000100030400000000800001720000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_192": { - "code": "0xef00010100040200010004040000000080000172000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_193": { - "code": "0xef0001010004020001000504000000008000017200000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_194": { - "code": "0xef000101000402000100060400000000800001720000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_195": { - "code": "0xef00010100040200010007040000000080000172000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_196": { - "code": "0xef0001010004020001000804000000008000017200000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_197": { - "code": "0xef000101000402000100090400000000800001720000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_198": { - "code": "0xef0001010004020001000a040000000080000172000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_199": { - "code": "0xef0001010004020001000b04000000008000017200000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_2": { - "code": "0xef00010100040200010001040000000080000161", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_20": { - "code": "0xef00010100040200010001040000000080000165", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_200": { - "code": "0xef0001010004020001000c0400000000800001720000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_201": { - "code": "0xef0001010004020001000d040000000080000172000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_202": { - "code": "0xef0001010004020001000e04000000008000017200000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_203": { - "code": "0xef0001010004020001000f0400000000800001720000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_204": { - "code": "0xef00010100040200010010040000000080000172000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_205": { - "code": "0xef0001010004020001001104000000008000017200000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_206": { - "code": "0xef000101000402000100120400000000800001720000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_207": { - "code": "0xef00010100040200010013040000000080000172000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_208": { - "code": "0xef000101000402000100150400000000800001720000000000000000000000000000000000000000", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_truncated_push_209": { - "code": "0xef00010100040200010001040000000080000173", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_21": { - "code": "0xef0001010004020001000204000000008000016500", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_210": { - "code": "0xef0001010004020001000204000000008000017300", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_211": { - "code": "0xef000101000402000100030400000000800001730000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_212": { - "code": "0xef00010100040200010004040000000080000173000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_213": { - "code": "0xef0001010004020001000504000000008000017300000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_214": { - "code": "0xef000101000402000100060400000000800001730000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_215": { - "code": "0xef00010100040200010007040000000080000173000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_216": { - "code": "0xef0001010004020001000804000000008000017300000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_217": { - "code": "0xef000101000402000100090400000000800001730000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_218": { - "code": "0xef0001010004020001000a040000000080000173000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_219": { - "code": "0xef0001010004020001000b04000000008000017300000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_22": { - "code": "0xef000101000402000100030400000000800001650000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_220": { - "code": "0xef0001010004020001000c0400000000800001730000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_221": { - "code": "0xef0001010004020001000d040000000080000173000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_222": { - "code": "0xef0001010004020001000e04000000008000017300000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_223": { - "code": "0xef0001010004020001000f0400000000800001730000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_224": { - "code": "0xef00010100040200010010040000000080000173000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_225": { - "code": "0xef0001010004020001001104000000008000017300000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_226": { - "code": "0xef000101000402000100120400000000800001730000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_227": { - "code": "0xef00010100040200010013040000000080000173000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_228": { - "code": "0xef0001010004020001001404000000008000017300000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_229": { - "code": "0xef00010100040200010016040000000080000173000000000000000000000000000000000000000000", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_truncated_push_23": { - "code": "0xef00010100040200010004040000000080000165000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_230": { - "code": "0xef00010100040200010001040000000080000174", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_231": { - "code": "0xef0001010004020001000204000000008000017400", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_232": { - "code": "0xef000101000402000100030400000000800001740000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_233": { - "code": "0xef00010100040200010004040000000080000174000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_234": { - "code": "0xef0001010004020001000504000000008000017400000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_235": { - "code": "0xef000101000402000100060400000000800001740000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_236": { - "code": "0xef00010100040200010007040000000080000174000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_237": { - "code": "0xef0001010004020001000804000000008000017400000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_238": { - "code": "0xef000101000402000100090400000000800001740000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_239": { - "code": "0xef0001010004020001000a040000000080000174000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_24": { - "code": "0xef0001010004020001000504000000008000016500000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_240": { - "code": "0xef0001010004020001000b04000000008000017400000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_241": { - "code": "0xef0001010004020001000c0400000000800001740000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_242": { - "code": "0xef0001010004020001000d040000000080000174000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_243": { - "code": "0xef0001010004020001000e04000000008000017400000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_244": { - "code": "0xef0001010004020001000f0400000000800001740000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_245": { - "code": "0xef00010100040200010010040000000080000174000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_246": { - "code": "0xef0001010004020001001104000000008000017400000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_247": { - "code": "0xef000101000402000100120400000000800001740000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_248": { - "code": "0xef00010100040200010013040000000080000174000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_249": { - "code": "0xef0001010004020001001404000000008000017400000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_25": { - "code": "0xef000101000402000100060400000000800001650000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_250": { - "code": "0xef000101000402000100150400000000800001740000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_251": { - "code": "0xef0001010004020001001704000000008000017400000000000000000000000000000000000000000000", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_truncated_push_252": { - "code": "0xef00010100040200010001040000000080000175", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_253": { - "code": "0xef0001010004020001000204000000008000017500", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_254": { - "code": "0xef000101000402000100030400000000800001750000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_255": { - "code": "0xef00010100040200010004040000000080000175000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_256": { - "code": "0xef0001010004020001000504000000008000017500000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_257": { - "code": "0xef000101000402000100060400000000800001750000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_258": { - "code": "0xef00010100040200010007040000000080000175000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_259": { - "code": "0xef0001010004020001000804000000008000017500000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_26": { - "code": "0xef0001010004020001000804000000008000016500000000000000", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_truncated_push_260": { - "code": "0xef000101000402000100090400000000800001750000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_261": { - "code": "0xef0001010004020001000a040000000080000175000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_262": { - "code": "0xef0001010004020001000b04000000008000017500000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_263": { - "code": "0xef0001010004020001000c0400000000800001750000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_264": { - "code": "0xef0001010004020001000d040000000080000175000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_265": { - "code": "0xef0001010004020001000e04000000008000017500000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_266": { - "code": "0xef0001010004020001000f0400000000800001750000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_267": { - "code": "0xef00010100040200010010040000000080000175000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_268": { - "code": "0xef0001010004020001001104000000008000017500000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_269": { - "code": "0xef000101000402000100120400000000800001750000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_27": { - "code": "0xef00010100040200010001040000000080000166", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_270": { - "code": "0xef00010100040200010013040000000080000175000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_271": { - "code": "0xef0001010004020001001404000000008000017500000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_272": { - "code": "0xef000101000402000100150400000000800001750000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_273": { - "code": "0xef00010100040200010016040000000080000175000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_274": { - "code": "0xef000101000402000100180400000000800001750000000000000000000000000000000000000000000000", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_truncated_push_275": { - "code": "0xef00010100040200010001040000000080000176", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_276": { - "code": "0xef0001010004020001000204000000008000017600", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_277": { - "code": "0xef000101000402000100030400000000800001760000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_278": { - "code": "0xef00010100040200010004040000000080000176000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_279": { - "code": "0xef0001010004020001000504000000008000017600000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_28": { - "code": "0xef0001010004020001000204000000008000016600", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_280": { - "code": "0xef000101000402000100060400000000800001760000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_281": { - "code": "0xef00010100040200010007040000000080000176000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_282": { - "code": "0xef0001010004020001000804000000008000017600000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_283": { - "code": "0xef000101000402000100090400000000800001760000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_284": { - "code": "0xef0001010004020001000a040000000080000176000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_285": { - "code": "0xef0001010004020001000b04000000008000017600000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_286": { - "code": "0xef0001010004020001000c0400000000800001760000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_287": { - "code": "0xef0001010004020001000d040000000080000176000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_288": { - "code": "0xef0001010004020001000e04000000008000017600000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_289": { - "code": "0xef0001010004020001000f0400000000800001760000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_29": { - "code": "0xef000101000402000100030400000000800001660000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_290": { - "code": "0xef00010100040200010010040000000080000176000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_291": { - "code": "0xef0001010004020001001104000000008000017600000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_292": { - "code": "0xef000101000402000100120400000000800001760000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_293": { - "code": "0xef00010100040200010013040000000080000176000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_294": { - "code": "0xef0001010004020001001404000000008000017600000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_295": { - "code": "0xef000101000402000100150400000000800001760000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_296": { - "code": "0xef00010100040200010016040000000080000176000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_297": { - "code": "0xef0001010004020001001704000000008000017600000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_298": { - "code": "0xef00010100040200010019040000000080000176000000000000000000000000000000000000000000000000", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_truncated_push_299": { - "code": "0xef00010100040200010001040000000080000177", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_3": { - "code": "0xef0001010004020001000204000000008000016100", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_30": { - "code": "0xef00010100040200010004040000000080000166000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_300": { - "code": "0xef0001010004020001000204000000008000017700", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_301": { - "code": "0xef000101000402000100030400000000800001770000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_302": { - "code": "0xef00010100040200010004040000000080000177000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_303": { - "code": "0xef0001010004020001000504000000008000017700000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_304": { - "code": "0xef000101000402000100060400000000800001770000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_305": { - "code": "0xef00010100040200010007040000000080000177000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_306": { - "code": "0xef0001010004020001000804000000008000017700000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_307": { - "code": "0xef000101000402000100090400000000800001770000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_308": { - "code": "0xef0001010004020001000a040000000080000177000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_309": { - "code": "0xef0001010004020001000b04000000008000017700000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_31": { - "code": "0xef0001010004020001000504000000008000016600000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_310": { - "code": "0xef0001010004020001000c0400000000800001770000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_311": { - "code": "0xef0001010004020001000d040000000080000177000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_312": { - "code": "0xef0001010004020001000e04000000008000017700000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_313": { - "code": "0xef0001010004020001000f0400000000800001770000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_314": { - "code": "0xef00010100040200010010040000000080000177000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_315": { - "code": "0xef0001010004020001001104000000008000017700000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_316": { - "code": "0xef000101000402000100120400000000800001770000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_317": { - "code": "0xef00010100040200010013040000000080000177000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_318": { - "code": "0xef0001010004020001001404000000008000017700000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_319": { - "code": "0xef000101000402000100150400000000800001770000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_32": { - "code": "0xef000101000402000100060400000000800001660000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_320": { - "code": "0xef00010100040200010016040000000080000177000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_321": { - "code": "0xef0001010004020001001704000000008000017700000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_322": { - "code": "0xef000101000402000100180400000000800001770000000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_323": { - "code": "0xef0001010004020001001a04000000008000017700000000000000000000000000000000000000000000000000", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_truncated_push_324": { - "code": "0xef00010100040200010001040000000080000178", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_325": { - "code": "0xef0001010004020001000204000000008000017800", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_326": { - "code": "0xef000101000402000100030400000000800001780000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_327": { - "code": "0xef00010100040200010004040000000080000178000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_328": { - "code": "0xef0001010004020001000504000000008000017800000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_329": { - "code": "0xef000101000402000100060400000000800001780000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_33": { - "code": "0xef00010100040200010007040000000080000166000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_330": { - "code": "0xef00010100040200010007040000000080000178000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_331": { - "code": "0xef0001010004020001000804000000008000017800000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_332": { - "code": "0xef000101000402000100090400000000800001780000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_333": { - "code": "0xef0001010004020001000a040000000080000178000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_334": { - "code": "0xef0001010004020001000b04000000008000017800000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_335": { - "code": "0xef0001010004020001000c0400000000800001780000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_336": { - "code": "0xef0001010004020001000d040000000080000178000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_337": { - "code": "0xef0001010004020001000e04000000008000017800000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_338": { - "code": "0xef0001010004020001000f0400000000800001780000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_339": { - "code": "0xef00010100040200010010040000000080000178000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_34": { - "code": "0xef000101000402000100090400000000800001660000000000000000", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_truncated_push_340": { - "code": "0xef0001010004020001001104000000008000017800000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_341": { - "code": "0xef000101000402000100120400000000800001780000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_342": { - "code": "0xef00010100040200010013040000000080000178000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_343": { - "code": "0xef0001010004020001001404000000008000017800000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_344": { - "code": "0xef000101000402000100150400000000800001780000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_345": { - "code": "0xef00010100040200010016040000000080000178000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_346": { - "code": "0xef0001010004020001001704000000008000017800000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_347": { - "code": "0xef000101000402000100180400000000800001780000000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_348": { - "code": "0xef00010100040200010019040000000080000178000000000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_349": { - "code": "0xef0001010004020001001b0400000000800001780000000000000000000000000000000000000000000000000000", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_truncated_push_35": { - "code": "0xef00010100040200010001040000000080000167", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_350": { - "code": "0xef00010100040200010001040000000080000179", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_351": { - "code": "0xef0001010004020001000204000000008000017900", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_352": { - "code": "0xef000101000402000100030400000000800001790000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_353": { - "code": "0xef00010100040200010004040000000080000179000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_354": { - "code": "0xef0001010004020001000504000000008000017900000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_355": { - "code": "0xef000101000402000100060400000000800001790000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_356": { - "code": "0xef00010100040200010007040000000080000179000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_357": { - "code": "0xef0001010004020001000804000000008000017900000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_358": { - "code": "0xef000101000402000100090400000000800001790000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_359": { - "code": "0xef0001010004020001000a040000000080000179000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_36": { - "code": "0xef0001010004020001000204000000008000016700", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_360": { - "code": "0xef0001010004020001000b04000000008000017900000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_361": { - "code": "0xef0001010004020001000c0400000000800001790000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_362": { - "code": "0xef0001010004020001000d040000000080000179000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_363": { - "code": "0xef0001010004020001000e04000000008000017900000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_364": { - "code": "0xef0001010004020001000f0400000000800001790000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_365": { - "code": "0xef00010100040200010010040000000080000179000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_366": { - "code": "0xef0001010004020001001104000000008000017900000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_367": { - "code": "0xef000101000402000100120400000000800001790000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_368": { - "code": "0xef00010100040200010013040000000080000179000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_369": { - "code": "0xef0001010004020001001404000000008000017900000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_37": { - "code": "0xef000101000402000100030400000000800001670000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_370": { - "code": "0xef000101000402000100150400000000800001790000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_371": { - "code": "0xef00010100040200010016040000000080000179000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_372": { - "code": "0xef0001010004020001001704000000008000017900000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_373": { - "code": "0xef000101000402000100180400000000800001790000000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_374": { - "code": "0xef00010100040200010019040000000080000179000000000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_375": { - "code": "0xef0001010004020001001a04000000008000017900000000000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_376": { - "code": "0xef0001010004020001001c040000000080000179000000000000000000000000000000000000000000000000000000", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_truncated_push_377": { - "code": "0xef0001010004020001000104000000008000017a", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_378": { - "code": "0xef0001010004020001000204000000008000017a00", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_379": { - "code": "0xef0001010004020001000304000000008000017a0000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_38": { - "code": "0xef00010100040200010004040000000080000167000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_380": { - "code": "0xef0001010004020001000404000000008000017a000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_381": { - "code": "0xef0001010004020001000504000000008000017a00000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_382": { - "code": "0xef0001010004020001000604000000008000017a0000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_383": { - "code": "0xef0001010004020001000704000000008000017a000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_384": { - "code": "0xef0001010004020001000804000000008000017a00000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_385": { - "code": "0xef0001010004020001000904000000008000017a0000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_386": { - "code": "0xef0001010004020001000a04000000008000017a000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_387": { - "code": "0xef0001010004020001000b04000000008000017a00000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_388": { - "code": "0xef0001010004020001000c04000000008000017a0000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_389": { - "code": "0xef0001010004020001000d04000000008000017a000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_39": { - "code": "0xef0001010004020001000504000000008000016700000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_390": { - "code": "0xef0001010004020001000e04000000008000017a00000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_391": { - "code": "0xef0001010004020001000f04000000008000017a0000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_392": { - "code": "0xef0001010004020001001004000000008000017a000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_393": { - "code": "0xef0001010004020001001104000000008000017a00000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_394": { - "code": "0xef0001010004020001001204000000008000017a0000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_395": { - "code": "0xef0001010004020001001304000000008000017a000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_396": { - "code": "0xef0001010004020001001404000000008000017a00000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_397": { - "code": "0xef0001010004020001001504000000008000017a0000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_398": { - "code": "0xef0001010004020001001604000000008000017a000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_399": { - "code": "0xef0001010004020001001704000000008000017a00000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_4": { - "code": "0xef00010100040200010004040000000080000161000000", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_truncated_push_40": { - "code": "0xef000101000402000100060400000000800001670000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_400": { - "code": "0xef0001010004020001001804000000008000017a0000000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_401": { - "code": "0xef0001010004020001001904000000008000017a000000000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_402": { - "code": "0xef0001010004020001001a04000000008000017a00000000000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_403": { - "code": "0xef0001010004020001001b04000000008000017a0000000000000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_404": { - "code": "0xef0001010004020001001d04000000008000017a00000000000000000000000000000000000000000000000000000000", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_truncated_push_405": { - "code": "0xef0001010004020001000104000000008000017b", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_406": { - "code": "0xef0001010004020001000204000000008000017b00", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_407": { - "code": "0xef0001010004020001000304000000008000017b0000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_408": { - "code": "0xef0001010004020001000404000000008000017b000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_409": { - "code": "0xef0001010004020001000504000000008000017b00000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_41": { - "code": "0xef00010100040200010007040000000080000167000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_410": { - "code": "0xef0001010004020001000604000000008000017b0000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_411": { - "code": "0xef0001010004020001000704000000008000017b000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_412": { - "code": "0xef0001010004020001000804000000008000017b00000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_413": { - "code": "0xef0001010004020001000904000000008000017b0000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_414": { - "code": "0xef0001010004020001000a04000000008000017b000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_415": { - "code": "0xef0001010004020001000b04000000008000017b00000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_416": { - "code": "0xef0001010004020001000c04000000008000017b0000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_417": { - "code": "0xef0001010004020001000d04000000008000017b000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_418": { - "code": "0xef0001010004020001000e04000000008000017b00000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_419": { - "code": "0xef0001010004020001000f04000000008000017b0000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_42": { - "code": "0xef0001010004020001000804000000008000016700000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_420": { - "code": "0xef0001010004020001001004000000008000017b000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_421": { - "code": "0xef0001010004020001001104000000008000017b00000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_422": { - "code": "0xef0001010004020001001204000000008000017b0000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_423": { - "code": "0xef0001010004020001001304000000008000017b000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_424": { - "code": "0xef0001010004020001001404000000008000017b00000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_425": { - "code": "0xef0001010004020001001504000000008000017b0000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_426": { - "code": "0xef0001010004020001001604000000008000017b000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_427": { - "code": "0xef0001010004020001001704000000008000017b00000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_428": { - "code": "0xef0001010004020001001804000000008000017b0000000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_429": { - "code": "0xef0001010004020001001904000000008000017b000000000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_43": { - "code": "0xef0001010004020001000a040000000080000167000000000000000000", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_truncated_push_430": { - "code": "0xef0001010004020001001a04000000008000017b00000000000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_431": { - "code": "0xef0001010004020001001b04000000008000017b0000000000000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_432": { - "code": "0xef0001010004020001001c04000000008000017b000000000000000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_433": { - "code": "0xef0001010004020001001e04000000008000017b0000000000000000000000000000000000000000000000000000000000", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_truncated_push_434": { - "code": "0xef0001010004020001000104000000008000017c", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_435": { - "code": "0xef0001010004020001000204000000008000017c00", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_436": { - "code": "0xef0001010004020001000304000000008000017c0000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_437": { - "code": "0xef0001010004020001000404000000008000017c000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_438": { - "code": "0xef0001010004020001000504000000008000017c00000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_439": { - "code": "0xef0001010004020001000604000000008000017c0000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_44": { - "code": "0xef00010100040200010001040000000080000168", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_440": { - "code": "0xef0001010004020001000704000000008000017c000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_441": { - "code": "0xef0001010004020001000804000000008000017c00000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_442": { - "code": "0xef0001010004020001000904000000008000017c0000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_443": { - "code": "0xef0001010004020001000a04000000008000017c000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_444": { - "code": "0xef0001010004020001000b04000000008000017c00000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_445": { - "code": "0xef0001010004020001000c04000000008000017c0000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_446": { - "code": "0xef0001010004020001000d04000000008000017c000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_447": { - "code": "0xef0001010004020001000e04000000008000017c00000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_448": { - "code": "0xef0001010004020001000f04000000008000017c0000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_449": { - "code": "0xef0001010004020001001004000000008000017c000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_45": { - "code": "0xef0001010004020001000204000000008000016800", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_450": { - "code": "0xef0001010004020001001104000000008000017c00000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_451": { - "code": "0xef0001010004020001001204000000008000017c0000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_452": { - "code": "0xef0001010004020001001304000000008000017c000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_453": { - "code": "0xef0001010004020001001404000000008000017c00000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_454": { - "code": "0xef0001010004020001001504000000008000017c0000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_455": { - "code": "0xef0001010004020001001604000000008000017c000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_456": { - "code": "0xef0001010004020001001704000000008000017c00000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_457": { - "code": "0xef0001010004020001001804000000008000017c0000000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_458": { - "code": "0xef0001010004020001001904000000008000017c000000000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_459": { - "code": "0xef0001010004020001001a04000000008000017c00000000000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_46": { - "code": "0xef000101000402000100030400000000800001680000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_460": { - "code": "0xef0001010004020001001b04000000008000017c0000000000000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_461": { - "code": "0xef0001010004020001001c04000000008000017c000000000000000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_462": { - "code": "0xef0001010004020001001d04000000008000017c00000000000000000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_463": { - "code": "0xef0001010004020001001f04000000008000017c000000000000000000000000000000000000000000000000000000000000", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_truncated_push_464": { - "code": "0xef0001010004020001000104000000008000017d", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_465": { - "code": "0xef0001010004020001000204000000008000017d00", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_466": { - "code": "0xef0001010004020001000304000000008000017d0000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_467": { - "code": "0xef0001010004020001000404000000008000017d000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_468": { - "code": "0xef0001010004020001000504000000008000017d00000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_469": { - "code": "0xef0001010004020001000604000000008000017d0000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_47": { - "code": "0xef00010100040200010004040000000080000168000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_470": { - "code": "0xef0001010004020001000704000000008000017d000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_471": { - "code": "0xef0001010004020001000804000000008000017d00000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_472": { - "code": "0xef0001010004020001000904000000008000017d0000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_473": { - "code": "0xef0001010004020001000a04000000008000017d000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_474": { - "code": "0xef0001010004020001000b04000000008000017d00000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_475": { - "code": "0xef0001010004020001000c04000000008000017d0000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_476": { - "code": "0xef0001010004020001000d04000000008000017d000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_477": { - "code": "0xef0001010004020001000e04000000008000017d00000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_478": { - "code": "0xef0001010004020001000f04000000008000017d0000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_479": { - "code": "0xef0001010004020001001004000000008000017d000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_48": { - "code": "0xef0001010004020001000504000000008000016800000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_480": { - "code": "0xef0001010004020001001104000000008000017d00000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_481": { - "code": "0xef0001010004020001001204000000008000017d0000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_482": { - "code": "0xef0001010004020001001304000000008000017d000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_483": { - "code": "0xef0001010004020001001404000000008000017d00000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_484": { - "code": "0xef0001010004020001001504000000008000017d0000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_485": { - "code": "0xef0001010004020001001604000000008000017d000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_486": { - "code": "0xef0001010004020001001704000000008000017d00000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_487": { - "code": "0xef0001010004020001001804000000008000017d0000000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_488": { - "code": "0xef0001010004020001001904000000008000017d000000000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_489": { - "code": "0xef0001010004020001001a04000000008000017d00000000000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_49": { - "code": "0xef000101000402000100060400000000800001680000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_490": { - "code": "0xef0001010004020001001b04000000008000017d0000000000000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_491": { - "code": "0xef0001010004020001001c04000000008000017d000000000000000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_492": { - "code": "0xef0001010004020001001d04000000008000017d00000000000000000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_493": { - "code": "0xef0001010004020001001e04000000008000017d0000000000000000000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_494": { - "code": "0xef0001010004020001002004000000008000017d00000000000000000000000000000000000000000000000000000000000000", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_truncated_push_495": { - "code": "0xef0001010004020001000104000000008000017e", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_496": { - "code": "0xef0001010004020001000204000000008000017e00", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_497": { - "code": "0xef0001010004020001000304000000008000017e0000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_498": { - "code": "0xef0001010004020001000404000000008000017e000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_499": { - "code": "0xef0001010004020001000504000000008000017e00000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_5": { - "code": "0xef00010100040200010001040000000080000162", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_50": { - "code": "0xef00010100040200010007040000000080000168000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_500": { - "code": "0xef0001010004020001000604000000008000017e0000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_501": { - "code": "0xef0001010004020001000704000000008000017e000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_502": { - "code": "0xef0001010004020001000804000000008000017e00000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_503": { - "code": "0xef0001010004020001000904000000008000017e0000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_504": { - "code": "0xef0001010004020001000a04000000008000017e000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_505": { - "code": "0xef0001010004020001000b04000000008000017e00000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_506": { - "code": "0xef0001010004020001000c04000000008000017e0000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_507": { - "code": "0xef0001010004020001000d04000000008000017e000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_508": { - "code": "0xef0001010004020001000e04000000008000017e00000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_509": { - "code": "0xef0001010004020001000f04000000008000017e0000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_51": { - "code": "0xef0001010004020001000804000000008000016800000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_510": { - "code": "0xef0001010004020001001004000000008000017e000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_511": { - "code": "0xef0001010004020001001104000000008000017e00000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_512": { - "code": "0xef0001010004020001001204000000008000017e0000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_513": { - "code": "0xef0001010004020001001304000000008000017e000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_514": { - "code": "0xef0001010004020001001404000000008000017e00000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_515": { - "code": "0xef0001010004020001001504000000008000017e0000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_516": { - "code": "0xef0001010004020001001604000000008000017e000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_517": { - "code": "0xef0001010004020001001704000000008000017e00000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_518": { - "code": "0xef0001010004020001001804000000008000017e0000000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_519": { - "code": "0xef0001010004020001001904000000008000017e000000000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_52": { - "code": "0xef000101000402000100090400000000800001680000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_520": { - "code": "0xef0001010004020001001a04000000008000017e00000000000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_521": { - "code": "0xef0001010004020001001b04000000008000017e0000000000000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_522": { - "code": "0xef0001010004020001001c04000000008000017e000000000000000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_523": { - "code": "0xef0001010004020001001d04000000008000017e00000000000000000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_524": { - "code": "0xef0001010004020001001e04000000008000017e0000000000000000000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_525": { - "code": "0xef0001010004020001001f04000000008000017e000000000000000000000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_526": { - "code": "0xef0001010004020001002104000000008000017e0000000000000000000000000000000000000000000000000000000000000000", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_truncated_push_527": { - "code": "0xef0001010004020001000104000000008000017f", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_528": { - "code": "0xef0001010004020001000204000000008000017f00", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_529": { - "code": "0xef0001010004020001000304000000008000017f0000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_53": { - "code": "0xef0001010004020001000b04000000008000016800000000000000000000", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_truncated_push_530": { - "code": "0xef0001010004020001000404000000008000017f000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_531": { - "code": "0xef0001010004020001000504000000008000017f00000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_532": { - "code": "0xef0001010004020001000604000000008000017f0000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_533": { - "code": "0xef0001010004020001000704000000008000017f000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_534": { - "code": "0xef0001010004020001000804000000008000017f00000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_535": { - "code": "0xef0001010004020001000904000000008000017f0000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_536": { - "code": "0xef0001010004020001000a04000000008000017f000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_537": { - "code": "0xef0001010004020001000b04000000008000017f00000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_538": { - "code": "0xef0001010004020001000c04000000008000017f0000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_539": { - "code": "0xef0001010004020001000d04000000008000017f000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_54": { - "code": "0xef00010100040200010001040000000080000169", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_540": { - "code": "0xef0001010004020001000e04000000008000017f00000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_541": { - "code": "0xef0001010004020001000f04000000008000017f0000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_542": { - "code": "0xef0001010004020001001004000000008000017f000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_543": { - "code": "0xef0001010004020001001104000000008000017f00000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_544": { - "code": "0xef0001010004020001001204000000008000017f0000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_545": { - "code": "0xef0001010004020001001304000000008000017f000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_546": { - "code": "0xef0001010004020001001404000000008000017f00000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_547": { - "code": "0xef0001010004020001001504000000008000017f0000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_548": { - "code": "0xef0001010004020001001604000000008000017f000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_549": { - "code": "0xef0001010004020001001704000000008000017f00000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_55": { - "code": "0xef0001010004020001000204000000008000016900", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_550": { - "code": "0xef0001010004020001001804000000008000017f0000000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_551": { - "code": "0xef0001010004020001001904000000008000017f000000000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_552": { - "code": "0xef0001010004020001001a04000000008000017f00000000000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_553": { - "code": "0xef0001010004020001001b04000000008000017f0000000000000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_554": { - "code": "0xef0001010004020001001c04000000008000017f000000000000000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_555": { - "code": "0xef0001010004020001001d04000000008000017f00000000000000000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_556": { - "code": "0xef0001010004020001001e04000000008000017f0000000000000000000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_557": { - "code": "0xef0001010004020001001f04000000008000017f000000000000000000000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_558": { - "code": "0xef0001010004020001002004000000008000017f00000000000000000000000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_559": { - "code": "0xef0001010004020001002204000000008000017f000000000000000000000000000000000000000000000000000000000000000000", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_truncated_push_56": { - "code": "0xef000101000402000100030400000000800001690000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_57": { - "code": "0xef00010100040200010004040000000080000169000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_58": { - "code": "0xef0001010004020001000504000000008000016900000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_59": { - "code": "0xef000101000402000100060400000000800001690000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_6": { - "code": "0xef0001010004020001000204000000008000016200", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_60": { - "code": "0xef00010100040200010007040000000080000169000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_61": { - "code": "0xef0001010004020001000804000000008000016900000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_62": { - "code": "0xef000101000402000100090400000000800001690000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_63": { - "code": "0xef0001010004020001000a040000000080000169000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_64": { - "code": "0xef0001010004020001000c0400000000800001690000000000000000000000", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_truncated_push_65": { - "code": "0xef0001010004020001000104000000008000016a", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_66": { - "code": "0xef0001010004020001000204000000008000016a00", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_67": { - "code": "0xef0001010004020001000304000000008000016a0000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_68": { - "code": "0xef0001010004020001000404000000008000016a000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_69": { - "code": "0xef0001010004020001000504000000008000016a00000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_7": { - "code": "0xef000101000402000100030400000000800001620000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_70": { - "code": "0xef0001010004020001000604000000008000016a0000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_71": { - "code": "0xef0001010004020001000704000000008000016a000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_72": { - "code": "0xef0001010004020001000804000000008000016a00000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_73": { - "code": "0xef0001010004020001000904000000008000016a0000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_74": { - "code": "0xef0001010004020001000a04000000008000016a000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_75": { - "code": "0xef0001010004020001000b04000000008000016a00000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_76": { - "code": "0xef0001010004020001000d04000000008000016a000000000000000000000000", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_truncated_push_77": { - "code": "0xef0001010004020001000104000000008000016b", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_78": { - "code": "0xef0001010004020001000204000000008000016b00", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_79": { - "code": "0xef0001010004020001000304000000008000016b0000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_8": { - "code": "0xef0001010004020001000504000000008000016200000000", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_truncated_push_80": { - "code": "0xef0001010004020001000404000000008000016b000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_81": { - "code": "0xef0001010004020001000504000000008000016b00000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_82": { - "code": "0xef0001010004020001000604000000008000016b0000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_83": { - "code": "0xef0001010004020001000704000000008000016b000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_84": { - "code": "0xef0001010004020001000804000000008000016b00000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_85": { - "code": "0xef0001010004020001000904000000008000016b0000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_86": { - "code": "0xef0001010004020001000a04000000008000016b000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_87": { - "code": "0xef0001010004020001000b04000000008000016b00000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_88": { - "code": "0xef0001010004020001000c04000000008000016b0000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_89": { - "code": "0xef0001010004020001000e04000000008000016b00000000000000000000000000", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_truncated_push_9": { - "code": "0xef00010100040200010001040000000080000163", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_90": { - "code": "0xef0001010004020001000104000000008000016c", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_91": { - "code": "0xef0001010004020001000204000000008000016c00", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_92": { - "code": "0xef0001010004020001000304000000008000016c0000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_93": { - "code": "0xef0001010004020001000404000000008000016c000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_94": { - "code": "0xef0001010004020001000504000000008000016c00000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_95": { - "code": "0xef0001010004020001000604000000008000016c0000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_96": { - "code": "0xef0001010004020001000704000000008000016c000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_97": { - "code": "0xef0001010004020001000804000000008000016c00000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_98": { - "code": "0xef0001010004020001000904000000008000016c0000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - }, - "EOF1_truncated_push_99": { - "code": "0xef0001010004020001000a04000000008000016c000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TruncatedImmediate", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_truncated_section.json b/crates/interpreter/tests/EOFTests/eof_validation/EOF1_truncated_section.json deleted file mode 100644 index 663059882f..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_truncated_section.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "EOF1_truncated_section": { - "vectors": { - "EOF1_truncated_section_0": { - "code": "0xef0001010004020001000204000000", - "results": { - "Prague": { - "exception": "EOF_InvalidSectionBodiesSize", - "result": false - } - } - }, - "EOF1_truncated_section_1": { - "code": "0xef0001010004020001000204000000008000", - "results": { - "Prague": { - "exception": "EOF_InvalidSectionBodiesSize", - "result": false - } - } - }, - "EOF1_truncated_section_2": { - "code": "0xef000101000402000100020400000000800000fe", - "results": { - "Prague": { - "exception": "EOF_InvalidSectionBodiesSize", - "result": false - } - } - }, - "EOF1_truncated_section_3": { - "code": "0xef000101000402000100010400020000800000fe", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_truncated_section_4": { - "code": "0xef000101000402000100010400020000800000feaa", - "results": { - "Prague": { - "result": true - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_type_section_missing.json b/crates/interpreter/tests/EOFTests/eof_validation/EOF1_type_section_missing.json deleted file mode 100644 index c91d4ac595..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_type_section_missing.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "EOF1_type_section_missing": { - "vectors": { - "EOF1_type_section_missing_0": { - "code": "0xef0001020001000100fe", - "results": { - "Prague": { - "exception": "EOF_TypeSectionMissing", - "result": false - } - } - }, - "EOF1_type_section_missing_1": { - "code": "0xef0001020001000103000100feda", - "results": { - "Prague": { - "exception": "EOF_TypeSectionMissing", - "result": false - } - } - }, - "EOF1_type_section_missing_2": { - "code": "0xef000100", - "results": { - "Prague": { - "exception": "EOF_TypeSectionMissing", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_type_section_not_first.json b/crates/interpreter/tests/EOFTests/eof_validation/EOF1_type_section_not_first.json deleted file mode 100644 index fa9d847516..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_type_section_not_first.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "EOF1_type_section_not_first": { - "vectors": { - "EOF1_type_section_not_first_0": { - "code": "0xef0001020001000101000400fe00800000", - "results": { - "Prague": { - "exception": "EOF_TypeSectionMissing", - "result": false - } - } - }, - "EOF1_type_section_not_first_1": { - "code": "0xef00010200020001000101000400fefe00800000", - "results": { - "Prague": { - "exception": "EOF_TypeSectionMissing", - "result": false - } - } - }, - "EOF1_type_section_not_first_2": { - "code": "0xef0001020001000101000404000300fe00800000aabbcc", - "results": { - "Prague": { - "exception": "EOF_TypeSectionMissing", - "result": false - } - } - }, - "EOF1_type_section_not_first_3": { - "code": "0xef0001020001000104000301000400feaabbcc00800000", - "results": { - "Prague": { - "exception": "EOF_TypeSectionMissing", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_types_section_0_size.json b/crates/interpreter/tests/EOFTests/eof_validation/EOF1_types_section_0_size.json deleted file mode 100644 index 9f2cc36649..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_types_section_0_size.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "EOF1_types_section_0_size": { - "vectors": { - "EOF1_types_section_0_size_0": { - "code": "0xef0001010000020001000100fe", - "results": { - "Prague": { - "exception": "EOF_ZeroSectionSize", - "result": false - } - } - }, - "EOF1_types_section_0_size_1": { - "code": "0xef0001010000020001000104000100feda", - "results": { - "Prague": { - "exception": "EOF_ZeroSectionSize", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_types_section_missing.json b/crates/interpreter/tests/EOFTests/eof_validation/EOF1_types_section_missing.json deleted file mode 100644 index a82c85ba26..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_types_section_missing.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "EOF1_types_section_missing": { - "vectors": { - "EOF1_types_section_missing_0": { - "code": "0xef0001020001000100fe", - "results": { - "Prague": { - "exception": "EOF_TypeSectionMissing", - "result": false - } - } - }, - "EOF1_types_section_missing_1": { - "code": "0xef0001020001000104000100feda", - "results": { - "Prague": { - "exception": "EOF_TypeSectionMissing", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_undefined_opcodes.json b/crates/interpreter/tests/EOFTests/eof_validation/EOF1_undefined_opcodes.json deleted file mode 100644 index ae4289f8b8..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_undefined_opcodes.json +++ /dev/null @@ -1,1677 +0,0 @@ -{ - "EOF1_undefined_opcodes": { - "vectors": { - "EOF1_undefined_opcodes_0": { - "code": "0xef00010100040200010013040000000080001160018080808080808080808080808080808000", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_1": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080800100", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_10": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080800a00", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_100": { - "code": "0xef0001010004020001001404000000008000126001808080808080808080808080808080808d00", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_101": { - "code": "0xef0001010004020001001404000000008000126001808080808080808080808080808080808e00", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_102": { - "code": "0xef0001010004020001001404000000008000126001808080808080808080808080808080808f00", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_103": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080809000", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_104": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080809100", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_105": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080809200", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_106": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080809300", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_107": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080809400", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_108": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080809500", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_109": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080809600", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_11": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080800b00", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_110": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080809700", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_111": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080809800", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_112": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080809900", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_113": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080809a00", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_114": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080809b00", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_115": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080809c00", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_116": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080809d00", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_117": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080809e00", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_118": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080809f00", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_119": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080a000", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_12": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080800c00", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_120": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080a100", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_121": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080a200", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_122": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080a300", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_123": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080a400", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_124": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080a500", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_125": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080a600", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_126": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080a700", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_127": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080a800", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_128": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080a900", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_129": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080aa00", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_13": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080800d00", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_130": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080ab00", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_131": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080ac00", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_132": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080ad00", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_133": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080ae00", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_134": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080af00", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_135": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080b000", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_136": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080b100", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_137": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080b200", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_138": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080b300", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_139": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080b400", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_14": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080800e00", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_140": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080b500", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_141": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080b600", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_142": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080b700", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_143": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080b800", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_144": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080b900", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_145": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080ba00", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_146": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080bb00", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_147": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080bc00", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_148": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080bd00", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_149": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080be00", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_15": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080800f00", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_150": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080bf00", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_151": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080c000", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_152": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080c100", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_153": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080c200", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_154": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080c300", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_155": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080c400", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_156": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080c500", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_157": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080c600", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_158": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080c700", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_159": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080c800", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_16": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080801000", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_160": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080c900", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_161": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080ca00", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_162": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080cb00", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_163": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080cc00", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_164": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080cd00", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_165": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080ce00", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_166": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080cf00", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_167": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080d000", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_168": { - "code": "0xef000101000402000100140400000000800012600180808080808080808080808080808080d200", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_169": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080d300", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_17": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080801100", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_170": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080d400", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_171": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080d500", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_172": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080d600", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_173": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080d700", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_174": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080d800", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_175": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080d900", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_176": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080da00", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_177": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080db00", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_178": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080dc00", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_179": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080dd00", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_18": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080801200", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_180": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080de00", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_181": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080df00", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_182": { - "code": "0xef000101000802000200040001040000000080000000000000e3000100e4", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_183": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080e900", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_184": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080ea00", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_185": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080eb00", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_186": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080ed00", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_187": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080ef00", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_188": { - "code": "0xef000101000402000100130400000000800011600180808080808080808080808080808080f3", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_189": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080f600", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_19": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080801300", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_190": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080f700", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_191": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080f800", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_192": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080f900", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_193": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080fb00", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_194": { - "code": "0xef000101000402000100140400000000800011600180808080808080808080808080808080fc00", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_195": { - "code": "0xef000101000402000100130400000000800011600180808080808080808080808080808080fd", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_196": { - "code": "0xef000101000402000100130400000000800011600180808080808080808080808080808080fe", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_197": { - "code": "0xef000101000402000100010400000000800000fe", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_2": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080800200", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_20": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080801400", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_21": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080801500", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_22": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080801600", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_23": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080801700", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_24": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080801800", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_25": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080801900", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_26": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080801a00", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_27": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080801b00", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_28": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080801c00", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_29": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080801d00", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_3": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080800300", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_30": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080801e00", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_31": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080801f00", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_32": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080802000", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_33": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080802100", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_34": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080802200", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_35": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080802300", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_36": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080802400", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_37": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080802500", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_38": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080802600", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_39": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080802700", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_4": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080800400", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_40": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080802800", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_41": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080802900", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_42": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080802a00", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_43": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080802b00", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_44": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080802c00", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_45": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080802d00", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_46": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080802e00", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_47": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080802f00", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_48": { - "code": "0xef0001010004020001001404000000008000126001808080808080808080808080808080803000", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_49": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080803100", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_5": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080800500", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_50": { - "code": "0xef0001010004020001001404000000008000126001808080808080808080808080808080803200", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_51": { - "code": "0xef0001010004020001001404000000008000126001808080808080808080808080808080803300", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_52": { - "code": "0xef0001010004020001001404000000008000126001808080808080808080808080808080803400", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_53": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080803500", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_54": { - "code": "0xef0001010004020001001404000000008000126001808080808080808080808080808080803600", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_55": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080803700", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_56": { - "code": "0xef0001010004020001001404000000008000126001808080808080808080808080808080803a00", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_57": { - "code": "0xef0001010004020001001404000000008000126001808080808080808080808080808080803d00", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_58": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080803e00", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_59": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080804000", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_6": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080800600", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_60": { - "code": "0xef0001010004020001001404000000008000126001808080808080808080808080808080804100", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_61": { - "code": "0xef0001010004020001001404000000008000126001808080808080808080808080808080804200", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_62": { - "code": "0xef0001010004020001001404000000008000126001808080808080808080808080808080804300", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_63": { - "code": "0xef0001010004020001001404000000008000126001808080808080808080808080808080804400", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_64": { - "code": "0xef0001010004020001001404000000008000126001808080808080808080808080808080804500", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_65": { - "code": "0xef0001010004020001001404000000008000126001808080808080808080808080808080804600", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_66": { - "code": "0xef0001010004020001001404000000008000126001808080808080808080808080808080804700", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_67": { - "code": "0xef0001010004020001001404000000008000126001808080808080808080808080808080804800", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_68": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080804900", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_69": { - "code": "0xef0001010004020001001404000000008000126001808080808080808080808080808080804a00", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_7": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080800700", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_70": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080804b00", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_71": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080804c00", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_72": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080804d00", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_73": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080804e00", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_74": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080804f00", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "EOF1_undefined_opcodes_75": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080805000", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_76": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080805100", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_77": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080805200", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_78": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080805300", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_79": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080805400", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_8": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080800800", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_80": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080805500", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_81": { - "code": "0xef0001010004020001001404000000008000126001808080808080808080808080808080805900", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_82": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080805b00", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_83": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080805c00", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_84": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080805d00", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_85": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080805e00", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_86": { - "code": "0xef0001010004020001001404000000008000126001808080808080808080808080808080805f00", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_87": { - "code": "0xef0001010004020001001404000000008000126001808080808080808080808080808080808000", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_88": { - "code": "0xef0001010004020001001404000000008000126001808080808080808080808080808080808100", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_89": { - "code": "0xef0001010004020001001404000000008000126001808080808080808080808080808080808200", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_9": { - "code": "0xef0001010004020001001404000000008000116001808080808080808080808080808080800900", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_90": { - "code": "0xef0001010004020001001404000000008000126001808080808080808080808080808080808300", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_91": { - "code": "0xef0001010004020001001404000000008000126001808080808080808080808080808080808400", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_92": { - "code": "0xef0001010004020001001404000000008000126001808080808080808080808080808080808500", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_93": { - "code": "0xef0001010004020001001404000000008000126001808080808080808080808080808080808600", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_94": { - "code": "0xef0001010004020001001404000000008000126001808080808080808080808080808080808700", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_95": { - "code": "0xef0001010004020001001404000000008000126001808080808080808080808080808080808800", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_96": { - "code": "0xef0001010004020001001404000000008000126001808080808080808080808080808080808900", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_97": { - "code": "0xef0001010004020001001404000000008000126001808080808080808080808080808080808a00", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_98": { - "code": "0xef0001010004020001001404000000008000126001808080808080808080808080808080808b00", - "results": { - "Prague": { - "result": true - } - } - }, - "EOF1_undefined_opcodes_99": { - "code": "0xef0001010004020001001404000000008000126001808080808080808080808080808080808c00", - "results": { - "Prague": { - "result": true - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_unknown_section.json b/crates/interpreter/tests/EOFTests/eof_validation/EOF1_unknown_section.json deleted file mode 100644 index 4c15cc70d3..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_unknown_section.json +++ /dev/null @@ -1,60 +0,0 @@ -{ - "EOF1_unknown_section": { - "vectors": { - "EOF1_unknown_section_0": { - "code": "0xef000105000100fe", - "results": { - "Prague": { - "exception": "EOF_TypeSectionMissing", - "result": false - } - } - }, - "EOF1_unknown_section_1": { - "code": "0xef0001ff000100fe", - "results": { - "Prague": { - "exception": "EOF_TypeSectionMissing", - "result": false - } - } - }, - "EOF1_unknown_section_2": { - "code": "0xef000101000402000100010500010000800000fe00", - "results": { - "Prague": { - "exception": "EOF_DataSectionMissing", - "result": false - } - } - }, - "EOF1_unknown_section_3": { - "code": "0xef00010100040200010001ff00010000800000fe00", - "results": { - "Prague": { - "exception": "EOF_DataSectionMissing", - "result": false - } - } - }, - "EOF1_unknown_section_4": { - "code": "0xef000101000402000100010400010500010000800000feaa00", - "results": { - "Prague": { - "exception": "EOF_HeaderTerminatorMissing", - "result": false - } - } - }, - "EOF1_unknown_section_5": { - "code": "0xef00010100040200010001040001ff00010000800000feaa00", - "results": { - "Prague": { - "exception": "EOF_HeaderTerminatorMissing", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_valid_rjump.json b/crates/interpreter/tests/EOFTests/eof_validation/EOF1_valid_rjump.json deleted file mode 100644 index 6309192917..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_valid_rjump.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "EOF1_valid_rjump": { - "vectors": { - "offset_negative": { - "code": "0xef0001010004020001000404000000008000005be0fffc", - "results": { - "Prague": { - "result": true - } - } - }, - "offset_positive": { - "code": "0xef0001010004020001000d04000000008000025fe100055f5fe000035f600100", - "results": { - "Prague": { - "result": true - } - } - }, - "offset_zero": { - "code": "0xef000101000402000100040400000000800000e0000000", - "results": { - "Prague": { - "result": true - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_valid_rjumpi.json b/crates/interpreter/tests/EOFTests/eof_validation/EOF1_valid_rjumpi.json deleted file mode 100644 index fe3b175a7e..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_valid_rjumpi.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "EOF1_valid_rjumpi": { - "vectors": { - "offset_negative": { - "code": "0xef0001010004020001000604000000008000016000e1fffb00", - "results": { - "Prague": { - "result": true - } - } - }, - "offset_positive": { - "code": "0xef0001010004020001000904000000008000016000e100035b5b5b00", - "results": { - "Prague": { - "result": true - } - } - }, - "offset_zero": { - "code": "0xef0001010004020001000604000000008000016000e1000000", - "results": { - "Prague": { - "result": true - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_valid_rjumpv.json b/crates/interpreter/tests/EOFTests/eof_validation/EOF1_valid_rjumpv.json deleted file mode 100644 index 774f82caf0..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/EOF1_valid_rjumpv.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "EOF1_valid_rjumpv": { - "vectors": { - "single_entry_case_0": { - "code": "0xef0001010004020001000904000000008000016000e2000000600100", - "results": { - "Prague": { - "result": true - } - } - }, - "three_entries_case_2": { - "code": "0xef0001010004020001001004000000008000016002e20200000003fff6600100600200", - "results": { - "Prague": { - "result": true - } - } - }, - "two_entries_case_0": { - "code": "0xef0001010004020001000e04000000008000016000e20100000003600100600200", - "results": { - "Prague": { - "result": true - } - } - }, - "two_entries_case_2": { - "code": "0xef0001010004020001000e04000000008000016002e20100000003600100600200", - "results": { - "Prague": { - "result": true - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/callf_into_nonreturning.json b/crates/interpreter/tests/EOFTests/eof_validation/callf_into_nonreturning.json deleted file mode 100644 index f753f692e9..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/callf_into_nonreturning.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "callf_into_nonreturning": { - "vectors": { - "callf_into_nonreturning_0": { - "code": "0xef000101000802000200040001040000000080000000800000e300010000", - "results": { - "Prague": { - "exception": "EOF_CallfToNonReturningFunction", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/callf_invalid_code_section_index.json b/crates/interpreter/tests/EOFTests/eof_validation/callf_invalid_code_section_index.json deleted file mode 100644 index f934ccab93..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/callf_invalid_code_section_index.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "callf_invalid_code_section_index": { - "vectors": { - "callf_invalid_code_section_index_0": { - "code": "0xef000101000402000100040400000000800000e3000100", - "results": { - "Prague": { - "exception": "EOF_InvalidCodeSectionIndex", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/data_section_missing.json b/crates/interpreter/tests/EOFTests/eof_validation/data_section_missing.json deleted file mode 100644 index 19479cd60b..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/data_section_missing.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "data_section_missing": { - "vectors": { - "data_section_missing_0": { - "code": "0xef000101000402000100010000800000fe", - "results": { - "Prague": { - "exception": "EOF_DataSectionMissing", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/dataloadn.json b/crates/interpreter/tests/EOFTests/eof_validation/dataloadn.json deleted file mode 100644 index 14724fd6af..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/dataloadn.json +++ /dev/null @@ -1,75 +0,0 @@ -{ - "dataloadn": { - "vectors": { - "dataloadn_0": { - "code": "0xef000101000402000100050400200000800001d1000050000000000000000000111111111111111122222222222222223333333333333333", - "results": { - "Prague": { - "result": true - } - } - }, - "dataloadn_1": { - "code": "0xef000101000402000100050400210000800001d100015000000000000000000011111111111111112222222222222222333333333333333344", - "results": { - "Prague": { - "result": true - } - } - }, - "dataloadn_2": { - "code": "0xef000101000402000100050400400000800001d10020500000000000000000001111111111111111222222222222222233333333333333330000000000000000111111111111111122222222222222223333333333333333", - "results": { - "Prague": { - "result": true - } - } - }, - "dataloadn_3": { - "code": "0xef000101000402000100050400000000800001d100005000", - "results": { - "Prague": { - "exception": "EOF_InvalidDataloadnIndex", - "result": false - } - } - }, - "dataloadn_4": { - "code": "0xef000101000402000100050400010000800001d10001500000", - "results": { - "Prague": { - "exception": "EOF_InvalidDataloadnIndex", - "result": false - } - } - }, - "dataloadn_5": { - "code": "0xef000101000402000100050400200000800001d1002050000000000000000000111111111111111122222222222222223333333333333333", - "results": { - "Prague": { - "exception": "EOF_InvalidDataloadnIndex", - "result": false - } - } - }, - "dataloadn_6": { - "code": "0xef000101000402000100050400200000800001d1ffff50000000000000000000111111111111111122222222222222223333333333333333", - "results": { - "Prague": { - "exception": "EOF_InvalidDataloadnIndex", - "result": false - } - } - }, - "dataloadn_7": { - "code": "0xef0001010004020001000504003f0000800001d100205000000000000000000011111111111111112222222222222222333333333333333300000000000000001111111111111111222222222222222233333333333333", - "results": { - "Prague": { - "exception": "EOF_InvalidDataloadnIndex", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/deprecated_instructions.json b/crates/interpreter/tests/EOFTests/eof_validation/deprecated_instructions.json deleted file mode 100644 index 3da4711525..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/deprecated_instructions.json +++ /dev/null @@ -1,150 +0,0 @@ -{ - "deprecated_instructions": { - "vectors": { - "deprecated_instructions_0": { - "code": "0xef000101000402000100010400000000800000f2", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "deprecated_instructions_1": { - "code": "0xef000101000402000100010400000000800000ff", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "deprecated_instructions_10": { - "code": "0xef00010100040200010001040000000080000038", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "deprecated_instructions_11": { - "code": "0xef00010100040200010001040000000080000039", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "deprecated_instructions_12": { - "code": "0xef0001010004020001000104000000008000003b", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "deprecated_instructions_13": { - "code": "0xef0001010004020001000104000000008000003c", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "deprecated_instructions_14": { - "code": "0xef0001010004020001000104000000008000003f", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "deprecated_instructions_15": { - "code": "0xef0001010004020001000104000000008000005a", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "deprecated_instructions_2": { - "code": "0xef00010100040200010001040000000080000056", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "deprecated_instructions_3": { - "code": "0xef00010100040200010001040000000080000057", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "deprecated_instructions_4": { - "code": "0xef00010100040200010001040000000080000058", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "deprecated_instructions_5": { - "code": "0xef000101000402000100010400000000800000f1", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "deprecated_instructions_6": { - "code": "0xef000101000402000100010400000000800000fa", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "deprecated_instructions_7": { - "code": "0xef000101000402000100010400000000800000f4", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "deprecated_instructions_8": { - "code": "0xef000101000402000100010400000000800000f0", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - }, - "deprecated_instructions_9": { - "code": "0xef000101000402000100010400000000800000f5", - "results": { - "Prague": { - "exception": "EOF_UndefinedInstruction", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/incomplete_section_size.json b/crates/interpreter/tests/EOFTests/eof_validation/incomplete_section_size.json deleted file mode 100644 index 9cc794d5c0..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/incomplete_section_size.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "incomplete_section_size": { - "vectors": { - "incomplete_section_size_0": { - "code": "0xef000101010002003f0100", - "results": { - "Prague": { - "exception": "EOF_IncompleteSectionSize", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/jumpf_compatible_outputs.json b/crates/interpreter/tests/EOFTests/eof_validation/jumpf_compatible_outputs.json deleted file mode 100644 index 4fab55d449..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/jumpf_compatible_outputs.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "jumpf_compatible_outputs": { - "vectors": { - "jumpf_compatible_outputs_0": { - "code": "0xef000101000c02000300040005000404000000008000050005000200030003e30001005f5fe500025f5f5fe4", - "results": { - "Prague": { - "result": true - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/jumpf_equal_outputs.json b/crates/interpreter/tests/EOFTests/eof_validation/jumpf_equal_outputs.json deleted file mode 100644 index b9aba3a0c5..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/jumpf_equal_outputs.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "jumpf_equal_outputs": { - "vectors": { - "jumpf_equal_outputs_0": { - "code": "0xef000101000c02000300040003000404000000008000030003000000030003e3000100e500025f5f5fe4", - "results": { - "Prague": { - "result": true - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/jumpf_incompatible_outputs.json b/crates/interpreter/tests/EOFTests/eof_validation/jumpf_incompatible_outputs.json deleted file mode 100644 index b79ea57bb5..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/jumpf_incompatible_outputs.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "jumpf_incompatible_outputs": { - "vectors": { - "jumpf_incompatible_outputs_0": { - "code": "0xef000101000c02000300040005000404000000008000030003000200050003e3000100e500025f5f5f5f5fe4", - "results": { - "Prague": { - "exception": "EOF_JumpfDestinationIncompatibleOutputs", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/many_code_sections_1023.json b/crates/interpreter/tests/EOFTests/eof_validation/many_code_sections_1023.json deleted file mode 100644 index 05c74681b7..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/many_code_sections_1023.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "many_code_sections_1023": { - "vectors": { - "many_code_sections_1023_0": { - "code": "0xef0001010ffc0203ff00030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000304000000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000e50001e50002e50003e50004e50005e50006e50007e50008e50009e5000ae5000be5000ce5000de5000ee5000fe50010e50011e50012e50013e50014e50015e50016e50017e50018e50019e5001ae5001be5001ce5001de5001ee5001fe50020e50021e50022e50023e50024e50025e50026e50027e50028e50029e5002ae5002be5002ce5002de5002ee5002fe50030e50031e50032e50033e50034e50035e50036e50037e50038e50039e5003ae5003be5003ce5003de5003ee5003fe50040e50041e50042e50043e50044e50045e50046e50047e50048e50049e5004ae5004be5004ce5004de5004ee5004fe50050e50051e50052e50053e50054e50055e50056e50057e50058e50059e5005ae5005be5005ce5005de5005ee5005fe50060e50061e50062e50063e50064e50065e50066e50067e50068e50069e5006ae5006be5006ce5006de5006ee5006fe50070e50071e50072e50073e50074e50075e50076e50077e50078e50079e5007ae5007be5007ce5007de5007ee5007fe50080e50081e50082e50083e50084e50085e50086e50087e50088e50089e5008ae5008be5008ce5008de5008ee5008fe50090e50091e50092e50093e50094e50095e50096e50097e50098e50099e5009ae5009be5009ce5009de5009ee5009fe500a0e500a1e500a2e500a3e500a4e500a5e500a6e500a7e500a8e500a9e500aae500abe500ace500ade500aee500afe500b0e500b1e500b2e500b3e500b4e500b5e500b6e500b7e500b8e500b9e500bae500bbe500bce500bde500bee500bfe500c0e500c1e500c2e500c3e500c4e500c5e500c6e500c7e500c8e500c9e500cae500cbe500cce500cde500cee500cfe500d0e500d1e500d2e500d3e500d4e500d5e500d6e500d7e500d8e500d9e500dae500dbe500dce500dde500dee500dfe500e0e500e1e500e2e500e3e500e4e500e5e500e6e500e7e500e8e500e9e500eae500ebe500ece500ede500eee500efe500f0e500f1e500f2e500f3e500f4e500f5e500f6e500f7e500f8e500f9e500fae500fbe500fce500fde500fee500ffe50100e50101e50102e50103e50104e50105e50106e50107e50108e50109e5010ae5010be5010ce5010de5010ee5010fe50110e50111e50112e50113e50114e50115e50116e50117e50118e50119e5011ae5011be5011ce5011de5011ee5011fe50120e50121e50122e50123e50124e50125e50126e50127e50128e50129e5012ae5012be5012ce5012de5012ee5012fe50130e50131e50132e50133e50134e50135e50136e50137e50138e50139e5013ae5013be5013ce5013de5013ee5013fe50140e50141e50142e50143e50144e50145e50146e50147e50148e50149e5014ae5014be5014ce5014de5014ee5014fe50150e50151e50152e50153e50154e50155e50156e50157e50158e50159e5015ae5015be5015ce5015de5015ee5015fe50160e50161e50162e50163e50164e50165e50166e50167e50168e50169e5016ae5016be5016ce5016de5016ee5016fe50170e50171e50172e50173e50174e50175e50176e50177e50178e50179e5017ae5017be5017ce5017de5017ee5017fe50180e50181e50182e50183e50184e50185e50186e50187e50188e50189e5018ae5018be5018ce5018de5018ee5018fe50190e50191e50192e50193e50194e50195e50196e50197e50198e50199e5019ae5019be5019ce5019de5019ee5019fe501a0e501a1e501a2e501a3e501a4e501a5e501a6e501a7e501a8e501a9e501aae501abe501ace501ade501aee501afe501b0e501b1e501b2e501b3e501b4e501b5e501b6e501b7e501b8e501b9e501bae501bbe501bce501bde501bee501bfe501c0e501c1e501c2e501c3e501c4e501c5e501c6e501c7e501c8e501c9e501cae501cbe501cce501cde501cee501cfe501d0e501d1e501d2e501d3e501d4e501d5e501d6e501d7e501d8e501d9e501dae501dbe501dce501dde501dee501dfe501e0e501e1e501e2e501e3e501e4e501e5e501e6e501e7e501e8e501e9e501eae501ebe501ece501ede501eee501efe501f0e501f1e501f2e501f3e501f4e501f5e501f6e501f7e501f8e501f9e501fae501fbe501fce501fde501fee501ffe50200e50201e50202e50203e50204e50205e50206e50207e50208e50209e5020ae5020be5020ce5020de5020ee5020fe50210e50211e50212e50213e50214e50215e50216e50217e50218e50219e5021ae5021be5021ce5021de5021ee5021fe50220e50221e50222e50223e50224e50225e50226e50227e50228e50229e5022ae5022be5022ce5022de5022ee5022fe50230e50231e50232e50233e50234e50235e50236e50237e50238e50239e5023ae5023be5023ce5023de5023ee5023fe50240e50241e50242e50243e50244e50245e50246e50247e50248e50249e5024ae5024be5024ce5024de5024ee5024fe50250e50251e50252e50253e50254e50255e50256e50257e50258e50259e5025ae5025be5025ce5025de5025ee5025fe50260e50261e50262e50263e50264e50265e50266e50267e50268e50269e5026ae5026be5026ce5026de5026ee5026fe50270e50271e50272e50273e50274e50275e50276e50277e50278e50279e5027ae5027be5027ce5027de5027ee5027fe50280e50281e50282e50283e50284e50285e50286e50287e50288e50289e5028ae5028be5028ce5028de5028ee5028fe50290e50291e50292e50293e50294e50295e50296e50297e50298e50299e5029ae5029be5029ce5029de5029ee5029fe502a0e502a1e502a2e502a3e502a4e502a5e502a6e502a7e502a8e502a9e502aae502abe502ace502ade502aee502afe502b0e502b1e502b2e502b3e502b4e502b5e502b6e502b7e502b8e502b9e502bae502bbe502bce502bde502bee502bfe502c0e502c1e502c2e502c3e502c4e502c5e502c6e502c7e502c8e502c9e502cae502cbe502cce502cde502cee502cfe502d0e502d1e502d2e502d3e502d4e502d5e502d6e502d7e502d8e502d9e502dae502dbe502dce502dde502dee502dfe502e0e502e1e502e2e502e3e502e4e502e5e502e6e502e7e502e8e502e9e502eae502ebe502ece502ede502eee502efe502f0e502f1e502f2e502f3e502f4e502f5e502f6e502f7e502f8e502f9e502fae502fbe502fce502fde502fee502ffe50300e50301e50302e50303e50304e50305e50306e50307e50308e50309e5030ae5030be5030ce5030de5030ee5030fe50310e50311e50312e50313e50314e50315e50316e50317e50318e50319e5031ae5031be5031ce5031de5031ee5031fe50320e50321e50322e50323e50324e50325e50326e50327e50328e50329e5032ae5032be5032ce5032de5032ee5032fe50330e50331e50332e50333e50334e50335e50336e50337e50338e50339e5033ae5033be5033ce5033de5033ee5033fe50340e50341e50342e50343e50344e50345e50346e50347e50348e50349e5034ae5034be5034ce5034de5034ee5034fe50350e50351e50352e50353e50354e50355e50356e50357e50358e50359e5035ae5035be5035ce5035de5035ee5035fe50360e50361e50362e50363e50364e50365e50366e50367e50368e50369e5036ae5036be5036ce5036de5036ee5036fe50370e50371e50372e50373e50374e50375e50376e50377e50378e50379e5037ae5037be5037ce5037de5037ee5037fe50380e50381e50382e50383e50384e50385e50386e50387e50388e50389e5038ae5038be5038ce5038de5038ee5038fe50390e50391e50392e50393e50394e50395e50396e50397e50398e50399e5039ae5039be5039ce5039de5039ee5039fe503a0e503a1e503a2e503a3e503a4e503a5e503a6e503a7e503a8e503a9e503aae503abe503ace503ade503aee503afe503b0e503b1e503b2e503b3e503b4e503b5e503b6e503b7e503b8e503b9e503bae503bbe503bce503bde503bee503bfe503c0e503c1e503c2e503c3e503c4e503c5e503c6e503c7e503c8e503c9e503cae503cbe503cce503cde503cee503cfe503d0e503d1e503d2e503d3e503d4e503d5e503d6e503d7e503d8e503d9e503dae503dbe503dce503dde503dee503dfe503e0e503e1e503e2e503e3e503e4e503e5e503e6e503e7e503e8e503e9e503eae503ebe503ece503ede503eee503efe503f0e503f1e503f2e503f3e503f4e503f5e503f6e503f7e503f8e503f9e503fae503fbe503fce503fde503fe5b5b00", - "results": { - "Prague": { - "result": true - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/many_code_sections_1024.json b/crates/interpreter/tests/EOFTests/eof_validation/many_code_sections_1024.json deleted file mode 100644 index 656812192b..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/many_code_sections_1024.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "many_code_sections_1024": { - "vectors": { - "many_code_sections_1024_0": { - "code": "0xef000101100002040000030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030400000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000e50001e50002e50003e50004e50005e50006e50007e50008e50009e5000ae5000be5000ce5000de5000ee5000fe50010e50011e50012e50013e50014e50015e50016e50017e50018e50019e5001ae5001be5001ce5001de5001ee5001fe50020e50021e50022e50023e50024e50025e50026e50027e50028e50029e5002ae5002be5002ce5002de5002ee5002fe50030e50031e50032e50033e50034e50035e50036e50037e50038e50039e5003ae5003be5003ce5003de5003ee5003fe50040e50041e50042e50043e50044e50045e50046e50047e50048e50049e5004ae5004be5004ce5004de5004ee5004fe50050e50051e50052e50053e50054e50055e50056e50057e50058e50059e5005ae5005be5005ce5005de5005ee5005fe50060e50061e50062e50063e50064e50065e50066e50067e50068e50069e5006ae5006be5006ce5006de5006ee5006fe50070e50071e50072e50073e50074e50075e50076e50077e50078e50079e5007ae5007be5007ce5007de5007ee5007fe50080e50081e50082e50083e50084e50085e50086e50087e50088e50089e5008ae5008be5008ce5008de5008ee5008fe50090e50091e50092e50093e50094e50095e50096e50097e50098e50099e5009ae5009be5009ce5009de5009ee5009fe500a0e500a1e500a2e500a3e500a4e500a5e500a6e500a7e500a8e500a9e500aae500abe500ace500ade500aee500afe500b0e500b1e500b2e500b3e500b4e500b5e500b6e500b7e500b8e500b9e500bae500bbe500bce500bde500bee500bfe500c0e500c1e500c2e500c3e500c4e500c5e500c6e500c7e500c8e500c9e500cae500cbe500cce500cde500cee500cfe500d0e500d1e500d2e500d3e500d4e500d5e500d6e500d7e500d8e500d9e500dae500dbe500dce500dde500dee500dfe500e0e500e1e500e2e500e3e500e4e500e5e500e6e500e7e500e8e500e9e500eae500ebe500ece500ede500eee500efe500f0e500f1e500f2e500f3e500f4e500f5e500f6e500f7e500f8e500f9e500fae500fbe500fce500fde500fee500ffe50100e50101e50102e50103e50104e50105e50106e50107e50108e50109e5010ae5010be5010ce5010de5010ee5010fe50110e50111e50112e50113e50114e50115e50116e50117e50118e50119e5011ae5011be5011ce5011de5011ee5011fe50120e50121e50122e50123e50124e50125e50126e50127e50128e50129e5012ae5012be5012ce5012de5012ee5012fe50130e50131e50132e50133e50134e50135e50136e50137e50138e50139e5013ae5013be5013ce5013de5013ee5013fe50140e50141e50142e50143e50144e50145e50146e50147e50148e50149e5014ae5014be5014ce5014de5014ee5014fe50150e50151e50152e50153e50154e50155e50156e50157e50158e50159e5015ae5015be5015ce5015de5015ee5015fe50160e50161e50162e50163e50164e50165e50166e50167e50168e50169e5016ae5016be5016ce5016de5016ee5016fe50170e50171e50172e50173e50174e50175e50176e50177e50178e50179e5017ae5017be5017ce5017de5017ee5017fe50180e50181e50182e50183e50184e50185e50186e50187e50188e50189e5018ae5018be5018ce5018de5018ee5018fe50190e50191e50192e50193e50194e50195e50196e50197e50198e50199e5019ae5019be5019ce5019de5019ee5019fe501a0e501a1e501a2e501a3e501a4e501a5e501a6e501a7e501a8e501a9e501aae501abe501ace501ade501aee501afe501b0e501b1e501b2e501b3e501b4e501b5e501b6e501b7e501b8e501b9e501bae501bbe501bce501bde501bee501bfe501c0e501c1e501c2e501c3e501c4e501c5e501c6e501c7e501c8e501c9e501cae501cbe501cce501cde501cee501cfe501d0e501d1e501d2e501d3e501d4e501d5e501d6e501d7e501d8e501d9e501dae501dbe501dce501dde501dee501dfe501e0e501e1e501e2e501e3e501e4e501e5e501e6e501e7e501e8e501e9e501eae501ebe501ece501ede501eee501efe501f0e501f1e501f2e501f3e501f4e501f5e501f6e501f7e501f8e501f9e501fae501fbe501fce501fde501fee501ffe50200e50201e50202e50203e50204e50205e50206e50207e50208e50209e5020ae5020be5020ce5020de5020ee5020fe50210e50211e50212e50213e50214e50215e50216e50217e50218e50219e5021ae5021be5021ce5021de5021ee5021fe50220e50221e50222e50223e50224e50225e50226e50227e50228e50229e5022ae5022be5022ce5022de5022ee5022fe50230e50231e50232e50233e50234e50235e50236e50237e50238e50239e5023ae5023be5023ce5023de5023ee5023fe50240e50241e50242e50243e50244e50245e50246e50247e50248e50249e5024ae5024be5024ce5024de5024ee5024fe50250e50251e50252e50253e50254e50255e50256e50257e50258e50259e5025ae5025be5025ce5025de5025ee5025fe50260e50261e50262e50263e50264e50265e50266e50267e50268e50269e5026ae5026be5026ce5026de5026ee5026fe50270e50271e50272e50273e50274e50275e50276e50277e50278e50279e5027ae5027be5027ce5027de5027ee5027fe50280e50281e50282e50283e50284e50285e50286e50287e50288e50289e5028ae5028be5028ce5028de5028ee5028fe50290e50291e50292e50293e50294e50295e50296e50297e50298e50299e5029ae5029be5029ce5029de5029ee5029fe502a0e502a1e502a2e502a3e502a4e502a5e502a6e502a7e502a8e502a9e502aae502abe502ace502ade502aee502afe502b0e502b1e502b2e502b3e502b4e502b5e502b6e502b7e502b8e502b9e502bae502bbe502bce502bde502bee502bfe502c0e502c1e502c2e502c3e502c4e502c5e502c6e502c7e502c8e502c9e502cae502cbe502cce502cde502cee502cfe502d0e502d1e502d2e502d3e502d4e502d5e502d6e502d7e502d8e502d9e502dae502dbe502dce502dde502dee502dfe502e0e502e1e502e2e502e3e502e4e502e5e502e6e502e7e502e8e502e9e502eae502ebe502ece502ede502eee502efe502f0e502f1e502f2e502f3e502f4e502f5e502f6e502f7e502f8e502f9e502fae502fbe502fce502fde502fee502ffe50300e50301e50302e50303e50304e50305e50306e50307e50308e50309e5030ae5030be5030ce5030de5030ee5030fe50310e50311e50312e50313e50314e50315e50316e50317e50318e50319e5031ae5031be5031ce5031de5031ee5031fe50320e50321e50322e50323e50324e50325e50326e50327e50328e50329e5032ae5032be5032ce5032de5032ee5032fe50330e50331e50332e50333e50334e50335e50336e50337e50338e50339e5033ae5033be5033ce5033de5033ee5033fe50340e50341e50342e50343e50344e50345e50346e50347e50348e50349e5034ae5034be5034ce5034de5034ee5034fe50350e50351e50352e50353e50354e50355e50356e50357e50358e50359e5035ae5035be5035ce5035de5035ee5035fe50360e50361e50362e50363e50364e50365e50366e50367e50368e50369e5036ae5036be5036ce5036de5036ee5036fe50370e50371e50372e50373e50374e50375e50376e50377e50378e50379e5037ae5037be5037ce5037de5037ee5037fe50380e50381e50382e50383e50384e50385e50386e50387e50388e50389e5038ae5038be5038ce5038de5038ee5038fe50390e50391e50392e50393e50394e50395e50396e50397e50398e50399e5039ae5039be5039ce5039de5039ee5039fe503a0e503a1e503a2e503a3e503a4e503a5e503a6e503a7e503a8e503a9e503aae503abe503ace503ade503aee503afe503b0e503b1e503b2e503b3e503b4e503b5e503b6e503b7e503b8e503b9e503bae503bbe503bce503bde503bee503bfe503c0e503c1e503c2e503c3e503c4e503c5e503c6e503c7e503c8e503c9e503cae503cbe503cce503cde503cee503cfe503d0e503d1e503d2e503d3e503d4e503d5e503d6e503d7e503d8e503d9e503dae503dbe503dce503dde503dee503dfe503e0e503e1e503e2e503e3e503e4e503e5e503e6e503e7e503e8e503e9e503eae503ebe503ece503ede503eee503efe503f0e503f1e503f2e503f3e503f4e503f5e503f6e503f7e503f8e503f9e503fae503fbe503fce503fde503fee503ff5b5b00", - "results": { - "Prague": { - "result": true - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/max_arguments_count.json b/crates/interpreter/tests/EOFTests/eof_validation/max_arguments_count.json deleted file mode 100644 index 646333188a..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/max_arguments_count.json +++ /dev/null @@ -1,57 +0,0 @@ -{ - "max_arguments_count": { - "vectors": { - "max_arguments_count_0": { - "code": "0xef000101000802000200830001040000000080007f7f7f007f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5fe3000100e4", - "results": { - "Prague": { - "result": true - } - } - }, - "max_arguments_count_1": { - "code": "0xef00010100080200020001000104000000008000008080008000e4", - "results": { - "Prague": { - "exception": "EOF_InputsOutputsNumAboveLimit", - "result": false - } - } - }, - "max_arguments_count_2": { - "code": "0xef0001010008020002000400ff040000000080007f007f007fe30001006001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001e4", - "results": { - "Prague": { - "result": true - } - } - }, - "max_arguments_count_3": { - "code": "0xef0001010008020002000101010400000000800000008100810060016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001e4", - "results": { - "Prague": { - "exception": "EOF_InputsOutputsNumAboveLimit", - "result": false - } - } - }, - "max_arguments_count_4": { - "code": "0xef000101000802000200830080040000000080007f7f00007f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5fe300010050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050e4", - "results": { - "Prague": { - "result": true - } - } - }, - "max_arguments_count_5": { - "code": "0xef000101000802000200010081040000000080000080000080005050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050e4", - "results": { - "Prague": { - "exception": "EOF_InputsOutputsNumAboveLimit", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/max_stack_height.json b/crates/interpreter/tests/EOFTests/eof_validation/max_stack_height.json deleted file mode 100644 index 6d00623aae..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/max_stack_height.json +++ /dev/null @@ -1,84 +0,0 @@ -{ - "max_stack_height": { - "vectors": { - "max_stack_height_0": { - "code": "0xef000101000802000200040bfe0400000000800000000003ffe3000100600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050e4", - "results": { - "Prague": { - "result": true - } - } - }, - "max_stack_height_1": { - "code": "0xef00010100080200020c01000104000000008003ff00000000600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050e3000100e4", - "results": { - "Prague": { - "result": true - } - } - }, - "max_stack_height_2": { - "code": "0xef000101000802000200010c0104000000008000000000040000600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600150505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050e4", - "results": { - "Prague": { - "exception": "EOF_MaxStackHeightExceeded", - "result": false - } - } - }, - "max_stack_height_3": { - "code": "0xef00010100080200020c01000104000000008004000000000060016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160015050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505000e4", - "results": { - "Prague": { - "exception": "EOF_MaxStackHeightExceeded", - "result": false - } - } - }, - "max_stack_height_4": { - "code": "0xef000101000802000200010c010400000000800000000003ff00600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600150505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050e4", - "results": { - "Prague": { - "exception": "EOF_InvalidMaxStackHeight", - "result": false - } - } - }, - "max_stack_height_5": { - "code": "0xef00010100080200020c01000104000000008003ff0000000060016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160015050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505000e4", - "results": { - "Prague": { - "exception": "EOF_InvalidMaxStackHeight", - "result": false - } - } - }, - "max_stack_height_6": { - "code": "0xef0001010004020001000804000000008000016000e10002600100", - "results": { - "Prague": { - "result": true - } - } - }, - "max_stack_height_7": { - "code": "0xef0001010004020001000604000000008000016000e1fffd00", - "results": { - "Prague": { - "exception": "EOF_ConflictingStackHeight", - "result": false - } - } - }, - "max_stack_height_8": { - "code": "0xef0001010004020001000704000000008000016000e200fffc00", - "results": { - "Prague": { - "exception": "EOF_ConflictingStackHeight", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/minimal_valid_EOF1_code.json b/crates/interpreter/tests/EOFTests/eof_validation/minimal_valid_EOF1_code.json deleted file mode 100644 index 69b66da04c..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/minimal_valid_EOF1_code.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "minimal_valid_EOF1_code": { - "vectors": { - "minimal_valid_EOF1_code_0": { - "code": "0xef000101000402000100010400000000800000fe", - "results": { - "Prague": { - "result": true - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/minimal_valid_EOF1_code_with_data.json b/crates/interpreter/tests/EOFTests/eof_validation/minimal_valid_EOF1_code_with_data.json deleted file mode 100644 index 3155e80573..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/minimal_valid_EOF1_code_with_data.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "minimal_valid_EOF1_code_with_data": { - "vectors": { - "minimal_valid_EOF1_code_with_data_0": { - "code": "0xef000101000402000100010400010000800000feda", - "results": { - "Prague": { - "result": true - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/minimal_valid_EOF1_multiple_code_sections.json b/crates/interpreter/tests/EOFTests/eof_validation/minimal_valid_EOF1_multiple_code_sections.json deleted file mode 100644 index 29a4384403..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/minimal_valid_EOF1_multiple_code_sections.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "minimal_valid_EOF1_multiple_code_sections": { - "vectors": { - "no_data_section": { - "code": "0xef000101000802000200010001000080000000800000fefe", - "results": { - "Prague": { - "exception": "EOF_DataSectionMissing", - "result": false - } - } - }, - "non_void_input_output": { - "code": "0xef0001010010020004000500060008000204000000008000010100000100010003020300035fe300010050e3000250e43080e300035050e480e4", - "results": { - "Prague": { - "result": true - } - } - }, - "with_data_section": { - "code": "0xef000101000802000200030001040001000080000000800000e50001feda", - "results": { - "Prague": { - "result": true - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/multiple_code_sections_headers.json b/crates/interpreter/tests/EOFTests/eof_validation/multiple_code_sections_headers.json deleted file mode 100644 index 0fd093f540..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/multiple_code_sections_headers.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "multiple_code_sections_headers": { - "vectors": { - "multiple_code_sections_headers_0": { - "code": "0xef0001010008020001000402000100050400000000800000045c000000405c0000002e0005", - "results": { - "Prague": { - "exception": "EOF_DataSectionMissing", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/non_returning_status.json b/crates/interpreter/tests/EOFTests/eof_validation/non_returning_status.json deleted file mode 100644 index 3627dd3474..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/non_returning_status.json +++ /dev/null @@ -1,124 +0,0 @@ -{ - "non_returning_status": { - "vectors": { - "non_returning_status_0": { - "code": "0xef00010100040200010001040000000080000000", - "results": { - "Prague": { - "result": true - } - } - }, - "non_returning_status_1": { - "code": "0xef000101000802000200030001040000000080000000800000e5000100", - "results": { - "Prague": { - "result": true - } - } - }, - "non_returning_status_10": { - "code": "0xef000101000c0200030001000700010400000000800000018000010000000000e10001e4e50002e4", - "results": { - "Prague": { - "exception": "EOF_InvalidNonReturningFlag", - "result": false - } - } - }, - "non_returning_status_11": { - "code": "0xef00010100080200020001000704000000008000000180000100e10001e4e50000", - "results": { - "Prague": { - "exception": "EOF_InvalidNonReturningFlag", - "result": false - } - } - }, - "non_returning_status_12": { - "code": "0xef000101000c02000300030003000304000000008000000080000000800000e50001e50002e50001", - "results": { - "Prague": { - "result": true - } - } - }, - "non_returning_status_13": { - "code": "0xef000101000c02000300040003000304000000008000000000000000000000e3000100e50002e50001", - "results": { - "Prague": { - "result": true - } - } - }, - "non_returning_status_2": { - "code": "0xef000101000802000200040001040000000080000000000000e3000100e4", - "results": { - "Prague": { - "result": true - } - } - }, - "non_returning_status_3": { - "code": "0xef000101000c02000300040003000104000000008000000000000000000000e3000100e50002e4", - "results": { - "Prague": { - "result": true - } - } - }, - "non_returning_status_4": { - "code": "0xef000101000c020003000500070001040000000080000101000001000000005fe3000100e10001e4e50002e4", - "results": { - "Prague": { - "result": true - } - } - }, - "non_returning_status_5": { - "code": "0xef0001010008020002000500070400000000800001010000015fe3000100e10001e4e50000", - "results": { - "Prague": { - "result": true - } - } - }, - "non_returning_status_6": { - "code": "0xef00010100080200020001000104000000008000000080000000e4", - "results": { - "Prague": { - "exception": "EOF_InvalidNonReturningFlag", - "result": false - } - } - }, - "non_returning_status_7": { - "code": "0xef000101000402000100010400000000800000e4", - "results": { - "Prague": { - "exception": "EOF_InvalidNonReturningFlag", - "result": false - } - } - }, - "non_returning_status_8": { - "code": "0xef000101000c0200030001000300010400000000800000008000000000000000e50002e4", - "results": { - "Prague": { - "exception": "EOF_InvalidNonReturningFlag", - "result": false - } - } - }, - "non_returning_status_9": { - "code": "0xef00010100080200020001000304000000008000000000000000e50000", - "results": { - "Prague": { - "exception": "EOF_InvalidNonReturningFlag", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/stack/backwards_rjump.json b/crates/interpreter/tests/EOFTests/eof_validation/stack/backwards_rjump.json deleted file mode 100644 index 4e0e76d213..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/stack/backwards_rjump.json +++ /dev/null @@ -1,57 +0,0 @@ -{ - "backwards_rjump": { - "vectors": { - "backwards_rjump_0": { - "code": "0xef000101000402000100030400000000800000e0fffd", - "results": { - "Prague": { - "result": true - } - } - }, - "backwards_rjump_1": { - "code": "0xef0001010004020001000504000000008000015f50e0fffb", - "results": { - "Prague": { - "result": true - } - } - }, - "backwards_rjump_2": { - "code": "0xef0001010004020001000d04000000008000015f506001e10003e0fff8e0fff5", - "results": { - "Prague": { - "result": true - } - } - }, - "backwards_rjump_3": { - "code": "0xef0001010004020001000e04000000008000015f506001e10003e0fff85fe0fff4", - "results": { - "Prague": { - "exception": "EOF_ConflictingStackHeight", - "result": false - } - } - }, - "backwards_rjump_4": { - "code": "0xef0001010004020001000404000000008000015fe0fffc", - "results": { - "Prague": { - "exception": "EOF_ConflictingStackHeight", - "result": false - } - } - }, - "backwards_rjump_5": { - "code": "0xef0001010004020001000504000000008000015f50e0fffc", - "results": { - "Prague": { - "exception": "EOF_ConflictingStackHeight", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/stack/backwards_rjump_variable_stack.json b/crates/interpreter/tests/EOFTests/eof_validation/stack/backwards_rjump_variable_stack.json deleted file mode 100644 index 972572398a..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/stack/backwards_rjump_variable_stack.json +++ /dev/null @@ -1,75 +0,0 @@ -{ - "backwards_rjump_variable_stack": { - "vectors": { - "backwards_rjump_variable_stack_0": { - "code": "0xef0001010004020001000b04000000008000035f6000e100025f5fe0fffd", - "results": { - "Prague": { - "result": true - } - } - }, - "backwards_rjump_variable_stack_1": { - "code": "0xef0001010004020001000d04000000008000045f6000e100025f5f5f50e0fffb", - "results": { - "Prague": { - "result": true - } - } - }, - "backwards_rjump_variable_stack_2": { - "code": "0xef0001010004020001001504000000008000045f6000e100025f5f5f506001e10003e0fff8e0fff5", - "results": { - "Prague": { - "result": true - } - } - }, - "backwards_rjump_variable_stack_3": { - "code": "0xef0001010004020001001604000000008000045f6000e100025f5f5f506001e10003e0fff85fe0fff4", - "results": { - "Prague": { - "exception": "EOF_ConflictingStackHeight", - "result": false - } - } - }, - "backwards_rjump_variable_stack_4": { - "code": "0xef0001010004020001001104000000008000045f6000e100025f5f6000e100015fe0fff9", - "results": { - "Prague": { - "exception": "EOF_ConflictingStackHeight", - "result": false - } - } - }, - "backwards_rjump_variable_stack_5": { - "code": "0xef0001010004020001001104000000008000045f6000e100025f5f6000e1000150e0fff9", - "results": { - "Prague": { - "exception": "EOF_ConflictingStackHeight", - "result": false - } - } - }, - "backwards_rjump_variable_stack_6": { - "code": "0xef0001010004020001000c04000000008000045f6000e100025f5f5fe0fffc", - "results": { - "Prague": { - "exception": "EOF_ConflictingStackHeight", - "result": false - } - } - }, - "backwards_rjump_variable_stack_7": { - "code": "0xef0001010004020001000d04000000008000035f6000e100025f5f5f50e0fffc", - "results": { - "Prague": { - "exception": "EOF_ConflictingStackHeight", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/stack/backwards_rjumpi.json b/crates/interpreter/tests/EOFTests/eof_validation/stack/backwards_rjumpi.json deleted file mode 100644 index cdc6a5873a..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/stack/backwards_rjumpi.json +++ /dev/null @@ -1,100 +0,0 @@ -{ - "backwards_rjumpi": { - "vectors": { - "backwards_rjumpi_0": { - "code": "0xef0001010004020001000604000000008000016000e1fffb00", - "results": { - "Prague": { - "result": true - } - } - }, - "backwards_rjumpi_1": { - "code": "0xef0001010004020001000804000000008000015f506000e1fff900", - "results": { - "Prague": { - "result": true - } - } - }, - "backwards_rjumpi_10": { - "code": "0xef0001010004020001000e040000000080000360be6000e10001506000e1fff500", - "results": { - "Prague": { - "exception": "EOF_ConflictingStackHeight", - "result": false - } - } - }, - "backwards_rjumpi_2": { - "code": "0xef0001010004020001000d04000000008000015f506000e1fff96000e1fff400", - "results": { - "Prague": { - "result": true - } - } - }, - "backwards_rjumpi_3": { - "code": "0xef0001010004020001000e04000000008000025f506000e1fff95f6000e1fff300", - "results": { - "Prague": { - "exception": "EOF_ConflictingStackHeight", - "result": false - } - } - }, - "backwards_rjumpi_4": { - "code": "0xef0001010004020001000904000000008000025f60010180e1fff900", - "results": { - "Prague": { - "result": true - } - } - }, - "backwards_rjumpi_5": { - "code": "0xef0001010004020001000a04000000008000025f6001018080e1fff800", - "results": { - "Prague": { - "exception": "EOF_ConflictingStackHeight", - "result": false - } - } - }, - "backwards_rjumpi_6": { - "code": "0xef0001010004020001000804000000008000025f5f5f50e1fffc00", - "results": { - "Prague": { - "exception": "EOF_ConflictingStackHeight", - "result": false - } - } - }, - "backwards_rjumpi_7": { - "code": "0xef0001010004020001000a04000000008000015f506000e1fff9e0fff6", - "results": { - "Prague": { - "result": true - } - } - }, - "backwards_rjumpi_8": { - "code": "0xef0001010004020001000b04000000008000015f506000e1fff95fe0fff5", - "results": { - "Prague": { - "exception": "EOF_ConflictingStackHeight", - "result": false - } - } - }, - "backwards_rjumpi_9": { - "code": "0xef0001010004020001000d04000000008000035f6000e100015f6000e1fff500", - "results": { - "Prague": { - "exception": "EOF_ConflictingStackHeight", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/stack/backwards_rjumpi_variable_stack.json b/crates/interpreter/tests/EOFTests/eof_validation/stack/backwards_rjumpi_variable_stack.json deleted file mode 100644 index 427148d464..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/stack/backwards_rjumpi_variable_stack.json +++ /dev/null @@ -1,82 +0,0 @@ -{ - "backwards_rjumpi_variable_stack": { - "vectors": { - "backwards_rjumpi_variable_stack_0": { - "code": "0xef0001010004020001000e04000000008000045f6000e100025f5f6000e1fffb00", - "results": { - "Prague": { - "result": true - } - } - }, - "backwards_rjumpi_variable_stack_1": { - "code": "0xef0001010004020001001004000000008000045f6000e100025f5f5f506000e1fff900", - "results": { - "Prague": { - "result": true - } - } - }, - "backwards_rjumpi_variable_stack_2": { - "code": "0xef0001010004020001001504000000008000045f6000e100025f5f5f506000e1fff96000e1fff400", - "results": { - "Prague": { - "result": true - } - } - }, - "backwards_rjumpi_variable_stack_3": { - "code": "0xef0001010004020001001604000000008000055f6000e100025f5f5f506000e1fff95f6000e1fff300", - "results": { - "Prague": { - "exception": "EOF_ConflictingStackHeight", - "result": false - } - } - }, - "backwards_rjumpi_variable_stack_4": { - "code": "0xef0001010004020001001104000000008000055f6000e100025f5f5f60010180e1fff900", - "results": { - "Prague": { - "result": true - } - } - }, - "backwards_rjumpi_variable_stack_5": { - "code": "0xef0001010004020001001204000000008000055f6000e100025f5f5f6001018080e1fff800", - "results": { - "Prague": { - "exception": "EOF_ConflictingStackHeight", - "result": false - } - } - }, - "backwards_rjumpi_variable_stack_6": { - "code": "0xef0001010004020001001004000000008000055f6000e100025f5f5f5f5f50e1fffc00", - "results": { - "Prague": { - "exception": "EOF_ConflictingStackHeight", - "result": false - } - } - }, - "backwards_rjumpi_variable_stack_7": { - "code": "0xef0001010004020001001204000000008000045f6000e100025f5f5f506000e1fff9e0fff6", - "results": { - "Prague": { - "result": true - } - } - }, - "backwards_rjumpi_variable_stack_8": { - "code": "0xef0001010004020001001304000000008000045f6000e100025f5f5f506000e1fff95fe0fff5", - "results": { - "Prague": { - "exception": "EOF_ConflictingStackHeight", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/stack/backwards_rjumpv.json b/crates/interpreter/tests/EOFTests/eof_validation/stack/backwards_rjumpv.json deleted file mode 100644 index fae2f6081e..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/stack/backwards_rjumpv.json +++ /dev/null @@ -1,74 +0,0 @@ -{ - "backwards_rjumpv": { - "vectors": { - "backwards_rjumpv_0": { - "code": "0xef0001010004020001000704000000008000016000e200fffa00", - "results": { - "Prague": { - "result": true - } - } - }, - "backwards_rjumpv_1": { - "code": "0xef0001010004020001000904000000008000015f506000e200fff800", - "results": { - "Prague": { - "result": true - } - } - }, - "backwards_rjumpv_2": { - "code": "0xef0001010004020001000f04000000008000015f506000e200fff86000e200fff200", - "results": { - "Prague": { - "result": true - } - } - }, - "backwards_rjumpv_3": { - "code": "0xef0001010004020001001004000000008000025f506000e200fff85f6000e200fff100", - "results": { - "Prague": { - "exception": "EOF_ConflictingStackHeight", - "result": false - } - } - }, - "backwards_rjumpv_4": { - "code": "0xef0001010004020001000b04000000008000015f506000e200fff8e0fff5", - "results": { - "Prague": { - "result": true - } - } - }, - "backwards_rjumpv_5": { - "code": "0xef0001010004020001000c04000000008000015f506000e200fff85fe0fff4", - "results": { - "Prague": { - "exception": "EOF_ConflictingStackHeight", - "result": false - } - } - }, - "backwards_rjumpv_6": { - "code": "0xef0001010004020001000e04000000008000035f6000e100015f6000e200fff400", - "results": { - "Prague": { - "exception": "EOF_ConflictingStackHeight", - "result": false - } - } - }, - "backwards_rjumpv_7": { - "code": "0xef0001010004020001000f040000000080000360be6000e10001506000e200fff400", - "results": { - "Prague": { - "exception": "EOF_ConflictingStackHeight", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/stack/backwards_rjumpv_variable_stack.json b/crates/interpreter/tests/EOFTests/eof_validation/stack/backwards_rjumpv_variable_stack.json deleted file mode 100644 index 0cce8488cd..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/stack/backwards_rjumpv_variable_stack.json +++ /dev/null @@ -1,74 +0,0 @@ -{ - "backwards_rjumpv_variable_stack": { - "vectors": { - "backwards_rjumpv_variable_stack_0": { - "code": "0xef0001010004020001000f04000000008000045f6000e100025f5f6000e200fffa00", - "results": { - "Prague": { - "result": true - } - } - }, - "backwards_rjumpv_variable_stack_1": { - "code": "0xef0001010004020001001104000000008000045f6000e100025f5f5f506000e200fff800", - "results": { - "Prague": { - "result": true - } - } - }, - "backwards_rjumpv_variable_stack_2": { - "code": "0xef0001010004020001001704000000008000045f6000e100025f5f5f506000e200fff86000e200fff200", - "results": { - "Prague": { - "result": true - } - } - }, - "backwards_rjumpv_variable_stack_3": { - "code": "0xef0001010004020001001804000000008000055f6000e100025f5f5f506000e200fff85f6000e200fff100", - "results": { - "Prague": { - "exception": "EOF_ConflictingStackHeight", - "result": false - } - } - }, - "backwards_rjumpv_variable_stack_4": { - "code": "0xef0001010004020001001304000000008000045f6000e100025f5f5f506000e200fff8e0fff5", - "results": { - "Prague": { - "result": true - } - } - }, - "backwards_rjumpv_variable_stack_5": { - "code": "0xef0001010004020001001404000000008000045f6000e100025f5f5f506000e200fff85fe0fff4", - "results": { - "Prague": { - "exception": "EOF_ConflictingStackHeight", - "result": false - } - } - }, - "backwards_rjumpv_variable_stack_6": { - "code": "0xef0001010004020001001604000000008000055f6000e100025f5f5f6000e100015f6000e200fff400", - "results": { - "Prague": { - "exception": "EOF_ConflictingStackHeight", - "result": false - } - } - }, - "backwards_rjumpv_variable_stack_7": { - "code": "0xef0001010004020001001704000000008000055f6000e100025f5f5f5f6000e10001506000e200fff400", - "results": { - "Prague": { - "exception": "EOF_ConflictingStackHeight", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/stack/callf_stack_overflow.json b/crates/interpreter/tests/EOFTests/eof_validation/stack/callf_stack_overflow.json deleted file mode 100644 index bc17fd15a5..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/stack/callf_stack_overflow.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "callf_stack_overflow": { - "vectors": { - "callf_stack_overflow_0": { - "code": "0xef000101000802000200040604040000000080000000000200e300010060016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001e300015050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050e4", - "results": { - "Prague": { - "result": true - } - } - }, - "callf_stack_overflow_1": { - "code": "0xef000101000802000200040607040000000080000000000201e3000100600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001e30001505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050e4", - "results": { - "Prague": { - "exception": "EOF_StackOverflow", - "result": false - } - } - }, - "callf_stack_overflow_2": { - "code": "0xef000101000802000200040c010400000000800000000003ffe3000100600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001e30001505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050e4", - "results": { - "Prague": { - "exception": "EOF_StackOverflow", - "result": false - } - } - }, - "callf_stack_overflow_3": { - "code": "0xef000101000c02000300040c0100030400000000800000000003ff00000001e3000100600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001e30002505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050e45f50e4", - "results": { - "Prague": { - "result": true - } - } - }, - "callf_stack_overflow_4": { - "code": "0xef000101000c02000300040c0100050400000000800000000003ff00000002e3000100600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001e30002505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050e45f5f5050e4", - "results": { - "Prague": { - "exception": "EOF_StackOverflow", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/stack/callf_stack_overflow_variable_stack.json b/crates/interpreter/tests/EOFTests/eof_validation/stack/callf_stack_overflow_variable_stack.json deleted file mode 100644 index cd78ff8f8f..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/stack/callf_stack_overflow_variable_stack.json +++ /dev/null @@ -1,58 +0,0 @@ -{ - "callf_stack_overflow_variable_stack": { - "vectors": { - "callf_stack_overflow_variable_stack_0": { - "code": "0xef0001010008020002040606010400000000800200000002005f6000e100025f5f60016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001e3000100600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160015050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050e4", - "results": { - "Prague": { - "result": true - } - } - }, - "callf_stack_overflow_variable_stack_1": { - "code": "0xef00010100080200020406060a0400000000800200000002035f6000e100025f5f60016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001e3000100600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160015050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050e4", - "results": { - "Prague": { - "exception": "EOF_StackOverflow", - "result": false - } - } - }, - "callf_stack_overflow_variable_stack_2": { - "code": "0xef0001010008020002040606070400000000800200000002025f6000e100025f5f60016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001e3000100600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600150505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050e4", - "results": { - "Prague": { - "exception": "EOF_StackOverflow", - "result": false - } - } - }, - "callf_stack_overflow_variable_stack_3": { - "code": "0xef00010100080200020804000304000000008003ff000000015f6000e100025f5f600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001e30001005f50e4", - "results": { - "Prague": { - "result": true - } - } - }, - "callf_stack_overflow_variable_stack_4": { - "code": "0xef00010100080200020804000b04000000008003ff000000055f6000e100025f5f600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001e30001005f5f5f5f5f5050505050e4", - "results": { - "Prague": { - "exception": "EOF_StackOverflow", - "result": false - } - } - }, - "callf_stack_overflow_variable_stack_5": { - "code": "0xef00010100080200020804000504000000008003ff000000025f6000e100025f5f600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001e30001005f5f5050e4", - "results": { - "Prague": { - "exception": "EOF_StackOverflow", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/stack/callf_stack_validation.json b/crates/interpreter/tests/EOFTests/eof_validation/stack/callf_stack_validation.json deleted file mode 100644 index b0eda869ce..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/stack/callf_stack_validation.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "callf_stack_validation": { - "vectors": { - "callf_stack_validation_0": { - "code": "0xef000101000c02000300040006000204000000008000010001000202010002e30001005f5fe30002e450e4", - "results": { - "Prague": { - "result": true - } - } - }, - "callf_stack_validation_1": { - "code": "0xef000101000c02000300040007000204000000008000010001000302010002e30001005f5f5fe30002e450e4", - "results": { - "Prague": { - "exception": "EOF_InvalidNumberOfOutputs", - "result": false - } - } - }, - "callf_stack_validation_2": { - "code": "0xef000101000c02000300040005000204000000008000010001000102010002e30001005fe30002e450e4", - "results": { - "Prague": { - "exception": "EOF_StackUnderflow", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/stack/callf_with_inputs_stack_overflow.json b/crates/interpreter/tests/EOFTests/eof_validation/stack/callf_with_inputs_stack_overflow.json deleted file mode 100644 index a6f5af7c67..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/stack/callf_with_inputs_stack_overflow.json +++ /dev/null @@ -1,58 +0,0 @@ -{ - "callf_with_inputs_stack_overflow": { - "vectors": { - "callf_with_inputs_stack_overflow_0": { - "code": "0xef00010100080200020bfd000304000000008003ff02000002600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001e300015050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050f35050e4", - "results": { - "Prague": { - "result": true - } - } - }, - "callf_with_inputs_stack_overflow_1": { - "code": "0xef00010100080200020bff000404000000008003ff03030004600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001e3000150505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050f3600150e4", - "results": { - "Prague": { - "result": true - } - } - }, - "callf_with_inputs_stack_overflow_2": { - "code": "0xef00010100080200020bff000304000000008003ff03050005600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001e3000150505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050f35f5fe4", - "results": { - "Prague": { - "exception": "EOF_StackOverflow", - "result": false - } - } - }, - "callf_with_inputs_stack_overflow_3": { - "code": "0xef00010100080200020bff000504000000008003ff03030005600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001e3000150505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050f35f5f5050e4", - "results": { - "Prague": { - "exception": "EOF_StackOverflow", - "result": false - } - } - }, - "callf_with_inputs_stack_overflow_4": { - "code": "0xef00010100080200020c00000504000000008003ff020000036001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001e30001505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050f35f505050e4", - "results": { - "Prague": { - "exception": "EOF_StackOverflow", - "result": false - } - } - }, - "callf_with_inputs_stack_overflow_5": { - "code": "0xef00010100080200020bfe000704000000008003ff02000004600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001e30001505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050f35f5f50505050e4", - "results": { - "Prague": { - "exception": "EOF_StackOverflow", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/stack/callf_with_inputs_stack_overflow_variable_stack.json b/crates/interpreter/tests/EOFTests/eof_validation/stack/callf_with_inputs_stack_overflow_variable_stack.json deleted file mode 100644 index 85ac3816a7..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/stack/callf_with_inputs_stack_overflow_variable_stack.json +++ /dev/null @@ -1,94 +0,0 @@ -{ - "callf_with_inputs_stack_overflow_variable_stack": { - "vectors": { - "callf_with_inputs_stack_overflow_variable_stack_0": { - "code": "0xef00010100080200020804000304000000008003ff020000025f6000e100025f5f600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001e30001005050e4", - "results": { - "Prague": { - "result": true - } - } - }, - "callf_with_inputs_stack_overflow_variable_stack_1": { - "code": "0xef00010100080200020804000404000000008003ff030300045f6000e100025f5f600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001e3000100600150e4", - "results": { - "Prague": { - "result": true - } - } - }, - "callf_with_inputs_stack_overflow_variable_stack_2": { - "code": "0xef00010100080200020804000504000000008003ff030700075f6000e100025f5f600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001e30001005f5f5f5fe4", - "results": { - "Prague": { - "exception": "EOF_StackOverflow", - "result": false - } - } - }, - "callf_with_inputs_stack_overflow_variable_stack_3": { - "code": "0xef00010100080200020804000304000000008003ff030500055f6000e100025f5f600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001e30001005f5fe4", - "results": { - "Prague": { - "exception": "EOF_StackOverflow", - "result": false - } - } - }, - "callf_with_inputs_stack_overflow_variable_stack_4": { - "code": "0xef00010100080200020804000704000000008003ff030300075f6000e100025f5f600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001e30001005f5f5f5f5050e4", - "results": { - "Prague": { - "exception": "EOF_StackOverflow", - "result": false - } - } - }, - "callf_with_inputs_stack_overflow_variable_stack_5": { - "code": "0xef00010100080200020804000504000000008003ff030300055f6000e100025f5f600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001e30001005f5f5050e4", - "results": { - "Prague": { - "exception": "EOF_StackOverflow", - "result": false - } - } - }, - "callf_with_inputs_stack_overflow_variable_stack_6": { - "code": "0xef00010100080200020806000904000000008003ff020000055f6000e100025f5f6001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001e30001005f5f5f5050505050e4", - "results": { - "Prague": { - "exception": "EOF_StackOverflow", - "result": false - } - } - }, - "callf_with_inputs_stack_overflow_variable_stack_7": { - "code": "0xef00010100080200020806000504000000008003ff020000035f6000e100025f5f6001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001e30001005f505050e4", - "results": { - "Prague": { - "exception": "EOF_StackOverflow", - "result": false - } - } - }, - "callf_with_inputs_stack_overflow_variable_stack_8": { - "code": "0xef00010100080200020804000b04000000008003ff020000065f6000e100025f5f600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001e30001005f5f5f5f505050505050e4", - "results": { - "Prague": { - "exception": "EOF_StackOverflow", - "result": false - } - } - }, - "callf_with_inputs_stack_overflow_variable_stack_9": { - "code": "0xef00010100080200020804000704000000008003ff020000045f6000e100025f5f600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001e30001005f5f50505050e4", - "results": { - "Prague": { - "exception": "EOF_StackOverflow", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/stack/dupn_stack_validation.json b/crates/interpreter/tests/EOFTests/eof_validation/stack/dupn_stack_validation.json deleted file mode 100644 index e34d293dd3..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/stack/dupn_stack_validation.json +++ /dev/null @@ -1,58 +0,0 @@ -{ - "dupn_stack_validation": { - "vectors": { - "dupn_stack_validation_0": { - "code": "0xef0001010004020001002b040000000080001560016001600160016001600160016001600160016001600160016001600160016001600160016001e60000", - "results": { - "Prague": { - "result": true - } - } - }, - "dupn_stack_validation_1": { - "code": "0xef0001010004020001002b040000000080001560016001600160016001600160016001600160016001600160016001600160016001600160016001e61300", - "results": { - "Prague": { - "result": true - } - } - }, - "dupn_stack_validation_2": { - "code": "0xef0001010004020001002b040000000080001560016001600160016001600160016001600160016001600160016001600160016001600160016001e61400", - "results": { - "Prague": { - "exception": "EOF_StackUnderflow", - "result": false - } - } - }, - "dupn_stack_validation_3": { - "code": "0xef0001010004020001002b040000000080001560016001600160016001600160016001600160016001600160016001600160016001600160016001e6d000", - "results": { - "Prague": { - "exception": "EOF_StackUnderflow", - "result": false - } - } - }, - "dupn_stack_validation_4": { - "code": "0xef0001010004020001002b040000000080001560016001600160016001600160016001600160016001600160016001600160016001600160016001e6fe00", - "results": { - "Prague": { - "exception": "EOF_StackUnderflow", - "result": false - } - } - }, - "dupn_stack_validation_5": { - "code": "0xef0001010004020001002b040000000080001560016001600160016001600160016001600160016001600160016001600160016001600160016001e6ff00", - "results": { - "Prague": { - "exception": "EOF_StackUnderflow", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/stack/exchange_deep_stack_validation.json b/crates/interpreter/tests/EOFTests/eof_validation/stack/exchange_deep_stack_validation.json deleted file mode 100644 index 830e71fe4b..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/stack/exchange_deep_stack_validation.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "exchange_deep_stack_validation": { - "vectors": { - "exchange_deep_stack_validation_0": { - "code": "0xef000101000402000100450400000000800021600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001e8ff00", - "results": { - "Prague": { - "result": true - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/stack/exchange_empty_stack_validation.json b/crates/interpreter/tests/EOFTests/eof_validation/stack/exchange_empty_stack_validation.json deleted file mode 100644 index 99fddf702c..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/stack/exchange_empty_stack_validation.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "exchange_empty_stack_validation": { - "vectors": { - "exchange_empty_stack_validation_0": { - "code": "0xef000101000402000100030400000000800000e80000", - "results": { - "Prague": { - "exception": "EOF_StackUnderflow", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/stack/exchange_stack_validation.json b/crates/interpreter/tests/EOFTests/eof_validation/stack/exchange_stack_validation.json deleted file mode 100644 index 831f357963..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/stack/exchange_stack_validation.json +++ /dev/null @@ -1,201 +0,0 @@ -{ - "exchange_stack_validation": { - "vectors": { - "exchange_stack_validation_0": { - "code": "0xef00010100040200010017040000000080000a6001600160016001600160016001600160016001e80000", - "results": { - "Prague": { - "result": true - } - } - }, - "exchange_stack_validation_1": { - "code": "0xef00010100040200010017040000000080000a6001600160016001600160016001600160016001e81000", - "results": { - "Prague": { - "result": true - } - } - }, - "exchange_stack_validation_10": { - "code": "0xef00010100040200010017040000000080000a6001600160016001600160016001600160016001e81600", - "results": { - "Prague": { - "result": true - } - } - }, - "exchange_stack_validation_11": { - "code": "0xef00010100040200010017040000000080000a6001600160016001600160016001600160016001e86100", - "results": { - "Prague": { - "result": true - } - } - }, - "exchange_stack_validation_12": { - "code": "0xef00010100040200010017040000000080000a6001600160016001600160016001600160016001e88000", - "results": { - "Prague": { - "exception": "EOF_StackUnderflow", - "result": false - } - } - }, - "exchange_stack_validation_13": { - "code": "0xef00010100040200010017040000000080000a6001600160016001600160016001600160016001e80800", - "results": { - "Prague": { - "exception": "EOF_StackUnderflow", - "result": false - } - } - }, - "exchange_stack_validation_14": { - "code": "0xef00010100040200010017040000000080000a6001600160016001600160016001600160016001e87100", - "results": { - "Prague": { - "exception": "EOF_StackUnderflow", - "result": false - } - } - }, - "exchange_stack_validation_15": { - "code": "0xef00010100040200010017040000000080000a6001600160016001600160016001600160016001e81700", - "results": { - "Prague": { - "exception": "EOF_StackUnderflow", - "result": false - } - } - }, - "exchange_stack_validation_16": { - "code": "0xef00010100040200010017040000000080000a6001600160016001600160016001600160016001e84400", - "results": { - "Prague": { - "exception": "EOF_StackUnderflow", - "result": false - } - } - }, - "exchange_stack_validation_17": { - "code": "0xef00010100040200010017040000000080000a6001600160016001600160016001600160016001e85300", - "results": { - "Prague": { - "exception": "EOF_StackUnderflow", - "result": false - } - } - }, - "exchange_stack_validation_18": { - "code": "0xef00010100040200010017040000000080000a6001600160016001600160016001600160016001e83500", - "results": { - "Prague": { - "exception": "EOF_StackUnderflow", - "result": false - } - } - }, - "exchange_stack_validation_19": { - "code": "0xef00010100040200010017040000000080000a6001600160016001600160016001600160016001e8ee00", - "results": { - "Prague": { - "exception": "EOF_StackUnderflow", - "result": false - } - } - }, - "exchange_stack_validation_2": { - "code": "0xef00010100040200010017040000000080000a6001600160016001600160016001600160016001e80100", - "results": { - "Prague": { - "result": true - } - } - }, - "exchange_stack_validation_20": { - "code": "0xef00010100040200010017040000000080000a6001600160016001600160016001600160016001e8ef00", - "results": { - "Prague": { - "exception": "EOF_StackUnderflow", - "result": false - } - } - }, - "exchange_stack_validation_21": { - "code": "0xef00010100040200010017040000000080000a6001600160016001600160016001600160016001e8fe00", - "results": { - "Prague": { - "exception": "EOF_StackUnderflow", - "result": false - } - } - }, - "exchange_stack_validation_22": { - "code": "0xef00010100040200010017040000000080000a6001600160016001600160016001600160016001e8ff00", - "results": { - "Prague": { - "exception": "EOF_StackUnderflow", - "result": false - } - } - }, - "exchange_stack_validation_3": { - "code": "0xef00010100040200010017040000000080000a6001600160016001600160016001600160016001e82000", - "results": { - "Prague": { - "result": true - } - } - }, - "exchange_stack_validation_4": { - "code": "0xef00010100040200010017040000000080000a6001600160016001600160016001600160016001e80200", - "results": { - "Prague": { - "result": true - } - } - }, - "exchange_stack_validation_5": { - "code": "0xef00010100040200010017040000000080000a6001600160016001600160016001600160016001e87000", - "results": { - "Prague": { - "result": true - } - } - }, - "exchange_stack_validation_6": { - "code": "0xef00010100040200010017040000000080000a6001600160016001600160016001600160016001e80700", - "results": { - "Prague": { - "result": true - } - } - }, - "exchange_stack_validation_7": { - "code": "0xef00010100040200010017040000000080000a6001600160016001600160016001600160016001e81100", - "results": { - "Prague": { - "result": true - } - } - }, - "exchange_stack_validation_8": { - "code": "0xef00010100040200010017040000000080000a6001600160016001600160016001600160016001e83400", - "results": { - "Prague": { - "result": true - } - } - }, - "exchange_stack_validation_9": { - "code": "0xef00010100040200010017040000000080000a6001600160016001600160016001600160016001e84300", - "results": { - "Prague": { - "result": true - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/stack/forwards_rjump.json b/crates/interpreter/tests/EOFTests/eof_validation/stack/forwards_rjump.json deleted file mode 100644 index e2b99000ae..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/stack/forwards_rjump.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "forwards_rjump": { - "vectors": { - "forwards_rjump_0": { - "code": "0xef000101000402000100040400000000800000e0000000", - "results": { - "Prague": { - "result": true - } - } - }, - "forwards_rjump_1": { - "code": "0xef0001010004020001000b04000000008000025f6000e10003e000011900", - "results": { - "Prague": { - "result": true - } - } - }, - "forwards_rjump_2": { - "code": "0xef0001010004020001001304000000008000025f6000e100086000e10006e00004e000011900", - "results": { - "Prague": { - "result": true - } - } - }, - "forwards_rjump_3": { - "code": "0xef0001010004020001000b04000000008000025f6000e10003e000015f00", - "results": { - "Prague": { - "result": true - } - } - }, - "forwards_rjump_4": { - "code": "0xef0001010004020001001404000000008000025f6000e100086000e10007e000055fe000011900", - "results": { - "Prague": { - "result": true - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/stack/forwards_rjump_variable_stack.json b/crates/interpreter/tests/EOFTests/eof_validation/stack/forwards_rjump_variable_stack.json deleted file mode 100644 index 62c5fb2b5b..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/stack/forwards_rjump_variable_stack.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "forwards_rjump_variable_stack": { - "vectors": { - "forwards_rjump_variable_stack_0": { - "code": "0xef0001010004020001000c04000000008000035f6000e100025f5fe0000000", - "results": { - "Prague": { - "result": true - } - } - }, - "forwards_rjump_variable_stack_1": { - "code": "0xef0001010004020001001304000000008000055f6000e100025f5f5f6000e10003e000011900", - "results": { - "Prague": { - "result": true - } - } - }, - "forwards_rjump_variable_stack_2": { - "code": "0xef0001010004020001001b04000000008000055f6000e100025f5f5f6000e100086000e10006e00004e000011900", - "results": { - "Prague": { - "result": true - } - } - }, - "forwards_rjump_variable_stack_3": { - "code": "0xef0001010004020001001304000000008000055f6000e100025f5f5f6000e10003e000015f00", - "results": { - "Prague": { - "result": true - } - } - }, - "forwards_rjump_variable_stack_4": { - "code": "0xef0001010004020001001b04000000008000045f6000e100025f5f6000e100086000e10007e000055fe000011900", - "results": { - "Prague": { - "result": true - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/stack/forwards_rjumpi.json b/crates/interpreter/tests/EOFTests/eof_validation/stack/forwards_rjumpi.json deleted file mode 100644 index b7f9d445bb..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/stack/forwards_rjumpi.json +++ /dev/null @@ -1,110 +0,0 @@ -{ - "forwards_rjumpi": { - "vectors": { - "forwards_rjumpi_0": { - "code": "0xef0001010004020001000604000000008000016001e1000000", - "results": { - "Prague": { - "result": true - } - } - }, - "forwards_rjumpi_1": { - "code": "0xef0001010004020001000804000000008000025f6000e100011900", - "results": { - "Prague": { - "result": true - } - } - }, - "forwards_rjumpi_10": { - "code": "0xef0001010004020001000c04000000008000025f6000e1000450e000011900", - "results": { - "Prague": { - "result": true - } - } - }, - "forwards_rjumpi_11": { - "code": "0xef0001010004020001000a04000000008000025f6000e10003e0000000", - "results": { - "Prague": { - "result": true - } - } - }, - "forwards_rjumpi_12": { - "code": "0xef0001010004020001000b04000000008000025f6000e100045fe0000000", - "results": { - "Prague": { - "result": true - } - } - }, - "forwards_rjumpi_2": { - "code": "0xef0001010004020001000d04000000008000025f6000e100066000e100011900", - "results": { - "Prague": { - "result": true - } - } - }, - "forwards_rjumpi_3": { - "code": "0xef0001010004020001000804000000008000025f6000e100015f00", - "results": { - "Prague": { - "result": true - } - } - }, - "forwards_rjumpi_4": { - "code": "0xef0001010004020001000e04000000008000035f6000e100075f6000e100011900", - "results": { - "Prague": { - "result": true - } - } - }, - "forwards_rjumpi_5": { - "code": "0xef0001010004020001001004000000008000035f60010180600a11e1000480e1fff200", - "results": { - "Prague": { - "result": true - } - } - }, - "forwards_rjumpi_6": { - "code": "0xef0001010004020001001104000000008000035f60010180600a11e100055f80e1fff300", - "results": { - "Prague": { - "result": true - } - } - }, - "forwards_rjumpi_7": { - "code": "0xef0001010004020001000c04000000008000025f6000e100045fe000015f00", - "results": { - "Prague": { - "result": true - } - } - }, - "forwards_rjumpi_8": { - "code": "0xef0001010004020001000c04000000008000025f6000e100045fe000011900", - "results": { - "Prague": { - "result": true - } - } - }, - "forwards_rjumpi_9": { - "code": "0xef0001010004020001000c04000000008000025f6000e1000450e000015000", - "results": { - "Prague": { - "result": true - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/stack/forwards_rjumpi_variable_stack.json b/crates/interpreter/tests/EOFTests/eof_validation/stack/forwards_rjumpi_variable_stack.json deleted file mode 100644 index cc0c419203..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/stack/forwards_rjumpi_variable_stack.json +++ /dev/null @@ -1,110 +0,0 @@ -{ - "forwards_rjumpi_variable_stack": { - "vectors": { - "forwards_rjumpi_variable_stack_0": { - "code": "0xef0001010004020001000e04000000008000045f6000e100025f5f6001e1000000", - "results": { - "Prague": { - "result": true - } - } - }, - "forwards_rjumpi_variable_stack_1": { - "code": "0xef0001010004020001001004000000008000055f6000e100025f5f5f6000e100011900", - "results": { - "Prague": { - "result": true - } - } - }, - "forwards_rjumpi_variable_stack_10": { - "code": "0xef0001010004020001001404000000008000055f6000e100025f5f5f6000e1000450e000011900", - "results": { - "Prague": { - "result": true - } - } - }, - "forwards_rjumpi_variable_stack_11": { - "code": "0xef0001010004020001001204000000008000055f6000e100025f5f5f6000e10003e0000000", - "results": { - "Prague": { - "result": true - } - } - }, - "forwards_rjumpi_variable_stack_12": { - "code": "0xef0001010004020001001304000000008000055f6000e100025f5f5f6000e100045fe0000000", - "results": { - "Prague": { - "result": true - } - } - }, - "forwards_rjumpi_variable_stack_2": { - "code": "0xef0001010004020001001504000000008000055f6000e100025f5f5f6000e100066000e100011900", - "results": { - "Prague": { - "result": true - } - } - }, - "forwards_rjumpi_variable_stack_3": { - "code": "0xef0001010004020001001004000000008000055f6000e100025f5f5f6000e100015f00", - "results": { - "Prague": { - "result": true - } - } - }, - "forwards_rjumpi_variable_stack_4": { - "code": "0xef0001010004020001001604000000008000065f6000e100025f5f5f6000e100075f6000e100011900", - "results": { - "Prague": { - "result": true - } - } - }, - "forwards_rjumpi_variable_stack_5": { - "code": "0xef0001010004020001001804000000008000065f6000e100025f5f5f60010180600a11e1000480e1fff200", - "results": { - "Prague": { - "result": true - } - } - }, - "forwards_rjumpi_variable_stack_6": { - "code": "0xef0001010004020001001904000000008000065f6000e100025f5f5f60010180600a11e100055f80e1fff300", - "results": { - "Prague": { - "result": true - } - } - }, - "forwards_rjumpi_variable_stack_7": { - "code": "0xef0001010004020001001404000000008000055f6000e100025f5f5f6000e100045fe000015f00", - "results": { - "Prague": { - "result": true - } - } - }, - "forwards_rjumpi_variable_stack_8": { - "code": "0xef0001010004020001001404000000008000055f6000e100025f5f5f6000e100045fe000011900", - "results": { - "Prague": { - "result": true - } - } - }, - "forwards_rjumpi_variable_stack_9": { - "code": "0xef0001010004020001001404000000008000055f6000e100025f5f5f6000e1000450e000015000", - "results": { - "Prague": { - "result": true - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/stack/forwards_rjumpv.json b/crates/interpreter/tests/EOFTests/eof_validation/stack/forwards_rjumpv.json deleted file mode 100644 index dcfe6faa9d..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/stack/forwards_rjumpv.json +++ /dev/null @@ -1,86 +0,0 @@ -{ - "forwards_rjumpv": { - "vectors": { - "forwards_rjumpv_0": { - "code": "0xef0001010004020001000704000000008000016001e200000000", - "results": { - "Prague": { - "result": true - } - } - }, - "forwards_rjumpv_1": { - "code": "0xef0001010004020001000904000000008000025f6000e20000011900", - "results": { - "Prague": { - "result": true - } - } - }, - "forwards_rjumpv_2": { - "code": "0xef0001010004020001000d04000000008000025f6000e201000200035f501900", - "results": { - "Prague": { - "result": true - } - } - }, - "forwards_rjumpv_3": { - "code": "0xef0001010004020001000904000000008000025f6000e20000015f00", - "results": { - "Prague": { - "result": true - } - } - }, - "forwards_rjumpv_4": { - "code": "0xef0001010004020001000d04000000008000035f6000e201000100025f5f1900", - "results": { - "Prague": { - "result": true - } - } - }, - "forwards_rjumpv_5": { - "code": "0xef0001010004020001001604000000008000025f6000e2010005000a6001e000076002e00002600300", - "results": { - "Prague": { - "result": true - } - } - }, - "forwards_rjumpv_6": { - "code": "0xef0001010004020001001604000000008000045f6000e201000400095fe000085f5fe000035f5f5f00", - "results": { - "Prague": { - "result": true - } - } - }, - "forwards_rjumpv_7": { - "code": "0xef0001010004020001001904000000008000055f5f5f5f6000e2010004000950e000085050e0000350505000", - "results": { - "Prague": { - "result": true - } - } - }, - "forwards_rjumpv_8": { - "code": "0xef0001010004020001000b04000000008000025f6000e2000003e0000000", - "results": { - "Prague": { - "result": true - } - } - }, - "forwards_rjumpv_9": { - "code": "0xef0001010004020001000c04000000008000025f6000e20000045fe0000000", - "results": { - "Prague": { - "result": true - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/stack/forwards_rjumpv_variable_stack.json b/crates/interpreter/tests/EOFTests/eof_validation/stack/forwards_rjumpv_variable_stack.json deleted file mode 100644 index a4d3aea555..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/stack/forwards_rjumpv_variable_stack.json +++ /dev/null @@ -1,86 +0,0 @@ -{ - "forwards_rjumpv_variable_stack": { - "vectors": { - "forwards_rjumpv_variable_stack_0": { - "code": "0xef0001010004020001000f04000000008000045f6000e100025f5f6001e200000000", - "results": { - "Prague": { - "result": true - } - } - }, - "forwards_rjumpv_variable_stack_1": { - "code": "0xef0001010004020001001104000000008000055f6000e100025f5f5f6000e20000011900", - "results": { - "Prague": { - "result": true - } - } - }, - "forwards_rjumpv_variable_stack_2": { - "code": "0xef0001010004020001001504000000008000055f6000e100025f5f5f6000e201000200035f501900", - "results": { - "Prague": { - "result": true - } - } - }, - "forwards_rjumpv_variable_stack_3": { - "code": "0xef0001010004020001001104000000008000055f6000e100025f5f5f6000e20000015f00", - "results": { - "Prague": { - "result": true - } - } - }, - "forwards_rjumpv_variable_stack_4": { - "code": "0xef0001010004020001001504000000008000065f6000e100025f5f5f6000e201000100025f5f1900", - "results": { - "Prague": { - "result": true - } - } - }, - "forwards_rjumpv_variable_stack_5": { - "code": "0xef0001010004020001001e04000000008000055f6000e100025f5f5f6000e2010005000a6001e000076002e00002600300", - "results": { - "Prague": { - "result": true - } - } - }, - "forwards_rjumpv_variable_stack_6": { - "code": "0xef0001010004020001001e04000000008000075f6000e100025f5f5f6000e201000400095fe000085f5fe000035f5f5f00", - "results": { - "Prague": { - "result": true - } - } - }, - "forwards_rjumpv_variable_stack_7": { - "code": "0xef0001010004020001002104000000008000085f6000e100025f5f5f5f5f5f6000e2010004000950e000085050e0000350505000", - "results": { - "Prague": { - "result": true - } - } - }, - "forwards_rjumpv_variable_stack_8": { - "code": "0xef0001010004020001001304000000008000055f6000e100025f5f5f6000e2000003e0000000", - "results": { - "Prague": { - "result": true - } - } - }, - "forwards_rjumpv_variable_stack_9": { - "code": "0xef0001010004020001001404000000008000055f6000e100025f5f5f6000e20000045fe0000000", - "results": { - "Prague": { - "result": true - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/stack/jumpf_stack_overflow.json b/crates/interpreter/tests/EOFTests/eof_validation/stack/jumpf_stack_overflow.json deleted file mode 100644 index 1b7a0d95cc..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/stack/jumpf_stack_overflow.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "jumpf_stack_overflow": { - "vectors": { - "jumpf_stack_overflow_0": { - "code": "0xef00010100040200010403040000000080020060016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001e50000", - "results": { - "Prague": { - "result": true - } - } - }, - "jumpf_stack_overflow_1": { - "code": "0xef000101000402000104050400000000800201600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001e50000", - "results": { - "Prague": { - "exception": "EOF_StackOverflow", - "result": false - } - } - }, - "jumpf_stack_overflow_2": { - "code": "0xef0001010004020001080104000000008003ff600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001e50000", - "results": { - "Prague": { - "exception": "EOF_StackOverflow", - "result": false - } - } - }, - "jumpf_stack_overflow_3": { - "code": "0xef00010100080200020801000204000000008003ff00800001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001e500015f00", - "results": { - "Prague": { - "result": true - } - } - }, - "jumpf_stack_overflow_4": { - "code": "0xef00010100080200020801000304000000008003ff00800002600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001600160016001e500015f5f00", - "results": { - "Prague": { - "exception": "EOF_StackOverflow", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/stack/jumpf_stack_overflow_variable_stack.json b/crates/interpreter/tests/EOFTests/eof_validation/stack/jumpf_stack_overflow_variable_stack.json deleted file mode 100644 index 4554f84bfa..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/stack/jumpf_stack_overflow_variable_stack.json +++ /dev/null @@ -1,58 +0,0 @@ -{ - "jumpf_stack_overflow_variable_stack": { - "vectors": { - "jumpf_stack_overflow_variable_stack_0": { - "code": "0xef0001010004020001020804000000008002005f6000e100025f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5fe50000", - "results": { - "Prague": { - "result": true - } - } - }, - "jumpf_stack_overflow_variable_stack_1": { - "code": "0xef0001010008020002020802040400000000800200008002035f6000e100025f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5fe500015f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f00", - "results": { - "Prague": { - "exception": "EOF_StackOverflow", - "result": false - } - } - }, - "jumpf_stack_overflow_variable_stack_2": { - "code": "0xef0001010008020002020802030400000000800200008002025f6000e100025f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5fe500015f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f00", - "results": { - "Prague": { - "exception": "EOF_StackOverflow", - "result": false - } - } - }, - "jumpf_stack_overflow_variable_stack_3": { - "code": "0xef00010100080200020407000204000000008003ff008000015f6000e100025f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5fe500015f00", - "results": { - "Prague": { - "result": true - } - } - }, - "jumpf_stack_overflow_variable_stack_4": { - "code": "0xef00010100080200020407000604000000008003ff008000055f6000e100025f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5fe500015f5f5f5f5f00", - "results": { - "Prague": { - "exception": "EOF_StackOverflow", - "result": false - } - } - }, - "jumpf_stack_overflow_variable_stack_5": { - "code": "0xef00010100080200020407000304000000008003ff008000025f6000e100025f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5fe500015f5f00", - "results": { - "Prague": { - "exception": "EOF_StackOverflow", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/stack/jumpf_to_nonreturning.json b/crates/interpreter/tests/EOFTests/eof_validation/stack/jumpf_to_nonreturning.json deleted file mode 100644 index 7cfccdeaf7..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/stack/jumpf_to_nonreturning.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "jumpf_to_nonreturning": { - "vectors": { - "jumpf_to_nonreturning_0": { - "code": "0xef000101000802000200030001040000000080000000800000e5000100", - "results": { - "Prague": { - "result": true - } - } - }, - "jumpf_to_nonreturning_1": { - "code": "0xef0001010008020002000500010400000000800002008000005f5fe5000100", - "results": { - "Prague": { - "result": true - } - } - }, - "jumpf_to_nonreturning_2": { - "code": "0xef0001010008020002000600010400000000800003038000035f5f5fe5000100", - "results": { - "Prague": { - "result": true - } - } - }, - "jumpf_to_nonreturning_3": { - "code": "0xef0001010008020002000700010400000000800004038000035f5f5f5fe5000100", - "results": { - "Prague": { - "result": true - } - } - }, - "jumpf_to_nonreturning_4": { - "code": "0xef0001010008020002000500010400000000800002038000035f5fe5000100", - "results": { - "Prague": { - "exception": "EOF_StackUnderflow", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/stack/jumpf_to_nonreturning_variable_stack.json b/crates/interpreter/tests/EOFTests/eof_validation/stack/jumpf_to_nonreturning_variable_stack.json deleted file mode 100644 index 8ac969b806..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/stack/jumpf_to_nonreturning_variable_stack.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "jumpf_to_nonreturning_variable_stack": { - "vectors": { - "jumpf_to_nonreturning_variable_stack_0": { - "code": "0xef0001010008020002000b00010400000000800003058000055f6000e100025f5fe50001fe", - "results": { - "Prague": { - "exception": "EOF_StackUnderflow", - "result": false - } - } - }, - "jumpf_to_nonreturning_variable_stack_1": { - "code": "0xef0001010008020002000b00010400000000800003038000035f6000e100025f5fe50001fe", - "results": { - "Prague": { - "exception": "EOF_StackUnderflow", - "result": false - } - } - }, - "jumpf_to_nonreturning_variable_stack_2": { - "code": "0xef0001010008020002000b00010400000000800003018000015f6000e100025f5fe50001fe", - "results": { - "Prague": { - "result": true - } - } - }, - "jumpf_to_nonreturning_variable_stack_3": { - "code": "0xef0001010008020002000b00010400000000800003008000005f6000e100025f5fe50001fe", - "results": { - "Prague": { - "result": true - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/stack/jumpf_to_returning.json b/crates/interpreter/tests/EOFTests/eof_validation/stack/jumpf_to_returning.json deleted file mode 100644 index 4731686f08..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/stack/jumpf_to_returning.json +++ /dev/null @@ -1,101 +0,0 @@ -{ - "jumpf_to_returning": { - "vectors": { - "jumpf_to_returning_0": { - "code": "0xef000101000c02000300040003000304000000008000020002000000020002e3000100e500025f5fe4", - "results": { - "Prague": { - "result": true - } - } - }, - "jumpf_to_returning_1": { - "code": "0xef000101000c02000300040005000304000000008000020002000200020002e30001005f5fe500025f5fe4", - "results": { - "Prague": { - "exception": "EOF_InvalidNumberOfOutputs", - "result": false - } - } - }, - "jumpf_to_returning_10": { - "code": "0xef000101000c02000300040006000304000000008000020002000303010003e30001005f5f5fe500025050e4", - "results": { - "Prague": { - "exception": "EOF_StackUnderflow", - "result": false - } - } - }, - "jumpf_to_returning_2": { - "code": "0xef000101000c02000300040006000204000000008000020002000303020003e30001005f5f5fe5000250e4", - "results": { - "Prague": { - "result": true - } - } - }, - "jumpf_to_returning_3": { - "code": "0xef000101000c02000300040007000204000000008000020002000403020003e30001005f5f5f5fe5000250e4", - "results": { - "Prague": { - "exception": "EOF_InvalidNumberOfOutputs", - "result": false - } - } - }, - "jumpf_to_returning_4": { - "code": "0xef000101000c02000300040005000204000000008000020002000203020003e30001005f5fe5000250e4", - "results": { - "Prague": { - "exception": "EOF_StackUnderflow", - "result": false - } - } - }, - "jumpf_to_returning_5": { - "code": "0xef000101000c02000300040004000204000000008000020002000100010001e30001005fe500025fe4", - "results": { - "Prague": { - "result": true - } - } - }, - "jumpf_to_returning_6": { - "code": "0xef000101000c02000300040006000204000000008000020002000300010001e30001005f5f5fe500025fe4", - "results": { - "Prague": { - "exception": "EOF_InvalidNumberOfOutputs", - "result": false - } - } - }, - "jumpf_to_returning_7": { - "code": "0xef000101000c02000300040003000204000000008000020002000000010001e3000100e500025fe4", - "results": { - "Prague": { - "exception": "EOF_StackUnderflow", - "result": false - } - } - }, - "jumpf_to_returning_8": { - "code": "0xef000101000c02000300040007000304000000008000020002000403010003e30001005f5f5f5fe500025050e4", - "results": { - "Prague": { - "result": true - } - } - }, - "jumpf_to_returning_9": { - "code": "0xef000101000c02000300040008000304000000008000020002000503010003e30001005f5f5f5f5fe500025050e4", - "results": { - "Prague": { - "exception": "EOF_InvalidNumberOfOutputs", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/stack/jumpf_to_returning_variable_stack.json b/crates/interpreter/tests/EOFTests/eof_validation/stack/jumpf_to_returning_variable_stack.json deleted file mode 100644 index af4bc13d39..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/stack/jumpf_to_returning_variable_stack.json +++ /dev/null @@ -1,78 +0,0 @@ -{ - "jumpf_to_returning_variable_stack": { - "vectors": { - "jumpf_to_returning_variable_stack_0": { - "code": "0xef000101000c0200030004000b000204000000008000030003000305030003e30001005f6000e100025f5fe500025fe4", - "results": { - "Prague": { - "exception": "EOF_StackUnderflow", - "result": false - } - } - }, - "jumpf_to_returning_variable_stack_1": { - "code": "0xef000101000c0200030004000b000104000000008000030003000303030003e30001005f6000e100025f5fe50002e4", - "results": { - "Prague": { - "exception": "EOF_StackUnderflow", - "result": false - } - } - }, - "jumpf_to_returning_variable_stack_2": { - "code": "0xef000101000c0200030004000b000304000000008000030003000301030005e30001005f6000e100025f5fe500025f5fe4", - "results": { - "Prague": { - "exception": "EOF_InvalidNumberOfOutputs", - "result": false - } - } - }, - "jumpf_to_returning_variable_stack_3": { - "code": "0xef000101000c0200030004000b000404000000008000030003000300030003e30001005f6000e100025f5fe500025f5f5fe4", - "results": { - "Prague": { - "exception": "EOF_InvalidNumberOfOutputs", - "result": false - } - } - }, - "jumpf_to_returning_variable_stack_4": { - "code": "0xef000101000c0200030004000b000504000000008000020002000305010005e30001005f6000e100025f5fe5000250505050e4", - "results": { - "Prague": { - "exception": "EOF_StackUnderflow", - "result": false - } - } - }, - "jumpf_to_returning_variable_stack_5": { - "code": "0xef000101000c0200030004000b000304000000008000020002000303010003e30001005f6000e100025f5fe500025050e4", - "results": { - "Prague": { - "exception": "EOF_StackUnderflow", - "result": false - } - } - }, - "jumpf_to_returning_variable_stack_6": { - "code": "0xef000101000c0200030004000b000104000000008000020002000301010001e30001005f6000e100025f5fe50002e4", - "results": { - "Prague": { - "exception": "EOF_InvalidNumberOfOutputs", - "result": false - } - } - }, - "jumpf_to_returning_variable_stack_7": { - "code": "0xef000101000c0200030004000b000204000000008000020002000300010001e30001005f6000e100025f5fe500025fe4", - "results": { - "Prague": { - "exception": "EOF_InvalidNumberOfOutputs", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/stack/jumpf_with_inputs_stack_overflow.json b/crates/interpreter/tests/EOFTests/eof_validation/stack/jumpf_with_inputs_stack_overflow.json deleted file mode 100644 index cd30b9ffd2..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/stack/jumpf_with_inputs_stack_overflow.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "jumpf_with_inputs_stack_overflow": { - "vectors": { - "jumpf_with_inputs_stack_overflow_0": { - "code": "0xef00010100080200020402000204000000008003ff028000035f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5fe500015f00", - "results": { - "Prague": { - "result": true - } - } - }, - "jumpf_with_inputs_stack_overflow_1": { - "code": "0xef00010100080200020402000304000000008003ff028000045f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5fe500015f5f00", - "results": { - "Prague": { - "exception": "EOF_StackOverflow", - "result": false - } - } - }, - "jumpf_with_inputs_stack_overflow_2": { - "code": "0xef00010100080200020403000204000000008003ff028000035f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5fe500015f00", - "results": { - "Prague": { - "exception": "EOF_StackOverflow", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/stack/jumpf_with_inputs_stack_overflow_variable_stack.json b/crates/interpreter/tests/EOFTests/eof_validation/stack/jumpf_with_inputs_stack_overflow_variable_stack.json deleted file mode 100644 index d83e86a0b5..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/stack/jumpf_with_inputs_stack_overflow_variable_stack.json +++ /dev/null @@ -1,50 +0,0 @@ -{ - "jumpf_with_inputs_stack_overflow_variable_stack": { - "vectors": { - "jumpf_with_inputs_stack_overflow_variable_stack_0": { - "code": "0xef00010100080200020407000204000000008003ff028000035f6000e100025f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5fe500015f00", - "results": { - "Prague": { - "result": true - } - } - }, - "jumpf_with_inputs_stack_overflow_variable_stack_1": { - "code": "0xef00010100080200020407000504000000008003ff028000065f6000e100025f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5fe500015f5f5f5f00", - "results": { - "Prague": { - "exception": "EOF_StackOverflow", - "result": false - } - } - }, - "jumpf_with_inputs_stack_overflow_variable_stack_2": { - "code": "0xef00010100080200020407000304000000008003ff028000045f6000e100025f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5fe500015f5f00", - "results": { - "Prague": { - "exception": "EOF_StackOverflow", - "result": false - } - } - }, - "jumpf_with_inputs_stack_overflow_variable_stack_3": { - "code": "0xef00010100080200020408000404000000008003ff028000055f6000e100025f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5fe500015f5f5f00", - "results": { - "Prague": { - "exception": "EOF_StackOverflow", - "result": false - } - } - }, - "jumpf_with_inputs_stack_overflow_variable_stack_4": { - "code": "0xef00010100080200020408000204000000008003ff028000035f6000e100025f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5fe500015f00", - "results": { - "Prague": { - "exception": "EOF_StackOverflow", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/stack/no_terminating_instruction.json b/crates/interpreter/tests/EOFTests/eof_validation/stack/no_terminating_instruction.json deleted file mode 100644 index dda6c5a12c..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/stack/no_terminating_instruction.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "no_terminating_instruction": { - "vectors": { - "no_terminating_instruction_0": { - "code": "0xef0001010004020001000104000000008000005f", - "results": { - "Prague": { - "exception": "EOF_InvalidCodeTermination", - "result": false - } - } - }, - "no_terminating_instruction_1": { - "code": "0xef0001010004020001000504000000008000006002600101", - "results": { - "Prague": { - "exception": "EOF_InvalidCodeTermination", - "result": false - } - } - }, - "no_terminating_instruction_2": { - "code": "0xef0001010004020001000504000000008000006001e1fffb", - "results": { - "Prague": { - "exception": "EOF_InvalidCodeTermination", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/stack/non_constant_stack_height.json b/crates/interpreter/tests/EOFTests/eof_validation/stack/non_constant_stack_height.json deleted file mode 100644 index 95903fbe84..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/stack/non_constant_stack_height.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "non_constant_stack_height": { - "vectors": { - "non_constant_stack_height_0": { - "code": "0xef0001010004020001000e04000000008000045fe100075f5f5fe10001505f5ffd", - "results": { - "Prague": { - "result": true - } - } - }, - "non_constant_stack_height_1": { - "code": "0xef0001010004020001000f04000000008000055f5fe100075f5f5fe10001505f5ffd", - "results": { - "Prague": { - "result": true - } - } - }, - "non_constant_stack_height_2": { - "code": "0xef0001010004020001000f04000000008000045fe100075f5f5fe1000150505f5ffd", - "results": { - "Prague": { - "exception": "EOF_StackUnderflow", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/stack/retf_stack_validation.json b/crates/interpreter/tests/EOFTests/eof_validation/stack/retf_stack_validation.json deleted file mode 100644 index 825c7b9a46..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/stack/retf_stack_validation.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "retf_stack_validation": { - "vectors": { - "retf_stack_validation_0": { - "code": "0xef000101000802000200040003040000000080000200020002e30001005f5fe4", - "results": { - "Prague": { - "result": true - } - } - }, - "retf_stack_validation_1": { - "code": "0xef000101000802000200040002040000000080000200020001e30001005fe4", - "results": { - "Prague": { - "exception": "EOF_StackUnderflow", - "result": false - } - } - }, - "retf_stack_validation_2": { - "code": "0xef000101000802000200040004040000000080000200020003e30001005f5f5fe4", - "results": { - "Prague": { - "exception": "EOF_InvalidNumberOfOutputs", - "result": false - } - } - }, - "retf_stack_validation_3": { - "code": "0xef00010100080200020005000d0400000000800002010200025fe3000100e1000760016001e000025f5fe4", - "results": { - "Prague": { - "result": true - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/stack/retf_variable_stack.json b/crates/interpreter/tests/EOFTests/eof_validation/stack/retf_variable_stack.json deleted file mode 100644 index 0c0d2608fa..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/stack/retf_variable_stack.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "retf_variable_stack": { - "vectors": { - "retf_variable_stack_0": { - "code": "0xef000101000802000200040009040000000080000500050003e30001005f6000e100025f5fe4", - "results": { - "Prague": { - "exception": "EOF_StackUnderflow", - "result": false - } - } - }, - "retf_variable_stack_1": { - "code": "0xef000101000802000200040009040000000080000300030003e30001005f6000e100025f5fe4", - "results": { - "Prague": { - "exception": "EOF_StackUnderflow", - "result": false - } - } - }, - "retf_variable_stack_2": { - "code": "0xef000101000802000200040009040000000080000100010003e30001005f6000e100025f5fe4", - "results": { - "Prague": { - "exception": "EOF_InvalidNumberOfOutputs", - "result": false - } - } - }, - "retf_variable_stack_3": { - "code": "0xef000101000802000200040009040000000080000000000003e30001005f6000e100025f5fe4", - "results": { - "Prague": { - "exception": "EOF_InvalidNumberOfOutputs", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/stack/self_referencing_jumps.json b/crates/interpreter/tests/EOFTests/eof_validation/stack/self_referencing_jumps.json deleted file mode 100644 index 7d6e133833..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/stack/self_referencing_jumps.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "self_referencing_jumps": { - "vectors": { - "rjump": { - "code": "0xef000101000402000100030400000000800000e0fffd", - "results": { - "Prague": { - "result": true - } - } - }, - "rjumpi": { - "code": "0xef0001010004020001000604000000008000006000e1fffd00", - "results": { - "Prague": { - "exception": "EOF_ConflictingStackHeight", - "result": false - } - } - }, - "rjumpv": { - "code": "0xef0001010004020001000704000000008000006000e200fffc00", - "results": { - "Prague": { - "exception": "EOF_ConflictingStackHeight", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/stack/self_referencing_jumps_variable_stack.json b/crates/interpreter/tests/EOFTests/eof_validation/stack/self_referencing_jumps_variable_stack.json deleted file mode 100644 index 7c545a45b6..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/stack/self_referencing_jumps_variable_stack.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "self_referencing_jumps_variable_stack": { - "vectors": { - "rjump": { - "code": "0xef0001010004020001000b04000000008000035f6000e100025f5fe0fffd", - "results": { - "Prague": { - "result": true - } - } - }, - "rjumpi": { - "code": "0xef0001010004020001000e04000000008000045f6000e100025f5f6000e1fffd00", - "results": { - "Prague": { - "exception": "EOF_ConflictingStackHeight", - "result": false - } - } - }, - "rjumpv": { - "code": "0xef0001010004020001000f04000000008000045f6000e100025f5f6000e200fffc00", - "results": { - "Prague": { - "exception": "EOF_ConflictingStackHeight", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/stack/stack_range_maximally_broad.json b/crates/interpreter/tests/EOFTests/eof_validation/stack/stack_range_maximally_broad.json deleted file mode 100644 index 768020dcae..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/stack/stack_range_maximally_broad.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "stack_range_maximally_broad": { - "vectors": { - "invalid_1024_rjumpis": { - "code": "0xef0001010004020001140104000000008003ff5fe113fc5f5fe113f75f5fe113f25f5fe113ed5f5fe113e85f5fe113e35f5fe113de5f5fe113d95f5fe113d45f5fe113cf5f5fe113ca5f5fe113c55f5fe113c05f5fe113bb5f5fe113b65f5fe113b15f5fe113ac5f5fe113a75f5fe113a25f5fe1139d5f5fe113985f5fe113935f5fe1138e5f5fe113895f5fe113845f5fe1137f5f5fe1137a5f5fe113755f5fe113705f5fe1136b5f5fe113665f5fe113615f5fe1135c5f5fe113575f5fe113525f5fe1134d5f5fe113485f5fe113435f5fe1133e5f5fe113395f5fe113345f5fe1132f5f5fe1132a5f5fe113255f5fe113205f5fe1131b5f5fe113165f5fe113115f5fe1130c5f5fe113075f5fe113025f5fe112fd5f5fe112f85f5fe112f35f5fe112ee5f5fe112e95f5fe112e45f5fe112df5f5fe112da5f5fe112d55f5fe112d05f5fe112cb5f5fe112c65f5fe112c15f5fe112bc5f5fe112b75f5fe112b25f5fe112ad5f5fe112a85f5fe112a35f5fe1129e5f5fe112995f5fe112945f5fe1128f5f5fe1128a5f5fe112855f5fe112805f5fe1127b5f5fe112765f5fe112715f5fe1126c5f5fe112675f5fe112625f5fe1125d5f5fe112585f5fe112535f5fe1124e5f5fe112495f5fe112445f5fe1123f5f5fe1123a5f5fe112355f5fe112305f5fe1122b5f5fe112265f5fe112215f5fe1121c5f5fe112175f5fe112125f5fe1120d5f5fe112085f5fe112035f5fe111fe5f5fe111f95f5fe111f45f5fe111ef5f5fe111ea5f5fe111e55f5fe111e05f5fe111db5f5fe111d65f5fe111d15f5fe111cc5f5fe111c75f5fe111c25f5fe111bd5f5fe111b85f5fe111b35f5fe111ae5f5fe111a95f5fe111a45f5fe1119f5f5fe1119a5f5fe111955f5fe111905f5fe1118b5f5fe111865f5fe111815f5fe1117c5f5fe111775f5fe111725f5fe1116d5f5fe111685f5fe111635f5fe1115e5f5fe111595f5fe111545f5fe1114f5f5fe1114a5f5fe111455f5fe111405f5fe1113b5f5fe111365f5fe111315f5fe1112c5f5fe111275f5fe111225f5fe1111d5f5fe111185f5fe111135f5fe1110e5f5fe111095f5fe111045f5fe110ff5f5fe110fa5f5fe110f55f5fe110f05f5fe110eb5f5fe110e65f5fe110e15f5fe110dc5f5fe110d75f5fe110d25f5fe110cd5f5fe110c85f5fe110c35f5fe110be5f5fe110b95f5fe110b45f5fe110af5f5fe110aa5f5fe110a55f5fe110a05f5fe1109b5f5fe110965f5fe110915f5fe1108c5f5fe110875f5fe110825f5fe1107d5f5fe110785f5fe110735f5fe1106e5f5fe110695f5fe110645f5fe1105f5f5fe1105a5f5fe110555f5fe110505f5fe1104b5f5fe110465f5fe110415f5fe1103c5f5fe110375f5fe110325f5fe1102d5f5fe110285f5fe110235f5fe1101e5f5fe110195f5fe110145f5fe1100f5f5fe1100a5f5fe110055f5fe110005f5fe10ffb5f5fe10ff65f5fe10ff15f5fe10fec5f5fe10fe75f5fe10fe25f5fe10fdd5f5fe10fd85f5fe10fd35f5fe10fce5f5fe10fc95f5fe10fc45f5fe10fbf5f5fe10fba5f5fe10fb55f5fe10fb05f5fe10fab5f5fe10fa65f5fe10fa15f5fe10f9c5f5fe10f975f5fe10f925f5fe10f8d5f5fe10f885f5fe10f835f5fe10f7e5f5fe10f795f5fe10f745f5fe10f6f5f5fe10f6a5f5fe10f655f5fe10f605f5fe10f5b5f5fe10f565f5fe10f515f5fe10f4c5f5fe10f475f5fe10f425f5fe10f3d5f5fe10f385f5fe10f335f5fe10f2e5f5fe10f295f5fe10f245f5fe10f1f5f5fe10f1a5f5fe10f155f5fe10f105f5fe10f0b5f5fe10f065f5fe10f015f5fe10efc5f5fe10ef75f5fe10ef25f5fe10eed5f5fe10ee85f5fe10ee35f5fe10ede5f5fe10ed95f5fe10ed45f5fe10ecf5f5fe10eca5f5fe10ec55f5fe10ec05f5fe10ebb5f5fe10eb65f5fe10eb15f5fe10eac5f5fe10ea75f5fe10ea25f5fe10e9d5f5fe10e985f5fe10e935f5fe10e8e5f5fe10e895f5fe10e845f5fe10e7f5f5fe10e7a5f5fe10e755f5fe10e705f5fe10e6b5f5fe10e665f5fe10e615f5fe10e5c5f5fe10e575f5fe10e525f5fe10e4d5f5fe10e485f5fe10e435f5fe10e3e5f5fe10e395f5fe10e345f5fe10e2f5f5fe10e2a5f5fe10e255f5fe10e205f5fe10e1b5f5fe10e165f5fe10e115f5fe10e0c5f5fe10e075f5fe10e025f5fe10dfd5f5fe10df85f5fe10df35f5fe10dee5f5fe10de95f5fe10de45f5fe10ddf5f5fe10dda5f5fe10dd55f5fe10dd05f5fe10dcb5f5fe10dc65f5fe10dc15f5fe10dbc5f5fe10db75f5fe10db25f5fe10dad5f5fe10da85f5fe10da35f5fe10d9e5f5fe10d995f5fe10d945f5fe10d8f5f5fe10d8a5f5fe10d855f5fe10d805f5fe10d7b5f5fe10d765f5fe10d715f5fe10d6c5f5fe10d675f5fe10d625f5fe10d5d5f5fe10d585f5fe10d535f5fe10d4e5f5fe10d495f5fe10d445f5fe10d3f5f5fe10d3a5f5fe10d355f5fe10d305f5fe10d2b5f5fe10d265f5fe10d215f5fe10d1c5f5fe10d175f5fe10d125f5fe10d0d5f5fe10d085f5fe10d035f5fe10cfe5f5fe10cf95f5fe10cf45f5fe10cef5f5fe10cea5f5fe10ce55f5fe10ce05f5fe10cdb5f5fe10cd65f5fe10cd15f5fe10ccc5f5fe10cc75f5fe10cc25f5fe10cbd5f5fe10cb85f5fe10cb35f5fe10cae5f5fe10ca95f5fe10ca45f5fe10c9f5f5fe10c9a5f5fe10c955f5fe10c905f5fe10c8b5f5fe10c865f5fe10c815f5fe10c7c5f5fe10c775f5fe10c725f5fe10c6d5f5fe10c685f5fe10c635f5fe10c5e5f5fe10c595f5fe10c545f5fe10c4f5f5fe10c4a5f5fe10c455f5fe10c405f5fe10c3b5f5fe10c365f5fe10c315f5fe10c2c5f5fe10c275f5fe10c225f5fe10c1d5f5fe10c185f5fe10c135f5fe10c0e5f5fe10c095f5fe10c045f5fe10bff5f5fe10bfa5f5fe10bf55f5fe10bf05f5fe10beb5f5fe10be65f5fe10be15f5fe10bdc5f5fe10bd75f5fe10bd25f5fe10bcd5f5fe10bc85f5fe10bc35f5fe10bbe5f5fe10bb95f5fe10bb45f5fe10baf5f5fe10baa5f5fe10ba55f5fe10ba05f5fe10b9b5f5fe10b965f5fe10b915f5fe10b8c5f5fe10b875f5fe10b825f5fe10b7d5f5fe10b785f5fe10b735f5fe10b6e5f5fe10b695f5fe10b645f5fe10b5f5f5fe10b5a5f5fe10b555f5fe10b505f5fe10b4b5f5fe10b465f5fe10b415f5fe10b3c5f5fe10b375f5fe10b325f5fe10b2d5f5fe10b285f5fe10b235f5fe10b1e5f5fe10b195f5fe10b145f5fe10b0f5f5fe10b0a5f5fe10b055f5fe10b005f5fe10afb5f5fe10af65f5fe10af15f5fe10aec5f5fe10ae75f5fe10ae25f5fe10add5f5fe10ad85f5fe10ad35f5fe10ace5f5fe10ac95f5fe10ac45f5fe10abf5f5fe10aba5f5fe10ab55f5fe10ab05f5fe10aab5f5fe10aa65f5fe10aa15f5fe10a9c5f5fe10a975f5fe10a925f5fe10a8d5f5fe10a885f5fe10a835f5fe10a7e5f5fe10a795f5fe10a745f5fe10a6f5f5fe10a6a5f5fe10a655f5fe10a605f5fe10a5b5f5fe10a565f5fe10a515f5fe10a4c5f5fe10a475f5fe10a425f5fe10a3d5f5fe10a385f5fe10a335f5fe10a2e5f5fe10a295f5fe10a245f5fe10a1f5f5fe10a1a5f5fe10a155f5fe10a105f5fe10a0b5f5fe10a065f5fe10a015f5fe109fc5f5fe109f75f5fe109f25f5fe109ed5f5fe109e85f5fe109e35f5fe109de5f5fe109d95f5fe109d45f5fe109cf5f5fe109ca5f5fe109c55f5fe109c05f5fe109bb5f5fe109b65f5fe109b15f5fe109ac5f5fe109a75f5fe109a25f5fe1099d5f5fe109985f5fe109935f5fe1098e5f5fe109895f5fe109845f5fe1097f5f5fe1097a5f5fe109755f5fe109705f5fe1096b5f5fe109665f5fe109615f5fe1095c5f5fe109575f5fe109525f5fe1094d5f5fe109485f5fe109435f5fe1093e5f5fe109395f5fe109345f5fe1092f5f5fe1092a5f5fe109255f5fe109205f5fe1091b5f5fe109165f5fe109115f5fe1090c5f5fe109075f5fe109025f5fe108fd5f5fe108f85f5fe108f35f5fe108ee5f5fe108e95f5fe108e45f5fe108df5f5fe108da5f5fe108d55f5fe108d05f5fe108cb5f5fe108c65f5fe108c15f5fe108bc5f5fe108b75f5fe108b25f5fe108ad5f5fe108a85f5fe108a35f5fe1089e5f5fe108995f5fe108945f5fe1088f5f5fe1088a5f5fe108855f5fe108805f5fe1087b5f5fe108765f5fe108715f5fe1086c5f5fe108675f5fe108625f5fe1085d5f5fe108585f5fe108535f5fe1084e5f5fe108495f5fe108445f5fe1083f5f5fe1083a5f5fe108355f5fe108305f5fe1082b5f5fe108265f5fe108215f5fe1081c5f5fe108175f5fe108125f5fe1080d5f5fe108085f5fe108035f5fe107fe5f5fe107f95f5fe107f45f5fe107ef5f5fe107ea5f5fe107e55f5fe107e05f5fe107db5f5fe107d65f5fe107d15f5fe107cc5f5fe107c75f5fe107c25f5fe107bd5f5fe107b85f5fe107b35f5fe107ae5f5fe107a95f5fe107a45f5fe1079f5f5fe1079a5f5fe107955f5fe107905f5fe1078b5f5fe107865f5fe107815f5fe1077c5f5fe107775f5fe107725f5fe1076d5f5fe107685f5fe107635f5fe1075e5f5fe107595f5fe107545f5fe1074f5f5fe1074a5f5fe107455f5fe107405f5fe1073b5f5fe107365f5fe107315f5fe1072c5f5fe107275f5fe107225f5fe1071d5f5fe107185f5fe107135f5fe1070e5f5fe107095f5fe107045f5fe106ff5f5fe106fa5f5fe106f55f5fe106f05f5fe106eb5f5fe106e65f5fe106e15f5fe106dc5f5fe106d75f5fe106d25f5fe106cd5f5fe106c85f5fe106c35f5fe106be5f5fe106b95f5fe106b45f5fe106af5f5fe106aa5f5fe106a55f5fe106a05f5fe1069b5f5fe106965f5fe106915f5fe1068c5f5fe106875f5fe106825f5fe1067d5f5fe106785f5fe106735f5fe1066e5f5fe106695f5fe106645f5fe1065f5f5fe1065a5f5fe106555f5fe106505f5fe1064b5f5fe106465f5fe106415f5fe1063c5f5fe106375f5fe106325f5fe1062d5f5fe106285f5fe106235f5fe1061e5f5fe106195f5fe106145f5fe1060f5f5fe1060a5f5fe106055f5fe106005f5fe105fb5f5fe105f65f5fe105f15f5fe105ec5f5fe105e75f5fe105e25f5fe105dd5f5fe105d85f5fe105d35f5fe105ce5f5fe105c95f5fe105c45f5fe105bf5f5fe105ba5f5fe105b55f5fe105b05f5fe105ab5f5fe105a65f5fe105a15f5fe1059c5f5fe105975f5fe105925f5fe1058d5f5fe105885f5fe105835f5fe1057e5f5fe105795f5fe105745f5fe1056f5f5fe1056a5f5fe105655f5fe105605f5fe1055b5f5fe105565f5fe105515f5fe1054c5f5fe105475f5fe105425f5fe1053d5f5fe105385f5fe105335f5fe1052e5f5fe105295f5fe105245f5fe1051f5f5fe1051a5f5fe105155f5fe105105f5fe1050b5f5fe105065f5fe105015f5fe104fc5f5fe104f75f5fe104f25f5fe104ed5f5fe104e85f5fe104e35f5fe104de5f5fe104d95f5fe104d45f5fe104cf5f5fe104ca5f5fe104c55f5fe104c05f5fe104bb5f5fe104b65f5fe104b15f5fe104ac5f5fe104a75f5fe104a25f5fe1049d5f5fe104985f5fe104935f5fe1048e5f5fe104895f5fe104845f5fe1047f5f5fe1047a5f5fe104755f5fe104705f5fe1046b5f5fe104665f5fe104615f5fe1045c5f5fe104575f5fe104525f5fe1044d5f5fe104485f5fe104435f5fe1043e5f5fe104395f5fe104345f5fe1042f5f5fe1042a5f5fe104255f5fe104205f5fe1041b5f5fe104165f5fe104115f5fe1040c5f5fe104075f5fe104025f5fe103fd5f5fe103f85f5fe103f35f5fe103ee5f5fe103e95f5fe103e45f5fe103df5f5fe103da5f5fe103d55f5fe103d05f5fe103cb5f5fe103c65f5fe103c15f5fe103bc5f5fe103b75f5fe103b25f5fe103ad5f5fe103a85f5fe103a35f5fe1039e5f5fe103995f5fe103945f5fe1038f5f5fe1038a5f5fe103855f5fe103805f5fe1037b5f5fe103765f5fe103715f5fe1036c5f5fe103675f5fe103625f5fe1035d5f5fe103585f5fe103535f5fe1034e5f5fe103495f5fe103445f5fe1033f5f5fe1033a5f5fe103355f5fe103305f5fe1032b5f5fe103265f5fe103215f5fe1031c5f5fe103175f5fe103125f5fe1030d5f5fe103085f5fe103035f5fe102fe5f5fe102f95f5fe102f45f5fe102ef5f5fe102ea5f5fe102e55f5fe102e05f5fe102db5f5fe102d65f5fe102d15f5fe102cc5f5fe102c75f5fe102c25f5fe102bd5f5fe102b85f5fe102b35f5fe102ae5f5fe102a95f5fe102a45f5fe1029f5f5fe1029a5f5fe102955f5fe102905f5fe1028b5f5fe102865f5fe102815f5fe1027c5f5fe102775f5fe102725f5fe1026d5f5fe102685f5fe102635f5fe1025e5f5fe102595f5fe102545f5fe1024f5f5fe1024a5f5fe102455f5fe102405f5fe1023b5f5fe102365f5fe102315f5fe1022c5f5fe102275f5fe102225f5fe1021d5f5fe102185f5fe102135f5fe1020e5f5fe102095f5fe102045f5fe101ff5f5fe101fa5f5fe101f55f5fe101f05f5fe101eb5f5fe101e65f5fe101e15f5fe101dc5f5fe101d75f5fe101d25f5fe101cd5f5fe101c85f5fe101c35f5fe101be5f5fe101b95f5fe101b45f5fe101af5f5fe101aa5f5fe101a55f5fe101a05f5fe1019b5f5fe101965f5fe101915f5fe1018c5f5fe101875f5fe101825f5fe1017d5f5fe101785f5fe101735f5fe1016e5f5fe101695f5fe101645f5fe1015f5f5fe1015a5f5fe101555f5fe101505f5fe1014b5f5fe101465f5fe101415f5fe1013c5f5fe101375f5fe101325f5fe1012d5f5fe101285f5fe101235f5fe1011e5f5fe101195f5fe101145f5fe1010f5f5fe1010a5f5fe101055f5fe101005f5fe100fb5f5fe100f65f5fe100f15f5fe100ec5f5fe100e75f5fe100e25f5fe100dd5f5fe100d85f5fe100d35f5fe100ce5f5fe100c95f5fe100c45f5fe100bf5f5fe100ba5f5fe100b55f5fe100b05f5fe100ab5f5fe100a65f5fe100a15f5fe1009c5f5fe100975f5fe100925f5fe1008d5f5fe100885f5fe100835f5fe1007e5f5fe100795f5fe100745f5fe1006f5f5fe1006a5f5fe100655f5fe100605f5fe1005b5f5fe100565f5fe100515f5fe1004c5f5fe100475f5fe100425f5fe1003d5f5fe100385f5fe100335f5fe1002e5f5fe100295f5fe100245f5fe1001f5f5fe1001a5f5fe100155f5fe100105f5fe1000b5f5fe100065f5fe100015f00", - "results": { - "Prague": { - "exception": "EOF_InvalidMaxStackHeight", - "result": false - } - } - }, - "valid_1023_rjumpis": { - "code": "0xef000101000402000113fc04000000008003ff5fe113f75f5fe113f25f5fe113ed5f5fe113e85f5fe113e35f5fe113de5f5fe113d95f5fe113d45f5fe113cf5f5fe113ca5f5fe113c55f5fe113c05f5fe113bb5f5fe113b65f5fe113b15f5fe113ac5f5fe113a75f5fe113a25f5fe1139d5f5fe113985f5fe113935f5fe1138e5f5fe113895f5fe113845f5fe1137f5f5fe1137a5f5fe113755f5fe113705f5fe1136b5f5fe113665f5fe113615f5fe1135c5f5fe113575f5fe113525f5fe1134d5f5fe113485f5fe113435f5fe1133e5f5fe113395f5fe113345f5fe1132f5f5fe1132a5f5fe113255f5fe113205f5fe1131b5f5fe113165f5fe113115f5fe1130c5f5fe113075f5fe113025f5fe112fd5f5fe112f85f5fe112f35f5fe112ee5f5fe112e95f5fe112e45f5fe112df5f5fe112da5f5fe112d55f5fe112d05f5fe112cb5f5fe112c65f5fe112c15f5fe112bc5f5fe112b75f5fe112b25f5fe112ad5f5fe112a85f5fe112a35f5fe1129e5f5fe112995f5fe112945f5fe1128f5f5fe1128a5f5fe112855f5fe112805f5fe1127b5f5fe112765f5fe112715f5fe1126c5f5fe112675f5fe112625f5fe1125d5f5fe112585f5fe112535f5fe1124e5f5fe112495f5fe112445f5fe1123f5f5fe1123a5f5fe112355f5fe112305f5fe1122b5f5fe112265f5fe112215f5fe1121c5f5fe112175f5fe112125f5fe1120d5f5fe112085f5fe112035f5fe111fe5f5fe111f95f5fe111f45f5fe111ef5f5fe111ea5f5fe111e55f5fe111e05f5fe111db5f5fe111d65f5fe111d15f5fe111cc5f5fe111c75f5fe111c25f5fe111bd5f5fe111b85f5fe111b35f5fe111ae5f5fe111a95f5fe111a45f5fe1119f5f5fe1119a5f5fe111955f5fe111905f5fe1118b5f5fe111865f5fe111815f5fe1117c5f5fe111775f5fe111725f5fe1116d5f5fe111685f5fe111635f5fe1115e5f5fe111595f5fe111545f5fe1114f5f5fe1114a5f5fe111455f5fe111405f5fe1113b5f5fe111365f5fe111315f5fe1112c5f5fe111275f5fe111225f5fe1111d5f5fe111185f5fe111135f5fe1110e5f5fe111095f5fe111045f5fe110ff5f5fe110fa5f5fe110f55f5fe110f05f5fe110eb5f5fe110e65f5fe110e15f5fe110dc5f5fe110d75f5fe110d25f5fe110cd5f5fe110c85f5fe110c35f5fe110be5f5fe110b95f5fe110b45f5fe110af5f5fe110aa5f5fe110a55f5fe110a05f5fe1109b5f5fe110965f5fe110915f5fe1108c5f5fe110875f5fe110825f5fe1107d5f5fe110785f5fe110735f5fe1106e5f5fe110695f5fe110645f5fe1105f5f5fe1105a5f5fe110555f5fe110505f5fe1104b5f5fe110465f5fe110415f5fe1103c5f5fe110375f5fe110325f5fe1102d5f5fe110285f5fe110235f5fe1101e5f5fe110195f5fe110145f5fe1100f5f5fe1100a5f5fe110055f5fe110005f5fe10ffb5f5fe10ff65f5fe10ff15f5fe10fec5f5fe10fe75f5fe10fe25f5fe10fdd5f5fe10fd85f5fe10fd35f5fe10fce5f5fe10fc95f5fe10fc45f5fe10fbf5f5fe10fba5f5fe10fb55f5fe10fb05f5fe10fab5f5fe10fa65f5fe10fa15f5fe10f9c5f5fe10f975f5fe10f925f5fe10f8d5f5fe10f885f5fe10f835f5fe10f7e5f5fe10f795f5fe10f745f5fe10f6f5f5fe10f6a5f5fe10f655f5fe10f605f5fe10f5b5f5fe10f565f5fe10f515f5fe10f4c5f5fe10f475f5fe10f425f5fe10f3d5f5fe10f385f5fe10f335f5fe10f2e5f5fe10f295f5fe10f245f5fe10f1f5f5fe10f1a5f5fe10f155f5fe10f105f5fe10f0b5f5fe10f065f5fe10f015f5fe10efc5f5fe10ef75f5fe10ef25f5fe10eed5f5fe10ee85f5fe10ee35f5fe10ede5f5fe10ed95f5fe10ed45f5fe10ecf5f5fe10eca5f5fe10ec55f5fe10ec05f5fe10ebb5f5fe10eb65f5fe10eb15f5fe10eac5f5fe10ea75f5fe10ea25f5fe10e9d5f5fe10e985f5fe10e935f5fe10e8e5f5fe10e895f5fe10e845f5fe10e7f5f5fe10e7a5f5fe10e755f5fe10e705f5fe10e6b5f5fe10e665f5fe10e615f5fe10e5c5f5fe10e575f5fe10e525f5fe10e4d5f5fe10e485f5fe10e435f5fe10e3e5f5fe10e395f5fe10e345f5fe10e2f5f5fe10e2a5f5fe10e255f5fe10e205f5fe10e1b5f5fe10e165f5fe10e115f5fe10e0c5f5fe10e075f5fe10e025f5fe10dfd5f5fe10df85f5fe10df35f5fe10dee5f5fe10de95f5fe10de45f5fe10ddf5f5fe10dda5f5fe10dd55f5fe10dd05f5fe10dcb5f5fe10dc65f5fe10dc15f5fe10dbc5f5fe10db75f5fe10db25f5fe10dad5f5fe10da85f5fe10da35f5fe10d9e5f5fe10d995f5fe10d945f5fe10d8f5f5fe10d8a5f5fe10d855f5fe10d805f5fe10d7b5f5fe10d765f5fe10d715f5fe10d6c5f5fe10d675f5fe10d625f5fe10d5d5f5fe10d585f5fe10d535f5fe10d4e5f5fe10d495f5fe10d445f5fe10d3f5f5fe10d3a5f5fe10d355f5fe10d305f5fe10d2b5f5fe10d265f5fe10d215f5fe10d1c5f5fe10d175f5fe10d125f5fe10d0d5f5fe10d085f5fe10d035f5fe10cfe5f5fe10cf95f5fe10cf45f5fe10cef5f5fe10cea5f5fe10ce55f5fe10ce05f5fe10cdb5f5fe10cd65f5fe10cd15f5fe10ccc5f5fe10cc75f5fe10cc25f5fe10cbd5f5fe10cb85f5fe10cb35f5fe10cae5f5fe10ca95f5fe10ca45f5fe10c9f5f5fe10c9a5f5fe10c955f5fe10c905f5fe10c8b5f5fe10c865f5fe10c815f5fe10c7c5f5fe10c775f5fe10c725f5fe10c6d5f5fe10c685f5fe10c635f5fe10c5e5f5fe10c595f5fe10c545f5fe10c4f5f5fe10c4a5f5fe10c455f5fe10c405f5fe10c3b5f5fe10c365f5fe10c315f5fe10c2c5f5fe10c275f5fe10c225f5fe10c1d5f5fe10c185f5fe10c135f5fe10c0e5f5fe10c095f5fe10c045f5fe10bff5f5fe10bfa5f5fe10bf55f5fe10bf05f5fe10beb5f5fe10be65f5fe10be15f5fe10bdc5f5fe10bd75f5fe10bd25f5fe10bcd5f5fe10bc85f5fe10bc35f5fe10bbe5f5fe10bb95f5fe10bb45f5fe10baf5f5fe10baa5f5fe10ba55f5fe10ba05f5fe10b9b5f5fe10b965f5fe10b915f5fe10b8c5f5fe10b875f5fe10b825f5fe10b7d5f5fe10b785f5fe10b735f5fe10b6e5f5fe10b695f5fe10b645f5fe10b5f5f5fe10b5a5f5fe10b555f5fe10b505f5fe10b4b5f5fe10b465f5fe10b415f5fe10b3c5f5fe10b375f5fe10b325f5fe10b2d5f5fe10b285f5fe10b235f5fe10b1e5f5fe10b195f5fe10b145f5fe10b0f5f5fe10b0a5f5fe10b055f5fe10b005f5fe10afb5f5fe10af65f5fe10af15f5fe10aec5f5fe10ae75f5fe10ae25f5fe10add5f5fe10ad85f5fe10ad35f5fe10ace5f5fe10ac95f5fe10ac45f5fe10abf5f5fe10aba5f5fe10ab55f5fe10ab05f5fe10aab5f5fe10aa65f5fe10aa15f5fe10a9c5f5fe10a975f5fe10a925f5fe10a8d5f5fe10a885f5fe10a835f5fe10a7e5f5fe10a795f5fe10a745f5fe10a6f5f5fe10a6a5f5fe10a655f5fe10a605f5fe10a5b5f5fe10a565f5fe10a515f5fe10a4c5f5fe10a475f5fe10a425f5fe10a3d5f5fe10a385f5fe10a335f5fe10a2e5f5fe10a295f5fe10a245f5fe10a1f5f5fe10a1a5f5fe10a155f5fe10a105f5fe10a0b5f5fe10a065f5fe10a015f5fe109fc5f5fe109f75f5fe109f25f5fe109ed5f5fe109e85f5fe109e35f5fe109de5f5fe109d95f5fe109d45f5fe109cf5f5fe109ca5f5fe109c55f5fe109c05f5fe109bb5f5fe109b65f5fe109b15f5fe109ac5f5fe109a75f5fe109a25f5fe1099d5f5fe109985f5fe109935f5fe1098e5f5fe109895f5fe109845f5fe1097f5f5fe1097a5f5fe109755f5fe109705f5fe1096b5f5fe109665f5fe109615f5fe1095c5f5fe109575f5fe109525f5fe1094d5f5fe109485f5fe109435f5fe1093e5f5fe109395f5fe109345f5fe1092f5f5fe1092a5f5fe109255f5fe109205f5fe1091b5f5fe109165f5fe109115f5fe1090c5f5fe109075f5fe109025f5fe108fd5f5fe108f85f5fe108f35f5fe108ee5f5fe108e95f5fe108e45f5fe108df5f5fe108da5f5fe108d55f5fe108d05f5fe108cb5f5fe108c65f5fe108c15f5fe108bc5f5fe108b75f5fe108b25f5fe108ad5f5fe108a85f5fe108a35f5fe1089e5f5fe108995f5fe108945f5fe1088f5f5fe1088a5f5fe108855f5fe108805f5fe1087b5f5fe108765f5fe108715f5fe1086c5f5fe108675f5fe108625f5fe1085d5f5fe108585f5fe108535f5fe1084e5f5fe108495f5fe108445f5fe1083f5f5fe1083a5f5fe108355f5fe108305f5fe1082b5f5fe108265f5fe108215f5fe1081c5f5fe108175f5fe108125f5fe1080d5f5fe108085f5fe108035f5fe107fe5f5fe107f95f5fe107f45f5fe107ef5f5fe107ea5f5fe107e55f5fe107e05f5fe107db5f5fe107d65f5fe107d15f5fe107cc5f5fe107c75f5fe107c25f5fe107bd5f5fe107b85f5fe107b35f5fe107ae5f5fe107a95f5fe107a45f5fe1079f5f5fe1079a5f5fe107955f5fe107905f5fe1078b5f5fe107865f5fe107815f5fe1077c5f5fe107775f5fe107725f5fe1076d5f5fe107685f5fe107635f5fe1075e5f5fe107595f5fe107545f5fe1074f5f5fe1074a5f5fe107455f5fe107405f5fe1073b5f5fe107365f5fe107315f5fe1072c5f5fe107275f5fe107225f5fe1071d5f5fe107185f5fe107135f5fe1070e5f5fe107095f5fe107045f5fe106ff5f5fe106fa5f5fe106f55f5fe106f05f5fe106eb5f5fe106e65f5fe106e15f5fe106dc5f5fe106d75f5fe106d25f5fe106cd5f5fe106c85f5fe106c35f5fe106be5f5fe106b95f5fe106b45f5fe106af5f5fe106aa5f5fe106a55f5fe106a05f5fe1069b5f5fe106965f5fe106915f5fe1068c5f5fe106875f5fe106825f5fe1067d5f5fe106785f5fe106735f5fe1066e5f5fe106695f5fe106645f5fe1065f5f5fe1065a5f5fe106555f5fe106505f5fe1064b5f5fe106465f5fe106415f5fe1063c5f5fe106375f5fe106325f5fe1062d5f5fe106285f5fe106235f5fe1061e5f5fe106195f5fe106145f5fe1060f5f5fe1060a5f5fe106055f5fe106005f5fe105fb5f5fe105f65f5fe105f15f5fe105ec5f5fe105e75f5fe105e25f5fe105dd5f5fe105d85f5fe105d35f5fe105ce5f5fe105c95f5fe105c45f5fe105bf5f5fe105ba5f5fe105b55f5fe105b05f5fe105ab5f5fe105a65f5fe105a15f5fe1059c5f5fe105975f5fe105925f5fe1058d5f5fe105885f5fe105835f5fe1057e5f5fe105795f5fe105745f5fe1056f5f5fe1056a5f5fe105655f5fe105605f5fe1055b5f5fe105565f5fe105515f5fe1054c5f5fe105475f5fe105425f5fe1053d5f5fe105385f5fe105335f5fe1052e5f5fe105295f5fe105245f5fe1051f5f5fe1051a5f5fe105155f5fe105105f5fe1050b5f5fe105065f5fe105015f5fe104fc5f5fe104f75f5fe104f25f5fe104ed5f5fe104e85f5fe104e35f5fe104de5f5fe104d95f5fe104d45f5fe104cf5f5fe104ca5f5fe104c55f5fe104c05f5fe104bb5f5fe104b65f5fe104b15f5fe104ac5f5fe104a75f5fe104a25f5fe1049d5f5fe104985f5fe104935f5fe1048e5f5fe104895f5fe104845f5fe1047f5f5fe1047a5f5fe104755f5fe104705f5fe1046b5f5fe104665f5fe104615f5fe1045c5f5fe104575f5fe104525f5fe1044d5f5fe104485f5fe104435f5fe1043e5f5fe104395f5fe104345f5fe1042f5f5fe1042a5f5fe104255f5fe104205f5fe1041b5f5fe104165f5fe104115f5fe1040c5f5fe104075f5fe104025f5fe103fd5f5fe103f85f5fe103f35f5fe103ee5f5fe103e95f5fe103e45f5fe103df5f5fe103da5f5fe103d55f5fe103d05f5fe103cb5f5fe103c65f5fe103c15f5fe103bc5f5fe103b75f5fe103b25f5fe103ad5f5fe103a85f5fe103a35f5fe1039e5f5fe103995f5fe103945f5fe1038f5f5fe1038a5f5fe103855f5fe103805f5fe1037b5f5fe103765f5fe103715f5fe1036c5f5fe103675f5fe103625f5fe1035d5f5fe103585f5fe103535f5fe1034e5f5fe103495f5fe103445f5fe1033f5f5fe1033a5f5fe103355f5fe103305f5fe1032b5f5fe103265f5fe103215f5fe1031c5f5fe103175f5fe103125f5fe1030d5f5fe103085f5fe103035f5fe102fe5f5fe102f95f5fe102f45f5fe102ef5f5fe102ea5f5fe102e55f5fe102e05f5fe102db5f5fe102d65f5fe102d15f5fe102cc5f5fe102c75f5fe102c25f5fe102bd5f5fe102b85f5fe102b35f5fe102ae5f5fe102a95f5fe102a45f5fe1029f5f5fe1029a5f5fe102955f5fe102905f5fe1028b5f5fe102865f5fe102815f5fe1027c5f5fe102775f5fe102725f5fe1026d5f5fe102685f5fe102635f5fe1025e5f5fe102595f5fe102545f5fe1024f5f5fe1024a5f5fe102455f5fe102405f5fe1023b5f5fe102365f5fe102315f5fe1022c5f5fe102275f5fe102225f5fe1021d5f5fe102185f5fe102135f5fe1020e5f5fe102095f5fe102045f5fe101ff5f5fe101fa5f5fe101f55f5fe101f05f5fe101eb5f5fe101e65f5fe101e15f5fe101dc5f5fe101d75f5fe101d25f5fe101cd5f5fe101c85f5fe101c35f5fe101be5f5fe101b95f5fe101b45f5fe101af5f5fe101aa5f5fe101a55f5fe101a05f5fe1019b5f5fe101965f5fe101915f5fe1018c5f5fe101875f5fe101825f5fe1017d5f5fe101785f5fe101735f5fe1016e5f5fe101695f5fe101645f5fe1015f5f5fe1015a5f5fe101555f5fe101505f5fe1014b5f5fe101465f5fe101415f5fe1013c5f5fe101375f5fe101325f5fe1012d5f5fe101285f5fe101235f5fe1011e5f5fe101195f5fe101145f5fe1010f5f5fe1010a5f5fe101055f5fe101005f5fe100fb5f5fe100f65f5fe100f15f5fe100ec5f5fe100e75f5fe100e25f5fe100dd5f5fe100d85f5fe100d35f5fe100ce5f5fe100c95f5fe100c45f5fe100bf5f5fe100ba5f5fe100b55f5fe100b05f5fe100ab5f5fe100a65f5fe100a15f5fe1009c5f5fe100975f5fe100925f5fe1008d5f5fe100885f5fe100835f5fe1007e5f5fe100795f5fe100745f5fe1006f5f5fe1006a5f5fe100655f5fe100605f5fe1005b5f5fe100565f5fe100515f5fe1004c5f5fe100475f5fe100425f5fe1003d5f5fe100385f5fe100335f5fe1002e5f5fe100295f5fe100245f5fe1001f5f5fe1001a5f5fe100155f5fe100105f5fe1000b5f5fe100065f5fe100015f00", - "results": { - "Prague": { - "result": true - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/stack/swapn_stack_validation.json b/crates/interpreter/tests/EOFTests/eof_validation/stack/swapn_stack_validation.json deleted file mode 100644 index 276041f4b2..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/stack/swapn_stack_validation.json +++ /dev/null @@ -1,58 +0,0 @@ -{ - "swapn_stack_validation": { - "vectors": { - "swapn_stack_validation_0": { - "code": "0xef0001010004020001002b040000000080001460016001600160016001600160016001600160016001600160016001600160016001600160016001e70000", - "results": { - "Prague": { - "result": true - } - } - }, - "swapn_stack_validation_1": { - "code": "0xef0001010004020001002b040000000080001460016001600160016001600160016001600160016001600160016001600160016001600160016001e71200", - "results": { - "Prague": { - "result": true - } - } - }, - "swapn_stack_validation_2": { - "code": "0xef0001010004020001002b040000000080001460016001600160016001600160016001600160016001600160016001600160016001600160016001e71300", - "results": { - "Prague": { - "exception": "EOF_StackUnderflow", - "result": false - } - } - }, - "swapn_stack_validation_3": { - "code": "0xef0001010004020001002b040000000080001460016001600160016001600160016001600160016001600160016001600160016001600160016001e7d000", - "results": { - "Prague": { - "exception": "EOF_StackUnderflow", - "result": false - } - } - }, - "swapn_stack_validation_4": { - "code": "0xef0001010004020001002b040000000080001460016001600160016001600160016001600160016001600160016001600160016001600160016001e7fe00", - "results": { - "Prague": { - "exception": "EOF_StackUnderflow", - "result": false - } - } - }, - "swapn_stack_validation_5": { - "code": "0xef0001010004020001002b040000000080001460016001600160016001600160016001600160016001600160016001600160016001600160016001e7ff00", - "results": { - "Prague": { - "exception": "EOF_StackUnderflow", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/stack/underflow.json b/crates/interpreter/tests/EOFTests/eof_validation/stack/underflow.json deleted file mode 100644 index e44554ec1b..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/stack/underflow.json +++ /dev/null @@ -1,51 +0,0 @@ -{ - "underflow": { - "vectors": { - "underflow_0": { - "code": "0xef0001010004020001000204000000008000000100", - "results": { - "Prague": { - "exception": "EOF_StackUnderflow", - "result": false - } - } - }, - "underflow_1": { - "code": "0xef000101000802000200040002040000000080000101020002e30001005fe4", - "results": { - "Prague": { - "exception": "EOF_StackUnderflow", - "result": false - } - } - }, - "underflow_2": { - "code": "0xef000101000c02000300040003000204000000008000020002000001020002e3000100e500025fe4", - "results": { - "Prague": { - "exception": "EOF_StackUnderflow", - "result": false - } - } - }, - "underflow_3": { - "code": "0xef000101000802000200030005040000000080000001800003e5000160006000fd", - "results": { - "Prague": { - "exception": "EOF_StackUnderflow", - "result": false - } - } - }, - "underflow_4": { - "code": "0xef000101000802000200040002040000000080000200020001e30001005fe4", - "results": { - "Prague": { - "exception": "EOF_StackUnderflow", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/stack/underflow_variable_stack.json b/crates/interpreter/tests/EOFTests/eof_validation/stack/underflow_variable_stack.json deleted file mode 100644 index 035174da52..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/stack/underflow_variable_stack.json +++ /dev/null @@ -1,96 +0,0 @@ -{ - "underflow_variable_stack": { - "vectors": { - "underflow_variable_stack_0": { - "code": "0xef0001010004020001000a04000000008000035f6000e100025f5fa200", - "results": { - "Prague": { - "exception": "EOF_StackUnderflow", - "result": false - } - } - }, - "underflow_variable_stack_1": { - "code": "0xef0001010004020001000a04000000008000035f6000e100025f5f0100", - "results": { - "Prague": { - "exception": "EOF_StackUnderflow", - "result": false - } - } - }, - "underflow_variable_stack_2": { - "code": "0xef0001010008020002000c00020400000000800004040500055f6000e100025f5fe30001005fe4", - "results": { - "Prague": { - "exception": "EOF_StackUnderflow", - "result": false - } - } - }, - "underflow_variable_stack_3": { - "code": "0xef0001010008020002000c00020400000000800004030400045f6000e100025f5fe30001005fe4", - "results": { - "Prague": { - "exception": "EOF_StackUnderflow", - "result": false - } - } - }, - "underflow_variable_stack_4": { - "code": "0xef000101000c0200030004000b000304000000008000030003000305030003e30001005f6000e100025f5fe500025050e4", - "results": { - "Prague": { - "exception": "EOF_StackUnderflow", - "result": false - } - } - }, - "underflow_variable_stack_5": { - "code": "0xef000101000c0200030004000b000104000000008000030003000303030003e30001005f6000e100025f5fe50002e4", - "results": { - "Prague": { - "exception": "EOF_StackUnderflow", - "result": false - } - } - }, - "underflow_variable_stack_6": { - "code": "0xef0001010008020002000b00050400000000800000058000075f6000e100025f5fe5000160006000fd", - "results": { - "Prague": { - "exception": "EOF_StackUnderflow", - "result": false - } - } - }, - "underflow_variable_stack_7": { - "code": "0xef0001010008020002000b00050400000000800000038000055f6000e100025f5fe5000160006000fd", - "results": { - "Prague": { - "exception": "EOF_StackUnderflow", - "result": false - } - } - }, - "underflow_variable_stack_8": { - "code": "0xef000101000802000200040009040000000080000500050003e30001005f6000e100025f5fe4", - "results": { - "Prague": { - "exception": "EOF_StackUnderflow", - "result": false - } - } - }, - "underflow_variable_stack_9": { - "code": "0xef000101000802000200040009040000000080000300030003e30001005f6000e100025f5fe4", - "results": { - "Prague": { - "exception": "EOF_StackUnderflow", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/stack/unreachable_instructions.json b/crates/interpreter/tests/EOFTests/eof_validation/stack/unreachable_instructions.json deleted file mode 100644 index fe8ac098b6..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/stack/unreachable_instructions.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "unreachable_instructions": { - "vectors": { - "unreachable_instructions_0": { - "code": "0xef0001010004020001000204000000008000000000", - "results": { - "Prague": { - "exception": "EOF_UnreachableCode", - "result": false - } - } - }, - "unreachable_instructions_1": { - "code": "0xef000101000402000100050400000000800000e000010000", - "results": { - "Prague": { - "exception": "EOF_UnreachableCode", - "result": false - } - } - }, - "unreachable_instructions_2": { - "code": "0xef000101000402000100070400000000800000e0000100e0fffc", - "results": { - "Prague": { - "exception": "EOF_UnreachableCode", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/too_many_code_sections.json b/crates/interpreter/tests/EOFTests/eof_validation/too_many_code_sections.json deleted file mode 100644 index 485b898784..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/too_many_code_sections.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "too_many_code_sections": { - "vectors": { - "too_many_code_sections_0": { - "code": "0xef0001011004020401000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010400000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "results": { - "Prague": { - "exception": "EOF_TooManyCodeSections", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/unreachable_code_sections.json b/crates/interpreter/tests/EOFTests/eof_validation/unreachable_code_sections.json deleted file mode 100644 index 9c7d8d3bde..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/unreachable_code_sections.json +++ /dev/null @@ -1,78 +0,0 @@ -{ - "unreachable_code_sections": { - "vectors": { - "unreachable_code_sections_0": { - "code": "0xef000101000802000200010001040000000080000000800000fefe", - "results": { - "Prague": { - "exception": "EOF_UnreachableCodeSections", - "result": false - } - } - }, - "unreachable_code_sections_1": { - "code": "0xef000101000c02000300040002000104000000008000000000000000800000e30001005be4fe", - "results": { - "Prague": { - "exception": "EOF_UnreachableCodeSections", - "result": false - } - } - }, - "unreachable_code_sections_2": { - "code": "0xef000101000c02000300040001000204000000008000000080000000000000e3000200fe5be4", - "results": { - "Prague": { - "exception": "EOF_UnreachableCodeSections", - "result": false - } - } - }, - "unreachable_code_sections_3": { - "code": "0xef000101001002000400040001000200040400000000800000008000000000000000000000e3000300fe5be4e30002e4", - "results": { - "Prague": { - "exception": "EOF_UnreachableCodeSections", - "result": false - } - } - }, - "unreachable_code_sections_4": { - "code": "0xef000101000802000200030003040000000080000000800000e50000e50001", - "results": { - "Prague": { - "exception": "EOF_UnreachableCodeSections", - "result": false - } - } - }, - "unreachable_code_sections_5": { - "code": "0xef000101000c02000300030001000204000000008000000080000000000000e50001005be4", - "results": { - "Prague": { - "exception": "EOF_UnreachableCodeSections", - "result": false - } - } - }, - "unreachable_code_sections_6": { - "code": "0xef000101040002010000030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300040400000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000e50001e50001e50003e50004e50005e50006e50007e50008e50009e5000ae5000be5000ce5000de5000ee5000fe50010e50011e50012e50013e50014e50015e50016e50017e50018e50019e5001ae5001be5001ce5001de5001ee5001fe50020e50021e50022e50023e50024e50025e50026e50027e50028e50029e5002ae5002be5002ce5002de5002ee5002fe50030e50031e50032e50033e50034e50035e50036e50037e50038e50039e5003ae5003be5003ce5003de5003ee5003fe50040e50041e50042e50043e50044e50045e50046e50047e50048e50049e5004ae5004be5004ce5004de5004ee5004fe50050e50051e50052e50053e50054e50055e50056e50057e50058e50059e5005ae5005be5005ce5005de5005ee5005fe50060e50061e50062e50063e50064e50065e50066e50067e50068e50069e5006ae5006be5006ce5006de5006ee5006fe50070e50071e50072e50073e50074e50075e50076e50077e50078e50079e5007ae5007be5007ce5007de5007ee5007fe50080e50081e50082e50083e50084e50085e50086e50087e50088e50089e5008ae5008be5008ce5008de5008ee5008fe50090e50091e50092e50093e50094e50095e50096e50097e50098e50099e5009ae5009be5009ce5009de5009ee5009fe500a0e500a1e500a2e500a3e500a4e500a5e500a6e500a7e500a8e500a9e500aae500abe500ace500ade500aee500afe500b0e500b1e500b2e500b3e500b4e500b5e500b6e500b7e500b8e500b9e500bae500bbe500bce500bde500bee500bfe500c0e500c1e500c2e500c3e500c4e500c5e500c6e500c7e500c8e500c9e500cae500cbe500cce500cde500cee500cfe500d0e500d1e500d2e500d3e500d4e500d5e500d6e500d7e500d8e500d9e500dae500dbe500dce500dde500dee500dfe500e0e500e1e500e2e500e3e500e4e500e5e500e6e500e7e500e8e500e9e500eae500ebe500ece500ede500eee500efe500f0e500f1e500f2e500f3e500f4e500f5e500f6e500f7e500f8e500f9e500fae500fbe500fce500fde500fee500ff5b5b5b00", - "results": { - "Prague": { - "exception": "EOF_UnreachableCodeSections", - "result": false - } - } - }, - "unreachable_code_sections_7": { - "code": "0xef000101040002010000030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300040400000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000008000000080000000800000e50001e50002e50003e50004e50005e50006e50007e50008e50009e5000ae5000be5000ce5000de5000ee5000fe50010e50011e50012e50013e50014e50015e50016e50017e50018e50019e5001ae5001be5001ce5001de5001ee5001fe50020e50021e50022e50023e50024e50025e50026e50027e50028e50029e5002ae5002be5002ce5002de5002ee5002fe50030e50031e50032e50033e50034e50035e50036e50037e50038e50039e5003ae5003be5003ce5003de5003ee5003fe50040e50041e50042e50043e50044e50045e50046e50047e50048e50049e5004ae5004be5004ce5004de5004ee5004fe50050e50051e50052e50053e50054e50055e50056e50057e50058e50059e5005ae5005be5005ce5005de5005ee5005fe50060e50061e50062e50063e50064e50065e50066e50067e50068e50069e5006ae5006be5006ce5006de5006ee5006fe50070e50071e50072e50073e50074e50075e50076e50077e50078e50079e5007ae5007be5007ce5007de5007ee5007fe50080e50081e50082e50083e50084e50085e50086e50087e50088e50089e5008ae5008be5008ce5008de5008ee5008fe50090e50091e50092e50093e50094e50095e50096e50097e50098e50099e5009ae5009be5009ce5009de5009ee5009fe500a0e500a1e500a2e500a3e500a4e500a5e500a6e500a7e500a8e500a9e500aae500abe500ace500ade500aee500afe500b0e500b1e500b2e500b3e500b4e500b5e500b6e500b7e500b8e500b9e500bae500bbe500bce500bde500bee500bfe500c0e500c1e500c2e500c3e500c4e500c5e500c6e500c7e500c8e500c9e500cae500cbe500cce500cde500cee500cfe500d0e500d1e500d2e500d3e500d4e500d5e500d6e500d7e500d8e500d9e500dae500dbe500dce500dde500dee500dfe500e0e500e1e500e2e500e3e500e4e500e5e500e6e500e7e500e8e500e9e500eae500ebe500ece500ede500eee500efe500f0e500f1e500f2e500f3e500f4e500f5e500f6e500f7e500f8e500f9e500fae500fbe500fce500fde500fee500fe5b5b5b00", - "results": { - "Prague": { - "exception": "EOF_UnreachableCodeSections", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/validate_EOF_prefix.json b/crates/interpreter/tests/EOFTests/eof_validation/validate_EOF_prefix.json deleted file mode 100644 index 0e11c22b9b..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/validate_EOF_prefix.json +++ /dev/null @@ -1,87 +0,0 @@ -{ - "validate_EOF_prefix": { - "vectors": { - "valid_except_magic": { - "code": "0xefff0101000402000100030300040000800000600000aabbccdd", - "results": { - "Prague": { - "exception": "EOF_InvalidPrefix", - "result": false - } - } - }, - "validate_EOF_prefix_0": { - "code": "0x00", - "results": { - "Prague": { - "exception": "EOF_InvalidPrefix", - "result": false - } - } - }, - "validate_EOF_prefix_1": { - "code": "0xfe", - "results": { - "Prague": { - "exception": "EOF_InvalidPrefix", - "result": false - } - } - }, - "validate_EOF_prefix_2": { - "code": "0xef", - "results": { - "Prague": { - "exception": "EOF_InvalidPrefix", - "result": false - } - } - }, - "validate_EOF_prefix_3": { - "code": "0xef0101", - "results": { - "Prague": { - "exception": "EOF_InvalidPrefix", - "result": false - } - } - }, - "validate_EOF_prefix_4": { - "code": "0xefef01", - "results": { - "Prague": { - "exception": "EOF_InvalidPrefix", - "result": false - } - } - }, - "validate_EOF_prefix_5": { - "code": "0xefff01", - "results": { - "Prague": { - "exception": "EOF_InvalidPrefix", - "result": false - } - } - }, - "validate_EOF_prefix_6": { - "code": "0xef00", - "results": { - "Prague": { - "exception": "EOF_UnknownVersion", - "result": false - } - } - }, - "validate_EOF_prefix_7": { - "code": "0xef0001", - "results": { - "Prague": { - "exception": "EOF_SectionHeadersNotTerminated", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/validate_EOF_version.json b/crates/interpreter/tests/EOFTests/eof_validation/validate_EOF_version.json deleted file mode 100644 index a55f420058..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/validate_EOF_version.json +++ /dev/null @@ -1,51 +0,0 @@ -{ - "validate_EOF_version": { - "vectors": { - "valid_except_version_00": { - "code": "0xef000001000402000100030200040000800000600000aabbccdd", - "results": { - "Prague": { - "exception": "EOF_UnknownVersion", - "result": false - } - } - }, - "valid_except_version_02": { - "code": "0xef000201000402000100030200040000800000600000aabbccdd", - "results": { - "Prague": { - "exception": "EOF_UnknownVersion", - "result": false - } - } - }, - "valid_except_version_FF": { - "code": "0xef00ff01000402000100030200040000800000600000aabbccdd", - "results": { - "Prague": { - "exception": "EOF_UnknownVersion", - "result": false - } - } - }, - "validate_EOF_version_0": { - "code": "0xef0002", - "results": { - "Prague": { - "exception": "EOF_UnknownVersion", - "result": false - } - } - }, - "validate_EOF_version_1": { - "code": "0xef00ff", - "results": { - "Prague": { - "exception": "EOF_UnknownVersion", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/eof_validation/validate_empty_code.json b/crates/interpreter/tests/EOFTests/eof_validation/validate_empty_code.json deleted file mode 100644 index 4f60ba26ec..0000000000 --- a/crates/interpreter/tests/EOFTests/eof_validation/validate_empty_code.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "validate_empty_code": { - "vectors": { - "validate_empty_code_0": { - "code": "0x", - "results": { - "Prague": { - "exception": "EOF_InvalidPrefix", - "result": false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/EOFTests/ori/validInvalid.json b/crates/interpreter/tests/EOFTests/ori/validInvalid.json deleted file mode 100644 index 2f33a251b2..0000000000 --- a/crates/interpreter/tests/EOFTests/ori/validInvalid.json +++ /dev/null @@ -1,677 +0,0 @@ -{ - "validInvalid" : { - "_info" : { - "comment" : "Ori Pomerantz qbzzt1@gmail.com\nImplements EOF1I0001, EOF1I0002, EOF1I0003, EOF1I0004, EOF1I0005,\nEOF1I0006, EOF1I0007, EOF1I0008, EOF1I0009, EOF1I0010,\nEOF1I0011, EOF1I0012, EOF1I0013, EOF1I0014, EOF1I0015,\nEOF1I0016, EOF1I0017, EOF1I0018, EOF1I0019, EOF1I0020,\nEOF1I0021, EOF1I0022, EOF1I0023, EOF1I0024, EOF1I0025,\nEOF1V0001, EOF1V0002, EOF1V0003, EOF1V0004, EOF1V0005,\nEOF1V0006, EOF1V0007, EOF1V0008, EOF1V0009, EOF1V0010,\nEOF1V0011, EOF1V0012, EOF1V0013, EOF1V0014, EOF1V0015\n", - "filling-rpc-server" : "evmone-t8n 0.12.0-dev+commit.14ba7529", - "filling-tool-version" : "retesteth-0.3.2-cancun+commit.9d793abd.Linux.g++", - "generatedTestHash" : "42a674b5b1d41a51050ca56d5e2924a22edcd0e4f8b251913bfc7bb34c5d1457", - "lllcversion" : "Version: 0.5.14-develop.2022.4.6+commit.401d5358.Linux.g++", - "solidity" : "Version: 0.8.18-develop.2023.1.16+commit.469d6d4d.Linux.g++", - "source" : "src/EOFTestsFiller/ori/validInvalidFiller.yml", - "sourceHash" : "f4594e906050a1a0e30a17822dbb83cd4382fc613a1a7dac7f6b97360ba2e903" - }, - "vectors" : { - "validInvalid_0" : { - "code" : "0xef020101000402000100030400010000800001305000ef", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidPrefix", - "result" : false - } - } - }, - "validInvalid_1" : { - "code" : "0xef000001000402000100030400010000800001305000ef", - "results" : { - "Prague" : { - "exception" : "EOF_UnknownVersion", - "result" : false - } - } - }, - "validInvalid_10" : { - "code" : "0xef000101000402000100010400010000800000efef", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_11" : { - "code" : "0xef0001010004020001000504000100008000013030505000ef", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidMaxStackHeight", - "result" : false - } - } - }, - "validInvalid_12" : { - "code" : "0xef0001010004020001000504000100008000033030505000ef", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidMaxStackHeight", - "result" : false - } - } - }, - "validInvalid_13" : { - "code" : "0xef00010100040200010004040001000080000130505000ef", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_14" : { - "code" : "0xef000101000c0200030037000b001f0400010000800400000a000a00640064e30002e30002e30002e30002e30002e30002e30002e30002e30002e300023030303030303030303030303030303030303030303030300030303030303030303030e4e30001e30001e30001e30001e30001e30001e30001e30001e30001e30001e4ef", - "results" : { - "Prague" : { - "exception" : "EOF_MaxStackHeightExceeded", - "result" : false - } - } - }, - "validInvalid_15" : { - "code" : "0xef000101000802000200070004040001000180000200000001300150e3000100305000e4ef", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidFirstSectionType", - "result" : false - } - } - }, - "validInvalid_16" : { - "code" : "0xef000101000802000200060003040001000001000200800001303001e50001305000ef", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidFirstSectionType", - "result" : false - } - } - }, - "validInvalid_17" : { - "code" : "0xef000101000802000200040001040001000080000000800000e300020000ef", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidCodeSectionIndex", - "result" : false - } - } - }, - "validInvalid_18" : { - "code" : "0xef00010100040200010004040001000080000130015000ef", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_19" : { - "code" : "0xef0001010008020002000600040400010000800002020000005f80e3000100505050e4ef", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_2" : { - "code" : "0xef000201000402000100030400010000800001305000ef", - "results" : { - "Prague" : { - "exception" : "EOF_UnknownVersion", - "result" : false - } - } - }, - "validInvalid_20" : { - "code" : "0xef0001010008020002000600050400010000800002020000035f80e300010082505050e4ef", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_21" : { - "code" : "0xef0001010008020002000600040400010000800002020000025f80e3000100915050e4ef", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_22" : { - "code" : "0xef000101000802000200040005040001000080000000000001e30001005b600056e4ef", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_23" : { - "code" : "0xef000101000802000200040007040001000080000000000001e30001005b6001600057e4ef", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_24" : { - "code" : "0xef00010100040200010006040001000080000260016002ff00ef", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_25" : { - "code" : "0xef0001010004020001001004000100008000076001600260036004600560066007f200ef", - "results" : { - "Prague" : { - "exception" : "EOF_UndefinedInstruction", - "result" : false - } - } - }, - "validInvalid_26" : { - "code" : "0xef000101000802000200040004040001000080000000000000e3000100e00010e4ef", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidJumpDestination", - "result" : false - } - } - }, - "validInvalid_27" : { - "code" : "0xef000101000802000200040004040001000080000000000000e3000100e0ff00e4ef", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidJumpDestination", - "result" : false - } - } - }, - "validInvalid_28" : { - "code" : "0xef000101000c02000300060004000104000100008000000000000000800000e30001e50002e00001e400ef", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidJumpDestination", - "result" : false - } - } - }, - "validInvalid_29" : { - "code" : "0xef000101000c02000300060004000104000100008000000000000000800000e30001e50002e0fffce400ef", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidJumpDestination", - "result" : false - } - } - }, - "validInvalid_3" : { - "code" : "0xef000102000100030400010100040000800001305000ef", - "results" : { - "Prague" : { - "exception" : "EOF_TypeSectionMissing", - "result" : false - } - } - }, - "validInvalid_30" : { - "code" : "0xef000101000802000200060007040001000080000200020003e30001505000600160026003e4ef", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidNumberOfOutputs", - "result" : false - } - } - }, - "validInvalid_31" : { - "code" : "0xef000101000802000200040008040001000080000000000001e3000100e0000160ff60ffe4ef", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidJumpDestination", - "result" : false - } - } - }, - "validInvalid_32" : { - "code" : "0xef000101000802000200040009040001000080000000000001e30001006001e1000160ff50e4ef", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidJumpDestination", - "result" : false - } - } - }, - "validInvalid_33" : { - "code" : "0xef0001010004020001001304000100008000016001e204000000010001000200010060ff5000ef", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidJumpDestination", - "result" : false - } - } - }, - "validInvalid_34" : { - "code" : "0xef0001010004020001001304000100008000016001e204000000010001fffe00010060ff5000ef", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidJumpDestination", - "result" : false - } - } - }, - "validInvalid_35" : { - "code" : "0xef000101000402000100050400010000800000e000010000ef", - "results" : { - "Prague" : { - "exception" : "EOF_UnreachableCode", - "result" : false - } - } - }, - "validInvalid_36" : { - "code" : "0xef0001010004020001000a04000100008000016001e100020000305000ef", - "results" : { - "Prague" : { - "exception" : "EOF_UnreachableCode", - "result" : false - } - } - }, - "validInvalid_37" : { - "code" : "0xef0001010004020001000f04000100008000016001e2010002000430500000305000ef", - "results" : { - "Prague" : { - "exception" : "EOF_UnreachableCode", - "result" : false - } - } - }, - "validInvalid_38" : { - "code" : "0xef00010100080200020005000304000100008000010200000230e30001005050e4ef", - "results" : { - "Prague" : { - "exception" : "EOF_StackUnderflow", - "result" : false - } - } - }, - "validInvalid_39" : { - "code" : "0xef0001010004020001000804000100008000046000600060006000ef", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidCodeTermination", - "result" : false - } - } - }, - "validInvalid_4" : { - "code" : "0xef00010100040400010000800001305000ef", - "results" : { - "Prague" : { - "exception" : "EOF_CodeSectionMissing", - "result" : false - } - } - }, - "validInvalid_40" : { - "code" : "0xef000101000402000100090400010000800004600060006000600001ef", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidCodeTermination", - "result" : false - } - } - }, - "validInvalid_41" : { - "code" : "0xef000101000402000100090400010000800004600060006000600034ef", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidCodeTermination", - "result" : false - } - } - }, - "validInvalid_42" : { - "code" : "0xef000101000402000100090400010000800004600060006000600003ef", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidCodeTermination", - "result" : false - } - } - }, - "validInvalid_43" : { - "code" : "0xef0001010004020001000d0400010000800006600060006000600060006000a4ef", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidCodeTermination", - "result" : false - } - } - }, - "validInvalid_44" : { - "code" : "0xef0001010004020001000304000100008000013050e4ef", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidNonReturningFlag", - "result" : false - } - } - }, - "validInvalid_45" : { - "code" : "0xef000101000402000100030400010000800001305000ef", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_46" : { - "code" : "0xef0001010008020002000600050400010000800001000000023050e300010030305050e4ef", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_47" : { - "code" : "0xef0001010010020004000600060006000304000100008000010000000100000001000000013050e30001003050e30002e43050e30003e43050e4ef", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_48" : { - "code" : "0xef000101000402000100030400060000800001305000ef", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_49" : { - "code" : "0xef000101000402000100010400010000800000feef", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_5" : { - "code" : "0xef000101000402000100030000800001305000", - "results" : { - "Prague" : { - "exception" : "EOF_DataSectionMissing", - "result" : false - } - } - }, - "validInvalid_50" : { - "code" : "0xef0001010004020001000504000100008000023030505000ef", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_51" : { - "code" : "0xef000101000c0200030036000b001f04000100008003ff000a000a00640064e30002e30002e30002e30002e30002e30002e30002e30002e30002e3000230303030303030303030303030303030303030303030300030303030303030303030e4e30001e30001e30001e30001e30001e30001e30001e30001e30001e30001e4ef", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_52" : { - "code" : "0xef00010100080200020005000404000100008000010100000230e3000100300150e4ef", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_53" : { - "code" : "0xef0001010008020002000700040400010000800001000100023050e300015000303001e4ef", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_54" : { - "code" : "0xef0001010004020001000504000100008000023030015000ef", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_55" : { - "code" : "0xef0001010004020001000504000100008000013050e50000ef", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_56" : { - "code" : "0xef00010100080200020006000204000100008000010100000160ffe300010050e4ef", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_57" : { - "code" : "0xef0001010008020002000600050400010000800002020000035f80e300010081505050e4ef", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_58" : { - "code" : "0xef0001010008020002000600040400010000800002020000025f80e3000100905050e4ef", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_59" : { - "code" : "0xef000101000802000200030004040001000080000000800000e50001e0000000ef", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_6" : { - "code" : "0xef00010100040200010003040001ff00800001305000ef", - "results" : { - "Prague" : { - "exception" : "EOF_HeaderTerminatorMissing", - "result" : false - } - } - }, - "validInvalid_60" : { - "code" : "0xef000101000802000200040009040001000080000000000001e30001006001e10001e4e0fffcef", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_61" : { - "code" : "0xef000101000802000200040007040001000080000000000000e3000100e00000e00000e4ef", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_62" : { - "code" : "0xef000101000802000200030007040001000080000000800001e500016000e100003000ef", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_63" : { - "code" : "0xef000101000802000200030009040001000080000000800001e500016000e1000230503000ef", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_64" : { - "code" : "0xef000101000802000200030009040001000080000000800001e500016000e1000230503000ef", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_65" : { - "code" : "0xef000101000802000200030008040001000080000000800002e500016000e10001303000ef", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_66" : { - "code" : "0xef000101000802000200050003040001000080000100010001e30001500060ffe4ef", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_67" : { - "code" : "0xef0001010004020001000f04000100008000016001e2040000000000000000000000ef", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_68" : { - "code" : "0xef0001010004020001001204000100008000016001e2040000000100010000000100305000ef", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_69" : { - "code" : "0xef000101000402000100040400010000800000e0000000ef", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_7" : { - "code" : "0xef000101000802000100030400010000800001305000ef", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidSectionBodiesSize", - "result" : false - } - } - }, - "validInvalid_70" : { - "code" : "0xef0001010004020001000904000100008000016001e1000100305000ef", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_71" : { - "code" : "0xef0001010004020001000f04000100008000016001e2010002000430503050305000ef", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_72" : { - "code" : "0xef0001010008020002000600030400010000800002020000023030e30001005050e4ef", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_73" : { - "code" : "0xef000101000402000100090400010000800004600060006000600000ef", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_74" : { - "code" : "0xef0001010004020001000904000100008000046000600060006000f3ef", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_75" : { - "code" : "0xef0001010004020001000904000100008000046000600060006000fdef", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_76" : { - "code" : "0xef0001010004020001000904000100008000046000600060006000feef", - "results" : { - "Prague" : { - "result" : true - } - } - }, - "validInvalid_8" : { - "code" : "0xef000101000402000100030400010000800001305000000bad", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidSectionBodiesSize", - "result" : false - } - } - }, - "validInvalid_9" : { - "code" : "0xef000101000302000100030400010000800001305000ef", - "results" : { - "Prague" : { - "exception" : "EOF_InvalidSectionBodiesSize", - "result" : false - } - } - } - } - } -} \ No newline at end of file diff --git a/crates/interpreter/tests/eof.rs b/crates/interpreter/tests/eof.rs deleted file mode 100644 index 84bfc347ff..0000000000 --- a/crates/interpreter/tests/eof.rs +++ /dev/null @@ -1,184 +0,0 @@ -use revm_interpreter::analysis::{validate_raw_eof, EofError}; -use revm_primitives::{Bytes, Eof}; -use serde::Deserialize; -use std::{ - collections::BTreeMap, - path::{Path, PathBuf}, - time::Instant, -}; -use walkdir::{DirEntry, WalkDir}; - -/* -Types of error: { - FalsePossitive: 1, - Error( - Validation( - OpcodeDisabled, - ), - ): 19, -} -*/ -#[test] -fn eof_run_all_tests() { - let eof_tests = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/EOFTests"); - run_test(&eof_tests) -} - -/* -Types of error: { - FalsePossitive: 1, -} -Passed tests: 1262/1263 -EOF_EofCreateWithTruncatedContainer TODO -*/ -#[test] -fn eof_validation() { - let eof_tests = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/EOFTests/eof_validation"); - run_test(&eof_tests) -} - -/* -Types of error: { - OpcodeDisabled: 8, -} -Passed tests: 194/202 -Probably same as below. -*/ -#[test] -fn eof_validation_eip5450() { - let eof_tests = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/EOFTests/EIP5450"); - run_test(&eof_tests) -} - -/* -Types of error: { - OpcodeDisabled: 9, -} -Passed tests: 290/299 - */ -// 0x60018080808080fa00 STATICCALL validInvalid - validInvalid_89 -// 0x60018080808080f400 DELEGATECALL validInvalid - validInvalid_88 -// 0x60018080808080f400 CALL validInvalid - validInvalid_86 -// 0x38e4 CODESIZE validInvalid - validInvalid_4 -// 0x60013f00 EXTCODEHASH validInvalid - validInvalid_39 -// 0x60018080803c00 EXTCODECOPY validInvalid - validInvalid_37 -// 0x60013b00 EXTCODESIZE validInvalid - validInvalid_36 -// 0x600180803900 CODECOPY validInvalid - validInvalid_35 -// 0x5a00 GAS validInvalid - validInvalid_60 -// 0xfe opcode is considered valid, should it be disabled? -#[test] -fn eof_validation_eip3670() { - let eof_tests = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/EOFTests/EIP3670"); - run_test(&eof_tests) -} - -/// PASSING ALL -#[test] -fn eof_validation_eip4750() { - let inst = Instant::now(); - let eof_tests = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/EOFTests/EIP4750"); - run_test(&eof_tests); - println!("Elapsed:{:?}", inst.elapsed()) -} - -/// PASSING ALL -#[test] -fn eof_validation_eip3540() { - let eof_tests = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/EOFTests/EIP3540"); - run_test(&eof_tests) -} - -/// PASSING ALL -#[test] -fn eof_validation_eip4200() { - let eof_tests = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/EOFTests/EIP4200"); - run_test(&eof_tests); -} - -pub fn run_test(path: &Path) { - let test_files = find_all_json_tests(path); - let mut test_sum = 0; - let mut passed_tests = 0; - - #[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)] - enum ErrorType { - FalsePositive, - Error(EofError), - } - let mut types_of_error: BTreeMap = BTreeMap::new(); - for test_file in test_files { - let s = std::fs::read_to_string(test_file).unwrap(); - let suite: TestSuite = serde_json::from_str(&s).unwrap(); - for (name, test_unit) in suite.0 { - for (vector_name, test_vector) in test_unit.vectors { - test_sum += 1; - let res = validate_raw_eof(test_vector.code.clone()); - if res.is_ok() != test_vector.results.prague.result { - let eof = Eof::decode(test_vector.code.clone()); - println!( - "\nTest failed: {} - {}\nresult:{:?}\nrevm err_result:{:#?}\nbytes:{:?}\n,eof:{eof:#?}", - name, - vector_name, - test_vector.results.prague, - res.as_ref().err(), - test_vector.code - ); - *types_of_error - .entry( - res.err() - .map(ErrorType::Error) - .unwrap_or(ErrorType::FalsePositive), - ) - .or_default() += 1; - } else { - //println!("Test passed: {} - {}", name, vector_name); - passed_tests += 1; - } - } - } - } - println!("Types of error: {:#?}", types_of_error); - println!("Passed tests: {}/{}", passed_tests, test_sum); -} - -pub fn find_all_json_tests(path: &Path) -> Vec { - WalkDir::new(path) - .into_iter() - .filter_map(|e| e.ok()) - .filter(|e| e.file_name().to_string_lossy().ends_with(".json")) - .map(DirEntry::into_path) - .collect::>() -} - -#[derive(Debug, PartialEq, Eq, Deserialize)] -pub struct TestSuite(pub BTreeMap); - -#[derive(Debug, PartialEq, Eq, Deserialize)] -#[serde(deny_unknown_fields)] -pub struct TestUnit { - /// Test info is optional - #[serde(default, rename = "_info")] - pub info: Option, - - pub vectors: BTreeMap, -} - -#[derive(Debug, PartialEq, Eq, Deserialize)] -#[serde(deny_unknown_fields)] -pub struct TestVector { - code: Bytes, - results: PragueResult, -} - -#[derive(Debug, PartialEq, Eq, Deserialize)] -#[serde(deny_unknown_fields)] -pub struct PragueResult { - #[serde(rename = "Prague")] - prague: Result, -} - -#[derive(Debug, PartialEq, Eq, Deserialize)] -pub struct Result { - result: bool, - exception: Option, -} diff --git a/crates/op-revm/CHANGELOG.md b/crates/op-revm/CHANGELOG.md new file mode 100644 index 0000000000..bc9d37965e --- /dev/null +++ b/crates/op-revm/CHANGELOG.md @@ -0,0 +1,381 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [8.1.0](https://github.com/bluealloy/revm/compare/op-revm-v8.0.3...op-revm-v8.1.0) - 2025-07-23 + +### Added + +- *(osaka)* update EIP-7825 constant ([#2753](https://github.com/bluealloy/revm/pull/2753)) + +### Fixed + +- gas deduction with `disable_balance_check` ([#2699](https://github.com/bluealloy/revm/pull/2699)) + +### Other + +- *(op-revm)* test for optional balance check ([#2746](https://github.com/bluealloy/revm/pull/2746)) +- change gas parameter to immutable reference ([#2702](https://github.com/bluealloy/revm/pull/2702)) + +## [8.0.3](https://github.com/bluealloy/revm/compare/op-revm-v8.0.2...op-revm-v8.0.3) - 2025-07-14 + +### Other + +- simplify gas calculations by introducing a used() method ([#2703](https://github.com/bluealloy/revm/pull/2703)) + +## [8.0.2](https://github.com/bluealloy/revm/compare/op-revm-v8.0.1...op-revm-v8.0.2) - 2025-07-03 + +### Other + +- updated the following local packages: revm + +## [8.0.1](https://github.com/bluealloy/revm/compare/op-revm-v7.0.1...op-revm-v8.0.1) - 2025-06-30 + +### Added + +- optional_eip3541 ([#2661](https://github.com/bluealloy/revm/pull/2661)) + +### Other + +- cargo clippy --fix --all ([#2671](https://github.com/bluealloy/revm/pull/2671)) +- *(op/handler)* verify caller account is touched by zero value transfer ([#2669](https://github.com/bluealloy/revm/pull/2669)) +- use TxEnv::builder ([#2652](https://github.com/bluealloy/revm/pull/2652)) + +## [7.0.1](https://github.com/bluealloy/revm/compare/op-revm-v7.0.0...op-revm-v7.0.1) - 2025-06-20 + +### Fixed + +- call stack_frame.clear() at end ([#2656](https://github.com/bluealloy/revm/pull/2656)) + +## [7.0.0](https://github.com/bluealloy/revm/compare/op-revm-v6.0.0...op-revm-v7.0.0) - 2025-06-19 + +### Added + +- add fallible conversion from OpHaltReason to HaltReason ([#2649](https://github.com/bluealloy/revm/pull/2649)) +- remove EOF ([#2644](https://github.com/bluealloy/revm/pull/2644)) +- *(precompile)* rug/gmp-based modexp ([#2596](https://github.com/bluealloy/revm/pull/2596)) +- enable P256 in Osaka ([#2601](https://github.com/bluealloy/revm/pull/2601)) + +### Other + +- re-use frame allocation ([#2636](https://github.com/bluealloy/revm/pull/2636)) +- rename `transact` methods ([#2616](https://github.com/bluealloy/revm/pull/2616)) + +## [6.0.0](https://github.com/bluealloy/revm/compare/op-revm-v5.0.1...op-revm-v6.0.0) - 2025-06-06 + +### Added + +- add with_caller for system_transact ([#2587](https://github.com/bluealloy/revm/pull/2587)) +- *(Osaka)* EIP-7825 tx limit cap ([#2575](https://github.com/bluealloy/revm/pull/2575)) +- expand timestamp/block_number to u256 ([#2546](https://github.com/bluealloy/revm/pull/2546)) +- transact multi tx ([#2517](https://github.com/bluealloy/revm/pull/2517)) + +### Fixed + +- *(multitx)* Add local flags for create and selfdestruct ([#2581](https://github.com/bluealloy/revm/pull/2581)) + +### Other + +- tag v75 revm v24.0.1 ([#2563](https://github.com/bluealloy/revm/pull/2563)) ([#2589](https://github.com/bluealloy/revm/pull/2589)) +- *(op-revm)* impl type alias for Default OpEvm ([#2576](https://github.com/bluealloy/revm/pull/2576)) +- *(docs)* add lints to database-interface and op-revm crates ([#2568](https://github.com/bluealloy/revm/pull/2568)) +- ContextTr rm *_ref, and add *_mut fn ([#2560](https://github.com/bluealloy/revm/pull/2560)) +- *(test)* preserve order of fields in json fixtures ([#2541](https://github.com/bluealloy/revm/pull/2541)) + +## [5.0.1](https://github.com/bluealloy/revm/compare/op-revm-v5.0.0...op-revm-v5.0.1) - 2025-05-31 + +### Other + +- updated the following local packages: revm + +## [5.0.0](https://github.com/bluealloy/revm/compare/op-revm-v4.0.2...op-revm-v5.0.0) - 2025-05-22 + +### Added + +- *(op-revm)* add testdata comparison utility for EVM execution output ([#2525](https://github.com/bluealloy/revm/pull/2525)) + +### Other + +- make crates.io version badge clickable ([#2526](https://github.com/bluealloy/revm/pull/2526)) + +## [4.0.2](https://github.com/bluealloy/revm/compare/op-revm-v4.0.1...op-revm-v4.0.2) - 2025-05-09 + +### Fixed + +- *(op)* bump nonce on deposit ([#2503](https://github.com/bluealloy/revm/pull/2503)) +- *(op)* call cleanup on local context ([#2499](https://github.com/bluealloy/revm/pull/2499)) + +### Other + +- *(op)* revert previous and localize fix ([#2504](https://github.com/bluealloy/revm/pull/2504)) + +## [4.0.1](https://github.com/bluealloy/revm/compare/op-revm-v4.0.0...op-revm-v4.0.1) - 2025-05-09 + +### Fixed + +- *(op)* mark caller account as touched ([#2495](https://github.com/bluealloy/revm/pull/2495)) + +### Other + +- *(op)* Add test coverage to OP result module ([#2491](https://github.com/bluealloy/revm/pull/2491)) +- *(op)* Add test coverage to `OpTransactionError` ([#2490](https://github.com/bluealloy/revm/pull/2490)) + +## [4.0.0](https://github.com/bluealloy/revm/compare/op-revm-v3.1.0...op-revm-v4.0.0) - 2025-05-07 + +Dependency bump + +## [3.1.0](https://github.com/bluealloy/revm/compare/op-revm-v3.0.2...op-revm-v3.1.0) - 2025-05-07 + +### Added + +- system_call switch order of inputs, address than bytes ([#2485](https://github.com/bluealloy/revm/pull/2485)) +- *(Osaka)* disable EOF ([#2480](https://github.com/bluealloy/revm/pull/2480)) +- skip cloning of call input from shared memory ([#2462](https://github.com/bluealloy/revm/pull/2462)) +- *(Handler)* merge state validation with deduct_caller ([#2460](https://github.com/bluealloy/revm/pull/2460)) +- *(tx)* Add Either RecoveredAuthorization ([#2448](https://github.com/bluealloy/revm/pull/2448)) +- add precompiles getter to OpPrecompiles ([#2444](https://github.com/bluealloy/revm/pull/2444)) +- *(EOF)* Changes needed for devnet-1 ([#2377](https://github.com/bluealloy/revm/pull/2377)) + +### Other + +- *(op)* Set l2 block num in reloaded isthmus l1 block info ([#2465](https://github.com/bluealloy/revm/pull/2465)) +- Add clones to FrameData ([#2482](https://github.com/bluealloy/revm/pull/2482)) +- *(op)* Add test for verifying default OpSpecId update ([#2478](https://github.com/bluealloy/revm/pull/2478)) +- copy edit The Book ([#2463](https://github.com/bluealloy/revm/pull/2463)) +- bump dependency version ([#2431](https://github.com/bluealloy/revm/pull/2431)) +- fixed broken link ([#2421](https://github.com/bluealloy/revm/pull/2421)) +- backport from release branch ([#2415](https://github.com/bluealloy/revm/pull/2415)) ([#2416](https://github.com/bluealloy/revm/pull/2416)) + +## [3.0.2](https://github.com/bluealloy/revm/compare/op-revm-v3.0.1...op-revm-v3.0.2) - 2025-04-15 + +### Other + +## [3.0.1](https://github.com/bluealloy/revm/compare/op-revm-v3.0.0...op-revm-v3.0.1) - 2025-04-13 + +### Fixed + +- *(isthmus)* Add input size limitations to bls12-381 {G1/G2} MSM + pairing ([#2406](https://github.com/bluealloy/revm/pull/2406)) + +## [3.0.0](https://github.com/bluealloy/revm/compare/op-revm-v2.0.0...op-revm-v3.0.0) - 2025-04-09 + +### Added + +- support for system calls ([#2350](https://github.com/bluealloy/revm/pull/2350)) + +### Other + +- bump alloy 13.0.0 and alloy-primitives v1.0.0 ([#2394](https://github.com/bluealloy/revm/pull/2394)) +- fixed `EIP` to `RIP` ([#2388](https://github.com/bluealloy/revm/pull/2388)) +- clean unsed indicatif ([#2379](https://github.com/bluealloy/revm/pull/2379)) +- *(op-inspector)* Add test for inspecting logs ([#2352](https://github.com/bluealloy/revm/pull/2352)) +- *(op-tx)* Cover DepositTransactionParts constructor in test ([#2358](https://github.com/bluealloy/revm/pull/2358)) +- add 0x prefix to b256! and address! calls ([#2345](https://github.com/bluealloy/revm/pull/2345)) + +## [2.0.0](https://github.com/bluealloy/revm/compare/op-revm-v1.0.0...op-revm-v2.0.0) - 2025-03-28 + +### Added + +- cache precompile warming ([#2317](https://github.com/bluealloy/revm/pull/2317)) +- Add arkworks wrapper for bls12-381 ([#2316](https://github.com/bluealloy/revm/pull/2316)) +- provide more context to precompiles ([#2318](https://github.com/bluealloy/revm/pull/2318)) +- Add a wrapper for arkworks for EIP196 ([#2305](https://github.com/bluealloy/revm/pull/2305)) + +### Fixed + +- *(isthmus)* Correctly filter refunds for deposit transactions ([#2330](https://github.com/bluealloy/revm/pull/2330)) + +### Other + +- Remove LATEST variant from SpecId enum ([#2299](https://github.com/bluealloy/revm/pull/2299)) + +## [1.0.0](https://github.com/bluealloy/revm/compare/op-revm-v1.0.0-alpha.6...op-revm-v1.0.0) - 2025-03-24 + +### Other + +- *(op-precompiles)* Add test for checking that op default precompiles is updated ([#2291](https://github.com/bluealloy/revm/pull/2291)) +- *(op-precompiles)* Add missing g2 add tests ([#2253](https://github.com/bluealloy/revm/pull/2253)) + +## [1.0.0-alpha.6](https://github.com/bluealloy/revm/compare/op-revm-v1.0.0-alpha.5...op-revm-v1.0.0-alpha.6) - 2025-03-21 + +### Added + +- InspectEvm fn renames, inspector docs, book cleanup ([#2275](https://github.com/bluealloy/revm/pull/2275)) +- Return Fatal error on bls precompiles if in no_std ([#2249](https://github.com/bluealloy/revm/pull/2249)) +- Remove PrecompileError from PrecompileProvider ([#2233](https://github.com/bluealloy/revm/pull/2233)) + +### Fixed + +- *(op)* deposit txs are identifier 126 or 0x7e not 0x7f ([#2237](https://github.com/bluealloy/revm/pull/2237)) + +### Other + +- bring operator fee fixes to trunk ([#2273](https://github.com/bluealloy/revm/pull/2273)) +- *(op-test-cov)* Add test for serializing deposit transaction parts ([#2267](https://github.com/bluealloy/revm/pull/2267)) +- *(op-precompiles)* Check subset of l1 precompiles in op ([#2204](https://github.com/bluealloy/revm/pull/2204)) +- *(op-handler)* Add test for halted deposit tx post regolith ([#2269](https://github.com/bluealloy/revm/pull/2269)) +- *(op)* Remove redundant trait DepositTransaction ([#2265](https://github.com/bluealloy/revm/pull/2265)) +- Fix sys deposit tx gas test ([#2263](https://github.com/bluealloy/revm/pull/2263)) +- remove wrong `&mut` and duplicated spec ([#2276](https://github.com/bluealloy/revm/pull/2276)) +- *(op-precompiles)* clean up op tx tests ([#2242](https://github.com/bluealloy/revm/pull/2242)) +- make str to SpecId conversion fallible ([#2236](https://github.com/bluealloy/revm/pull/2236)) +- *(op-precompiles)* Add tests for bls12-381 map fp to g ([#2241](https://github.com/bluealloy/revm/pull/2241)) +- add a safe blst wrapper ([#2223](https://github.com/bluealloy/revm/pull/2223)) +- *(op-precompiles)* Reuse tests for bls12-381 msm tests for pairing ([#2239](https://github.com/bluealloy/revm/pull/2239)) +- *(op-precompiles)* add bls12-381 g2 add and msm tests ([#2231](https://github.com/bluealloy/revm/pull/2231)) +- *(op-precompiles)* Add test for g1 msm ([#2227](https://github.com/bluealloy/revm/pull/2227)) +- simplify single UT for OpSpecId compatibility. ([#2216](https://github.com/bluealloy/revm/pull/2216)) +- use AccessListItem associated type instead of AccessList ([#2214](https://github.com/bluealloy/revm/pull/2214)) + +## [1.0.0-alpha.5](https://github.com/bluealloy/revm/compare/op-revm-v1.0.0-alpha.4...op-revm-v1.0.0-alpha.5) - 2025-03-16 + +### Added + +- *(docs)* MyEvm example and book cleanup ([#2218](https://github.com/bluealloy/revm/pull/2218)) +- add test for calling `bn128_pair` before and after granite ([#2200](https://github.com/bluealloy/revm/pull/2200)) + +### Other + +- *(op-precompiles)* Add test for calling g1 add ([#2205](https://github.com/bluealloy/revm/pull/2205)) +- *(op-test)* Clean up precompile tests ([#2206](https://github.com/bluealloy/revm/pull/2206)) +- fix typo in method name ([#2202](https://github.com/bluealloy/revm/pull/2202)) +- Add tests for checking fjord precompile activation ([#2199](https://github.com/bluealloy/revm/pull/2199)) + +## [1.0.0-alpha.4](https://github.com/bluealloy/revm/compare/op-revm-v1.0.0-alpha.3...op-revm-v1.0.0-alpha.4) - 2025-03-12 + +### Added + +- Add tx/block to EvmExecution trait ([#2195](https://github.com/bluealloy/revm/pull/2195)) +- rename inspect_previous to inspect_replay ([#2194](https://github.com/bluealloy/revm/pull/2194)) + +### Other + +- add debug to precompiles type ([#2193](https://github.com/bluealloy/revm/pull/2193)) + +## [1.0.0-alpha.3](https://github.com/bluealloy/revm/compare/op-revm-v1.0.0-alpha.2...op-revm-v1.0.0-alpha.3) - 2025-03-11 + +### Fixed + +- fix(op) enable proper precompiles p256 ([#2186](https://github.com/bluealloy/revm/pull/2186)) +- *(op)* fix inspection call ([#2184](https://github.com/bluealloy/revm/pull/2184)) +- correct propagate features ([#2177](https://github.com/bluealloy/revm/pull/2177)) + +### Other + +- remove CTX phantomdata from precompile providers ([#2178](https://github.com/bluealloy/revm/pull/2178)) + +## [1.0.0-alpha.2](https://github.com/bluealloy/revm/compare/op-revm-v1.0.0-alpha.1...op-revm-v1.0.0-alpha.2) - 2025-03-10 + +### Other + +- updated the following local packages: revm + +## [1.0.0-alpha.1](https://github.com/bluealloy/revm/releases/tag/revm-optimism-v1.0.0-alpha.1) - 2025-02-16 + +### Added + +- Split Inspector trait from EthHandler into standalone crate (#2075) +- Introduce Auth and AccessList traits (#2079) +- derive Eq for OpSpec (#2073) +- *(op)* Isthmus precompiles (#2054) +- Evm structure (Cached Instructions and Precompiles) (#2049) +- simplify InspectorContext (#2036) +- Context execution (#2013) +- EthHandler trait (#2001) +- extract and export `estimate_tx_compressed_size` (#1985) +- *(EIP-7623)* Increase calldata cost. backport from rel/v51 (#1965) +- simplify Transaction trait (#1959) +- Split inspector.rs (#1958) +- align Block trait (#1957) +- expose precompile address in Journal, DB::Error: StdError (#1956) +- add isthmus spec (#1938) +- integrate codspeed (#1935) +- Make Ctx journal generic (#1933) +- Restucturing Part7 Handler and Context rework (#1865) +- restructuring Part6 transaction crate (#1814) +- Restructuring Part3 inspector crate (#1788) +- restructure Part2 database crate (#1784) +- project restructuring Part1 (#1776) +- introducing EvmWiring, a chain-specific configuration (#1672) +- *(examples)* generate block traces (#895) +- implement EIP-4844 (#668) +- *(Shanghai)* All EIPs: push0, warm coinbase, limit/measure initcode (#376) +- Migrate `primitive_types::U256` to `ruint::Uint<256, 4>` (#239) +- Introduce ByteCode format, Update Readme (#156) + +### Fixed + +- make macro crate-agnostic (#1802) +- fix typos ([#620](https://github.com/bluealloy/revm/pull/620)) + +### Other + +- set alpha.1 version +- backport op l1 fetch perf (#2076) +- remove OpSpec (#2074) +- Add helpers with_inspector with_precompile (#2063) +- *(op)* backport isthmus operator fee (#2059) +- Bump licence year to 2025 (#2058) +- rename OpHaltReason (#2042) +- simplify some generics (#2032) +- align crates versions (#1983) +- Make inspector use generics, rm associated types (#1934) +- add OpTransaction conversion tests (#1939) +- fix comments and docs into more sensible (#1920) +- Rename PRAGUE_EOF to OSAKA (#1903) +- refactor L1BlockInfo::tx_estimated_size_fjord (#1856) +- *(primitives)* replace HashMap re-exports with alloy_primitives::map (#1805) +- Test for l1 gas used and l1 fee for ecotone tx (#1748) +- *(deps)* bump anyhow from 1.0.88 to 1.0.89 (#1772) +- Bump new logo (#1735) +- *(README)* add rbuilder to used-by (#1585) +- added simular to used-by (#1521) +- add Trin to used by list (#1393) +- Fix typo in readme ([#1185](https://github.com/bluealloy/revm/pull/1185)) +- Add Hardhat to the "Used by" list ([#1164](https://github.com/bluealloy/revm/pull/1164)) +- Add VERBS to used by list ([#1141](https://github.com/bluealloy/revm/pull/1141)) +- license date and revm docs (#1080) +- *(docs)* Update the benchmark docs to point to revm package (#906) +- *(docs)* Update top-level benchmark docs (#894) +- clang requirement (#784) +- Readme Updates (#756) +- Logo (#743) +- book workflow ([#537](https://github.com/bluealloy/revm/pull/537)) +- add example to revm crate ([#468](https://github.com/bluealloy/revm/pull/468)) +- Update README.md ([#424](https://github.com/bluealloy/revm/pull/424)) +- add no_std to primitives ([#366](https://github.com/bluealloy/revm/pull/366)) +- revm-precompiles to revm-precompile +- Bump v20, changelog ([#350](https://github.com/bluealloy/revm/pull/350)) +- typos (#232) +- Add support for old forks. ([#191](https://github.com/bluealloy/revm/pull/191)) +- revm bump 1.8. update libs. snailtracer rename ([#159](https://github.com/bluealloy/revm/pull/159)) +- typo fixes +- fix readme typo +- Big Refactor. Machine to Interpreter. refactor instructions. call/create struct ([#52](https://github.com/bluealloy/revm/pull/52)) +- readme. debuger update +- Bump revm v0.3.0. README updated +- readme +- Add time elapsed for tests +- readme updated +- Include Basefee into cost calc. readme change +- Initialize precompile accounts +- Status update. Taking a break +- Merkle calc. Tweaks and debugging for eip158 +- Replace aurora bn lib with parity's. All Bn128Add/Mul/Pair tests passes +- TEMP +- one tab removed +- readme +- README Example simplified +- Gas calculation for Call/Create. Example Added +- readme usage +- README changes +- Static gas cost added +- Subroutine changelogs and reverts +- Readme postulates +- Spelling +- Restructure project +- First iteration. Machine is looking okay diff --git a/crates/op-revm/Cargo.toml b/crates/op-revm/Cargo.toml new file mode 100644 index 0000000000..5b8f39ae75 --- /dev/null +++ b/crates/op-revm/Cargo.toml @@ -0,0 +1,74 @@ +[package] +name = "op-revm" +description = "Optimism variant of Revm" +version = "8.1.0" +authors.workspace = true +edition.workspace = true +keywords.workspace = true +license.workspace = true +repository.workspace = true +readme.workspace = true + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] + +[lints] +workspace = true + +[dependencies] +# revm +revm.workspace = true +auto_impl.workspace = true + +# static precompile sets. +once_cell = { workspace = true, features = ["alloc"] } + +# Optional +serde = { workspace = true, features = ["derive", "rc"], optional = true } + +[dev-dependencies] +rstest.workspace = true +alloy-sol-types.workspace = true +sha2.workspace = true +serde_json = { workspace = true, features = ["alloc", "preserve_order"] } +alloy-primitives.workspace = true +serde = { workspace = true, features = ["derive"] } + +[features] +default = ["std", "c-kzg", "secp256k1", "portable", "blst"] +std = [ + "serde?/std", + "revm/std", + "alloy-sol-types/std", + "once_cell/std", + "sha2/std", + "serde_json/std", + "alloy-primitives/std", +] +hashbrown = ["revm/hashbrown"] +serde = ["dep:serde", "revm/serde", "alloy-primitives/serde"] +portable = ["revm/portable"] + +dev = [ + "memory_limit", + "optional_balance_check", + "optional_block_gas_limit", + "optional_eip3541", + "optional_eip3607", + "optional_no_base_fee", +] +memory_limit = ["revm/memory_limit"] +optional_balance_check = ["revm/optional_balance_check"] +optional_block_gas_limit = ["revm/optional_block_gas_limit"] +optional_eip3541 = ["revm/optional_eip3541"] +optional_eip3607 = ["revm/optional_eip3607"] +optional_no_base_fee = ["revm/optional_no_base_fee"] + +# See comments in `revm-precompile` +secp256k1 = ["revm/secp256k1"] +c-kzg = ["revm/c-kzg"] +# `kzg-rs` is not audited but useful for `no_std` environment, use it with causing and default to `c-kzg` if possible. +kzg-rs = ["revm/kzg-rs"] +blst = ["revm/blst"] +bn = ["revm/bn"] diff --git a/crates/op-revm/LICENSE b/crates/op-revm/LICENSE new file mode 100644 index 0000000000..be6d350ebe --- /dev/null +++ b/crates/op-revm/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021-2025 draganrakita + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/crates/op-revm/src/api.rs b/crates/op-revm/src/api.rs new file mode 100644 index 0000000000..b3d5771dc5 --- /dev/null +++ b/crates/op-revm/src/api.rs @@ -0,0 +1,9 @@ +//! Optimism API types. + +pub mod builder; +pub mod default_ctx; +pub mod exec; + +pub use builder::OpBuilder; +pub use default_ctx::DefaultOp; +pub use exec::{OpContextTr, OpError}; diff --git a/crates/op-revm/src/api/builder.rs b/crates/op-revm/src/api/builder.rs new file mode 100644 index 0000000000..d36708516e --- /dev/null +++ b/crates/op-revm/src/api/builder.rs @@ -0,0 +1,45 @@ +//! Optimism builder trait [`OpBuilder`] used to build [`OpEvm`]. +use crate::{evm::OpEvm, precompiles::OpPrecompiles, transaction::OpTxTr, L1BlockInfo, OpSpecId}; +use revm::{ + context::Cfg, + context_interface::{Block, JournalTr}, + handler::instructions::EthInstructions, + interpreter::interpreter::EthInterpreter, + state::EvmState, + Context, Database, +}; + +/// Type alias for default OpEvm +pub type DefaultOpEvm = + OpEvm, OpPrecompiles>; + +/// Trait that allows for optimism OpEvm to be built. +pub trait OpBuilder: Sized { + /// Type of the context. + type Context; + + /// Build the op. + fn build_op(self) -> DefaultOpEvm; + + /// Build the op with an inspector. + fn build_op_with_inspector(self, inspector: INSP) -> DefaultOpEvm; +} + +impl OpBuilder for Context +where + BLOCK: Block, + TX: OpTxTr, + CFG: Cfg, + DB: Database, + JOURNAL: JournalTr, +{ + type Context = Self; + + fn build_op(self) -> DefaultOpEvm { + OpEvm::new(self, ()) + } + + fn build_op_with_inspector(self, inspector: INSP) -> DefaultOpEvm { + OpEvm::new(self, inspector) + } +} diff --git a/crates/op-revm/src/api/default_ctx.rs b/crates/op-revm/src/api/default_ctx.rs new file mode 100644 index 0000000000..1b21507379 --- /dev/null +++ b/crates/op-revm/src/api/default_ctx.rs @@ -0,0 +1,47 @@ +//! Contains trait [`DefaultOp`] used to create a default context. +use crate::{L1BlockInfo, OpSpecId, OpTransaction}; +use revm::{ + context::{BlockEnv, CfgEnv, TxEnv}, + database_interface::EmptyDB, + Context, Journal, MainContext, +}; + +/// Type alias for the default context type of the OpEvm. +pub type OpContext = + Context, CfgEnv, DB, Journal, L1BlockInfo>; + +/// Trait that allows for a default context to be created. +pub trait DefaultOp { + /// Create a default context. + fn op() -> OpContext; +} + +impl DefaultOp for OpContext { + fn op() -> Self { + Context::mainnet() + .with_tx(OpTransaction::builder().build_fill()) + .with_cfg(CfgEnv::new_with_spec(OpSpecId::BEDROCK)) + .with_chain(L1BlockInfo::default()) + } +} + +#[cfg(test)] +mod test { + use super::*; + use crate::api::builder::OpBuilder; + use revm::{ + inspector::{InspectEvm, NoOpInspector}, + ExecuteEvm, + }; + + #[test] + fn default_run_op() { + let ctx = Context::op(); + // convert to optimism context + let mut evm = ctx.build_op_with_inspector(NoOpInspector {}); + // execute + let _ = evm.transact(OpTransaction::builder().build_fill()); + // inspect + let _ = evm.inspect_one_tx(OpTransaction::builder().build_fill()); + } +} diff --git a/crates/op-revm/src/api/exec.rs b/crates/op-revm/src/api/exec.rs new file mode 100644 index 0000000000..a5ddec95b6 --- /dev/null +++ b/crates/op-revm/src/api/exec.rs @@ -0,0 +1,144 @@ +//! Implementation of the [`ExecuteEvm`] trait for the [`OpEvm`]. +use crate::{ + evm::OpEvm, handler::OpHandler, transaction::OpTxTr, L1BlockInfo, OpHaltReason, OpSpecId, + OpTransactionError, +}; +use revm::{ + context::{result::ExecResultAndState, ContextSetters}, + context_interface::{ + result::{EVMError, ExecutionResult}, + Cfg, ContextTr, Database, JournalTr, + }, + handler::{ + instructions::EthInstructions, system_call::SystemCallEvm, EthFrame, Handler, + PrecompileProvider, SystemCallTx, + }, + inspector::{InspectCommitEvm, InspectEvm, Inspector, InspectorHandler, JournalExt}, + interpreter::{interpreter::EthInterpreter, InterpreterResult}, + primitives::{Address, Bytes}, + state::EvmState, + DatabaseCommit, ExecuteCommitEvm, ExecuteEvm, +}; + +/// Type alias for Optimism context +pub trait OpContextTr: + ContextTr< + Journal: JournalTr, + Tx: OpTxTr, + Cfg: Cfg, + Chain = L1BlockInfo, +> +{ +} + +impl OpContextTr for T where + T: ContextTr< + Journal: JournalTr, + Tx: OpTxTr, + Cfg: Cfg, + Chain = L1BlockInfo, + > +{ +} + +/// Type alias for the error type of the OpEvm. +pub type OpError = EVMError<<::Db as Database>::Error, OpTransactionError>; + +impl ExecuteEvm + for OpEvm, PRECOMPILE> +where + CTX: OpContextTr + ContextSetters, + PRECOMPILE: PrecompileProvider, +{ + type Tx = ::Tx; + type Block = ::Block; + type State = EvmState; + type Error = OpError; + type ExecutionResult = ExecutionResult; + + fn set_block(&mut self, block: Self::Block) { + self.0.ctx.set_block(block); + } + + fn transact_one(&mut self, tx: Self::Tx) -> Result { + self.0.ctx.set_tx(tx); + let mut h = OpHandler::<_, _, EthFrame>::new(); + h.run(self) + } + + fn finalize(&mut self) -> Self::State { + self.0.ctx.journal_mut().finalize() + } + + fn replay( + &mut self, + ) -> Result, Self::Error> { + let mut h = OpHandler::<_, _, EthFrame>::new(); + h.run(self).map(|result| { + let state = self.finalize(); + ExecResultAndState::new(result, state) + }) + } +} + +impl ExecuteCommitEvm + for OpEvm, PRECOMPILE> +where + CTX: OpContextTr + ContextSetters, + PRECOMPILE: PrecompileProvider, +{ + fn commit(&mut self, state: Self::State) { + self.0.ctx.db_mut().commit(state); + } +} + +impl InspectEvm + for OpEvm, PRECOMPILE> +where + CTX: OpContextTr + ContextSetters, + INSP: Inspector, + PRECOMPILE: PrecompileProvider, +{ + type Inspector = INSP; + + fn set_inspector(&mut self, inspector: Self::Inspector) { + self.0.inspector = inspector; + } + + fn inspect_one_tx(&mut self, tx: Self::Tx) -> Result { + self.0.ctx.set_tx(tx); + let mut h = OpHandler::<_, _, EthFrame>::new(); + h.inspect_run(self) + } +} + +impl InspectCommitEvm + for OpEvm, PRECOMPILE> +where + CTX: OpContextTr + ContextSetters, + INSP: Inspector, + PRECOMPILE: PrecompileProvider, +{ +} + +impl SystemCallEvm + for OpEvm, PRECOMPILE> +where + CTX: OpContextTr + ContextSetters, + PRECOMPILE: PrecompileProvider, +{ + fn transact_system_call_with_caller( + &mut self, + caller: Address, + system_contract_address: Address, + data: Bytes, + ) -> Result { + self.0.ctx.set_tx(CTX::Tx::new_system_tx_with_caller( + caller, + system_contract_address, + data, + )); + let mut h = OpHandler::<_, _, EthFrame>::new(); + h.run_system_call(self) + } +} diff --git a/crates/op-revm/src/constants.rs b/crates/op-revm/src/constants.rs new file mode 100644 index 0000000000..c639e8573c --- /dev/null +++ b/crates/op-revm/src/constants.rs @@ -0,0 +1,57 @@ +//! Optimism constants used in the Optimism EVM. +use revm::primitives::{address, Address, U256}; + +/// The cost of a non-zero byte in the EVM. +pub const NON_ZERO_BYTE_COST: u64 = 16; + +/// The two 4-byte Ecotone fee scalar values are packed into the same storage slot as the 8-byte sequence number. +/// Byte offset within the storage slot of the 4-byte baseFeeScalar attribute. +pub const BASE_FEE_SCALAR_OFFSET: usize = 16; +/// The two 4-byte Ecotone fee scalar values are packed into the same storage slot as the 8-byte sequence number. +/// Byte offset within the storage slot of the 4-byte blobBaseFeeScalar attribute. +pub const BLOB_BASE_FEE_SCALAR_OFFSET: usize = 20; + +/// The Isthmus operator fee scalar values are similarly packed. Byte offset within +/// the storage slot of the 4-byte operatorFeeScalar attribute. +pub const OPERATOR_FEE_SCALAR_OFFSET: usize = 20; +/// The Isthmus operator fee scalar values are similarly packed. Byte offset within +/// the storage slot of the 8-byte operatorFeeConstant attribute. +pub const OPERATOR_FEE_CONSTANT_OFFSET: usize = 24; + +/// The fixed point decimal scaling factor associated with the operator fee scalar. +/// +/// Allows users to use 6 decimal points of precision when specifying the operator_fee_scalar. +pub const OPERATOR_FEE_SCALAR_DECIMAL: u64 = 1_000_000; + +/// The L1 base fee slot. +pub const L1_BASE_FEE_SLOT: U256 = U256::from_limbs([1u64, 0, 0, 0]); +/// The L1 overhead slot. +pub const L1_OVERHEAD_SLOT: U256 = U256::from_limbs([5u64, 0, 0, 0]); +/// The L1 scalar slot. +pub const L1_SCALAR_SLOT: U256 = U256::from_limbs([6u64, 0, 0, 0]); + +/// [ECOTONE_L1_BLOB_BASE_FEE_SLOT] was added in the Ecotone upgrade and stores the L1 blobBaseFee attribute. +pub const ECOTONE_L1_BLOB_BASE_FEE_SLOT: U256 = U256::from_limbs([7u64, 0, 0, 0]); + +/// As of the ecotone upgrade, this storage slot stores the 32-bit basefeeScalar and blobBaseFeeScalar attributes at +/// offsets [BASE_FEE_SCALAR_OFFSET] and [BLOB_BASE_FEE_SCALAR_OFFSET] respectively. +pub const ECOTONE_L1_FEE_SCALARS_SLOT: U256 = U256::from_limbs([3u64, 0, 0, 0]); + +/// This storage slot stores the 32-bit operatorFeeScalar and operatorFeeConstant attributes at +/// offsets [OPERATOR_FEE_SCALAR_OFFSET] and [OPERATOR_FEE_CONSTANT_OFFSET] respectively. +pub const OPERATOR_FEE_SCALARS_SLOT: U256 = U256::from_limbs([8u64, 0, 0, 0]); + +/// An empty 64-bit set of scalar values. +pub const EMPTY_SCALARS: [u8; 8] = [0u8; 8]; + +/// The address of L1 fee recipient. +pub const L1_FEE_RECIPIENT: Address = address!("0x420000000000000000000000000000000000001A"); + +/// The address of the operator fee recipient. +pub const OPERATOR_FEE_RECIPIENT: Address = address!("0x420000000000000000000000000000000000001B"); + +/// The address of the base fee recipient. +pub const BASE_FEE_RECIPIENT: Address = address!("0x4200000000000000000000000000000000000019"); + +/// The address of the L1Block contract. +pub const L1_BLOCK_CONTRACT: Address = address!("0x4200000000000000000000000000000000000015"); diff --git a/crates/op-revm/src/evm.rs b/crates/op-revm/src/evm.rs new file mode 100644 index 0000000000..8f13b36c66 --- /dev/null +++ b/crates/op-revm/src/evm.rs @@ -0,0 +1,164 @@ +//! Contains the `[OpEvm]` type and its implementation of the execution EVM traits. +use crate::precompiles::OpPrecompiles; +use revm::{ + context::{ContextError, ContextSetters, Evm, FrameStack}, + context_interface::ContextTr, + handler::{ + evm::FrameTr, + instructions::{EthInstructions, InstructionProvider}, + EthFrame, EvmTr, FrameInitOrResult, ItemOrResult, PrecompileProvider, + }, + inspector::{InspectorEvmTr, JournalExt}, + interpreter::{interpreter::EthInterpreter, InterpreterResult}, + Database, Inspector, +}; + +/// Optimism EVM extends the [`Evm`] type with Optimism specific types and logic. +#[derive(Debug, Clone)] +pub struct OpEvm< + CTX, + INSP, + I = EthInstructions, + P = OpPrecompiles, + F = EthFrame, +>( + /// Inner EVM type. + pub Evm, +); + +impl OpEvm, OpPrecompiles> { + /// Create a new Optimism EVM. + pub fn new(ctx: CTX, inspector: INSP) -> Self { + Self(Evm { + ctx, + inspector, + instruction: EthInstructions::new_mainnet(), + precompiles: OpPrecompiles::default(), + frame_stack: FrameStack::new(), + }) + } +} + +impl OpEvm { + /// Consumed self and returns a new Evm type with given Inspector. + pub fn with_inspector(self, inspector: OINSP) -> OpEvm { + OpEvm(self.0.with_inspector(inspector)) + } + + /// Consumes self and returns a new Evm type with given Precompiles. + pub fn with_precompiles(self, precompiles: OP) -> OpEvm { + OpEvm(self.0.with_precompiles(precompiles)) + } + + /// Consumes self and returns the inner Inspector. + pub fn into_inspector(self) -> INSP { + self.0.into_inspector() + } +} + +impl InspectorEvmTr for OpEvm +where + CTX: ContextTr + ContextSetters, + I: InstructionProvider, + P: PrecompileProvider, + INSP: Inspector, +{ + type Inspector = INSP; + + fn inspector(&mut self) -> &mut Self::Inspector { + &mut self.0.inspector + } + + fn ctx_inspector(&mut self) -> (&mut Self::Context, &mut Self::Inspector) { + (&mut self.0.ctx, &mut self.0.inspector) + } + + fn ctx_inspector_frame( + &mut self, + ) -> (&mut Self::Context, &mut Self::Inspector, &mut Self::Frame) { + ( + &mut self.0.ctx, + &mut self.0.inspector, + self.0.frame_stack.get(), + ) + } + + fn ctx_inspector_frame_instructions( + &mut self, + ) -> ( + &mut Self::Context, + &mut Self::Inspector, + &mut Self::Frame, + &mut Self::Instructions, + ) { + ( + &mut self.0.ctx, + &mut self.0.inspector, + self.0.frame_stack.get(), + &mut self.0.instruction, + ) + } +} + +impl EvmTr for OpEvm> +where + CTX: ContextTr, + I: InstructionProvider, + P: PrecompileProvider, +{ + type Context = CTX; + type Instructions = I; + type Precompiles = P; + type Frame = EthFrame; + + fn ctx(&mut self) -> &mut Self::Context { + &mut self.0.ctx + } + + fn ctx_ref(&self) -> &Self::Context { + &self.0.ctx + } + + fn ctx_instructions(&mut self) -> (&mut Self::Context, &mut Self::Instructions) { + (&mut self.0.ctx, &mut self.0.instruction) + } + + fn ctx_precompiles(&mut self) -> (&mut Self::Context, &mut Self::Precompiles) { + (&mut self.0.ctx, &mut self.0.precompiles) + } + + fn frame_stack(&mut self) -> &mut FrameStack { + &mut self.0.frame_stack + } + + fn frame_init( + &mut self, + frame_input: ::FrameInit, + ) -> Result< + ItemOrResult<&mut Self::Frame, ::FrameResult>, + ContextError<<::Db as Database>::Error>, + > { + self.0.frame_init(frame_input) + } + + fn frame_run( + &mut self, + ) -> Result< + FrameInitOrResult, + ContextError<<::Db as Database>::Error>, + > { + self.0.frame_run() + } + + #[doc = " Returns the result of the frame to the caller. Frame is popped from the frame stack."] + #[doc = " Consumes the frame result or returns it if there is more frames to run."] + fn frame_return_result( + &mut self, + result: ::FrameResult, + ) -> Result< + Option<::FrameResult>, + ContextError<<::Db as Database>::Error>, + > { + self.0.frame_return_result(result) + } +} diff --git a/crates/revm/src/optimism/fast_lz.rs b/crates/op-revm/src/fast_lz.rs similarity index 92% rename from crates/revm/src/optimism/fast_lz.rs rename to crates/op-revm/src/fast_lz.rs index 51ea82d493..a1a262a079 100644 --- a/crates/revm/src/optimism/fast_lz.rs +++ b/crates/op-revm/src/fast_lz.rs @@ -1,5 +1,10 @@ +//! Contains the `[flz_compress_len]` function. + /// Returns the length of the data after compression through FastLZ, based on -// https://github.com/Vectorized/solady/blob/5315d937d79b335c668896d7533ac603adac5315/js/solady.js +/// +/// +/// The u32s match op-geth's Go port: +/// pub(crate) fn flz_compress_len(input: &[u8]) -> u32 { let mut idx: u32 = 2; @@ -105,22 +110,23 @@ fn u24(input: &[u8], idx: u32) -> u32 { #[cfg(test)] mod tests { + use super::*; + use crate::api::{builder::OpBuilder, default_ctx::DefaultOp}; use alloy_sol_types::sol; use alloy_sol_types::SolCall; - - use super::*; - use crate::db::BenchmarkDB; - use crate::{ - primitives::address, primitives::bytes, primitives::Bytecode, primitives::Bytes, - primitives::TransactTo, primitives::U256, Evm, + use revm::{ + bytecode::Bytecode, + database::{BenchmarkDB, EEADDRESS, FFADDRESS}, + primitives::{bytes, Bytes, TxKind, U256}, }; - + use revm::{Context, ExecuteEvm}; use rstest::rstest; + use std::vec::Vec; #[rstest] #[case::empty(&[], 0)] #[case::thousand_zeros(&[0; 1000], 21)] - #[case::thousand_fourty_twos(&[42; 1000], 21)] + #[case::thousand_forty_twos(&[42; 1000], 21)] #[case::short_hex(&bytes!("FACADE"), 4)] #[case::sample_contract_call(&bytes!("02f901550a758302df1483be21b88304743f94f80e51afb613d764fa61751affd3313c190a86bb870151bd62fd12adb8e41ef24f3f000000000000000000000000000000000000000000000000000000000000006e000000000000000000000000af88d065e77c8cc2239327c5edb3a432268e5831000000000000000000000000000000000000000000000000000000000003c1e5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000148c89ed219d02f1a5be012c689b4f5b731827bebe000000000000000000000000c001a033fd89cb37c31b2cba46b6466e040c61fc9b2a3675a7f5f493ebd5ad77c497f8a07cdf65680e238392693019b4092f610222e71b7cec06449cb922b93b6a12744e"), 202)] #[case::base_0x5dadeb52979f29fc7a7494c43fdabc5be1d8ff404f3aafe93d729fa8e5d00769(&bytes!("b9047c02f904788221050883036ee48409c6c87383037f6f941195cf65f83b3a5768f3c496d3a05ad6412c64b78644364c5bb000b90404d123b4d80000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000038000000000000000000000000000000000f6476f90447748c19248ccaa31e6b8bfda4eb9d830f5f47df7f0998f7c2123d9e6137761b75d3184efb0f788e3b14516000000000000000000000000000000000000000000000000000044364c5bb000000000000000000000000000f38e53bd45c8225a7c94b513beadaa7afe5d222d0000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000084d6574614d61736b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035697066733a2f2f516d656852577a743347745961776343347564745657557233454c587261436746434259416b66507331696f48610000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000cd0d83d9e840f8e27d5c2e365fd365ff1c05b2480000000000000000000000000000000000000000000000000000000000000ce40000000000000000000000000000000000000000000000000000000000000041e4480d358dbae20880960a0a464d63b06565a0c9f9b1b37aa94b522247b23ce149c81359bf4239d1a879eeb41047ec710c15f5c0f67453da59a383e6abd742971c00000000000000000000000000000000000000000000000000000000000000c001a0b57f0ff8516ea29cb26a44ac5055a5420847d1e16a8e7b03b70f0c02291ff2d5a00ad3771e5f39ccacfff0faa8c5d25ef7a1c179f79e66e828ffddcb994c8b512e"), 471)] @@ -152,6 +158,10 @@ mod tests { fn test_flz_native_evm_parity(#[case] input: Bytes) { // This bytecode and ABI is for a contract, which wraps the LibZip library for easier fuzz testing. // The source of this contract is here: https://github.com/danyalprout/fastlz/blob/main/src/FastLz.sol#L6-L10 + + use revm::context::TxEnv; + + use crate::OpTransaction; sol! { interface FastLz { function fastLz(bytes input) external view returns (uint256); @@ -162,21 +172,25 @@ mod tests { let native_val = flz_compress_len(&input); - let mut evm = Evm::builder() + let mut evm = Context::op() .with_db(BenchmarkDB::new_bytecode(contract_bytecode.clone())) - .modify_tx_env(|tx| { - tx.caller = address!("1000000000000000000000000000000000000000"); - tx.transact_to = - TransactTo::Call(address!("0000000000000000000000000000000000000000")); - tx.data = FastLz::fastLzCall::new((input,)).abi_encode().into(); - }) - .build(); - - let result_and_state = evm.transact().unwrap(); - let output = result_and_state.result.output().unwrap(); - let evm_val = FastLz::fastLzCall::abi_decode_returns(output, true) - .unwrap() - ._0; + .build_op(); + + let tx = OpTransaction::builder() + .base( + TxEnv::builder() + .caller(EEADDRESS) + .kind(TxKind::Call(FFADDRESS)) + .data(FastLz::fastLzCall::new((input,)).abi_encode().into()) + .gas_limit(3_000_000), + ) + .enveloped_tx(Some(Bytes::default())) + .build_fill(); + + let result = evm.transact_one(tx).unwrap(); + + let output = result.output().unwrap(); + let evm_val = FastLz::fastLzCall::abi_decode_returns(output).unwrap(); assert_eq!(U256::from(native_val), evm_val); } diff --git a/crates/op-revm/src/handler.rs b/crates/op-revm/src/handler.rs new file mode 100644 index 0000000000..e696aba055 --- /dev/null +++ b/crates/op-revm/src/handler.rs @@ -0,0 +1,1112 @@ +//!Handler related to Optimism chain +use crate::{ + api::exec::OpContextTr, + constants::{BASE_FEE_RECIPIENT, L1_FEE_RECIPIENT, OPERATOR_FEE_RECIPIENT}, + transaction::{deposit::DEPOSIT_TRANSACTION_TYPE, OpTransactionError, OpTxTr}, + L1BlockInfo, OpHaltReason, OpSpecId, +}; +use revm::{ + context::{result::InvalidTransaction, LocalContextTr}, + context_interface::{ + context::ContextError, + result::{EVMError, ExecutionResult, FromStringError}, + Block, Cfg, ContextTr, JournalTr, Transaction, + }, + handler::{ + evm::FrameTr, + handler::EvmTrError, + post_execution::{self, reimburse_caller}, + pre_execution::validate_account_nonce_and_code, + EthFrame, EvmTr, FrameResult, Handler, MainnetHandler, + }, + inspector::{Inspector, InspectorEvmTr, InspectorHandler}, + interpreter::{interpreter::EthInterpreter, interpreter_action::FrameInit, Gas}, + primitives::{hardfork::SpecId, U256}, +}; +use std::boxed::Box; + +/// Optimism handler extends the [`Handler`] with Optimism specific logic. +#[derive(Debug, Clone)] +pub struct OpHandler { + /// Mainnet handler allows us to use functions from the mainnet handler inside optimism handler. + /// So we dont duplicate the logic + pub mainnet: MainnetHandler, + /// Phantom data to avoid type inference issues. + pub _phantom: core::marker::PhantomData<(EVM, ERROR, FRAME)>, +} + +impl OpHandler { + /// Create a new Optimism handler. + pub fn new() -> Self { + Self { + mainnet: MainnetHandler::default(), + _phantom: core::marker::PhantomData, + } + } +} + +impl Default for OpHandler { + fn default() -> Self { + Self::new() + } +} + +/// Trait to check if the error is a transaction error. +/// +/// Used in cache_error handler to catch deposit transaction that was halted. +pub trait IsTxError { + /// Check if the error is a transaction error. + fn is_tx_error(&self) -> bool; +} + +impl IsTxError for EVMError { + fn is_tx_error(&self) -> bool { + matches!(self, EVMError::Transaction(_)) + } +} + +impl Handler for OpHandler +where + EVM: EvmTr, + ERROR: EvmTrError + From + FromStringError + IsTxError, + // TODO `FrameResult` should be a generic trait. + // TODO `FrameInit` should be a generic. + FRAME: FrameTr, +{ + type Evm = EVM; + type Error = ERROR; + type HaltReason = OpHaltReason; + + fn validate_env(&self, evm: &mut Self::Evm) -> Result<(), Self::Error> { + // Do not perform any extra validation for deposit transactions, they are pre-verified on L1. + let ctx = evm.ctx(); + let tx = ctx.tx(); + let tx_type = tx.tx_type(); + if tx_type == DEPOSIT_TRANSACTION_TYPE { + // Do not allow for a system transaction to be processed if Regolith is enabled. + if tx.is_system_transaction() + && evm.ctx().cfg().spec().is_enabled_in(OpSpecId::REGOLITH) + { + return Err(OpTransactionError::DepositSystemTxPostRegolith.into()); + } + return Ok(()); + } + self.mainnet.validate_env(evm) + } + + fn validate_against_state_and_deduct_caller( + &self, + evm: &mut Self::Evm, + ) -> Result<(), Self::Error> { + let ctx = evm.ctx(); + + let basefee = ctx.block().basefee() as u128; + let blob_price = ctx.block().blob_gasprice().unwrap_or_default(); + let is_deposit = ctx.tx().tx_type() == DEPOSIT_TRANSACTION_TYPE; + let spec = ctx.cfg().spec(); + let block_number = ctx.block().number(); + let is_balance_check_disabled = ctx.cfg().is_balance_check_disabled(); + let is_eip3607_disabled = ctx.cfg().is_eip3607_disabled(); + let is_nonce_check_disabled = ctx.cfg().is_nonce_check_disabled(); + + let mint = if is_deposit { + ctx.tx().mint().unwrap_or_default() + } else { + 0 + }; + + let mut additional_cost = U256::ZERO; + + // The L1-cost fee is only computed for Optimism non-deposit transactions. + if !is_deposit { + // L1 block info is stored in the context for later use. + // and it will be reloaded from the database if it is not for the current block. + if ctx.chain().l2_block != block_number { + *ctx.chain_mut() = L1BlockInfo::try_fetch(ctx.db_mut(), block_number, spec)?; + } + + // account for additional cost of l1 fee and operator fee + let enveloped_tx = ctx + .tx() + .enveloped_tx() + .expect("all not deposit tx have enveloped tx") + .clone(); + + // compute L1 cost + additional_cost = ctx.chain_mut().calculate_tx_l1_cost(&enveloped_tx, spec); + + // compute operator fee + if spec.is_enabled_in(OpSpecId::ISTHMUS) { + let gas_limit = U256::from(ctx.tx().gas_limit()); + let operator_fee_charge = ctx.chain().operator_fee_charge(&enveloped_tx, gas_limit); + additional_cost = additional_cost.saturating_add(operator_fee_charge); + } + } + + let (tx, journal) = ctx.tx_journal_mut(); + + let caller_account = journal.load_account_code(tx.caller())?.data; + + if !is_deposit { + // validates account nonce and code + validate_account_nonce_and_code( + &mut caller_account.info, + tx.nonce(), + is_eip3607_disabled, + is_nonce_check_disabled, + )?; + } + + // Bump the nonce for calls. Nonce for CREATE will be bumped in `handle_create`. + if tx.kind().is_call() { + caller_account.info.nonce = caller_account.info.nonce.saturating_add(1); + } + + let max_balance_spending = tx.max_balance_spending()?.saturating_add(additional_cost); + + // old balance is journaled before mint is incremented. + let old_balance = caller_account.info.balance; + + // If the transaction is a deposit with a `mint` value, add the mint value + // in wei to the caller's balance. This should be persisted to the database + // prior to the rest of execution. + let mut new_balance = caller_account.info.balance.saturating_add(U256::from(mint)); + + // Check if account has enough balance for `gas_limit * max_fee`` and value transfer. + // Transfer will be done inside `*_inner` functions. + if !is_deposit && max_balance_spending > new_balance && !is_balance_check_disabled { + // skip max balance check for deposit transactions. + // this check for deposit was skipped previously in `validate_tx_against_state` function + return Err(InvalidTransaction::LackOfFundForMaxFee { + fee: Box::new(max_balance_spending), + balance: Box::new(new_balance), + } + .into()); + } + + let effective_balance_spending = tx + .effective_balance_spending(basefee, blob_price) + .expect("effective balance is always smaller than max balance so it can't overflow"); + + // subtracting max balance spending with value that is going to be deducted later in the call. + let gas_balance_spending = effective_balance_spending - tx.value(); + + // If the transaction is not a deposit transaction, subtract the L1 data fee from the + // caller's balance directly after minting the requested amount of ETH. + // Additionally deduct the operator fee from the caller's account. + // + // In case of deposit additional cost will be zero. + let op_gas_balance_spending = gas_balance_spending.saturating_add(additional_cost); + + new_balance = new_balance.saturating_sub(op_gas_balance_spending); + + if is_balance_check_disabled { + // Make sure the caller's balance is at least the value of the transaction. + // this is not consensus critical, and it is used in testing. + new_balance = new_balance.max(tx.value()); + } + + // Touch account so we know it is changed. + caller_account.mark_touch(); + caller_account.info.balance = new_balance; + + // NOTE: all changes to the caller account should journaled so in case of error + // we can revert the changes. + journal.caller_accounting_journal_entry(tx.caller(), old_balance, tx.kind().is_call()); + + Ok(()) + } + + fn last_frame_result( + &mut self, + evm: &mut Self::Evm, + frame_result: &mut <::Frame as FrameTr>::FrameResult, + ) -> Result<(), Self::Error> { + let ctx = evm.ctx(); + let tx = ctx.tx(); + let is_deposit = tx.tx_type() == DEPOSIT_TRANSACTION_TYPE; + let tx_gas_limit = tx.gas_limit(); + let is_regolith = ctx.cfg().spec().is_enabled_in(OpSpecId::REGOLITH); + + let instruction_result = frame_result.interpreter_result().result; + let gas = frame_result.gas_mut(); + let remaining = gas.remaining(); + let refunded = gas.refunded(); + + // Spend the gas limit. Gas is reimbursed when the tx returns successfully. + *gas = Gas::new_spent(tx_gas_limit); + + if instruction_result.is_ok() { + // On Optimism, deposit transactions report gas usage uniquely to other + // transactions due to them being pre-paid on L1. + // + // Hardfork Behavior: + // - Bedrock (success path): + // - Deposit transactions (non-system) report their gas limit as the usage. + // No refunds. + // - Deposit transactions (system) report 0 gas used. No refunds. + // - Regular transactions report gas usage as normal. + // - Regolith (success path): + // - Deposit transactions (all) report their gas used as normal. Refunds + // enabled. + // - Regular transactions report their gas used as normal. + if !is_deposit || is_regolith { + // For regular transactions prior to Regolith and all transactions after + // Regolith, gas is reported as normal. + gas.erase_cost(remaining); + gas.record_refund(refunded); + } else if is_deposit { + let tx = ctx.tx(); + if tx.is_system_transaction() { + // System transactions were a special type of deposit transaction in + // the Bedrock hardfork that did not incur any gas costs. + gas.erase_cost(tx_gas_limit); + } + } + } else if instruction_result.is_revert() { + // On Optimism, deposit transactions report gas usage uniquely to other + // transactions due to them being pre-paid on L1. + // + // Hardfork Behavior: + // - Bedrock (revert path): + // - Deposit transactions (all) report the gas limit as the amount of gas + // used on failure. No refunds. + // - Regular transactions receive a refund on remaining gas as normal. + // - Regolith (revert path): + // - Deposit transactions (all) report the actual gas used as the amount of + // gas used on failure. Refunds on remaining gas enabled. + // - Regular transactions receive a refund on remaining gas as normal. + if !is_deposit || is_regolith { + gas.erase_cost(remaining); + } + } + Ok(()) + } + + fn reimburse_caller( + &self, + evm: &mut Self::Evm, + frame_result: &mut <::Frame as FrameTr>::FrameResult, + ) -> Result<(), Self::Error> { + let mut additional_refund = U256::ZERO; + + if evm.ctx().tx().tx_type() != DEPOSIT_TRANSACTION_TYPE { + let spec = evm.ctx().cfg().spec(); + additional_refund = evm + .ctx() + .chain() + .operator_fee_refund(frame_result.gas(), spec); + } + + reimburse_caller(evm.ctx(), frame_result.gas(), additional_refund).map_err(From::from) + } + + fn refund( + &self, + evm: &mut Self::Evm, + frame_result: &mut <::Frame as FrameTr>::FrameResult, + eip7702_refund: i64, + ) { + frame_result.gas_mut().record_refund(eip7702_refund); + + let is_deposit = evm.ctx().tx().tx_type() == DEPOSIT_TRANSACTION_TYPE; + let is_regolith = evm.ctx().cfg().spec().is_enabled_in(OpSpecId::REGOLITH); + + // Prior to Regolith, deposit transactions did not receive gas refunds. + let is_gas_refund_disabled = is_deposit && !is_regolith; + if !is_gas_refund_disabled { + frame_result.gas_mut().set_final_refund( + evm.ctx() + .cfg() + .spec() + .into_eth_spec() + .is_enabled_in(SpecId::LONDON), + ); + } + } + + fn reward_beneficiary( + &self, + evm: &mut Self::Evm, + frame_result: &mut <::Frame as FrameTr>::FrameResult, + ) -> Result<(), Self::Error> { + let is_deposit = evm.ctx().tx().tx_type() == DEPOSIT_TRANSACTION_TYPE; + + // Transfer fee to coinbase/beneficiary. + if is_deposit { + return Ok(()); + } + + self.mainnet.reward_beneficiary(evm, frame_result)?; + let basefee = evm.ctx().block().basefee() as u128; + + // If the transaction is not a deposit transaction, fees are paid out + // to both the Base Fee Vault as well as the L1 Fee Vault. + let ctx = evm.ctx(); + let enveloped = ctx.tx().enveloped_tx().cloned(); + let spec = ctx.cfg().spec(); + let l1_block_info = ctx.chain_mut(); + + let Some(enveloped_tx) = &enveloped else { + return Err(ERROR::from_string( + "[OPTIMISM] Failed to load enveloped transaction.".into(), + )); + }; + + let l1_cost = l1_block_info.calculate_tx_l1_cost(enveloped_tx, spec); + let operator_fee_cost = if spec.is_enabled_in(OpSpecId::ISTHMUS) { + l1_block_info.operator_fee_charge(enveloped_tx, U256::from(frame_result.gas().used())) + } else { + U256::ZERO + }; + let base_fee_amount = U256::from(basefee.saturating_mul(frame_result.gas().used() as u128)); + + // Send fees to their respective recipients + for (recipient, amount) in [ + (L1_FEE_RECIPIENT, l1_cost), + (BASE_FEE_RECIPIENT, base_fee_amount), + (OPERATOR_FEE_RECIPIENT, operator_fee_cost), + ] { + ctx.journal_mut().balance_incr(recipient, amount)?; + } + + Ok(()) + } + + fn execution_result( + &mut self, + evm: &mut Self::Evm, + frame_result: <::Frame as FrameTr>::FrameResult, + ) -> Result, Self::Error> { + match core::mem::replace(evm.ctx().error(), Ok(())) { + Err(ContextError::Db(e)) => return Err(e.into()), + Err(ContextError::Custom(e)) => return Err(Self::Error::from_string(e)), + Ok(_) => (), + } + + let exec_result = + post_execution::output(evm.ctx(), frame_result).map_haltreason(OpHaltReason::Base); + + if exec_result.is_halt() { + // Post-regolith, if the transaction is a deposit transaction and it halts, + // we bubble up to the global return handler. The mint value will be persisted + // and the caller nonce will be incremented there. + let is_deposit = evm.ctx().tx().tx_type() == DEPOSIT_TRANSACTION_TYPE; + if is_deposit && evm.ctx().cfg().spec().is_enabled_in(OpSpecId::REGOLITH) { + return Err(ERROR::from(OpTransactionError::HaltedDepositPostRegolith)); + } + } + evm.ctx().journal_mut().commit_tx(); + evm.ctx().chain_mut().clear_tx_l1_cost(); + evm.ctx().local_mut().clear(); + evm.frame_stack().clear(); + + Ok(exec_result) + } + + fn catch_error( + &self, + evm: &mut Self::Evm, + error: Self::Error, + ) -> Result, Self::Error> { + let is_deposit = evm.ctx().tx().tx_type() == DEPOSIT_TRANSACTION_TYPE; + let output = if error.is_tx_error() && is_deposit { + let ctx = evm.ctx(); + let spec = ctx.cfg().spec(); + let tx = ctx.tx(); + let caller = tx.caller(); + let mint = tx.mint(); + let is_system_tx = tx.is_system_transaction(); + let gas_limit = tx.gas_limit(); + + // discard all changes of this transaction + evm.ctx().journal_mut().discard_tx(); + + // If the transaction is a deposit transaction and it failed + // for any reason, the caller nonce must be bumped, and the + // gas reported must be altered depending on the Hardfork. This is + // also returned as a special Halt variant so that consumers can more + // easily distinguish between a failed deposit and a failed + // normal transaction. + + // Increment sender nonce and account balance for the mint amount. Deposits + // always persist the mint amount, even if the transaction fails. + let acc: &mut revm::state::Account = evm.ctx().journal_mut().load_account(caller)?.data; + + let old_balance = acc.info.balance; + + // decrement transaction id as it was incremented when we discarded the tx. + acc.transaction_id -= acc.transaction_id; + acc.info.nonce = acc.info.nonce.saturating_add(1); + acc.info.balance = acc + .info + .balance + .saturating_add(U256::from(mint.unwrap_or_default())); + acc.mark_touch(); + + // add journal entry for accounts + evm.ctx() + .journal_mut() + .caller_accounting_journal_entry(caller, old_balance, true); + + // The gas used of a failed deposit post-regolith is the gas + // limit of the transaction. pre-regolith, it is the gas limit + // of the transaction for non system transactions and 0 for system + // transactions. + let gas_used = if spec.is_enabled_in(OpSpecId::REGOLITH) || !is_system_tx { + gas_limit + } else { + 0 + }; + // clear the journal + Ok(ExecutionResult::Halt { + reason: OpHaltReason::FailedDeposit, + gas_used, + }) + } else { + Err(error) + }; + // do the cleanup + evm.ctx().chain_mut().clear_tx_l1_cost(); + evm.ctx().local_mut().clear(); + evm.frame_stack().clear(); + + output + } +} + +impl InspectorHandler for OpHandler> +where + EVM: InspectorEvmTr< + Context: OpContextTr, + Frame = EthFrame, + Inspector: Inspector<<::Evm as EvmTr>::Context, EthInterpreter>, + >, + ERROR: EvmTrError + From + FromStringError + IsTxError, +{ + type IT = EthInterpreter; +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{ + api::default_ctx::OpContext, + constants::{ + BASE_FEE_SCALAR_OFFSET, ECOTONE_L1_BLOB_BASE_FEE_SLOT, ECOTONE_L1_FEE_SCALARS_SLOT, + L1_BASE_FEE_SLOT, L1_BLOCK_CONTRACT, OPERATOR_FEE_SCALARS_SLOT, + }, + DefaultOp, OpBuilder, OpTransaction, + }; + use alloy_primitives::uint; + use revm::{ + context::{BlockEnv, Context, TxEnv}, + context_interface::result::InvalidTransaction, + database::InMemoryDB, + database_interface::EmptyDB, + handler::EthFrame, + interpreter::{CallOutcome, InstructionResult, InterpreterResult}, + primitives::{bytes, Address, Bytes, B256}, + state::AccountInfo, + }; + use rstest::rstest; + use std::boxed::Box; + + /// Creates frame result. + fn call_last_frame_return( + ctx: OpContext, + instruction_result: InstructionResult, + gas: Gas, + ) -> Gas { + let mut evm = ctx.build_op(); + + let mut exec_result = FrameResult::Call(CallOutcome::new( + InterpreterResult { + result: instruction_result, + output: Bytes::new(), + gas, + }, + 0..0, + )); + + let mut handler = + OpHandler::<_, EVMError<_, OpTransactionError>, EthFrame>::new(); + + handler + .last_frame_result(&mut evm, &mut exec_result) + .unwrap(); + handler.refund(&mut evm, &mut exec_result, 0); + *exec_result.gas() + } + + #[test] + fn test_revert_gas() { + let ctx = Context::op() + .with_tx( + OpTransaction::builder() + .base(TxEnv::builder().gas_limit(100)) + .build_fill(), + ) + .modify_cfg_chained(|cfg| cfg.spec = OpSpecId::BEDROCK); + + let gas = call_last_frame_return(ctx, InstructionResult::Revert, Gas::new(90)); + assert_eq!(gas.remaining(), 90); + assert_eq!(gas.spent(), 10); + assert_eq!(gas.refunded(), 0); + } + + #[test] + fn test_consume_gas() { + let ctx = Context::op() + .with_tx( + OpTransaction::builder() + .base(TxEnv::builder().gas_limit(100)) + .build_fill(), + ) + .modify_cfg_chained(|cfg| cfg.spec = OpSpecId::REGOLITH); + + let gas = call_last_frame_return(ctx, InstructionResult::Stop, Gas::new(90)); + assert_eq!(gas.remaining(), 90); + assert_eq!(gas.spent(), 10); + assert_eq!(gas.refunded(), 0); + } + + #[test] + fn test_consume_gas_with_refund() { + let ctx = Context::op() + .with_tx( + OpTransaction::builder() + .base(TxEnv::builder().gas_limit(100)) + .source_hash(B256::from([1u8; 32])) + .build_fill(), + ) + .modify_cfg_chained(|cfg| cfg.spec = OpSpecId::REGOLITH); + + let mut ret_gas = Gas::new(90); + ret_gas.record_refund(20); + + let gas = call_last_frame_return(ctx.clone(), InstructionResult::Stop, ret_gas); + assert_eq!(gas.remaining(), 90); + assert_eq!(gas.spent(), 10); + assert_eq!(gas.refunded(), 2); // min(20, 10/5) + + let gas = call_last_frame_return(ctx, InstructionResult::Revert, ret_gas); + assert_eq!(gas.remaining(), 90); + assert_eq!(gas.spent(), 10); + assert_eq!(gas.refunded(), 0); + } + + #[test] + fn test_consume_gas_deposit_tx() { + let ctx = Context::op() + .with_tx( + OpTransaction::builder() + .base(TxEnv::builder().gas_limit(100)) + .source_hash(B256::from([1u8; 32])) + .build_fill(), + ) + .modify_cfg_chained(|cfg| cfg.spec = OpSpecId::BEDROCK); + let gas = call_last_frame_return(ctx, InstructionResult::Stop, Gas::new(90)); + assert_eq!(gas.remaining(), 0); + assert_eq!(gas.spent(), 100); + assert_eq!(gas.refunded(), 0); + } + + #[test] + fn test_consume_gas_sys_deposit_tx() { + let ctx = Context::op() + .with_tx( + OpTransaction::builder() + .base(TxEnv::builder().gas_limit(100)) + .source_hash(B256::from([1u8; 32])) + .is_system_transaction() + .build_fill(), + ) + .modify_cfg_chained(|cfg| cfg.spec = OpSpecId::BEDROCK); + let gas = call_last_frame_return(ctx, InstructionResult::Stop, Gas::new(90)); + assert_eq!(gas.remaining(), 100); + assert_eq!(gas.spent(), 0); + assert_eq!(gas.refunded(), 0); + } + + #[test] + fn test_commit_mint_value() { + let caller = Address::ZERO; + let mut db = InMemoryDB::default(); + db.insert_account_info( + caller, + AccountInfo { + balance: U256::from(1000), + ..Default::default() + }, + ); + + let mut ctx = Context::op() + .with_db(db) + .with_chain(L1BlockInfo { + l1_base_fee: U256::from(1_000), + l1_fee_overhead: Some(U256::from(1_000)), + l1_base_fee_scalar: U256::from(1_000), + ..Default::default() + }) + .modify_cfg_chained(|cfg| cfg.spec = OpSpecId::REGOLITH); + ctx.modify_tx(|tx| { + tx.deposit.source_hash = B256::from([1u8; 32]); + tx.deposit.mint = Some(10); + }); + + let mut evm = ctx.build_op(); + + let handler = + OpHandler::<_, EVMError<_, OpTransactionError>, EthFrame>::new(); + handler + .validate_against_state_and_deduct_caller(&mut evm) + .unwrap(); + + // Check the account balance is updated. + let account = evm.ctx().journal_mut().load_account(caller).unwrap(); + assert_eq!(account.info.balance, U256::from(1010)); + } + + #[test] + fn test_remove_l1_cost_non_deposit() { + let caller = Address::ZERO; + let mut db = InMemoryDB::default(); + db.insert_account_info( + caller, + AccountInfo { + balance: U256::from(1058), // Increased to cover L1 fees (1048) + base fees + ..Default::default() + }, + ); + let ctx = Context::op() + .with_db(db) + .with_chain(L1BlockInfo { + l1_base_fee: U256::from(1_000), + l1_fee_overhead: Some(U256::from(1_000)), + l1_base_fee_scalar: U256::from(1_000), + ..Default::default() + }) + .modify_cfg_chained(|cfg| cfg.spec = OpSpecId::REGOLITH) + .with_tx( + OpTransaction::builder() + .base(TxEnv::builder().gas_limit(100)) + .enveloped_tx(Some(bytes!("FACADE"))) + .source_hash(B256::ZERO) + .build() + .unwrap(), + ); + + let mut evm = ctx.build_op(); + + let handler = + OpHandler::<_, EVMError<_, OpTransactionError>, EthFrame>::new(); + handler + .validate_against_state_and_deduct_caller(&mut evm) + .unwrap(); + + // Check the account balance is updated. + let account = evm.ctx().journal_mut().load_account(caller).unwrap(); + assert_eq!(account.info.balance, U256::from(10)); // 1058 - 1048 = 10 + } + + #[test] + fn test_reload_l1_block_info_isthmus() { + const BLOCK_NUM: U256 = uint!(100_U256); + const L1_BASE_FEE: U256 = uint!(1_U256); + const L1_BLOB_BASE_FEE: U256 = uint!(2_U256); + const L1_BASE_FEE_SCALAR: u64 = 3; + const L1_BLOB_BASE_FEE_SCALAR: u64 = 4; + const L1_FEE_SCALARS: U256 = U256::from_limbs([ + 0, + (L1_BASE_FEE_SCALAR << (64 - BASE_FEE_SCALAR_OFFSET * 2)) | L1_BLOB_BASE_FEE_SCALAR, + 0, + 0, + ]); + const OPERATOR_FEE_SCALAR: u64 = 5; + const OPERATOR_FEE_CONST: u64 = 6; + const OPERATOR_FEE: U256 = + U256::from_limbs([OPERATOR_FEE_CONST, OPERATOR_FEE_SCALAR, 0, 0]); + + let mut db = InMemoryDB::default(); + let l1_block_contract = db.load_account(L1_BLOCK_CONTRACT).unwrap(); + l1_block_contract + .storage + .insert(L1_BASE_FEE_SLOT, L1_BASE_FEE); + l1_block_contract + .storage + .insert(ECOTONE_L1_BLOB_BASE_FEE_SLOT, L1_BLOB_BASE_FEE); + l1_block_contract + .storage + .insert(ECOTONE_L1_FEE_SCALARS_SLOT, L1_FEE_SCALARS); + l1_block_contract + .storage + .insert(OPERATOR_FEE_SCALARS_SLOT, OPERATOR_FEE); + db.insert_account_info( + Address::ZERO, + AccountInfo { + balance: U256::from(1000), + ..Default::default() + }, + ); + + let ctx = Context::op() + .with_db(db) + .with_chain(L1BlockInfo { + l2_block: BLOCK_NUM + U256::from(1), // ahead by one block + ..Default::default() + }) + .with_block(BlockEnv { + number: BLOCK_NUM, + ..Default::default() + }) + .modify_cfg_chained(|cfg| cfg.spec = OpSpecId::ISTHMUS); + + let mut evm = ctx.build_op(); + + assert_ne!(evm.ctx().chain().l2_block, BLOCK_NUM); + + let handler = + OpHandler::<_, EVMError<_, OpTransactionError>, EthFrame>::new(); + handler + .validate_against_state_and_deduct_caller(&mut evm) + .unwrap(); + + assert_eq!( + *evm.ctx().chain(), + L1BlockInfo { + l2_block: BLOCK_NUM, + l1_base_fee: L1_BASE_FEE, + l1_base_fee_scalar: U256::from(L1_BASE_FEE_SCALAR), + l1_blob_base_fee: Some(L1_BLOB_BASE_FEE), + l1_blob_base_fee_scalar: Some(U256::from(L1_BLOB_BASE_FEE_SCALAR)), + empty_ecotone_scalars: false, + l1_fee_overhead: None, + operator_fee_scalar: Some(U256::from(OPERATOR_FEE_SCALAR)), + operator_fee_constant: Some(U256::from(OPERATOR_FEE_CONST)), + tx_l1_cost: Some(U256::ZERO), + } + ); + } + + #[test] + fn test_remove_l1_cost() { + let caller = Address::ZERO; + let mut db = InMemoryDB::default(); + db.insert_account_info( + caller, + AccountInfo { + balance: U256::from(1049), + ..Default::default() + }, + ); + let ctx = Context::op() + .with_db(db) + .with_chain(L1BlockInfo { + l1_base_fee: U256::from(1_000), + l1_fee_overhead: Some(U256::from(1_000)), + l1_base_fee_scalar: U256::from(1_000), + ..Default::default() + }) + .modify_cfg_chained(|cfg| cfg.spec = OpSpecId::REGOLITH) + .with_tx( + OpTransaction::builder() + .base(TxEnv::builder().gas_limit(100)) + .source_hash(B256::ZERO) + .enveloped_tx(Some(bytes!("FACADE"))) + .build() + .unwrap(), + ); + + let mut evm = ctx.build_op(); + let handler = + OpHandler::<_, EVMError<_, OpTransactionError>, EthFrame>::new(); + + // l1block cost is 1048 fee. + handler + .validate_against_state_and_deduct_caller(&mut evm) + .unwrap(); + + // Check the account balance is updated. + let account = evm.ctx().journal_mut().load_account(caller).unwrap(); + assert_eq!(account.info.balance, U256::from(1)); + } + + #[test] + fn test_remove_operator_cost() { + let caller = Address::ZERO; + let mut db = InMemoryDB::default(); + db.insert_account_info( + caller, + AccountInfo { + balance: U256::from(151), + ..Default::default() + }, + ); + let ctx = Context::op() + .with_db(db) + .with_chain(L1BlockInfo { + operator_fee_scalar: Some(U256::from(10_000_000)), + operator_fee_constant: Some(U256::from(50)), + ..Default::default() + }) + .modify_cfg_chained(|cfg| cfg.spec = OpSpecId::ISTHMUS) + .with_tx( + OpTransaction::builder() + .base(TxEnv::builder().gas_limit(10)) + .enveloped_tx(Some(bytes!("FACADE"))) + .build_fill(), + ); + + let mut evm = ctx.build_op(); + let handler = + OpHandler::<_, EVMError<_, OpTransactionError>, EthFrame>::new(); + + // operator fee cost is operator_fee_scalar * gas_limit / 1e6 + operator_fee_constant + // 10_000_000 * 10 / 1_000_000 + 50 = 150 + handler + .validate_against_state_and_deduct_caller(&mut evm) + .unwrap(); + + // Check the account balance is updated. + let account = evm.ctx().journal_mut().load_account(caller).unwrap(); + assert_eq!(account.info.balance, U256::from(1)); + } + + #[test] + fn test_remove_l1_cost_lack_of_funds() { + let caller = Address::ZERO; + let mut db = InMemoryDB::default(); + db.insert_account_info( + caller, + AccountInfo { + balance: U256::from(48), + ..Default::default() + }, + ); + let ctx = Context::op() + .with_db(db) + .with_chain(L1BlockInfo { + l1_base_fee: U256::from(1_000), + l1_fee_overhead: Some(U256::from(1_000)), + l1_base_fee_scalar: U256::from(1_000), + ..Default::default() + }) + .modify_cfg_chained(|cfg| cfg.spec = OpSpecId::REGOLITH) + .modify_tx_chained(|tx| { + tx.enveloped_tx = Some(bytes!("FACADE")); + }); + + // l1block cost is 1048 fee. + let mut evm = ctx.build_op(); + let handler = + OpHandler::<_, EVMError<_, OpTransactionError>, EthFrame>::new(); + + // l1block cost is 1048 fee. + assert_eq!( + handler.validate_against_state_and_deduct_caller(&mut evm), + Err(EVMError::Transaction( + InvalidTransaction::LackOfFundForMaxFee { + fee: Box::new(U256::from(1048)), + balance: Box::new(U256::from(48)), + } + .into(), + )) + ); + } + + #[test] + fn test_validate_sys_tx() { + // mark the tx as a system transaction. + let ctx = Context::op() + .modify_tx_chained(|tx| { + tx.deposit.source_hash = B256::from([1u8; 32]); + tx.deposit.is_system_transaction = true; + }) + .modify_cfg_chained(|cfg| cfg.spec = OpSpecId::REGOLITH); + + let mut evm = ctx.build_op(); + let handler = + OpHandler::<_, EVMError<_, OpTransactionError>, EthFrame>::new(); + + assert_eq!( + handler.validate_env(&mut evm), + Err(EVMError::Transaction( + OpTransactionError::DepositSystemTxPostRegolith + )) + ); + + evm.ctx().modify_cfg(|cfg| cfg.spec = OpSpecId::BEDROCK); + + // Pre-regolith system transactions should be allowed. + assert!(handler.validate_env(&mut evm).is_ok()); + } + + #[test] + fn test_validate_deposit_tx() { + // Set source hash. + let ctx = Context::op() + .modify_tx_chained(|tx| { + tx.deposit.source_hash = B256::from([1u8; 32]); + }) + .modify_cfg_chained(|cfg| cfg.spec = OpSpecId::REGOLITH); + + let mut evm = ctx.build_op(); + let handler = + OpHandler::<_, EVMError<_, OpTransactionError>, EthFrame>::new(); + + assert!(handler.validate_env(&mut evm).is_ok()); + } + + #[test] + fn test_validate_tx_against_state_deposit_tx() { + // Set source hash. + let ctx = Context::op() + .modify_tx_chained(|tx| { + tx.deposit.source_hash = B256::from([1u8; 32]); + }) + .modify_cfg_chained(|cfg| cfg.spec = OpSpecId::REGOLITH); + + let mut evm = ctx.build_op(); + let handler = + OpHandler::<_, EVMError<_, OpTransactionError>, EthFrame>::new(); + + // Nonce and balance checks should be skipped for deposit transactions. + assert!(handler.validate_env(&mut evm).is_ok()); + } + + #[test] + fn test_halted_deposit_tx_post_regolith() { + let ctx = Context::op() + .modify_tx_chained(|tx| { + // Set up as deposit transaction by having a deposit with source_hash + tx.deposit.source_hash = B256::from([1u8; 32]); + }) + .modify_cfg_chained(|cfg| cfg.spec = OpSpecId::REGOLITH); + + let mut evm = ctx.build_op(); + let mut handler = + OpHandler::<_, EVMError<_, OpTransactionError>, EthFrame>::new(); + + assert_eq!( + handler.execution_result( + &mut evm, + FrameResult::Call(CallOutcome { + result: InterpreterResult { + result: InstructionResult::OutOfGas, + output: Default::default(), + gas: Default::default(), + }, + memory_offset: Default::default(), + }) + ), + Err(EVMError::Transaction( + OpTransactionError::HaltedDepositPostRegolith + )) + ) + } + + #[test] + fn test_tx_zero_value_touch_caller() { + let ctx = Context::op(); + + let mut evm = ctx.build_op(); + + assert!(!evm + .0 + .ctx + .journal_mut() + .load_account(Address::ZERO) + .unwrap() + .is_touched()); + + let handler = + OpHandler::<_, EVMError<_, OpTransactionError>, EthFrame>::new(); + + handler + .validate_against_state_and_deduct_caller(&mut evm) + .unwrap(); + + assert!(evm + .0 + .ctx + .journal_mut() + .load_account(Address::ZERO) + .unwrap() + .is_touched()); + } + + #[rstest] + #[case::deposit(true)] + #[case::dyn_fee(false)] + fn test_operator_fee_refund(#[case] is_deposit: bool) { + const SENDER: Address = Address::ZERO; + const GAS_PRICE: u128 = 0xFF; + const OP_FEE_MOCK_PARAM: u128 = 0xFFFF; + + let ctx = Context::op() + .with_tx( + OpTransaction::builder() + .base( + TxEnv::builder() + .gas_price(GAS_PRICE) + .gas_priority_fee(None) + .caller(SENDER), + ) + .enveloped_tx(if is_deposit { + None + } else { + Some(bytes!("FACADE")) + }) + .source_hash(if is_deposit { + B256::from([1u8; 32]) + } else { + B256::ZERO + }) + .build_fill(), + ) + .modify_cfg_chained(|cfg| cfg.spec = OpSpecId::ISTHMUS); + + let mut evm = ctx.build_op(); + let handler = + OpHandler::<_, EVMError<_, OpTransactionError>, EthFrame>::new(); + + // Set the operator fee scalar & constant to non-zero values in the L1 block info. + evm.ctx().chain.operator_fee_scalar = Some(U256::from(OP_FEE_MOCK_PARAM)); + evm.ctx().chain.operator_fee_constant = Some(U256::from(OP_FEE_MOCK_PARAM)); + + let mut gas = Gas::new(100); + gas.set_spent(10); + let mut exec_result = FrameResult::Call(CallOutcome::new( + InterpreterResult { + result: InstructionResult::Return, + output: Default::default(), + gas, + }, + 0..0, + )); + + // Reimburse the caller for the unspent portion of the fees. + handler + .reimburse_caller(&mut evm, &mut exec_result) + .unwrap(); + + // Compute the expected refund amount. If the transaction is a deposit, the operator fee refund never + // applies. If the transaction is not a deposit, the operator fee refund is added to the refund amount. + let mut expected_refund = + U256::from(GAS_PRICE * (gas.remaining() + gas.refunded() as u64) as u128); + let op_fee_refund = evm + .ctx() + .chain() + .operator_fee_refund(&gas, OpSpecId::ISTHMUS); + assert!(op_fee_refund > U256::ZERO); + + if !is_deposit { + expected_refund += op_fee_refund; + } + + // Check that the caller was reimbursed the correct amount of ETH. + let account = evm.ctx().journal_mut().load_account(SENDER).unwrap(); + assert_eq!(account.info.balance, expected_refund); + } +} diff --git a/crates/op-revm/src/l1block.rs b/crates/op-revm/src/l1block.rs new file mode 100644 index 0000000000..cc4ec83000 --- /dev/null +++ b/crates/op-revm/src/l1block.rs @@ -0,0 +1,592 @@ +//! Contains the `[L1BlockInfo]` type and its implementation. +use crate::{ + constants::{ + BASE_FEE_SCALAR_OFFSET, BLOB_BASE_FEE_SCALAR_OFFSET, ECOTONE_L1_BLOB_BASE_FEE_SLOT, + ECOTONE_L1_FEE_SCALARS_SLOT, EMPTY_SCALARS, L1_BASE_FEE_SLOT, L1_BLOCK_CONTRACT, + L1_OVERHEAD_SLOT, L1_SCALAR_SLOT, NON_ZERO_BYTE_COST, OPERATOR_FEE_CONSTANT_OFFSET, + OPERATOR_FEE_SCALARS_SLOT, OPERATOR_FEE_SCALAR_DECIMAL, OPERATOR_FEE_SCALAR_OFFSET, + }, + transaction::estimate_tx_compressed_size, + OpSpecId, +}; +use revm::{ + database_interface::Database, + interpreter::{ + gas::{get_tokens_in_calldata, NON_ZERO_BYTE_MULTIPLIER_ISTANBUL, STANDARD_TOKEN_COST}, + Gas, + }, + primitives::{hardfork::SpecId, U256}, +}; + +/// L1 block info +/// +/// We can extract L1 epoch data from each L2 block, by looking at the `setL1BlockValues` +/// transaction data. This data is then used to calculate the L1 cost of a transaction. +/// +/// Here is the format of the `setL1BlockValues` transaction data: +/// +/// setL1BlockValues(uint64 _number, uint64 _timestamp, uint256 _basefee, bytes32 _hash, +/// uint64 _sequenceNumber, bytes32 _batcherHash, uint256 _l1FeeOverhead, uint256 _l1FeeScalar) +/// +/// For now, we only care about the fields necessary for L1 cost calculation. +#[derive(Clone, Debug, Default, PartialEq, Eq)] +pub struct L1BlockInfo { + /// The L2 block number. If not same as the one in the context, + /// L1BlockInfo is not valid and will be reloaded from the database. + pub l2_block: U256, + /// The base fee of the L1 origin block. + pub l1_base_fee: U256, + /// The current L1 fee overhead. None if Ecotone is activated. + pub l1_fee_overhead: Option, + /// The current L1 fee scalar. + pub l1_base_fee_scalar: U256, + /// The current L1 blob base fee. None if Ecotone is not activated, except if `empty_ecotone_scalars` is `true`. + pub l1_blob_base_fee: Option, + /// The current L1 blob base fee scalar. None if Ecotone is not activated. + pub l1_blob_base_fee_scalar: Option, + /// The current L1 blob base fee. None if Isthmus is not activated, except if `empty_ecotone_scalars` is `true`. + pub operator_fee_scalar: Option, + /// The current L1 blob base fee scalar. None if Isthmus is not activated. + pub operator_fee_constant: Option, + /// True if Ecotone is activated, but the L1 fee scalars have not yet been set. + pub(crate) empty_ecotone_scalars: bool, + /// Last calculated l1 fee cost. Uses as a cache between validation and pre execution stages. + pub tx_l1_cost: Option, +} + +impl L1BlockInfo { + /// Try to fetch the L1 block info from the database. + pub fn try_fetch( + db: &mut DB, + l2_block: U256, + spec_id: OpSpecId, + ) -> Result { + // Ensure the L1 Block account is loaded into the cache after Ecotone. With EIP-4788, it is no longer the case + // that the L1 block account is loaded into the cache prior to the first inquiry for the L1 block info. + if spec_id.into_eth_spec().is_enabled_in(SpecId::CANCUN) { + let _ = db.basic(L1_BLOCK_CONTRACT)?; + } + + let l1_base_fee = db.storage(L1_BLOCK_CONTRACT, L1_BASE_FEE_SLOT)?; + + if !spec_id.is_enabled_in(OpSpecId::ECOTONE) { + let l1_fee_overhead = db.storage(L1_BLOCK_CONTRACT, L1_OVERHEAD_SLOT)?; + let l1_fee_scalar = db.storage(L1_BLOCK_CONTRACT, L1_SCALAR_SLOT)?; + + Ok(L1BlockInfo { + l1_base_fee, + l1_fee_overhead: Some(l1_fee_overhead), + l1_base_fee_scalar: l1_fee_scalar, + ..Default::default() + }) + } else { + let l1_blob_base_fee = db.storage(L1_BLOCK_CONTRACT, ECOTONE_L1_BLOB_BASE_FEE_SLOT)?; + let l1_fee_scalars = db + .storage(L1_BLOCK_CONTRACT, ECOTONE_L1_FEE_SCALARS_SLOT)? + .to_be_bytes::<32>(); + + let l1_base_fee_scalar = U256::from_be_slice( + l1_fee_scalars[BASE_FEE_SCALAR_OFFSET..BASE_FEE_SCALAR_OFFSET + 4].as_ref(), + ); + let l1_blob_base_fee_scalar = U256::from_be_slice( + l1_fee_scalars[BLOB_BASE_FEE_SCALAR_OFFSET..BLOB_BASE_FEE_SCALAR_OFFSET + 4] + .as_ref(), + ); + + // Check if the L1 fee scalars are empty. If so, we use the Bedrock cost function. + // The L1 fee overhead is only necessary if `empty_ecotone_scalars` is true, as it was deprecated in Ecotone. + let empty_ecotone_scalars = l1_blob_base_fee.is_zero() + && l1_fee_scalars[BASE_FEE_SCALAR_OFFSET..BLOB_BASE_FEE_SCALAR_OFFSET + 4] + == EMPTY_SCALARS; + let l1_fee_overhead = empty_ecotone_scalars + .then(|| db.storage(L1_BLOCK_CONTRACT, L1_OVERHEAD_SLOT)) + .transpose()?; + + if spec_id.is_enabled_in(OpSpecId::ISTHMUS) { + let operator_fee_scalars = db + .storage(L1_BLOCK_CONTRACT, OPERATOR_FEE_SCALARS_SLOT)? + .to_be_bytes::<32>(); + + // Post-isthmus L1 block info + // The `operator_fee_scalar` is stored as a big endian u32 at + // OPERATOR_FEE_SCALAR_OFFSET. + let operator_fee_scalar = U256::from_be_slice( + operator_fee_scalars + [OPERATOR_FEE_SCALAR_OFFSET..OPERATOR_FEE_SCALAR_OFFSET + 4] + .as_ref(), + ); + // The `operator_fee_constant` is stored as a big endian u64 at + // OPERATOR_FEE_CONSTANT_OFFSET. + let operator_fee_constant = U256::from_be_slice( + operator_fee_scalars + [OPERATOR_FEE_CONSTANT_OFFSET..OPERATOR_FEE_CONSTANT_OFFSET + 8] + .as_ref(), + ); + Ok(L1BlockInfo { + l2_block, + l1_base_fee, + l1_base_fee_scalar, + l1_blob_base_fee: Some(l1_blob_base_fee), + l1_blob_base_fee_scalar: Some(l1_blob_base_fee_scalar), + empty_ecotone_scalars, + l1_fee_overhead, + operator_fee_scalar: Some(operator_fee_scalar), + operator_fee_constant: Some(operator_fee_constant), + tx_l1_cost: None, + }) + } else { + // Pre-isthmus L1 block info + Ok(L1BlockInfo { + l1_base_fee, + l1_base_fee_scalar, + l1_blob_base_fee: Some(l1_blob_base_fee), + l1_blob_base_fee_scalar: Some(l1_blob_base_fee_scalar), + empty_ecotone_scalars, + l1_fee_overhead, + ..Default::default() + }) + } + } + } + + /// Calculate the operator fee for executing this transaction. + /// + /// Introduced in isthmus. Prior to isthmus, the operator fee is always zero. + pub fn operator_fee_charge(&self, input: &[u8], gas_limit: U256) -> U256 { + // If the input is a deposit transaction or empty, the default value is zero. + if input.first() == Some(&0x7E) { + return U256::ZERO; + } + + self.operator_fee_charge_inner(gas_limit) + } + + /// Calculate the operator fee for the given `gas`. + fn operator_fee_charge_inner(&self, gas: U256) -> U256 { + let operator_fee_scalar = self + .operator_fee_scalar + .expect("Missing operator fee scalar for isthmus L1 Block"); + let operator_fee_constant = self + .operator_fee_constant + .expect("Missing operator fee constant for isthmus L1 Block"); + + let product = + gas.saturating_mul(operator_fee_scalar) / (U256::from(OPERATOR_FEE_SCALAR_DECIMAL)); + + product.saturating_add(operator_fee_constant) + } + + /// Calculate the operator fee for executing this transaction. + /// + /// Introduced in isthmus. Prior to isthmus, the operator fee is always zero. + pub fn operator_fee_refund(&self, gas: &Gas, spec_id: OpSpecId) -> U256 { + if !spec_id.is_enabled_in(OpSpecId::ISTHMUS) { + return U256::ZERO; + } + + let operator_cost_gas_limit = self.operator_fee_charge_inner(U256::from(gas.limit())); + let operator_cost_gas_used = self.operator_fee_charge_inner(U256::from( + gas.limit() - (gas.remaining() + gas.refunded() as u64), + )); + + operator_cost_gas_limit.saturating_sub(operator_cost_gas_used) + } + + /// Calculate the data gas for posting the transaction on L1. Calldata costs 16 gas per byte + /// after compression. + /// + /// Prior to fjord, calldata costs 16 gas per non-zero byte and 4 gas per zero byte. + /// + /// Prior to regolith, an extra 68 non-zero bytes were included in the rollup data costs to + /// account for the empty signature. + pub fn data_gas(&self, input: &[u8], spec_id: OpSpecId) -> U256 { + if spec_id.is_enabled_in(OpSpecId::FJORD) { + let estimated_size = self.tx_estimated_size_fjord(input); + + return estimated_size + .saturating_mul(U256::from(NON_ZERO_BYTE_COST)) + .wrapping_div(U256::from(1_000_000)); + }; + + // tokens in calldata where non-zero bytes are priced 4 times higher than zero bytes (Same as in Istanbul). + let mut tokens_in_transaction_data = get_tokens_in_calldata(input, true); + + // Prior to regolith, an extra 68 non zero bytes were included in the rollup data costs. + if !spec_id.is_enabled_in(OpSpecId::REGOLITH) { + tokens_in_transaction_data += 68 * NON_ZERO_BYTE_MULTIPLIER_ISTANBUL; + } + + U256::from(tokens_in_transaction_data.saturating_mul(STANDARD_TOKEN_COST)) + } + + // Calculate the estimated compressed transaction size in bytes, scaled by 1e6. + // This value is computed based on the following formula: + // max(minTransactionSize, intercept + fastlzCoef*fastlzSize) + fn tx_estimated_size_fjord(&self, input: &[u8]) -> U256 { + U256::from(estimate_tx_compressed_size(input)) + } + + /// Clears the cached L1 cost of the transaction. + pub fn clear_tx_l1_cost(&mut self) { + self.tx_l1_cost = None; + } + + /// Calculate the gas cost of a transaction based on L1 block data posted on L2, depending on the [OpSpecId] passed. + pub fn calculate_tx_l1_cost(&mut self, input: &[u8], spec_id: OpSpecId) -> U256 { + if let Some(tx_l1_cost) = self.tx_l1_cost { + return tx_l1_cost; + } + // If the input is a deposit transaction or empty, the default value is zero. + let tx_l1_cost = if input.is_empty() || input.first() == Some(&0x7E) { + return U256::ZERO; + } else if spec_id.is_enabled_in(OpSpecId::FJORD) { + self.calculate_tx_l1_cost_fjord(input) + } else if spec_id.is_enabled_in(OpSpecId::ECOTONE) { + self.calculate_tx_l1_cost_ecotone(input, spec_id) + } else { + self.calculate_tx_l1_cost_bedrock(input, spec_id) + }; + + self.tx_l1_cost = Some(tx_l1_cost); + tx_l1_cost + } + + /// Calculate the gas cost of a transaction based on L1 block data posted on L2, pre-Ecotone. + fn calculate_tx_l1_cost_bedrock(&self, input: &[u8], spec_id: OpSpecId) -> U256 { + let rollup_data_gas_cost = self.data_gas(input, spec_id); + rollup_data_gas_cost + .saturating_add(self.l1_fee_overhead.unwrap_or_default()) + .saturating_mul(self.l1_base_fee) + .saturating_mul(self.l1_base_fee_scalar) + .wrapping_div(U256::from(1_000_000)) + } + + /// Calculate the gas cost of a transaction based on L1 block data posted on L2, post-Ecotone. + /// + /// [OpSpecId::ECOTONE] L1 cost function: + /// `(calldataGas/16)*(l1BaseFee*16*l1BaseFeeScalar + l1BlobBaseFee*l1BlobBaseFeeScalar)/1e6` + /// + /// We divide "calldataGas" by 16 to change from units of calldata gas to "estimated # of bytes when compressed". + /// Known as "compressedTxSize" in the spec. + /// + /// Function is actually computed as follows for better precision under integer arithmetic: + /// `calldataGas*(l1BaseFee*16*l1BaseFeeScalar + l1BlobBaseFee*l1BlobBaseFeeScalar)/16e6` + fn calculate_tx_l1_cost_ecotone(&self, input: &[u8], spec_id: OpSpecId) -> U256 { + // There is an edgecase where, for the very first Ecotone block (unless it is activated at Genesis), we must + // use the Bedrock cost function. To determine if this is the case, we can check if the Ecotone parameters are + // unset. + if self.empty_ecotone_scalars { + return self.calculate_tx_l1_cost_bedrock(input, spec_id); + } + + let rollup_data_gas_cost = self.data_gas(input, spec_id); + let l1_fee_scaled = self.calculate_l1_fee_scaled_ecotone(); + + l1_fee_scaled + .saturating_mul(rollup_data_gas_cost) + .wrapping_div(U256::from(1_000_000 * NON_ZERO_BYTE_COST)) + } + + /// Calculate the gas cost of a transaction based on L1 block data posted on L2, post-Fjord. + /// + /// [OpSpecId::FJORD] L1 cost function: + /// `estimatedSize*(baseFeeScalar*l1BaseFee*16 + blobFeeScalar*l1BlobBaseFee)/1e12` + fn calculate_tx_l1_cost_fjord(&self, input: &[u8]) -> U256 { + let l1_fee_scaled = self.calculate_l1_fee_scaled_ecotone(); + let estimated_size = self.tx_estimated_size_fjord(input); + + estimated_size + .saturating_mul(l1_fee_scaled) + .wrapping_div(U256::from(1_000_000_000_000u64)) + } + + // l1BaseFee*16*l1BaseFeeScalar + l1BlobBaseFee*l1BlobBaseFeeScalar + fn calculate_l1_fee_scaled_ecotone(&self) -> U256 { + let calldata_cost_per_byte = self + .l1_base_fee + .saturating_mul(U256::from(NON_ZERO_BYTE_COST)) + .saturating_mul(self.l1_base_fee_scalar); + let blob_cost_per_byte = self + .l1_blob_base_fee + .unwrap_or_default() + .saturating_mul(self.l1_blob_base_fee_scalar.unwrap_or_default()); + + calldata_cost_per_byte.saturating_add(blob_cost_per_byte) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use revm::primitives::{bytes, hex}; + + #[test] + fn test_data_gas_non_zero_bytes() { + let l1_block_info = L1BlockInfo { + l1_base_fee: U256::from(1_000_000), + l1_fee_overhead: Some(U256::from(1_000_000)), + l1_base_fee_scalar: U256::from(1_000_000), + ..Default::default() + }; + + // 0xFACADE = 6 nibbles = 3 bytes + // 0xFACADE = 1111 1010 . 1100 1010 . 1101 1110 + + // Pre-regolith (ie bedrock) has an extra 68 non-zero bytes + // gas cost = 3 non-zero bytes * NON_ZERO_BYTE_COST + NON_ZERO_BYTE_COST * 68 + // gas cost = 3 * 16 + 68 * 16 = 1136 + let input = bytes!("FACADE"); + let bedrock_data_gas = l1_block_info.data_gas(&input, OpSpecId::BEDROCK); + assert_eq!(bedrock_data_gas, U256::from(1136)); + + // Regolith has no added 68 non zero bytes + // gas cost = 3 * 16 = 48 + let regolith_data_gas = l1_block_info.data_gas(&input, OpSpecId::REGOLITH); + assert_eq!(regolith_data_gas, U256::from(48)); + + // Fjord has a minimum compressed size of 100 bytes + // gas cost = 100 * 16 = 1600 + let fjord_data_gas = l1_block_info.data_gas(&input, OpSpecId::FJORD); + assert_eq!(fjord_data_gas, U256::from(1600)); + } + + #[test] + fn test_data_gas_zero_bytes() { + let l1_block_info = L1BlockInfo { + l1_base_fee: U256::from(1_000_000), + l1_fee_overhead: Some(U256::from(1_000_000)), + l1_base_fee_scalar: U256::from(1_000_000), + ..Default::default() + }; + + // 0xFA00CA00DE = 10 nibbles = 5 bytes + // 0xFA00CA00DE = 1111 1010 . 0000 0000 . 1100 1010 . 0000 0000 . 1101 1110 + + // Pre-regolith (ie bedrock) has an extra 68 non-zero bytes + // gas cost = 3 non-zero * NON_ZERO_BYTE_COST + 2 * ZERO_BYTE_COST + NON_ZERO_BYTE_COST * 68 + // gas cost = 3 * 16 + 2 * 4 + 68 * 16 = 1144 + let input = bytes!("FA00CA00DE"); + let bedrock_data_gas = l1_block_info.data_gas(&input, OpSpecId::BEDROCK); + assert_eq!(bedrock_data_gas, U256::from(1144)); + + // Regolith has no added 68 non zero bytes + // gas cost = 3 * 16 + 2 * 4 = 56 + let regolith_data_gas = l1_block_info.data_gas(&input, OpSpecId::REGOLITH); + assert_eq!(regolith_data_gas, U256::from(56)); + + // Fjord has a minimum compressed size of 100 bytes + // gas cost = 100 * 16 = 1600 + let fjord_data_gas = l1_block_info.data_gas(&input, OpSpecId::FJORD); + assert_eq!(fjord_data_gas, U256::from(1600)); + } + + #[test] + fn test_calculate_tx_l1_cost() { + let mut l1_block_info = L1BlockInfo { + l1_base_fee: U256::from(1_000), + l1_fee_overhead: Some(U256::from(1_000)), + l1_base_fee_scalar: U256::from(1_000), + ..Default::default() + }; + + let input = bytes!("FACADE"); + let gas_cost = l1_block_info.calculate_tx_l1_cost(&input, OpSpecId::REGOLITH); + assert_eq!(gas_cost, U256::from(1048)); + l1_block_info.clear_tx_l1_cost(); + + // Zero rollup data gas cost should result in zero + let input = bytes!(""); + let gas_cost = l1_block_info.calculate_tx_l1_cost(&input, OpSpecId::REGOLITH); + assert_eq!(gas_cost, U256::ZERO); + l1_block_info.clear_tx_l1_cost(); + + // Deposit transactions with the EIP-2718 type of 0x7E should result in zero + let input = bytes!("7EFACADE"); + let gas_cost = l1_block_info.calculate_tx_l1_cost(&input, OpSpecId::REGOLITH); + assert_eq!(gas_cost, U256::ZERO); + } + + #[test] + fn test_calculate_tx_l1_cost_ecotone() { + let mut l1_block_info = L1BlockInfo { + l1_base_fee: U256::from(1_000), + l1_base_fee_scalar: U256::from(1_000), + l1_blob_base_fee: Some(U256::from(1_000)), + l1_blob_base_fee_scalar: Some(U256::from(1_000)), + l1_fee_overhead: Some(U256::from(1_000)), + ..Default::default() + }; + + // calldataGas * (l1BaseFee * 16 * l1BaseFeeScalar + l1BlobBaseFee * l1BlobBaseFeeScalar) / (16 * 1e6) + // = (16 * 3) * (1000 * 16 * 1000 + 1000 * 1000) / (16 * 1e6) + // = 51 + let input = bytes!("FACADE"); + let gas_cost = l1_block_info.calculate_tx_l1_cost(&input, OpSpecId::ECOTONE); + assert_eq!(gas_cost, U256::from(51)); + l1_block_info.clear_tx_l1_cost(); + + // Zero rollup data gas cost should result in zero + let input = bytes!(""); + let gas_cost = l1_block_info.calculate_tx_l1_cost(&input, OpSpecId::ECOTONE); + assert_eq!(gas_cost, U256::ZERO); + l1_block_info.clear_tx_l1_cost(); + + // Deposit transactions with the EIP-2718 type of 0x7E should result in zero + let input = bytes!("7EFACADE"); + let gas_cost = l1_block_info.calculate_tx_l1_cost(&input, OpSpecId::ECOTONE); + assert_eq!(gas_cost, U256::ZERO); + l1_block_info.clear_tx_l1_cost(); + + // If the scalars are empty, the bedrock cost function should be used. + l1_block_info.empty_ecotone_scalars = true; + let input = bytes!("FACADE"); + let gas_cost = l1_block_info.calculate_tx_l1_cost(&input, OpSpecId::ECOTONE); + assert_eq!(gas_cost, U256::from(1048)); + } + + #[test] + fn calculate_tx_l1_cost_ecotone() { + // rig + + // l1 block info for OP mainnet ecotone block 118024092 + // 1710374401 (ecotone timestamp) + // 1711603765 (block 118024092 timestamp) + // 1720627201 (fjord timestamp) + // + // decoded from + let l1_block_info = L1BlockInfo { + l1_base_fee: U256::from_be_bytes(hex!( + "0000000000000000000000000000000000000000000000000000000af39ac327" + )), // 47036678951 + l1_base_fee_scalar: U256::from(1368), + l1_blob_base_fee: Some(U256::from_be_bytes(hex!( + "0000000000000000000000000000000000000000000000000000000d5ea528d2" + ))), // 57422457042 + l1_blob_base_fee_scalar: Some(U256::from(810949)), + ..Default::default() + }; + + // second tx in OP mainnet ecotone block 118024092 + // + const TX: &[u8] = &hex!("02f8b30a832253fc8402d11f39842c8a46398301388094dc6ff44d5d932cbd77b52e5612ba0529dc6226f180b844a9059cbb000000000000000000000000d43e02db81f4d46cdf8521f623d21ea0ec7562a50000000000000000000000000000000000000000000000008ac7230489e80000c001a02947e24750723b48f886931562c55d9e07f856d8e06468e719755e18bbc3a570a0784da9ce59fd7754ea5be6e17a86b348e441348cd48ace59d174772465eadbd1"); + + // l1 gas used for tx and l1 fee for tx, from OP mainnet block scanner + // + let expected_l1_gas_used = U256::from(2456); + let expected_l1_fee = U256::from_be_bytes(hex!( + "000000000000000000000000000000000000000000000000000006a510bd7431" // 7306020222001 wei + )); + + // test + + let gas_used = l1_block_info.data_gas(TX, OpSpecId::ECOTONE); + + assert_eq!(gas_used, expected_l1_gas_used); + + let l1_fee = l1_block_info.calculate_tx_l1_cost_ecotone(TX, OpSpecId::ECOTONE); + + assert_eq!(l1_fee, expected_l1_fee) + } + + #[test] + fn test_calculate_tx_l1_cost_fjord() { + // l1FeeScaled = baseFeeScalar*l1BaseFee*16 + blobFeeScalar*l1BlobBaseFee + // = 1000 * 1000 * 16 + 1000 * 1000 + // = 17e6 + let mut l1_block_info = L1BlockInfo { + l1_base_fee: U256::from(1_000), + l1_base_fee_scalar: U256::from(1_000), + l1_blob_base_fee: Some(U256::from(1_000)), + l1_blob_base_fee_scalar: Some(U256::from(1_000)), + ..Default::default() + }; + + // fastLzSize = 4 + // estimatedSize = max(minTransactionSize, intercept + fastlzCoef*fastlzSize) + // = max(100e6, 836500*4 - 42585600) + // = 100e6 + let input = bytes!("FACADE"); + // l1Cost = estimatedSize * l1FeeScaled / 1e12 + // = 100e6 * 17 / 1e6 + // = 1700 + let gas_cost = l1_block_info.calculate_tx_l1_cost(&input, OpSpecId::FJORD); + assert_eq!(gas_cost, U256::from(1700)); + l1_block_info.clear_tx_l1_cost(); + + // fastLzSize = 202 + // estimatedSize = max(minTransactionSize, intercept + fastlzCoef*fastlzSize) + // = max(100e6, 836500*202 - 42585600) + // = 126387400 + let input = bytes!("02f901550a758302df1483be21b88304743f94f80e51afb613d764fa61751affd3313c190a86bb870151bd62fd12adb8e41ef24f3f000000000000000000000000000000000000000000000000000000000000006e000000000000000000000000af88d065e77c8cc2239327c5edb3a432268e5831000000000000000000000000000000000000000000000000000000000003c1e5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000148c89ed219d02f1a5be012c689b4f5b731827bebe000000000000000000000000c001a033fd89cb37c31b2cba46b6466e040c61fc9b2a3675a7f5f493ebd5ad77c497f8a07cdf65680e238392693019b4092f610222e71b7cec06449cb922b93b6a12744e"); + // l1Cost = estimatedSize * l1FeeScaled / 1e12 + // = 126387400 * 17 / 1e6 + // = 2148 + let gas_cost = l1_block_info.calculate_tx_l1_cost(&input, OpSpecId::FJORD); + assert_eq!(gas_cost, U256::from(2148)); + l1_block_info.clear_tx_l1_cost(); + + // Zero rollup data gas cost should result in zero + let input = bytes!(""); + let gas_cost = l1_block_info.calculate_tx_l1_cost(&input, OpSpecId::FJORD); + assert_eq!(gas_cost, U256::ZERO); + l1_block_info.clear_tx_l1_cost(); + + // Deposit transactions with the EIP-2718 type of 0x7E should result in zero + let input = bytes!("7EFACADE"); + let gas_cost = l1_block_info.calculate_tx_l1_cost(&input, OpSpecId::FJORD); + assert_eq!(gas_cost, U256::ZERO); + } + + #[test] + fn calculate_tx_l1_cost_fjord() { + // rig + + // L1 block info for OP mainnet fjord block 124665056 + // + let l1_block_info = L1BlockInfo { + l1_base_fee: U256::from(1055991687), + l1_base_fee_scalar: U256::from(5227), + l1_blob_base_fee_scalar: Some(U256::from(1014213)), + l1_blob_base_fee: Some(U256::from(1)), + ..Default::default() // L1 fee overhead (l1 gas used) deprecated since Fjord + }; + + // Second tx in OP mainnet Fjord block 124665056 + // + const TX: &[u8] = &hex!("02f904940a8303fba78401d6d2798401db2b6d830493e0943e6f4f7866654c18f536170780344aa8772950b680b904246a761202000000000000000000000000087000a300de7200382b55d40045000000e5d60e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003a0000000000000000000000000000000000000000000000000000000000000022482ad56cb0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000dc6ff44d5d932cbd77b52e5612ba0529dc6226f1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044095ea7b300000000000000000000000021c4928109acb0659a88ae5329b5374a3024694c0000000000000000000000000000000000000000000000049b9ca9a6943400000000000000000000000000000000000000000000000000000000000000000000000000000000000021c4928109acb0659a88ae5329b5374a3024694c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000024b6b55f250000000000000000000000000000000000000000000000049b9ca9a694340000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000415ec214a3950bea839a7e6fbb0ba1540ac2076acd50820e2d5ef83d0902cdffb24a47aff7de5190290769c4f0a9c6fabf63012986a0d590b1b571547a8c7050ea1b00000000000000000000000000000000000000000000000000000000000000c080a06db770e6e25a617fe9652f0958bd9bd6e49281a53036906386ed39ec48eadf63a07f47cf51a4a40b4494cf26efc686709a9b03939e20ee27e59682f5faa536667e"); + + // L1 gas used for tx and L1 fee for tx, from OP mainnet block scanner + // https://optimistic.etherscan.io/tx/0x1059e8004daff32caa1f1b1ef97fe3a07a8cf40508f5b835b66d9420d87c4a4a + let expected_data_gas = U256::from(4471); + let expected_l1_fee = U256::from_be_bytes(hex!( + "00000000000000000000000000000000000000000000000000000005bf1ab43d" + )); + + // test + + let data_gas = l1_block_info.data_gas(TX, OpSpecId::FJORD); + + assert_eq!(data_gas, expected_data_gas); + + let l1_fee = l1_block_info.calculate_tx_l1_cost_fjord(TX); + + assert_eq!(l1_fee, expected_l1_fee) + } + + #[test] + fn test_operator_fee_refund() { + let gas = Gas::new(50000); + + let l1_block_info = L1BlockInfo { + l1_base_fee: U256::from(1055991687), + l1_base_fee_scalar: U256::from(5227), + operator_fee_scalar: Some(U256::from(2000)), + operator_fee_constant: Some(U256::from(5)), + ..Default::default() + }; + + let refunded = l1_block_info.operator_fee_refund(&gas, OpSpecId::ISTHMUS); + + assert_eq!(refunded, U256::from(100)) + } +} diff --git a/crates/op-revm/src/lib.rs b/crates/op-revm/src/lib.rs new file mode 100644 index 0000000000..485d5adc17 --- /dev/null +++ b/crates/op-revm/src/lib.rs @@ -0,0 +1,27 @@ +//! Optimism-specific constants, types, and helpers. +#![cfg_attr(not(test), warn(unused_crate_dependencies))] +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(not(feature = "std"))] +extern crate alloc as std; + +pub mod api; +pub mod constants; +pub mod evm; +pub mod fast_lz; +pub mod handler; +pub mod l1block; +pub mod precompiles; +pub mod result; +pub mod spec; +pub mod transaction; + +pub use api::{ + builder::OpBuilder, + default_ctx::{DefaultOp, OpContext}, +}; +pub use evm::OpEvm; +pub use l1block::L1BlockInfo; +pub use result::OpHaltReason; +pub use spec::*; +pub use transaction::{error::OpTransactionError, estimate_tx_compressed_size, OpTransaction}; diff --git a/crates/op-revm/src/precompiles.rs b/crates/op-revm/src/precompiles.rs new file mode 100644 index 0000000000..d29e566765 --- /dev/null +++ b/crates/op-revm/src/precompiles.rs @@ -0,0 +1,351 @@ +//! Contains Optimism specific precompiles. +use crate::OpSpecId; +use once_cell::race::OnceBox; +use revm::{ + context::Cfg, + context_interface::ContextTr, + handler::{EthPrecompiles, PrecompileProvider}, + interpreter::{InputsImpl, InterpreterResult}, + precompile::{ + self, bn128, secp256r1, PrecompileError, PrecompileResult, PrecompileWithAddress, + Precompiles, + }, + primitives::{hardfork::SpecId, Address}, +}; +use std::boxed::Box; +use std::string::String; + +/// Optimism precompile provider +#[derive(Debug, Clone)] +pub struct OpPrecompiles { + /// Inner precompile provider is same as Ethereums. + inner: EthPrecompiles, + /// Spec id of the precompile provider. + spec: OpSpecId, +} + +impl OpPrecompiles { + /// Create a new precompile provider with the given OpSpec. + #[inline] + pub fn new_with_spec(spec: OpSpecId) -> Self { + let precompiles = match spec { + spec @ (OpSpecId::BEDROCK + | OpSpecId::REGOLITH + | OpSpecId::CANYON + | OpSpecId::ECOTONE) => Precompiles::new(spec.into_eth_spec().into()), + OpSpecId::FJORD => fjord(), + OpSpecId::GRANITE | OpSpecId::HOLOCENE => granite(), + OpSpecId::ISTHMUS | OpSpecId::INTEROP | OpSpecId::OSAKA => isthmus(), + }; + + Self { + inner: EthPrecompiles { + precompiles, + spec: SpecId::default(), + }, + spec, + } + } + + /// Precompiles getter. + #[inline] + pub fn precompiles(&self) -> &'static Precompiles { + self.inner.precompiles + } +} + +/// Returns precompiles for Fjord spec. +pub fn fjord() -> &'static Precompiles { + static INSTANCE: OnceBox = OnceBox::new(); + INSTANCE.get_or_init(|| { + let mut precompiles = Precompiles::cancun().clone(); + // RIP-7212: secp256r1 P256verify + precompiles.extend([secp256r1::P256VERIFY]); + Box::new(precompiles) + }) +} + +/// Returns precompiles for Granite spec. +pub fn granite() -> &'static Precompiles { + static INSTANCE: OnceBox = OnceBox::new(); + INSTANCE.get_or_init(|| { + let mut precompiles = fjord().clone(); + // Restrict bn256Pairing input size + precompiles.extend([bn128_pair::GRANITE]); + Box::new(precompiles) + }) +} + +/// Returns precompiles for isthumus spec. +pub fn isthmus() -> &'static Precompiles { + static INSTANCE: OnceBox = OnceBox::new(); + INSTANCE.get_or_init(|| { + let mut precompiles = granite().clone(); + // Prague bls12 precompiles + precompiles.extend(precompile::bls12_381::precompiles()); + // Isthmus bls12 precompile modifications + precompiles.extend([ + bls12_381::ISTHMUS_G1_MSM, + bls12_381::ISTHMUS_G2_MSM, + bls12_381::ISTHMUS_PAIRING, + ]); + Box::new(precompiles) + }) +} + +impl PrecompileProvider for OpPrecompiles +where + CTX: ContextTr>, +{ + type Output = InterpreterResult; + + #[inline] + fn set_spec(&mut self, spec: ::Spec) -> bool { + if spec == self.spec { + return false; + } + *self = Self::new_with_spec(spec); + true + } + + #[inline] + fn run( + &mut self, + context: &mut CTX, + address: &Address, + inputs: &InputsImpl, + is_static: bool, + gas_limit: u64, + ) -> Result, String> { + self.inner + .run(context, address, inputs, is_static, gas_limit) + } + + #[inline] + fn warm_addresses(&self) -> Box> { + self.inner.warm_addresses() + } + + #[inline] + fn contains(&self, address: &Address) -> bool { + self.inner.contains(address) + } +} + +impl Default for OpPrecompiles { + fn default() -> Self { + Self::new_with_spec(OpSpecId::ISTHMUS) + } +} + +/// Bn128 pair precompile. +pub mod bn128_pair { + use super::*; + + /// Max input size for the bn128 pair precompile. + pub const GRANITE_MAX_INPUT_SIZE: usize = 112687; + /// Bn128 pair precompile. + pub const GRANITE: PrecompileWithAddress = + PrecompileWithAddress(bn128::pair::ADDRESS, |input, gas_limit| { + run_pair(input, gas_limit) + }); + + /// Run the bn128 pair precompile with Optimism input limit. + pub fn run_pair(input: &[u8], gas_limit: u64) -> PrecompileResult { + if input.len() > GRANITE_MAX_INPUT_SIZE { + return Err(PrecompileError::Bn128PairLength); + } + bn128::run_pair( + input, + bn128::pair::ISTANBUL_PAIR_PER_POINT, + bn128::pair::ISTANBUL_PAIR_BASE, + gas_limit, + ) + } +} + +/// Bls12_381 precompile. +pub mod bls12_381 { + use super::*; + use revm::precompile::bls12_381_const::{G1_MSM_ADDRESS, G2_MSM_ADDRESS, PAIRING_ADDRESS}; + + #[cfg(not(feature = "std"))] + use crate::std::string::ToString; + + /// Max input size for the g1 msm precompile. + pub const ISTHMUS_G1_MSM_MAX_INPUT_SIZE: usize = 513760; + /// Max input size for the g2 msm precompile. + pub const ISTHMUS_G2_MSM_MAX_INPUT_SIZE: usize = 488448; + /// Max input size for the pairing precompile. + pub const ISTHMUS_PAIRING_MAX_INPUT_SIZE: usize = 235008; + + /// G1 msm precompile. + pub const ISTHMUS_G1_MSM: PrecompileWithAddress = + PrecompileWithAddress(G1_MSM_ADDRESS, run_g1_msm); + /// G2 msm precompile. + pub const ISTHMUS_G2_MSM: PrecompileWithAddress = + PrecompileWithAddress(G2_MSM_ADDRESS, run_g2_msm); + /// Pairing precompile. + pub const ISTHMUS_PAIRING: PrecompileWithAddress = + PrecompileWithAddress(PAIRING_ADDRESS, run_pair); + + /// Run the g1 msm precompile with Optimism input limit. + pub fn run_g1_msm(input: &[u8], gas_limit: u64) -> PrecompileResult { + if input.len() > ISTHMUS_G1_MSM_MAX_INPUT_SIZE { + return Err(PrecompileError::Other( + "G1MSM input length too long for OP Stack input size limitation".to_string(), + )); + } + precompile::bls12_381::g1_msm::g1_msm(input, gas_limit) + } + + /// Run the g2 msm precompile with Optimism input limit. + pub fn run_g2_msm(input: &[u8], gas_limit: u64) -> PrecompileResult { + if input.len() > ISTHMUS_G2_MSM_MAX_INPUT_SIZE { + return Err(PrecompileError::Other( + "G2MSM input length too long for OP Stack input size limitation".to_string(), + )); + } + precompile::bls12_381::g2_msm::g2_msm(input, gas_limit) + } + + /// Run the pairing precompile with Optimism input limit. + pub fn run_pair(input: &[u8], gas_limit: u64) -> PrecompileResult { + if input.len() > ISTHMUS_PAIRING_MAX_INPUT_SIZE { + return Err(PrecompileError::Other( + "Pairing input length too long for OP Stack input size limitation".to_string(), + )); + } + precompile::bls12_381::pairing::pairing(input, gas_limit) + } +} + +#[cfg(test)] +mod tests { + use crate::precompiles::bls12_381::{ + run_g1_msm, run_g2_msm, ISTHMUS_G1_MSM_MAX_INPUT_SIZE, ISTHMUS_G2_MSM_MAX_INPUT_SIZE, + ISTHMUS_PAIRING_MAX_INPUT_SIZE, + }; + + use super::*; + use revm::{ + precompile::PrecompileError, + primitives::{hex, Bytes}, + }; + use std::vec; + + #[test] + fn test_bn128_pair() { + let input = hex::decode( + "\ + 1c76476f4def4bb94541d57ebba1193381ffa7aa76ada664dd31c16024c43f59\ + 3034dd2920f673e204fee2811c678745fc819b55d3e9d294e45c9b03a76aef41\ + 209dd15ebff5d46c4bd888e51a93cf99a7329636c63514396b4a452003a35bf7\ + 04bf11ca01483bfa8b34b43561848d28905960114c8ac04049af4b6315a41678\ + 2bb8324af6cfc93537a2ad1a445cfd0ca2a71acd7ac41fadbf933c2a51be344d\ + 120a2a4cf30c1bf9845f20c6fe39e07ea2cce61f0c9bb048165fe5e4de877550\ + 111e129f1cf1097710d41c4ac70fcdfa5ba2023c6ff1cbeac322de49d1b6df7c\ + 2032c61a830e3c17286de9462bf242fca2883585b93870a73853face6a6bf411\ + 198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2\ + 1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed\ + 090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b\ + 12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", + ) + .unwrap(); + let expected = + hex::decode("0000000000000000000000000000000000000000000000000000000000000001") + .unwrap(); + let outcome = bn128_pair::run_pair(&input, 260_000).unwrap(); + assert_eq!(outcome.bytes, expected); + + // Invalid input length + let input = hex::decode( + "\ + 1111111111111111111111111111111111111111111111111111111111111111\ + 1111111111111111111111111111111111111111111111111111111111111111\ + 111111111111111111111111111111\ + ", + ) + .unwrap(); + + let res = bn128_pair::run_pair(&input, 260_000); + assert!(matches!(res, Err(PrecompileError::Bn128PairLength))); + + // Valid input length shorter than 112687 + let input = vec![1u8; 586 * bn128::PAIR_ELEMENT_LEN]; + let res = bn128_pair::run_pair(&input, 260_000); + assert!(matches!(res, Err(PrecompileError::OutOfGas))); + + // Input length longer than 112687 + let input = vec![1u8; 587 * bn128::PAIR_ELEMENT_LEN]; + let res = bn128_pair::run_pair(&input, 260_000); + assert!(matches!(res, Err(PrecompileError::Bn128PairLength))); + } + + #[test] + fn test_cancun_precompiles_in_fjord() { + // additional to cancun, fjord has p256verify + assert_eq!(fjord().difference(Precompiles::cancun()).len(), 1) + } + + #[test] + fn test_cancun_precompiles_in_granite() { + // granite has p256verify (fjord) + // granite has modification of cancun's bn128 pair (doesn't count as new precompile) + assert_eq!(granite().difference(Precompiles::cancun()).len(), 1) + } + + #[test] + fn test_prague_precompiles_in_isthmus() { + let new_prague_precompiles = Precompiles::prague().difference(Precompiles::cancun()); + + // isthmus contains all precompiles that were new in prague, without modifications + assert!(new_prague_precompiles.difference(isthmus()).is_empty()) + } + + #[test] + fn test_default_precompiles_is_latest() { + let latest = OpPrecompiles::new_with_spec(OpSpecId::default()) + .inner + .precompiles; + let default = OpPrecompiles::default().inner.precompiles; + assert_eq!(latest.len(), default.len()); + + let intersection = default.intersection(latest); + assert_eq!(intersection.len(), latest.len()) + } + + #[test] + fn test_g1_isthmus_max_size() { + let oversized_input = vec![0u8; ISTHMUS_G1_MSM_MAX_INPUT_SIZE + 1]; + let input = Bytes::from(oversized_input); + + let res = run_g1_msm(&input, 260_000); + + assert!( + matches!(res, Err(PrecompileError::Other(msg)) if msg.contains("input length too long")) + ); + } + #[test] + fn test_g2_isthmus_max_size() { + let oversized_input = vec![0u8; ISTHMUS_G2_MSM_MAX_INPUT_SIZE + 1]; + let input = Bytes::from(oversized_input); + + let res = run_g2_msm(&input, 260_000); + + assert!( + matches!(res, Err(PrecompileError::Other(msg)) if msg.contains("input length too long")) + ); + } + #[test] + fn test_pair_isthmus_max_size() { + let oversized_input = vec![0u8; ISTHMUS_PAIRING_MAX_INPUT_SIZE + 1]; + let input = Bytes::from(oversized_input); + + let res = bls12_381::run_pair(&input, 260_000); + + assert!( + matches!(res, Err(PrecompileError::Other(msg)) if msg.contains("input length too long")) + ); + } +} diff --git a/crates/op-revm/src/result.rs b/crates/op-revm/src/result.rs new file mode 100644 index 0000000000..1607bc6e8f --- /dev/null +++ b/crates/op-revm/src/result.rs @@ -0,0 +1,46 @@ +//! Contains the `[OpHaltReason]` type. +use revm::context_interface::result::HaltReason; + +/// Optimism halt reason. +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub enum OpHaltReason { + /// Base halt reason. + Base(HaltReason), + /// Failed deposit halt reason. + FailedDeposit, +} + +impl From for OpHaltReason { + fn from(value: HaltReason) -> Self { + Self::Base(value) + } +} + +impl TryFrom for HaltReason { + type Error = OpHaltReason; + + fn try_from(value: OpHaltReason) -> Result { + match value { + OpHaltReason::Base(reason) => Ok(reason), + OpHaltReason::FailedDeposit => Err(value), + } + } +} + +#[cfg(all(test, feature = "serde"))] +mod tests { + use super::*; + use revm::context_interface::result::OutOfGasError; + + #[test] + fn test_serialize_json_op_halt_reason() { + let response = r#"{"Base":{"OutOfGas":"Basic"}}"#; + + let op_halt_reason: OpHaltReason = serde_json::from_str(response).unwrap(); + assert_eq!( + op_halt_reason, + HaltReason::OutOfGas(OutOfGasError::Basic).into() + ); + } +} diff --git a/crates/op-revm/src/spec.rs b/crates/op-revm/src/spec.rs new file mode 100644 index 0000000000..c0e764c598 --- /dev/null +++ b/crates/op-revm/src/spec.rs @@ -0,0 +1,224 @@ +//! Contains the `[OpSpecId]` type and its implementation. +use core::str::FromStr; +use revm::primitives::hardfork::{name as eth_name, SpecId, UnknownHardfork}; + +/// Optimism spec id. +#[repr(u8)] +#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Default)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[allow(non_camel_case_types)] +pub enum OpSpecId { + /// Bedrock spec id. + BEDROCK = 100, + /// Regolith spec id. + REGOLITH, + /// Canyon spec id. + CANYON, + /// Ecotone spec id. + ECOTONE, + /// Fjord spec id. + FJORD, + /// Granite spec id. + GRANITE, + /// Holocene spec id. + HOLOCENE, + /// Isthmus spec id. + #[default] + ISTHMUS, + /// Interop spec id. + INTEROP, + /// Osaka spec id. + OSAKA, +} + +impl OpSpecId { + /// Converts the [`OpSpecId`] into a [`SpecId`]. + pub const fn into_eth_spec(self) -> SpecId { + match self { + Self::BEDROCK | Self::REGOLITH => SpecId::MERGE, + Self::CANYON => SpecId::SHANGHAI, + Self::ECOTONE | Self::FJORD | Self::GRANITE | Self::HOLOCENE => SpecId::CANCUN, + Self::ISTHMUS | Self::INTEROP => SpecId::PRAGUE, + Self::OSAKA => SpecId::OSAKA, + } + } + + /// Checks if the [`OpSpecId`] is enabled in the other [`OpSpecId`]. + pub const fn is_enabled_in(self, other: OpSpecId) -> bool { + other as u8 <= self as u8 + } +} + +impl From for SpecId { + fn from(spec: OpSpecId) -> Self { + spec.into_eth_spec() + } +} + +impl FromStr for OpSpecId { + type Err = UnknownHardfork; + + fn from_str(s: &str) -> Result { + match s { + name::BEDROCK => Ok(OpSpecId::BEDROCK), + name::REGOLITH => Ok(OpSpecId::REGOLITH), + name::CANYON => Ok(OpSpecId::CANYON), + name::ECOTONE => Ok(OpSpecId::ECOTONE), + name::FJORD => Ok(OpSpecId::FJORD), + name::GRANITE => Ok(OpSpecId::GRANITE), + name::HOLOCENE => Ok(OpSpecId::HOLOCENE), + name::ISTHMUS => Ok(OpSpecId::ISTHMUS), + name::INTEROP => Ok(OpSpecId::INTEROP), + eth_name::OSAKA => Ok(OpSpecId::OSAKA), + _ => Err(UnknownHardfork), + } + } +} + +impl From for &'static str { + fn from(spec_id: OpSpecId) -> Self { + match spec_id { + OpSpecId::BEDROCK => name::BEDROCK, + OpSpecId::REGOLITH => name::REGOLITH, + OpSpecId::CANYON => name::CANYON, + OpSpecId::ECOTONE => name::ECOTONE, + OpSpecId::FJORD => name::FJORD, + OpSpecId::GRANITE => name::GRANITE, + OpSpecId::HOLOCENE => name::HOLOCENE, + OpSpecId::ISTHMUS => name::ISTHMUS, + OpSpecId::INTEROP => name::INTEROP, + OpSpecId::OSAKA => eth_name::OSAKA, + } + } +} + +/// String identifiers for Optimism hardforks +pub mod name { + /// Bedrock spec name. + pub const BEDROCK: &str = "Bedrock"; + /// Regolith spec name. + pub const REGOLITH: &str = "Regolith"; + /// Canyon spec name. + pub const CANYON: &str = "Canyon"; + /// Ecotone spec name. + pub const ECOTONE: &str = "Ecotone"; + /// Fjord spec name. + pub const FJORD: &str = "Fjord"; + /// Granite spec name. + pub const GRANITE: &str = "Granite"; + /// Holocene spec name. + pub const HOLOCENE: &str = "Holocene"; + /// Isthmus spec name. + pub const ISTHMUS: &str = "Isthmus"; + /// Interop spec name. + pub const INTEROP: &str = "Interop"; +} + +#[cfg(test)] +mod tests { + use super::*; + use std::vec; + + #[test] + fn test_op_spec_id_eth_spec_compatibility() { + // Define test cases: (OpSpecId, enabled in ETH specs, enabled in OP specs) + let test_cases = [ + ( + OpSpecId::BEDROCK, + vec![ + (SpecId::MERGE, true), + (SpecId::SHANGHAI, false), + (SpecId::CANCUN, false), + (SpecId::default(), false), + ], + vec![(OpSpecId::BEDROCK, true), (OpSpecId::REGOLITH, false)], + ), + ( + OpSpecId::REGOLITH, + vec![ + (SpecId::MERGE, true), + (SpecId::SHANGHAI, false), + (SpecId::CANCUN, false), + (SpecId::default(), false), + ], + vec![(OpSpecId::BEDROCK, true), (OpSpecId::REGOLITH, true)], + ), + ( + OpSpecId::CANYON, + vec![ + (SpecId::MERGE, true), + (SpecId::SHANGHAI, true), + (SpecId::CANCUN, false), + (SpecId::default(), false), + ], + vec![ + (OpSpecId::BEDROCK, true), + (OpSpecId::REGOLITH, true), + (OpSpecId::CANYON, true), + ], + ), + ( + OpSpecId::ECOTONE, + vec![ + (SpecId::MERGE, true), + (SpecId::SHANGHAI, true), + (SpecId::CANCUN, true), + (SpecId::default(), false), + ], + vec![ + (OpSpecId::BEDROCK, true), + (OpSpecId::REGOLITH, true), + (OpSpecId::CANYON, true), + (OpSpecId::ECOTONE, true), + ], + ), + ( + OpSpecId::FJORD, + vec![ + (SpecId::MERGE, true), + (SpecId::SHANGHAI, true), + (SpecId::CANCUN, true), + (SpecId::default(), false), + ], + vec![ + (OpSpecId::BEDROCK, true), + (OpSpecId::REGOLITH, true), + (OpSpecId::CANYON, true), + (OpSpecId::ECOTONE, true), + (OpSpecId::FJORD, true), + ], + ), + ]; + + for (op_spec, eth_tests, op_tests) in test_cases { + // Test ETH spec compatibility + for (eth_spec, expected) in eth_tests { + assert_eq!( + op_spec.into_eth_spec().is_enabled_in(eth_spec), + expected, + "{:?} should {} be enabled in ETH {:?}", + op_spec, + if expected { "" } else { "not " }, + eth_spec + ); + } + + // Test OP spec compatibility + for (other_op_spec, expected) in op_tests { + assert_eq!( + op_spec.is_enabled_in(other_op_spec), + expected, + "{:?} should {} be enabled in OP {:?}", + op_spec, + if expected { "" } else { "not " }, + other_op_spec + ); + } + } + } + + #[test] + fn default_op_spec_id() { + assert_eq!(OpSpecId::default(), OpSpecId::ISTHMUS); + } +} diff --git a/crates/op-revm/src/transaction.rs b/crates/op-revm/src/transaction.rs new file mode 100644 index 0000000000..702de9dfec --- /dev/null +++ b/crates/op-revm/src/transaction.rs @@ -0,0 +1,29 @@ +//! Contains the `[OpTransaction]` type and its implementation. +pub mod abstraction; +pub mod deposit; +pub mod error; + +pub use abstraction::{OpTransaction, OpTxTr}; +pub use error::OpTransactionError; + +use crate::fast_lz::flz_compress_len; + +/// +const L1_COST_FASTLZ_COEF: u64 = 836_500; + +/// +/// Inverted to be used with `saturating_sub`. +const L1_COST_INTERCEPT: u64 = 42_585_600; + +/// +const MIN_TX_SIZE_SCALED: u64 = 100 * 1_000_000; + +/// Estimates the compressed size of a transaction. +pub fn estimate_tx_compressed_size(input: &[u8]) -> u64 { + let fastlz_size = flz_compress_len(input) as u64; + + fastlz_size + .saturating_mul(L1_COST_FASTLZ_COEF) + .saturating_sub(L1_COST_INTERCEPT) + .max(MIN_TX_SIZE_SCALED) +} diff --git a/crates/op-revm/src/transaction/abstraction.rs b/crates/op-revm/src/transaction/abstraction.rs new file mode 100644 index 0000000000..65b50e3ddd --- /dev/null +++ b/crates/op-revm/src/transaction/abstraction.rs @@ -0,0 +1,386 @@ +//! Optimism transaction abstraction containing the `[OpTxTr]` trait and corresponding `[OpTransaction]` type. +use super::deposit::{DepositTransactionParts, DEPOSIT_TRANSACTION_TYPE}; +use auto_impl::auto_impl; +use revm::{ + context::{ + tx::{TxEnvBuildError, TxEnvBuilder}, + TxEnv, + }, + context_interface::transaction::Transaction, + handler::SystemCallTx, + primitives::{Address, Bytes, TxKind, B256, U256}, +}; +use std::vec; + +/// Optimism Transaction trait. +#[auto_impl(&, &mut, Box, Arc)] +pub trait OpTxTr: Transaction { + /// Enveloped transaction bytes. + fn enveloped_tx(&self) -> Option<&Bytes>; + + /// Source hash of the deposit transaction. + fn source_hash(&self) -> Option; + + /// Mint of the deposit transaction + fn mint(&self) -> Option; + + /// Whether the transaction is a system transaction + fn is_system_transaction(&self) -> bool; + + /// Returns `true` if transaction is of type [`DEPOSIT_TRANSACTION_TYPE`]. + fn is_deposit(&self) -> bool { + self.tx_type() == DEPOSIT_TRANSACTION_TYPE + } +} + +/// Optimism transaction. +#[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct OpTransaction { + /// Base transaction fields. + pub base: T, + /// An enveloped EIP-2718 typed transaction + /// + /// This is used to compute the L1 tx cost using the L1 block info, as + /// opposed to requiring downstream apps to compute the cost + /// externally. + pub enveloped_tx: Option, + /// Deposit transaction parts. + pub deposit: DepositTransactionParts, +} + +impl AsRef for OpTransaction { + fn as_ref(&self) -> &T { + &self.base + } +} + +impl OpTransaction { + /// Create a new Optimism transaction. + pub fn new(base: T) -> Self { + Self { + base, + enveloped_tx: None, + deposit: DepositTransactionParts::default(), + } + } +} + +impl OpTransaction { + /// Create a new Optimism transaction. + pub fn builder() -> OpTransactionBuilder { + OpTransactionBuilder::new() + } +} + +impl Default for OpTransaction { + fn default() -> Self { + Self { + base: TxEnv::default(), + enveloped_tx: Some(vec![0x00].into()), + deposit: DepositTransactionParts::default(), + } + } +} + +impl SystemCallTx for OpTransaction { + fn new_system_tx_with_caller( + caller: Address, + system_contract_address: Address, + data: Bytes, + ) -> Self { + OpTransaction::new(TX::new_system_tx_with_caller( + caller, + system_contract_address, + data, + )) + } +} + +impl Transaction for OpTransaction { + type AccessListItem<'a> + = T::AccessListItem<'a> + where + T: 'a; + type Authorization<'a> + = T::Authorization<'a> + where + T: 'a; + + fn tx_type(&self) -> u8 { + // If this is a deposit transaction (has source_hash set), return deposit type + if self.deposit.source_hash != B256::ZERO { + DEPOSIT_TRANSACTION_TYPE + } else { + self.base.tx_type() + } + } + + fn caller(&self) -> Address { + self.base.caller() + } + + fn gas_limit(&self) -> u64 { + self.base.gas_limit() + } + + fn value(&self) -> U256 { + self.base.value() + } + + fn input(&self) -> &Bytes { + self.base.input() + } + + fn nonce(&self) -> u64 { + self.base.nonce() + } + + fn kind(&self) -> TxKind { + self.base.kind() + } + + fn chain_id(&self) -> Option { + self.base.chain_id() + } + + fn access_list(&self) -> Option>> { + self.base.access_list() + } + + fn max_priority_fee_per_gas(&self) -> Option { + self.base.max_priority_fee_per_gas() + } + + fn max_fee_per_gas(&self) -> u128 { + self.base.max_fee_per_gas() + } + + fn gas_price(&self) -> u128 { + self.base.gas_price() + } + + fn blob_versioned_hashes(&self) -> &[B256] { + self.base.blob_versioned_hashes() + } + + fn max_fee_per_blob_gas(&self) -> u128 { + self.base.max_fee_per_blob_gas() + } + + fn effective_gas_price(&self, base_fee: u128) -> u128 { + // Deposit transactions use gas_price directly + if self.tx_type() == DEPOSIT_TRANSACTION_TYPE { + return self.gas_price(); + } + self.base.effective_gas_price(base_fee) + } + + fn authorization_list_len(&self) -> usize { + self.base.authorization_list_len() + } + + fn authorization_list(&self) -> impl Iterator> { + self.base.authorization_list() + } +} + +impl OpTxTr for OpTransaction { + fn enveloped_tx(&self) -> Option<&Bytes> { + self.enveloped_tx.as_ref() + } + + fn source_hash(&self) -> Option { + if self.tx_type() != DEPOSIT_TRANSACTION_TYPE { + return None; + } + Some(self.deposit.source_hash) + } + + fn mint(&self) -> Option { + self.deposit.mint + } + + fn is_system_transaction(&self) -> bool { + self.deposit.is_system_transaction + } +} + +/// Builder for constructing [`OpTransaction`] instances +#[derive(Default, Debug)] +pub struct OpTransactionBuilder { + base: TxEnvBuilder, + enveloped_tx: Option, + deposit: DepositTransactionParts, +} + +impl OpTransactionBuilder { + /// Create a new builder with default values + pub fn new() -> Self { + Self { + base: TxEnvBuilder::new(), + enveloped_tx: None, + deposit: DepositTransactionParts::default(), + } + } + + /// Set the base transaction builder based for TxEnvBuilder. + pub fn base(mut self, base: TxEnvBuilder) -> Self { + self.base = base; + self + } + + /// Set the enveloped transaction bytes. + pub fn enveloped_tx(mut self, enveloped_tx: Option) -> Self { + self.enveloped_tx = enveloped_tx; + self + } + + /// Set the source hash of the deposit transaction. + pub fn source_hash(mut self, source_hash: B256) -> Self { + self.deposit.source_hash = source_hash; + self + } + + /// Set the mint of the deposit transaction. + pub fn mint(mut self, mint: u128) -> Self { + self.deposit.mint = Some(mint); + self + } + + /// Set the deposit transaction to be a system transaction. + pub fn is_system_transaction(mut self) -> Self { + self.deposit.is_system_transaction = true; + self + } + + /// Set the deposit transaction to not be a system transaction. + pub fn not_system_transaction(mut self) -> Self { + self.deposit.is_system_transaction = false; + self + } + + /// Set the deposit transaction to be a deposit transaction. + pub fn is_deposit_tx(mut self) -> Self { + self.base = self.base.tx_type(Some(DEPOSIT_TRANSACTION_TYPE)); + self + } + + /// Build the [`OpTransaction`] with default values for missing fields. + /// + /// This is useful for testing and debugging where it is not necessary to + /// have full [`OpTransaction`] instance. + /// + /// If the source hash is not [`B256::ZERO`], set the transaction type to deposit and remove the enveloped transaction. + pub fn build_fill(mut self) -> OpTransaction { + let tx_type = self.base.get_tx_type(); + if tx_type.is_some() { + if tx_type == Some(DEPOSIT_TRANSACTION_TYPE) { + // source hash is required for deposit transactions + if self.deposit.source_hash == B256::ZERO { + self.deposit.source_hash = B256::from([1u8; 32]); + } + } else { + // enveloped is required for non-deposit transactions + self.enveloped_tx = Some(vec![0x00].into()); + } + } else if self.deposit.source_hash != B256::ZERO { + // if type is not set and source hash is set, set the transaction type to deposit + self.base = self.base.tx_type(Some(DEPOSIT_TRANSACTION_TYPE)); + } else if self.enveloped_tx.is_none() { + // if type is not set and source hash is not set, set the enveloped transaction to something. + self.enveloped_tx = Some(vec![0x00].into()); + } + + let base = self.base.build_fill(); + + OpTransaction { + base, + enveloped_tx: self.enveloped_tx, + deposit: self.deposit, + } + } + + /// Build the [`OpTransaction`] instance, return error if the transaction is not valid. + /// + pub fn build(mut self) -> Result, OpBuildError> { + let tx_type = self.base.get_tx_type(); + if tx_type.is_some() { + if Some(DEPOSIT_TRANSACTION_TYPE) == tx_type { + // if tx type is deposit, check if source hash is set + if self.deposit.source_hash == B256::ZERO { + return Err(OpBuildError::MissingSourceHashForDeposit); + } + } else if self.enveloped_tx.is_none() { + // enveloped is required for non-deposit transactions + return Err(OpBuildError::MissingEnvelopedTxBytes); + } + } else if self.deposit.source_hash != B256::ZERO { + // if type is not set and source hash is set, set the transaction type to deposit + self.base = self.base.tx_type(Some(DEPOSIT_TRANSACTION_TYPE)); + } else if self.enveloped_tx.is_none() { + // tx is not deposit and enveloped is required + return Err(OpBuildError::MissingEnvelopedTxBytes); + } + + let base = self.base.build()?; + + Ok(OpTransaction { + base, + enveloped_tx: self.enveloped_tx, + deposit: self.deposit, + }) + } +} + +/// Error type for building [`TxEnv`] +#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub enum OpBuildError { + /// Base transaction build error + Base(TxEnvBuildError), + /// Missing enveloped transaction bytes + MissingEnvelopedTxBytes, + /// Missing source hash for deposit transaction + MissingSourceHashForDeposit, +} + +impl From for OpBuildError { + fn from(error: TxEnvBuildError) -> Self { + OpBuildError::Base(error) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use revm::{ + context_interface::Transaction, + primitives::{Address, B256}, + }; + + #[test] + fn test_deposit_transaction_fields() { + let base_tx = TxEnv::builder() + .gas_limit(10) + .gas_price(100) + .gas_priority_fee(Some(5)); + + let op_tx = OpTransaction::builder() + .base(base_tx) + .enveloped_tx(None) + .not_system_transaction() + .mint(0u128) + .source_hash(B256::from([1u8; 32])) + .build() + .unwrap(); + // Verify transaction type (deposit transactions should have tx_type based on OpSpecId) + // The tx_type is derived from the transaction structure, not set manually + // Verify common fields access + assert_eq!(op_tx.gas_limit(), 10); + assert_eq!(op_tx.kind(), revm::primitives::TxKind::Call(Address::ZERO)); + // Verify gas related calculations - deposit transactions use gas_price for effective gas price + assert_eq!(op_tx.effective_gas_price(90), 100); + assert_eq!(op_tx.max_fee_per_gas(), 100); + } +} diff --git a/crates/op-revm/src/transaction/deposit.rs b/crates/op-revm/src/transaction/deposit.rs new file mode 100644 index 0000000000..1d51fb1224 --- /dev/null +++ b/crates/op-revm/src/transaction/deposit.rs @@ -0,0 +1,49 @@ +//! Contains Deposit transaction parts. +use revm::primitives::B256; + +/// Deposit transaction type. +pub const DEPOSIT_TRANSACTION_TYPE: u8 = 0x7E; + +/// Deposit transaction parts. +#[derive(Clone, Debug, Default, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct DepositTransactionParts { + /// Source hash of the deposit transaction. + pub source_hash: B256, + /// Minted value of the deposit transaction. + pub mint: Option, + /// Whether the transaction is a system transaction. + pub is_system_transaction: bool, +} + +impl DepositTransactionParts { + /// Create a new deposit transaction parts. + pub fn new(source_hash: B256, mint: Option, is_system_transaction: bool) -> Self { + Self { + source_hash, + mint, + is_system_transaction, + } + } +} + +#[cfg(all(test, feature = "serde"))] +mod tests { + use super::*; + use revm::primitives::b256; + + #[test] + fn serialize_json_deposit_tx_parts() { + let response = r#"{"source_hash":"0xe927a1448525fb5d32cb50ee1408461a945ba6c39bd5cf5621407d500ecc8de9","mint":52,"is_system_transaction":false}"#; + + let deposit_tx_parts: DepositTransactionParts = serde_json::from_str(response).unwrap(); + assert_eq!( + deposit_tx_parts, + DepositTransactionParts::new( + b256!("0xe927a1448525fb5d32cb50ee1408461a945ba6c39bd5cf5621407d500ecc8de9"), + Some(0x34), + false, + ) + ); + } +} diff --git a/crates/op-revm/src/transaction/error.rs b/crates/op-revm/src/transaction/error.rs new file mode 100644 index 0000000000..76169a3dd8 --- /dev/null +++ b/crates/op-revm/src/transaction/error.rs @@ -0,0 +1,110 @@ +//! Contains the `[OpTransactionError]` type. +use core::fmt::Display; +use revm::context_interface::{ + result::{EVMError, InvalidTransaction}, + transaction::TransactionError, +}; + +/// Optimism transaction validation error. +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub enum OpTransactionError { + /// Base transaction error. + Base(InvalidTransaction), + /// System transactions are not supported post-regolith hardfork. + /// + /// Before the Regolith hardfork, there was a special field in the `Deposit` transaction + /// type that differentiated between `system` and `user` deposit transactions. This field + /// was deprecated in the Regolith hardfork, and this error is thrown if a `Deposit` transaction + /// is found with this field set to `true` after the hardfork activation. + /// + /// In addition, this error is internal, and bubbles up into a [OpHaltReason::FailedDeposit][crate::OpHaltReason::FailedDeposit] error + /// in the `revm` handler for the consumer to easily handle. This is due to a state transition + /// rule on OP Stack chains where, if for any reason a deposit transaction fails, the transaction + /// must still be included in the block, the sender nonce is bumped, the `mint` value persists, and + /// special gas accounting rules are applied. Normally on L1, [EVMError::Transaction] errors + /// are cause for non-inclusion, so a special [OpHaltReason][crate::OpHaltReason] variant was introduced to handle this + /// case for failed deposit transactions. + DepositSystemTxPostRegolith, + /// Deposit transaction haults bubble up to the global main return handler, wiping state and + /// only increasing the nonce + persisting the mint value. + /// + /// This is a catch-all error for any deposit transaction that is results in a [OpHaltReason][crate::OpHaltReason] error + /// post-regolith hardfork. This allows for a consumer to easily handle special cases where + /// a deposit transaction fails during validation, but must still be included in the block. + /// + /// In addition, this error is internal, and bubbles up into a [OpHaltReason::FailedDeposit][crate::OpHaltReason::FailedDeposit] error + /// in the `revm` handler for the consumer to easily handle. This is due to a state transition + /// rule on OP Stack chains where, if for any reason a deposit transaction fails, the transaction + /// must still be included in the block, the sender nonce is bumped, the `mint` value persists, and + /// special gas accounting rules are applied. Normally on L1, [EVMError::Transaction] errors + /// are cause for non-inclusion, so a special [OpHaltReason][crate::OpHaltReason] variant was introduced to handle this + /// case for failed deposit transactions. + HaltedDepositPostRegolith, +} + +impl TransactionError for OpTransactionError {} + +impl Display for OpTransactionError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + Self::Base(error) => error.fmt(f), + Self::DepositSystemTxPostRegolith => { + write!( + f, + "deposit system transactions post regolith hardfork are not supported" + ) + } + Self::HaltedDepositPostRegolith => { + write!( + f, + "deposit transaction halted post-regolith; error will be bubbled up to main return handler" + ) + } + } + } +} + +impl core::error::Error for OpTransactionError {} + +impl From for OpTransactionError { + fn from(value: InvalidTransaction) -> Self { + Self::Base(value) + } +} + +impl From for EVMError { + fn from(value: OpTransactionError) -> Self { + Self::Transaction(value) + } +} + +#[cfg(test)] +mod test { + use super::*; + use std::string::ToString; + + #[test] + fn test_display_op_errors() { + assert_eq!( + OpTransactionError::DepositSystemTxPostRegolith.to_string(), + "deposit system transactions post regolith hardfork are not supported" + ); + assert_eq!( + OpTransactionError::HaltedDepositPostRegolith.to_string(), + "deposit transaction halted post-regolith; error will be bubbled up to main return handler" + ) + } + + #[cfg(feature = "serde")] + #[test] + fn test_serialize_json_op_transaction_error() { + let response = r#""DepositSystemTxPostRegolith""#; + + let op_transaction_error: OpTransactionError = serde_json::from_str(response).unwrap(); + assert_eq!( + op_transaction_error, + OpTransactionError::DepositSystemTxPostRegolith + ); + } +} diff --git a/crates/op-revm/tests/common.rs b/crates/op-revm/tests/common.rs new file mode 100644 index 0000000000..bca6e97ec5 --- /dev/null +++ b/crates/op-revm/tests/common.rs @@ -0,0 +1,111 @@ +//! Common test utilities used to compare execution results against testdata. +#![allow(dead_code)] + +use revm::{ + context::result::ResultAndState, + context_interface::result::{ExecutionResult, HaltReason, Output, SuccessReason}, + primitives::Bytes, + state::EvmState, +}; + +// Constant for testdata directory path +pub(crate) const TESTS_TESTDATA: &str = "tests/testdata"; + +#[cfg(not(feature = "serde"))] +pub(crate) fn compare_or_save_testdata( + _filename: &str, + _output: &ResultAndState, +) { + // serde needs to be enabled to use this function +} + +/// Compares or saves the execution output to a testdata file. +/// +/// This utility helps maintain consistent test behavior by comparing +/// execution results against known-good outputs stored in JSON files. +/// +/// # Arguments +/// +/// * `filename` - The name of the testdata file, relative to tests/testdata/ +/// * `output` - The execution output to compare or save +/// +/// # Returns +/// +/// `Ok(())` if the comparison or save was successful +/// `Err(anyhow::Error)` if there was an error +/// +/// # Note +/// +/// Tests using this function require the `serde` feature to be enabled: +/// ```bash +/// cargo test --features serde +/// ``` +#[cfg(feature = "serde")] +pub(crate) fn compare_or_save_testdata( + filename: &str, + output: &ResultAndState, +) where + HaltReasonTy: serde::Serialize + for<'a> serde::Deserialize<'a> + PartialEq, +{ + use std::{fs, path::PathBuf}; + + let tests_dir = PathBuf::from(TESTS_TESTDATA); + let testdata_file = tests_dir.join(filename); + + // Create directory if it doesn't exist + if !tests_dir.exists() { + fs::create_dir_all(&tests_dir).unwrap(); + } + + // Serialize the output to JSON for saving + let output_json = serde_json::to_string_pretty(output).unwrap(); + + // If the testdata file doesn't exist, save the output + if !testdata_file.exists() { + fs::write(&testdata_file, &output_json).unwrap(); + println!("Saved testdata to {}", testdata_file.display()); + return; + } + + // Read the expected output from the testdata file + let expected_json = fs::read_to_string(&testdata_file).unwrap(); + + // Deserialize to actual ResultAndState object for proper comparison + let expected = serde_json::from_str(&expected_json).unwrap(); + + // Compare the output objects directly + if output != &expected { + // If they don't match, generate a nicer error by pretty-printing both as JSON + // This helps with debugging by showing the exact differences + let expected_pretty = serde_json::to_string_pretty(&expected).unwrap(); + + panic!( + "Value does not match testdata.\nExpected:\n{expected_pretty}\n\nActual:\n{output_json}", + ); + } +} + +/// Example showing how to migrate an existing test to use the testdata comparison. +/// +/// This example consists of: +/// 1. The "original" test with standard assertions +/// 2. The migration approach - running assertions and saving testdata +/// 3. The final migrated test that only uses testdata comparison +#[test] +fn template_test() { + // Create a minimal result and state + let result = ResultAndState::new( + ExecutionResult::Success { + reason: SuccessReason::Stop, + gas_used: 1000, + gas_refunded: 0, + logs: vec![], + output: Output::Call(Bytes::from(vec![4, 5, 6])), + }, + EvmState::default(), + ); + + // Simply use the testdata comparison utility + // No assertions needed - full validation is done by comparing with testdata + compare_or_save_testdata::("template_test.json", &result); +} diff --git a/crates/op-revm/tests/integration.rs b/crates/op-revm/tests/integration.rs new file mode 100644 index 0000000000..2f7f2fcf96 --- /dev/null +++ b/crates/op-revm/tests/integration.rs @@ -0,0 +1,1074 @@ +//! Integration tests for the `op-revm` crate. +mod common; + +use common::compare_or_save_testdata; +use op_revm::{ + precompiles::bn128_pair::GRANITE_MAX_INPUT_SIZE, DefaultOp, L1BlockInfo, OpBuilder, + OpHaltReason, OpSpecId, OpTransaction, +}; +use revm::{ + bytecode::opcode, + context::{ + result::{ExecutionResult, OutOfGasError}, + BlockEnv, CfgEnv, TxEnv, + }, + context_interface::result::HaltReason, + database::{BenchmarkDB, EmptyDB, BENCH_CALLER, BENCH_CALLER_BALANCE, BENCH_TARGET}, + interpreter::{ + gas::{calculate_initial_tx_gas, InitialAndFloorGas}, + Interpreter, InterpreterTypes, + }, + precompile::{bls12_381_const, bls12_381_utils, bn128, secp256r1, u64_to_address}, + primitives::{eip7825, Address, Bytes, Log, TxKind, U256}, + state::Bytecode, + Context, ExecuteEvm, InspectEvm, Inspector, Journal, +}; +use std::vec::Vec; + +#[test] +fn test_deposit_tx() { + let ctx = Context::op() + .with_tx( + OpTransaction::builder() + .enveloped_tx(None) + .mint(100) + .source_hash(revm::primitives::B256::from([1u8; 32])) + .build_fill(), + ) + .modify_cfg_chained(|cfg| cfg.spec = OpSpecId::HOLOCENE); + + let mut evm = ctx.build_op(); + + let output = evm.replay().unwrap(); + + // balance should be 100 + assert_eq!( + output + .state + .get(&Address::default()) + .map(|a| a.info.balance), + Some(U256::from(100)) + ); + compare_or_save_testdata("test_deposit_tx.json", &output); +} + +#[test] +fn test_halted_deposit_tx() { + let ctx = Context::op() + .with_tx( + OpTransaction::builder() + .base( + TxEnv::builder() + .caller(BENCH_CALLER) + .kind(TxKind::Call(BENCH_TARGET)), + ) + .enveloped_tx(None) + .mint(100) + .source_hash(revm::primitives::B256::from([1u8; 32])) + .build_fill(), + ) + .modify_cfg_chained(|cfg| cfg.spec = OpSpecId::HOLOCENE) + .with_db(BenchmarkDB::new_bytecode(Bytecode::new_legacy( + [opcode::POP].into(), + ))); + + // POP would return a halt. + let mut evm = ctx.build_op(); + + let output = evm.replay().unwrap(); + + // balance should be 100 + previous balance + assert_eq!( + output.result, + ExecutionResult::Halt { + reason: OpHaltReason::FailedDeposit, + gas_used: eip7825::TX_GAS_LIMIT_CAP, + } + ); + assert_eq!( + output.state.get(&BENCH_CALLER).map(|a| a.info.balance), + Some(U256::from(100) + BENCH_CALLER_BALANCE) + ); + + compare_or_save_testdata("test_halted_deposit_tx.json", &output); +} + +fn p256verify_test_tx( +) -> Context, CfgEnv, EmptyDB, Journal, L1BlockInfo> +{ + const SPEC_ID: OpSpecId = OpSpecId::FJORD; + + let InitialAndFloorGas { initial_gas, .. } = + calculate_initial_tx_gas(SPEC_ID.into(), &[], false, 0, 0, 0); + + Context::op() + .with_tx( + OpTransaction::builder() + .base( + TxEnv::builder() + .kind(TxKind::Call(u64_to_address(secp256r1::P256VERIFY_ADDRESS))) + .gas_limit(initial_gas + secp256r1::P256VERIFY_BASE_GAS_FEE), + ) + .build_fill(), + ) + .modify_cfg_chained(|cfg| cfg.spec = SPEC_ID) +} + +#[test] +fn test_tx_call_p256verify() { + let ctx = p256verify_test_tx(); + + let mut evm = ctx.build_op(); + let output = evm.replay().unwrap(); + + // assert successful call to P256VERIFY + assert!(output.result.is_success()); + + compare_or_save_testdata("test_tx_call_p256verify.json", &output); +} + +#[test] +fn test_halted_tx_call_p256verify() { + const SPEC_ID: OpSpecId = OpSpecId::FJORD; + let InitialAndFloorGas { initial_gas, .. } = + calculate_initial_tx_gas(SPEC_ID.into(), &[], false, 0, 0, 0); + let original_gas_limit = initial_gas + secp256r1::P256VERIFY_BASE_GAS_FEE; + + let ctx = Context::op() + .with_tx( + OpTransaction::builder() + .base( + TxEnv::builder() + .kind(TxKind::Call(u64_to_address(secp256r1::P256VERIFY_ADDRESS))) + .gas_limit(original_gas_limit - 1), + ) + .build_fill(), + ) + .modify_cfg_chained(|cfg| cfg.spec = SPEC_ID); + + let mut evm = ctx.build_op(); + let output = evm.replay().unwrap(); + + // assert out of gas for P256VERIFY + assert!(matches!( + output.result, + ExecutionResult::Halt { + reason: OpHaltReason::Base(HaltReason::OutOfGas(OutOfGasError::Precompile)), + .. + } + )); + + compare_or_save_testdata("test_halted_tx_call_p256verify.json", &output); +} + +fn bn128_pair_test_tx( + spec: OpSpecId, +) -> Context, CfgEnv, EmptyDB, Journal, L1BlockInfo> +{ + let input = Bytes::from([1; GRANITE_MAX_INPUT_SIZE + 2]); + let InitialAndFloorGas { initial_gas, .. } = + calculate_initial_tx_gas(spec.into(), &input[..], false, 0, 0, 0); + + Context::op() + .with_tx( + OpTransaction::builder() + .base( + TxEnv::builder() + .kind(TxKind::Call(bn128::pair::ADDRESS)) + .data(input) + .gas_limit(initial_gas), + ) + .build_fill(), + ) + .modify_cfg_chained(|cfg| cfg.spec = spec) +} + +#[test] +fn test_halted_tx_call_bn128_pair_fjord() { + let ctx = bn128_pair_test_tx(OpSpecId::FJORD); + + let mut evm = ctx.build_op(); + let output = evm.replay().unwrap(); + + // assert out of gas + assert!(matches!( + output.result, + ExecutionResult::Halt { + reason: OpHaltReason::Base(HaltReason::OutOfGas(OutOfGasError::Precompile)), + .. + } + )); + + compare_or_save_testdata("test_halted_tx_call_bn128_pair_fjord.json", &output); +} + +#[test] +fn test_halted_tx_call_bn128_pair_granite() { + let ctx = bn128_pair_test_tx(OpSpecId::GRANITE); + + let mut evm = ctx.build_op(); + let output = evm.replay().unwrap(); + + // assert bails early because input size too big + assert!(matches!( + output.result, + ExecutionResult::Halt { + reason: OpHaltReason::Base(HaltReason::PrecompileError), + .. + } + )); + + compare_or_save_testdata("test_halted_tx_call_bn128_pair_granite.json", &output); +} + +#[test] +fn test_halted_tx_call_bls12_381_g1_add_out_of_gas() { + let ctx = Context::op() + .with_tx( + OpTransaction::builder() + .base( + TxEnv::builder() + .kind(TxKind::Call(bls12_381_const::G1_ADD_ADDRESS)) + .gas_limit(21_000 + bls12_381_const::G1_ADD_BASE_GAS_FEE - 1), + ) + .build_fill(), + ) + .modify_chain_chained(|l1_block| { + l1_block.operator_fee_constant = Some(U256::ZERO); + l1_block.operator_fee_scalar = Some(U256::ZERO) + }) + .modify_cfg_chained(|cfg| cfg.spec = OpSpecId::ISTHMUS); + + let mut evm = ctx.build_op(); + + let output = evm.replay().unwrap(); + + // assert out of gas + assert!(matches!( + output.result, + ExecutionResult::Halt { + reason: OpHaltReason::Base(HaltReason::OutOfGas(OutOfGasError::Precompile)), + .. + } + )); + + compare_or_save_testdata( + "test_halted_tx_call_bls12_381_g1_add_out_of_gas.json", + &output, + ); +} + +#[test] +fn test_halted_tx_call_bls12_381_g1_add_input_wrong_size() { + let ctx = Context::op() + .with_tx( + OpTransaction::builder() + .base( + TxEnv::builder() + .kind(TxKind::Call(bls12_381_const::G1_ADD_ADDRESS)) + .gas_limit(21_000 + bls12_381_const::G1_ADD_BASE_GAS_FEE), + ) + .build_fill(), + ) + .modify_chain_chained(|l1_block| { + l1_block.operator_fee_constant = Some(U256::ZERO); + l1_block.operator_fee_scalar = Some(U256::ZERO) + }) + .modify_cfg_chained(|cfg| cfg.spec = OpSpecId::ISTHMUS); + + let mut evm = ctx.build_op(); + let output = evm.replay().unwrap(); + + // assert fails post gas check, because input is wrong size + assert!(matches!( + output.result, + ExecutionResult::Halt { + reason: OpHaltReason::Base(HaltReason::PrecompileError), + .. + } + )); + + compare_or_save_testdata( + "test_halted_tx_call_bls12_381_g1_add_input_wrong_size.json", + &output, + ); +} + +fn g1_msm_test_tx( +) -> Context, CfgEnv, EmptyDB, Journal, L1BlockInfo> +{ + const SPEC_ID: OpSpecId = OpSpecId::ISTHMUS; + + let input = Bytes::from([1; bls12_381_const::G1_MSM_INPUT_LENGTH]); + let InitialAndFloorGas { initial_gas, .. } = + calculate_initial_tx_gas(SPEC_ID.into(), &input[..], false, 0, 0, 0); + let gs1_msm_gas = bls12_381_utils::msm_required_gas( + 1, + &bls12_381_const::DISCOUNT_TABLE_G1_MSM, + bls12_381_const::G1_MSM_BASE_GAS_FEE, + ); + + Context::op() + .with_tx( + OpTransaction::builder() + .base( + TxEnv::builder() + .kind(TxKind::Call(bls12_381_const::G1_MSM_ADDRESS)) + .data(input) + .gas_limit(initial_gas + gs1_msm_gas), + ) + .build_fill(), + ) + .modify_chain_chained(|l1_block| { + l1_block.operator_fee_constant = Some(U256::ZERO); + l1_block.operator_fee_scalar = Some(U256::ZERO) + }) + .modify_cfg_chained(|cfg| cfg.spec = SPEC_ID) +} + +#[test] +fn test_halted_tx_call_bls12_381_g1_msm_input_wrong_size() { + const SPEC_ID: OpSpecId = OpSpecId::ISTHMUS; + let input = Bytes::from([1; bls12_381_const::G1_MSM_INPUT_LENGTH]); + let InitialAndFloorGas { initial_gas, .. } = + calculate_initial_tx_gas(SPEC_ID.into(), &input[..], false, 0, 0, 0); + let gs1_msm_gas = bls12_381_utils::msm_required_gas( + 1, + &bls12_381_const::DISCOUNT_TABLE_G1_MSM, + bls12_381_const::G1_MSM_BASE_GAS_FEE, + ); + + let ctx = Context::op() + .with_tx( + OpTransaction::builder() + .base( + TxEnv::builder() + .kind(TxKind::Call(bls12_381_const::G1_MSM_ADDRESS)) + .data(input.slice(1..)) + .gas_limit(initial_gas + gs1_msm_gas), + ) + .build_fill(), + ) + .modify_chain_chained(|l1_block| { + l1_block.operator_fee_constant = Some(U256::ZERO); + l1_block.operator_fee_scalar = Some(U256::ZERO) + }) + .modify_cfg_chained(|cfg| cfg.spec = SPEC_ID); + + let mut evm = ctx.build_op(); + let output = evm.replay().unwrap(); + + // assert fails pre gas check, because input is wrong size + assert!(matches!( + output.result, + ExecutionResult::Halt { + reason: OpHaltReason::Base(HaltReason::PrecompileError), + .. + } + )); + + compare_or_save_testdata( + "test_halted_tx_call_bls12_381_g1_msm_input_wrong_size.json", + &output, + ); +} + +#[test] +fn test_halted_tx_call_bls12_381_g1_msm_out_of_gas() { + const SPEC_ID: OpSpecId = OpSpecId::ISTHMUS; + let input = Bytes::from([1; bls12_381_const::G1_MSM_INPUT_LENGTH]); + let InitialAndFloorGas { initial_gas, .. } = + calculate_initial_tx_gas(SPEC_ID.into(), &input[..], false, 0, 0, 0); + let gs1_msm_gas = bls12_381_utils::msm_required_gas( + 1, + &bls12_381_const::DISCOUNT_TABLE_G1_MSM, + bls12_381_const::G1_MSM_BASE_GAS_FEE, + ); + + let ctx = Context::op() + .with_tx( + OpTransaction::builder() + .base( + TxEnv::builder() + .kind(TxKind::Call(bls12_381_const::G1_MSM_ADDRESS)) + .data(input) + .gas_limit(initial_gas + gs1_msm_gas - 1), + ) + .build_fill(), + ) + .modify_chain_chained(|l1_block| { + l1_block.operator_fee_constant = Some(U256::ZERO); + l1_block.operator_fee_scalar = Some(U256::ZERO) + }) + .modify_cfg_chained(|cfg| cfg.spec = SPEC_ID); + + let mut evm = ctx.build_op(); + let output = evm.replay().unwrap(); + + // assert out of gas + assert!(matches!( + output.result, + ExecutionResult::Halt { + reason: OpHaltReason::Base(HaltReason::OutOfGas(OutOfGasError::Precompile)), + .. + } + )); + + compare_or_save_testdata( + "test_halted_tx_call_bls12_381_g1_msm_out_of_gas.json", + &output, + ); +} + +#[test] +fn test_halted_tx_call_bls12_381_g1_msm_wrong_input_layout() { + let ctx = g1_msm_test_tx(); + + let mut evm = ctx.build_op(); + let output = evm.replay().unwrap(); + + // assert fails post gas check, because input is wrong layout + assert!(matches!( + output.result, + ExecutionResult::Halt { + reason: OpHaltReason::Base(HaltReason::PrecompileError), + .. + } + )); + + compare_or_save_testdata( + "test_halted_tx_call_bls12_381_g1_msm_wrong_input_layout.json", + &output, + ); +} + +#[test] +fn test_halted_tx_call_bls12_381_g2_add_out_of_gas() { + let ctx = Context::op() + .with_tx( + OpTransaction::builder() + .base( + TxEnv::builder() + .kind(TxKind::Call(bls12_381_const::G2_ADD_ADDRESS)) + .gas_limit(21_000 + bls12_381_const::G2_ADD_BASE_GAS_FEE - 1), + ) + .build_fill(), + ) + .modify_chain_chained(|l1_block| { + l1_block.operator_fee_constant = Some(U256::ZERO); + l1_block.operator_fee_scalar = Some(U256::ZERO) + }) + .modify_cfg_chained(|cfg| cfg.spec = OpSpecId::ISTHMUS); + + let mut evm = ctx.build_op(); + + let output = evm.replay().unwrap(); + + // assert out of gas + assert!(matches!( + output.result, + ExecutionResult::Halt { + reason: OpHaltReason::Base(HaltReason::OutOfGas(OutOfGasError::Precompile)), + .. + } + )); + + compare_or_save_testdata( + "test_halted_tx_call_bls12_381_g2_add_out_of_gas.json", + &output, + ); +} + +#[test] +fn test_halted_tx_call_bls12_381_g2_add_input_wrong_size() { + let ctx = Context::op() + .with_tx( + OpTransaction::builder() + .base( + TxEnv::builder() + .kind(TxKind::Call(bls12_381_const::G2_ADD_ADDRESS)) + .gas_limit(21_000 + bls12_381_const::G2_ADD_BASE_GAS_FEE), + ) + .build_fill(), + ) + .modify_chain_chained(|l1_block| { + l1_block.operator_fee_constant = Some(U256::ZERO); + l1_block.operator_fee_scalar = Some(U256::ZERO) + }) + .modify_cfg_chained(|cfg| cfg.spec = OpSpecId::ISTHMUS); + + let mut evm = ctx.build_op(); + + let output = evm.replay().unwrap(); + + // assert fails post gas check, because input is wrong size + assert!(matches!( + output.result, + ExecutionResult::Halt { + reason: OpHaltReason::Base(HaltReason::PrecompileError), + .. + } + )); + + compare_or_save_testdata( + "test_halted_tx_call_bls12_381_g2_add_input_wrong_size.json", + &output, + ); +} + +fn g2_msm_test_tx( +) -> Context, CfgEnv, EmptyDB, Journal, L1BlockInfo> +{ + const SPEC_ID: OpSpecId = OpSpecId::ISTHMUS; + + let input = Bytes::from([1; bls12_381_const::G2_MSM_INPUT_LENGTH]); + let InitialAndFloorGas { initial_gas, .. } = + calculate_initial_tx_gas(SPEC_ID.into(), &input[..], false, 0, 0, 0); + let gs2_msm_gas = bls12_381_utils::msm_required_gas( + 1, + &bls12_381_const::DISCOUNT_TABLE_G2_MSM, + bls12_381_const::G2_MSM_BASE_GAS_FEE, + ); + + Context::op() + .with_tx( + OpTransaction::builder() + .base( + TxEnv::builder() + .kind(TxKind::Call(bls12_381_const::G2_MSM_ADDRESS)) + .data(input) + .gas_limit(initial_gas + gs2_msm_gas), + ) + .build_fill(), + ) + .modify_chain_chained(|l1_block| { + l1_block.operator_fee_constant = Some(U256::ZERO); + l1_block.operator_fee_scalar = Some(U256::ZERO) + }) + .modify_cfg_chained(|cfg| cfg.spec = SPEC_ID) +} + +#[test] +fn test_halted_tx_call_bls12_381_g2_msm_input_wrong_size() { + const SPEC_ID: OpSpecId = OpSpecId::ISTHMUS; + let input = Bytes::from([1; bls12_381_const::G2_MSM_INPUT_LENGTH]); + let InitialAndFloorGas { initial_gas, .. } = + calculate_initial_tx_gas(SPEC_ID.into(), &input[..], false, 0, 0, 0); + let gs2_msm_gas = bls12_381_utils::msm_required_gas( + 1, + &bls12_381_const::DISCOUNT_TABLE_G2_MSM, + bls12_381_const::G2_MSM_BASE_GAS_FEE, + ); + + let ctx = Context::op() + .with_tx( + OpTransaction::builder() + .base( + TxEnv::builder() + .kind(TxKind::Call(bls12_381_const::G2_MSM_ADDRESS)) + .data(input.slice(1..)) + .gas_limit(initial_gas + gs2_msm_gas), + ) + .build_fill(), + ) + .modify_chain_chained(|l1_block| { + l1_block.operator_fee_constant = Some(U256::ZERO); + l1_block.operator_fee_scalar = Some(U256::ZERO) + }) + .modify_cfg_chained(|cfg| cfg.spec = SPEC_ID); + + let mut evm = ctx.build_op(); + let output = evm.replay().unwrap(); + + // assert fails pre gas check, because input is wrong size + assert!(matches!( + output.result, + ExecutionResult::Halt { + reason: OpHaltReason::Base(HaltReason::PrecompileError), + .. + } + )); + + compare_or_save_testdata( + "test_halted_tx_call_bls12_381_g2_msm_input_wrong_size.json", + &output, + ); +} + +#[test] +fn test_halted_tx_call_bls12_381_g2_msm_out_of_gas() { + const SPEC_ID: OpSpecId = OpSpecId::ISTHMUS; + let input = Bytes::from([1; bls12_381_const::G2_MSM_INPUT_LENGTH]); + let InitialAndFloorGas { initial_gas, .. } = + calculate_initial_tx_gas(SPEC_ID.into(), &input[..], false, 0, 0, 0); + let gs2_msm_gas = bls12_381_utils::msm_required_gas( + 1, + &bls12_381_const::DISCOUNT_TABLE_G2_MSM, + bls12_381_const::G2_MSM_BASE_GAS_FEE, + ); + + let ctx = Context::op() + .with_tx( + OpTransaction::builder() + .base( + TxEnv::builder() + .kind(TxKind::Call(bls12_381_const::G2_MSM_ADDRESS)) + .data(input) + .gas_limit(initial_gas + gs2_msm_gas - 1), + ) + .build_fill(), + ) + .modify_chain_chained(|l1_block| { + l1_block.operator_fee_constant = Some(U256::ZERO); + l1_block.operator_fee_scalar = Some(U256::ZERO) + }) + .modify_cfg_chained(|cfg| cfg.spec = SPEC_ID); + + let mut evm = ctx.build_op(); + let output = evm.replay().unwrap(); + + // assert out of gas + assert!(matches!( + output.result, + ExecutionResult::Halt { + reason: OpHaltReason::Base(HaltReason::OutOfGas(OutOfGasError::Precompile)), + .. + } + )); + + compare_or_save_testdata( + "test_halted_tx_call_bls12_381_g2_msm_out_of_gas.json", + &output, + ); +} + +#[test] +fn test_halted_tx_call_bls12_381_g2_msm_wrong_input_layout() { + let ctx = g2_msm_test_tx(); + + let mut evm = ctx.build_op(); + let output = evm.replay().unwrap(); + + // assert fails post gas check, because input is wrong layout + assert!(matches!( + output.result, + ExecutionResult::Halt { + reason: OpHaltReason::Base(HaltReason::PrecompileError), + .. + } + )); + + compare_or_save_testdata( + "test_halted_tx_call_bls12_381_g2_msm_wrong_input_layout.json", + &output, + ); +} + +fn bl12_381_pairing_test_tx( +) -> Context, CfgEnv, EmptyDB, Journal, L1BlockInfo> +{ + const SPEC_ID: OpSpecId = OpSpecId::ISTHMUS; + + let input = Bytes::from([1; bls12_381_const::PAIRING_INPUT_LENGTH]); + let InitialAndFloorGas { initial_gas, .. } = + calculate_initial_tx_gas(SPEC_ID.into(), &input[..], false, 0, 0, 0); + + let pairing_gas: u64 = + bls12_381_const::PAIRING_MULTIPLIER_BASE + bls12_381_const::PAIRING_OFFSET_BASE; + + Context::op() + .with_tx( + OpTransaction::builder() + .base( + TxEnv::builder() + .kind(TxKind::Call(bls12_381_const::PAIRING_ADDRESS)) + .data(input) + .gas_limit(initial_gas + pairing_gas), + ) + .build_fill(), + ) + .modify_chain_chained(|l1_block| { + l1_block.operator_fee_constant = Some(U256::ZERO); + l1_block.operator_fee_scalar = Some(U256::ZERO) + }) + .modify_cfg_chained(|cfg| cfg.spec = OpSpecId::ISTHMUS) +} + +#[test] +fn test_halted_tx_call_bls12_381_pairing_input_wrong_size() { + const SPEC_ID: OpSpecId = OpSpecId::ISTHMUS; + let input = Bytes::from([1; bls12_381_const::PAIRING_INPUT_LENGTH]); + let InitialAndFloorGas { initial_gas, .. } = + calculate_initial_tx_gas(SPEC_ID.into(), &input[..], false, 0, 0, 0); + let pairing_gas: u64 = + bls12_381_const::PAIRING_MULTIPLIER_BASE + bls12_381_const::PAIRING_OFFSET_BASE; + + let ctx = Context::op() + .with_tx( + OpTransaction::builder() + .base( + TxEnv::builder() + .kind(TxKind::Call(bls12_381_const::PAIRING_ADDRESS)) + .data(input.slice(1..)) + .gas_limit(initial_gas + pairing_gas), + ) + .build_fill(), + ) + .modify_chain_chained(|l1_block| { + l1_block.operator_fee_constant = Some(U256::ZERO); + l1_block.operator_fee_scalar = Some(U256::ZERO) + }) + .modify_cfg_chained(|cfg| cfg.spec = OpSpecId::ISTHMUS); + + let mut evm = ctx.build_op(); + let output = evm.replay().unwrap(); + + // assert fails pre gas check, because input is wrong size + assert!(matches!( + output.result, + ExecutionResult::Halt { + reason: OpHaltReason::Base(HaltReason::PrecompileError), + .. + } + )); + + compare_or_save_testdata( + "test_halted_tx_call_bls12_381_pairing_input_wrong_size.json", + &output, + ); +} + +#[test] +fn test_halted_tx_call_bls12_381_pairing_out_of_gas() { + const SPEC_ID: OpSpecId = OpSpecId::ISTHMUS; + let input = Bytes::from([1; bls12_381_const::PAIRING_INPUT_LENGTH]); + let InitialAndFloorGas { initial_gas, .. } = + calculate_initial_tx_gas(SPEC_ID.into(), &input[..], false, 0, 0, 0); + let pairing_gas: u64 = + bls12_381_const::PAIRING_MULTIPLIER_BASE + bls12_381_const::PAIRING_OFFSET_BASE; + + let ctx = Context::op() + .with_tx( + OpTransaction::builder() + .base( + TxEnv::builder() + .kind(TxKind::Call(bls12_381_const::PAIRING_ADDRESS)) + .data(input) + .gas_limit(initial_gas + pairing_gas - 1), + ) + .build_fill(), + ) + .modify_chain_chained(|l1_block| { + l1_block.operator_fee_constant = Some(U256::ZERO); + l1_block.operator_fee_scalar = Some(U256::ZERO) + }) + .modify_cfg_chained(|cfg| cfg.spec = OpSpecId::ISTHMUS); + + let mut evm = ctx.build_op(); + let output = evm.replay().unwrap(); + + // assert out of gas + assert!(matches!( + output.result, + ExecutionResult::Halt { + reason: OpHaltReason::Base(HaltReason::OutOfGas(OutOfGasError::Precompile)), + .. + } + )); + + compare_or_save_testdata( + "test_halted_tx_call_bls12_381_pairing_out_of_gas.json", + &output, + ); +} + +#[test] +fn test_tx_call_bls12_381_pairing_wrong_input_layout() { + let ctx = bl12_381_pairing_test_tx(); + + let mut evm = ctx.build_op(); + let output = evm.replay().unwrap(); + + // assert fails post gas check, because input is wrong layout + assert!(matches!( + output.result, + ExecutionResult::Halt { + reason: OpHaltReason::Base(HaltReason::PrecompileError), + .. + } + )); + + compare_or_save_testdata( + "test_halted_tx_call_bls12_381_pairing_wrong_input_layout.json", + &output, + ); +} + +#[test] +fn test_halted_tx_call_bls12_381_map_fp_to_g1_out_of_gas() { + const SPEC_ID: OpSpecId = OpSpecId::ISTHMUS; + let input = Bytes::from([1; bls12_381_const::PADDED_FP_LENGTH]); + let InitialAndFloorGas { initial_gas, .. } = + calculate_initial_tx_gas(SPEC_ID.into(), &input[..], false, 0, 0, 0); + + let ctx = Context::op() + .with_tx( + OpTransaction::builder() + .base( + TxEnv::builder() + .kind(TxKind::Call(bls12_381_const::MAP_FP_TO_G1_ADDRESS)) + .data(input) + .gas_limit(initial_gas + bls12_381_const::MAP_FP_TO_G1_BASE_GAS_FEE - 1), + ) + .build_fill(), + ) + .modify_chain_chained(|l1_block| { + l1_block.operator_fee_constant = Some(U256::ZERO); + l1_block.operator_fee_scalar = Some(U256::ZERO) + }) + .modify_cfg_chained(|cfg| cfg.spec = SPEC_ID); + + let mut evm = ctx.build_op(); + let output = evm.replay().unwrap(); + + // assert out of gas + assert!(matches!( + output.result, + ExecutionResult::Halt { + reason: OpHaltReason::Base(HaltReason::OutOfGas(OutOfGasError::Precompile)), + .. + } + )); + + compare_or_save_testdata( + "test_halted_tx_call_bls12_381_map_fp_to_g1_out_of_gas.json", + &output, + ); +} + +#[test] +fn test_halted_tx_call_bls12_381_map_fp_to_g1_input_wrong_size() { + const SPEC_ID: OpSpecId = OpSpecId::ISTHMUS; + let input = Bytes::from([1; bls12_381_const::PADDED_FP_LENGTH]); + let InitialAndFloorGas { initial_gas, .. } = + calculate_initial_tx_gas(SPEC_ID.into(), &input[..], false, 0, 0, 0); + + let ctx = Context::op() + .with_tx( + OpTransaction::builder() + .base( + TxEnv::builder() + .kind(TxKind::Call(bls12_381_const::MAP_FP_TO_G1_ADDRESS)) + .data(input.slice(1..)) + .gas_limit(initial_gas + bls12_381_const::MAP_FP_TO_G1_BASE_GAS_FEE), + ) + .build_fill(), + ) + .modify_chain_chained(|l1_block| { + l1_block.operator_fee_constant = Some(U256::ZERO); + l1_block.operator_fee_scalar = Some(U256::ZERO) + }) + .modify_cfg_chained(|cfg| cfg.spec = SPEC_ID); + + let mut evm = ctx.build_op(); + let output = evm.replay().unwrap(); + + // assert fails post gas check, because input is wrong size + assert!(matches!( + output.result, + ExecutionResult::Halt { + reason: OpHaltReason::Base(HaltReason::PrecompileError), + .. + } + )); + + compare_or_save_testdata( + "test_halted_tx_call_bls12_381_map_fp_to_g1_input_wrong_size.json", + &output, + ); +} + +#[test] +fn test_halted_tx_call_bls12_381_map_fp2_to_g2_out_of_gas() { + const SPEC_ID: OpSpecId = OpSpecId::ISTHMUS; + let input = Bytes::from([1; bls12_381_const::PADDED_FP2_LENGTH]); + let InitialAndFloorGas { initial_gas, .. } = + calculate_initial_tx_gas(SPEC_ID.into(), &input[..], false, 0, 0, 0); + + let ctx = Context::op() + .with_tx( + OpTransaction::builder() + .base( + TxEnv::builder() + .kind(TxKind::Call(bls12_381_const::MAP_FP2_TO_G2_ADDRESS)) + .data(input) + .gas_limit(initial_gas + bls12_381_const::MAP_FP2_TO_G2_BASE_GAS_FEE - 1), + ) + .build_fill(), + ) + .modify_chain_chained(|l1_block| { + l1_block.operator_fee_constant = Some(U256::ZERO); + l1_block.operator_fee_scalar = Some(U256::ZERO) + }) + .modify_cfg_chained(|cfg| cfg.spec = SPEC_ID); + + let mut evm = ctx.build_op(); + let output = evm.replay().unwrap(); + + // assert out of gas + assert!(matches!( + output.result, + ExecutionResult::Halt { + reason: OpHaltReason::Base(HaltReason::OutOfGas(OutOfGasError::Precompile)), + .. + } + )); + + compare_or_save_testdata( + "test_halted_tx_call_bls12_381_map_fp2_to_g2_out_of_gas.json", + &output, + ); +} + +#[test] +fn test_halted_tx_call_bls12_381_map_fp2_to_g2_input_wrong_size() { + const SPEC_ID: OpSpecId = OpSpecId::ISTHMUS; + let input = Bytes::from([1; bls12_381_const::PADDED_FP2_LENGTH]); + let InitialAndFloorGas { initial_gas, .. } = + calculate_initial_tx_gas(SPEC_ID.into(), &input[..], false, 0, 0, 0); + + let ctx = Context::op() + .with_tx( + OpTransaction::builder() + .base( + TxEnv::builder() + .kind(TxKind::Call(bls12_381_const::MAP_FP2_TO_G2_ADDRESS)) + .data(input.slice(1..)) + .gas_limit(initial_gas + bls12_381_const::MAP_FP2_TO_G2_BASE_GAS_FEE), + ) + .build_fill(), + ) + .modify_chain_chained(|l1_block| { + l1_block.operator_fee_constant = Some(U256::ZERO); + l1_block.operator_fee_scalar = Some(U256::ZERO) + }) + .modify_cfg_chained(|cfg| cfg.spec = SPEC_ID); + + let mut evm = ctx.build_op(); + let output = evm.replay().unwrap(); + + // assert fails post gas check, because input is wrong size + assert!(matches!( + output.result, + ExecutionResult::Halt { + reason: OpHaltReason::Base(HaltReason::PrecompileError), + .. + } + )); + + compare_or_save_testdata( + "test_halted_tx_call_bls12_381_map_fp2_to_g2_input_wrong_size.json", + &output, + ); +} + +#[test] +#[cfg(feature = "optional_balance_check")] +fn test_disable_balance_check() { + const RETURN_CALLER_BALANCE_BYTECODE: &[u8] = &[ + opcode::CALLER, + opcode::BALANCE, + opcode::PUSH1, + 0x00, + opcode::MSTORE, + opcode::PUSH1, + 0x20, + opcode::PUSH1, + 0x00, + opcode::RETURN, + ]; + + let mut evm = Context::op() + .modify_cfg_chained(|cfg| cfg.disable_balance_check = true) + .with_db(BenchmarkDB::new_bytecode(Bytecode::new_legacy( + RETURN_CALLER_BALANCE_BYTECODE.into(), + ))) + .build_op(); + + // Construct tx so that effective cost is more than caller balance. + let gas_price = 1; + let gas_limit = 100_000; + // Make sure value doesn't consume all balance since we want to validate that all effective + // cost is deducted. + let tx_value = BENCH_CALLER_BALANCE - U256::from(1); + + let result = evm + .transact_one( + OpTransaction::builder() + .base( + TxEnv::builder_for_bench() + .gas_price(gas_price) + .gas_limit(gas_limit) + .value(tx_value), + ) + .build_fill(), + ) + .unwrap(); + + assert!(result.is_success()); + + let returned_balance = U256::from_be_slice(result.output().unwrap().as_ref()); + let expected_balance = U256::ZERO; + assert_eq!(returned_balance, expected_balance); +} + +#[derive(Default, Debug)] +struct LogInspector { + logs: Vec, +} + +impl Inspector for LogInspector { + fn log(&mut self, _interp: &mut Interpreter, _context: &mut CTX, log: Log) { + self.logs.push(log) + } +} + +#[test] +fn test_log_inspector() { + // simple yul contract emits a log in constructor + + /*object "Contract" { + code { + log0(0, 0) + } + }*/ + + let contract_data: Bytes = Bytes::from([ + opcode::PUSH1, + 0x00, + opcode::DUP1, + opcode::LOG0, + opcode::STOP, + ]); + let bytecode = Bytecode::new_raw(contract_data); + + let ctx = Context::op().with_db(BenchmarkDB::new_bytecode(bytecode.clone())); + + let mut evm = ctx.build_op_with_inspector(LogInspector::default()); + + let tx = OpTransaction::builder() + .base( + TxEnv::builder() + .caller(BENCH_CALLER) + .kind(TxKind::Call(BENCH_TARGET)), + ) + .build_fill(); + + // Run evm. + let output = evm.inspect_tx(tx).unwrap(); + + let inspector = &evm.0.inspector; + assert!(!inspector.logs.is_empty()); + + compare_or_save_testdata("test_log_inspector.json", &output); +} diff --git a/crates/op-revm/tests/testdata/template_test.json b/crates/op-revm/tests/testdata/template_test.json new file mode 100644 index 0000000000..5c35711ddd --- /dev/null +++ b/crates/op-revm/tests/testdata/template_test.json @@ -0,0 +1,14 @@ +{ + "result": { + "Success": { + "reason": "Stop", + "gas_used": 1000, + "gas_refunded": 0, + "logs": [], + "output": { + "Call": "0x040506" + } + } + }, + "state": {} +} \ No newline at end of file diff --git a/crates/op-revm/tests/testdata/test_deposit_tx.json b/crates/op-revm/tests/testdata/test_deposit_tx.json new file mode 100644 index 0000000000..c187d50833 --- /dev/null +++ b/crates/op-revm/tests/testdata/test_deposit_tx.json @@ -0,0 +1,40 @@ +{ + "result": { + "Success": { + "reason": "Stop", + "gas_used": 21000, + "gas_refunded": 0, + "logs": [], + "output": { + "Call": "0x" + } + } + }, + "state": { + "0x0000000000000000000000000000000000000000": { + "info": { + "balance": "0x64", + "nonce": 1, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + } + } +} \ No newline at end of file diff --git a/crates/op-revm/tests/testdata/test_halted_deposit_tx.json b/crates/op-revm/tests/testdata/test_halted_deposit_tx.json new file mode 100644 index 0000000000..8aac2ceb88 --- /dev/null +++ b/crates/op-revm/tests/testdata/test_halted_deposit_tx.json @@ -0,0 +1,62 @@ +{ + "result": { + "Halt": { + "reason": "FailedDeposit", + "gas_used": 16777216 + } + }, + "state": { + "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee": { + "info": { + "balance": "0x2386f26fc10064", + "nonce": 1, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched" + }, + "0xffffffffffffffffffffffffffffffffffffffff": { + "info": { + "balance": "0x2386f26fc10000", + "nonce": 1, + "code_hash": "0x7b2ab94bb7d45041581aa3757ae020084674ccad6f75dc3750eb2ea8a92c4e9a", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x5000", + "original_len": 1, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 1, + "data": [ + 0 + ] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Cold" + } + } +} \ No newline at end of file diff --git a/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_g1_add_input_wrong_size.json b/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_g1_add_input_wrong_size.json new file mode 100644 index 0000000000..5b5fc6861b --- /dev/null +++ b/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_g1_add_input_wrong_size.json @@ -0,0 +1,137 @@ +{ + "result": { + "Halt": { + "reason": { + "Base": "PrecompileError" + }, + "gas_used": 21375 + } + }, + "state": { + "0x420000000000000000000000000000000000001a": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x420000000000000000000000000000000000001b": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x4200000000000000000000000000000000000019": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x000000000000000000000000000000000000000b": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "LoadedAsNotExisting" + }, + "0x0000000000000000000000000000000000000000": { + "info": { + "balance": "0x0", + "nonce": 1, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + } + } +} \ No newline at end of file diff --git a/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_g1_add_out_of_gas.json b/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_g1_add_out_of_gas.json new file mode 100644 index 0000000000..5690b09303 --- /dev/null +++ b/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_g1_add_out_of_gas.json @@ -0,0 +1,139 @@ +{ + "result": { + "Halt": { + "reason": { + "Base": { + "OutOfGas": "Precompile" + } + }, + "gas_used": 21374 + } + }, + "state": { + "0x0000000000000000000000000000000000000000": { + "info": { + "balance": "0x0", + "nonce": 1, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x000000000000000000000000000000000000000b": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "LoadedAsNotExisting" + }, + "0x420000000000000000000000000000000000001b": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x420000000000000000000000000000000000001a": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x4200000000000000000000000000000000000019": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + } + } +} \ No newline at end of file diff --git a/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_g1_msm_input_wrong_size.json b/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_g1_msm_input_wrong_size.json new file mode 100644 index 0000000000..109343782b --- /dev/null +++ b/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_g1_msm_input_wrong_size.json @@ -0,0 +1,137 @@ +{ + "result": { + "Halt": { + "reason": { + "Base": "PrecompileError" + }, + "gas_used": 35560 + } + }, + "state": { + "0x420000000000000000000000000000000000001a": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x000000000000000000000000000000000000000c": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "LoadedAsNotExisting" + }, + "0x4200000000000000000000000000000000000019": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x420000000000000000000000000000000000001b": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x0000000000000000000000000000000000000000": { + "info": { + "balance": "0x0", + "nonce": 1, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + } + } +} \ No newline at end of file diff --git a/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_g1_msm_out_of_gas.json b/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_g1_msm_out_of_gas.json new file mode 100644 index 0000000000..38d133784c --- /dev/null +++ b/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_g1_msm_out_of_gas.json @@ -0,0 +1,139 @@ +{ + "result": { + "Halt": { + "reason": { + "Base": { + "OutOfGas": "Precompile" + } + }, + "gas_used": 35559 + } + }, + "state": { + "0x420000000000000000000000000000000000001a": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x420000000000000000000000000000000000001b": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x4200000000000000000000000000000000000019": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x000000000000000000000000000000000000000c": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "LoadedAsNotExisting" + }, + "0x0000000000000000000000000000000000000000": { + "info": { + "balance": "0x0", + "nonce": 1, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + } + } +} \ No newline at end of file diff --git a/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_g1_msm_wrong_input_layout.json b/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_g1_msm_wrong_input_layout.json new file mode 100644 index 0000000000..83fd20ba23 --- /dev/null +++ b/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_g1_msm_wrong_input_layout.json @@ -0,0 +1,137 @@ +{ + "result": { + "Halt": { + "reason": { + "Base": "PrecompileError" + }, + "gas_used": 35560 + } + }, + "state": { + "0x4200000000000000000000000000000000000019": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x000000000000000000000000000000000000000c": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "LoadedAsNotExisting" + }, + "0x0000000000000000000000000000000000000000": { + "info": { + "balance": "0x0", + "nonce": 1, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x420000000000000000000000000000000000001b": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x420000000000000000000000000000000000001a": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + } + } +} \ No newline at end of file diff --git a/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_g2_add_input_wrong_size.json b/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_g2_add_input_wrong_size.json new file mode 100644 index 0000000000..9b58339aba --- /dev/null +++ b/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_g2_add_input_wrong_size.json @@ -0,0 +1,137 @@ +{ + "result": { + "Halt": { + "reason": { + "Base": "PrecompileError" + }, + "gas_used": 21600 + } + }, + "state": { + "0x420000000000000000000000000000000000001b": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x000000000000000000000000000000000000000d": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "LoadedAsNotExisting" + }, + "0x420000000000000000000000000000000000001a": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x0000000000000000000000000000000000000000": { + "info": { + "balance": "0x0", + "nonce": 1, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x4200000000000000000000000000000000000019": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + } + } +} \ No newline at end of file diff --git a/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_g2_add_out_of_gas.json b/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_g2_add_out_of_gas.json new file mode 100644 index 0000000000..31d7f31de0 --- /dev/null +++ b/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_g2_add_out_of_gas.json @@ -0,0 +1,139 @@ +{ + "result": { + "Halt": { + "reason": { + "Base": { + "OutOfGas": "Precompile" + } + }, + "gas_used": 21599 + } + }, + "state": { + "0x420000000000000000000000000000000000001a": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x420000000000000000000000000000000000001b": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x000000000000000000000000000000000000000d": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "LoadedAsNotExisting" + }, + "0x4200000000000000000000000000000000000019": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x0000000000000000000000000000000000000000": { + "info": { + "balance": "0x0", + "nonce": 1, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + } + } +} \ No newline at end of file diff --git a/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_g2_msm_input_wrong_size.json b/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_g2_msm_input_wrong_size.json new file mode 100644 index 0000000000..d22cb09181 --- /dev/null +++ b/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_g2_msm_input_wrong_size.json @@ -0,0 +1,137 @@ +{ + "result": { + "Halt": { + "reason": { + "Base": "PrecompileError" + }, + "gas_used": 48108 + } + }, + "state": { + "0x0000000000000000000000000000000000000000": { + "info": { + "balance": "0x0", + "nonce": 1, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x420000000000000000000000000000000000001b": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x4200000000000000000000000000000000000019": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x420000000000000000000000000000000000001a": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x000000000000000000000000000000000000000e": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "LoadedAsNotExisting" + } + } +} \ No newline at end of file diff --git a/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_g2_msm_out_of_gas.json b/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_g2_msm_out_of_gas.json new file mode 100644 index 0000000000..60ab39f58c --- /dev/null +++ b/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_g2_msm_out_of_gas.json @@ -0,0 +1,139 @@ +{ + "result": { + "Halt": { + "reason": { + "Base": { + "OutOfGas": "Precompile" + } + }, + "gas_used": 48107 + } + }, + "state": { + "0x4200000000000000000000000000000000000019": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x420000000000000000000000000000000000001b": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x420000000000000000000000000000000000001a": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x000000000000000000000000000000000000000e": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "LoadedAsNotExisting" + }, + "0x0000000000000000000000000000000000000000": { + "info": { + "balance": "0x0", + "nonce": 1, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + } + } +} \ No newline at end of file diff --git a/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_g2_msm_wrong_input_layout.json b/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_g2_msm_wrong_input_layout.json new file mode 100644 index 0000000000..48c1006554 --- /dev/null +++ b/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_g2_msm_wrong_input_layout.json @@ -0,0 +1,137 @@ +{ + "result": { + "Halt": { + "reason": { + "Base": "PrecompileError" + }, + "gas_used": 48108 + } + }, + "state": { + "0x000000000000000000000000000000000000000e": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "LoadedAsNotExisting" + }, + "0x420000000000000000000000000000000000001a": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x0000000000000000000000000000000000000000": { + "info": { + "balance": "0x0", + "nonce": 1, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x4200000000000000000000000000000000000019": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x420000000000000000000000000000000000001b": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + } + } +} \ No newline at end of file diff --git a/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_map_fp2_to_g2_input_wrong_size.json b/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_map_fp2_to_g2_input_wrong_size.json new file mode 100644 index 0000000000..3e00f925e8 --- /dev/null +++ b/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_map_fp2_to_g2_input_wrong_size.json @@ -0,0 +1,137 @@ +{ + "result": { + "Halt": { + "reason": { + "Base": "PrecompileError" + }, + "gas_used": 46848 + } + }, + "state": { + "0x0000000000000000000000000000000000000000": { + "info": { + "balance": "0x0", + "nonce": 1, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x420000000000000000000000000000000000001b": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x4200000000000000000000000000000000000019": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x0000000000000000000000000000000000000011": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "LoadedAsNotExisting" + }, + "0x420000000000000000000000000000000000001a": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + } + } +} \ No newline at end of file diff --git a/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_map_fp2_to_g2_out_of_gas.json b/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_map_fp2_to_g2_out_of_gas.json new file mode 100644 index 0000000000..9152806db6 --- /dev/null +++ b/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_map_fp2_to_g2_out_of_gas.json @@ -0,0 +1,139 @@ +{ + "result": { + "Halt": { + "reason": { + "Base": { + "OutOfGas": "Precompile" + } + }, + "gas_used": 46847 + } + }, + "state": { + "0x0000000000000000000000000000000000000000": { + "info": { + "balance": "0x0", + "nonce": 1, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x420000000000000000000000000000000000001a": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x0000000000000000000000000000000000000011": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "LoadedAsNotExisting" + }, + "0x4200000000000000000000000000000000000019": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x420000000000000000000000000000000000001b": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + } + } +} \ No newline at end of file diff --git a/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_map_fp_to_g1_input_wrong_size.json b/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_map_fp_to_g1_input_wrong_size.json new file mode 100644 index 0000000000..db93c13ab6 --- /dev/null +++ b/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_map_fp_to_g1_input_wrong_size.json @@ -0,0 +1,137 @@ +{ + "result": { + "Halt": { + "reason": { + "Base": "PrecompileError" + }, + "gas_used": 27524 + } + }, + "state": { + "0x420000000000000000000000000000000000001b": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x0000000000000000000000000000000000000000": { + "info": { + "balance": "0x0", + "nonce": 1, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x0000000000000000000000000000000000000010": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "LoadedAsNotExisting" + }, + "0x420000000000000000000000000000000000001a": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x4200000000000000000000000000000000000019": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + } + } +} \ No newline at end of file diff --git a/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_map_fp_to_g1_out_of_gas.json b/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_map_fp_to_g1_out_of_gas.json new file mode 100644 index 0000000000..11a64278d3 --- /dev/null +++ b/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_map_fp_to_g1_out_of_gas.json @@ -0,0 +1,139 @@ +{ + "result": { + "Halt": { + "reason": { + "Base": { + "OutOfGas": "Precompile" + } + }, + "gas_used": 27523 + } + }, + "state": { + "0x0000000000000000000000000000000000000000": { + "info": { + "balance": "0x0", + "nonce": 1, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x4200000000000000000000000000000000000019": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x420000000000000000000000000000000000001b": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x420000000000000000000000000000000000001a": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x0000000000000000000000000000000000000010": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "LoadedAsNotExisting" + } + } +} \ No newline at end of file diff --git a/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_pairing_input_wrong_size.json b/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_pairing_input_wrong_size.json new file mode 100644 index 0000000000..001577b3a3 --- /dev/null +++ b/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_pairing_input_wrong_size.json @@ -0,0 +1,137 @@ +{ + "result": { + "Halt": { + "reason": { + "Base": "PrecompileError" + }, + "gas_used": 97444 + } + }, + "state": { + "0x0000000000000000000000000000000000000000": { + "info": { + "balance": "0x0", + "nonce": 1, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x000000000000000000000000000000000000000f": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "LoadedAsNotExisting" + }, + "0x420000000000000000000000000000000000001a": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x420000000000000000000000000000000000001b": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x4200000000000000000000000000000000000019": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + } + } +} \ No newline at end of file diff --git a/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_pairing_out_of_gas.json b/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_pairing_out_of_gas.json new file mode 100644 index 0000000000..628f248bd2 --- /dev/null +++ b/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_pairing_out_of_gas.json @@ -0,0 +1,139 @@ +{ + "result": { + "Halt": { + "reason": { + "Base": { + "OutOfGas": "Precompile" + } + }, + "gas_used": 97443 + } + }, + "state": { + "0x420000000000000000000000000000000000001b": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x000000000000000000000000000000000000000f": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "LoadedAsNotExisting" + }, + "0x4200000000000000000000000000000000000019": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x0000000000000000000000000000000000000000": { + "info": { + "balance": "0x0", + "nonce": 1, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x420000000000000000000000000000000000001a": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + } + } +} \ No newline at end of file diff --git a/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_pairing_wrong_input_layout.json b/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_pairing_wrong_input_layout.json new file mode 100644 index 0000000000..a7245cc245 --- /dev/null +++ b/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_pairing_wrong_input_layout.json @@ -0,0 +1,137 @@ +{ + "result": { + "Halt": { + "reason": { + "Base": "PrecompileError" + }, + "gas_used": 97444 + } + }, + "state": { + "0x4200000000000000000000000000000000000019": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x420000000000000000000000000000000000001a": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x420000000000000000000000000000000000001b": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x0000000000000000000000000000000000000000": { + "info": { + "balance": "0x0", + "nonce": 1, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x000000000000000000000000000000000000000f": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "LoadedAsNotExisting" + } + } +} \ No newline at end of file diff --git a/crates/op-revm/tests/testdata/test_halted_tx_call_bn128_pair_fjord.json b/crates/op-revm/tests/testdata/test_halted_tx_call_bn128_pair_fjord.json new file mode 100644 index 0000000000..eae5c631fa --- /dev/null +++ b/crates/op-revm/tests/testdata/test_halted_tx_call_bn128_pair_fjord.json @@ -0,0 +1,139 @@ +{ + "result": { + "Halt": { + "reason": { + "Base": { + "OutOfGas": "Precompile" + } + }, + "gas_used": 1824024 + } + }, + "state": { + "0x4200000000000000000000000000000000000019": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x420000000000000000000000000000000000001b": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x0000000000000000000000000000000000000000": { + "info": { + "balance": "0x0", + "nonce": 1, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x0000000000000000000000000000000000000008": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "LoadedAsNotExisting" + }, + "0x420000000000000000000000000000000000001a": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + } + } +} \ No newline at end of file diff --git a/crates/op-revm/tests/testdata/test_halted_tx_call_bn128_pair_granite.json b/crates/op-revm/tests/testdata/test_halted_tx_call_bn128_pair_granite.json new file mode 100644 index 0000000000..ce92b11014 --- /dev/null +++ b/crates/op-revm/tests/testdata/test_halted_tx_call_bn128_pair_granite.json @@ -0,0 +1,137 @@ +{ + "result": { + "Halt": { + "reason": { + "Base": "PrecompileError" + }, + "gas_used": 1824024 + } + }, + "state": { + "0x4200000000000000000000000000000000000019": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x420000000000000000000000000000000000001b": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x420000000000000000000000000000000000001a": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x0000000000000000000000000000000000000000": { + "info": { + "balance": "0x0", + "nonce": 1, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x0000000000000000000000000000000000000008": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "LoadedAsNotExisting" + } + } +} \ No newline at end of file diff --git a/crates/op-revm/tests/testdata/test_halted_tx_call_p256verify.json b/crates/op-revm/tests/testdata/test_halted_tx_call_p256verify.json new file mode 100644 index 0000000000..98a205f483 --- /dev/null +++ b/crates/op-revm/tests/testdata/test_halted_tx_call_p256verify.json @@ -0,0 +1,139 @@ +{ + "result": { + "Halt": { + "reason": { + "Base": { + "OutOfGas": "Precompile" + } + }, + "gas_used": 24449 + } + }, + "state": { + "0x0000000000000000000000000000000000000000": { + "info": { + "balance": "0x0", + "nonce": 1, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x0000000000000000000000000000000000000100": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "LoadedAsNotExisting" + }, + "0x420000000000000000000000000000000000001b": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x4200000000000000000000000000000000000019": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x420000000000000000000000000000000000001a": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + } + } +} \ No newline at end of file diff --git a/crates/op-revm/tests/testdata/test_log_inspector.json b/crates/op-revm/tests/testdata/test_log_inspector.json new file mode 100644 index 0000000000..04fbaf3a18 --- /dev/null +++ b/crates/op-revm/tests/testdata/test_log_inspector.json @@ -0,0 +1,173 @@ +{ + "result": { + "Success": { + "reason": "Stop", + "gas_used": 21381, + "gas_refunded": 0, + "logs": [ + { + "address": "0xffffffffffffffffffffffffffffffffffffffff", + "topics": [], + "data": "0x" + } + ], + "output": { + "Call": "0x" + } + } + }, + "state": { + "0xffffffffffffffffffffffffffffffffffffffff": { + "info": { + "balance": "0x2386f26fc10000", + "nonce": 1, + "code_hash": "0x8013c386d5a03c3fa0a6ccbfefcf7d91471dedba2bb94eefef57f916e5929a8d", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x600080a000", + "original_len": 5, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 5, + "data": [ + 0 + ] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched" + }, + "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee": { + "info": { + "balance": "0x2386f26fc10000", + "nonce": 1, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched" + }, + "0x0000000000000000000000000000000000000000": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x420000000000000000000000000000000000001a": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x420000000000000000000000000000000000001b": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x4200000000000000000000000000000000000019": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + } + } +} \ No newline at end of file diff --git a/crates/op-revm/tests/testdata/test_tx_call_p256verify.json b/crates/op-revm/tests/testdata/test_tx_call_p256verify.json new file mode 100644 index 0000000000..edca703816 --- /dev/null +++ b/crates/op-revm/tests/testdata/test_tx_call_p256verify.json @@ -0,0 +1,140 @@ +{ + "result": { + "Success": { + "reason": "Return", + "gas_used": 24450, + "gas_refunded": 0, + "logs": [], + "output": { + "Call": "0x" + } + } + }, + "state": { + "0x420000000000000000000000000000000000001b": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x4200000000000000000000000000000000000019": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x420000000000000000000000000000000000001a": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x0000000000000000000000000000000000000000": { + "info": { + "balance": "0x0", + "nonce": 1, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x0000000000000000000000000000000000000100": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + } + } +} \ No newline at end of file diff --git a/crates/precompile/CHANGELOG.md b/crates/precompile/CHANGELOG.md index ac868f2e44..c36189fd5c 100644 --- a/crates/precompile/CHANGELOG.md +++ b/crates/precompile/CHANGELOG.md @@ -6,6 +6,358 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [25.0.0](https://github.com/bluealloy/revm/compare/revm-precompile-v24.0.1...revm-precompile-v25.0.0) - 2025-07-23 + +### Added + +- *(precompiles)* Use bytes API for underlying precompile library APIs ([#2705](https://github.com/bluealloy/revm/pull/2705)) +- *(precompile)* update osaka modexp gas divisor ([#2740](https://github.com/bluealloy/revm/pull/2740)) +- *(precompile)* update p256 verify osaka gas cost ([#2741](https://github.com/bluealloy/revm/pull/2741)) +- add a way for precompiles to revert ([#2711](https://github.com/bluealloy/revm/pull/2711)) + +### Fixed + +- features and check in ci ([#2766](https://github.com/bluealloy/revm/pull/2766)) + +### Other + +- use `EncodedPoint` to decode uncompressed public key ([#2736](https://github.com/bluealloy/revm/pull/2736)) +- *(precompile)* refactor blake2 input parsing ([#2734](https://github.com/bluealloy/revm/pull/2734)) +- Add blake2 benchmarks ([#2735](https://github.com/bluealloy/revm/pull/2735)) +- add asm-sha2 feature for sha2 precompile ([#2712](https://github.com/bluealloy/revm/pull/2712)) + +## [24.0.1](https://github.com/bluealloy/revm/compare/revm-precompile-v24.0.0...revm-precompile-v24.0.1) - 2025-07-14 + +### Other + +- use c-kzg precompute value 8 ([#2698](https://github.com/bluealloy/revm/pull/2698)) + +## [24.0.0](https://github.com/bluealloy/revm/compare/revm-precompile-v23.0.0...revm-precompile-v24.0.0) - 2025-06-30 + +### Added + +- blake2 avx2 ([#2670](https://github.com/bluealloy/revm/pull/2670)) + +### Other + +- cargo clippy --fix --all ([#2671](https://github.com/bluealloy/revm/pull/2671)) + +## [23.0.0](https://github.com/bluealloy/revm/compare/revm-precompile-v22.0.0...revm-precompile-v23.0.0) - 2025-06-19 + +### Added + +- *(osaka)* modexp assume minimal base/mod length of 32 ([#2613](https://github.com/bluealloy/revm/pull/2613)) ([#2643](https://github.com/bluealloy/revm/pull/2643)) +- *(precompile)* rug/gmp-based modexp ([#2596](https://github.com/bluealloy/revm/pull/2596)) +- add basic tests for modexp ([#2603](https://github.com/bluealloy/revm/pull/2603)) +- enable P256 in Osaka ([#2601](https://github.com/bluealloy/revm/pull/2601)) + +### Other + +- bump all deps ([#2647](https://github.com/bluealloy/revm/pull/2647)) +- build less benchmark binaries ([#2629](https://github.com/bluealloy/revm/pull/2629)) + +## [22.0.0](https://github.com/bluealloy/revm/compare/revm-precompile-v21.0.0...revm-precompile-v22.0.0) - 2025-06-06 + +### Added + +- transact multi tx ([#2517](https://github.com/bluealloy/revm/pull/2517)) + +## [21.0.0](https://github.com/bluealloy/revm/compare/revm-precompile-v20.1.0...revm-precompile-v21.0.0) - 2025-05-22 + +### Added + +- *(Osaka)* modexp input limit and gas change, EIP-7823 and EIP-7883 ([#2531](https://github.com/bluealloy/revm/pull/2531)) + +### Other + +- make crates.io version badge clickable ([#2526](https://github.com/bluealloy/revm/pull/2526)) +- fixed dead link kzg_point_evaluation.rs ([#2508](https://github.com/bluealloy/revm/pull/2508)) + +## [20.1.0](https://github.com/bluealloy/revm/compare/revm-precompile-v20.0.0...revm-precompile-v20.1.0) - 2025-05-07 + +Dependency bump + +## [20.0.0](https://github.com/bluealloy/revm/compare/revm-precompile-v19.0.0...revm-precompile-v20.0.0) - 2025-05-07 + +### Added + +- skip cloning of call input from shared memory ([#2462](https://github.com/bluealloy/revm/pull/2462)) + +### Fixed + +- *(isthmus)* Add input size limitations to bls12-381 {G1/G2} MSM + pairing ([#2406](https://github.com/bluealloy/revm/pull/2406)) + +### Other + +- typos ([#2474](https://github.com/bluealloy/revm/pull/2474)) +- copy edit The Book ([#2463](https://github.com/bluealloy/revm/pull/2463)) +- make OPCODE_INFO a static ([#2459](https://github.com/bluealloy/revm/pull/2459)) +- bump dependency version ([#2431](https://github.com/bluealloy/revm/pull/2431)) +- fixed broken link ([#2421](https://github.com/bluealloy/revm/pull/2421)) +- *(docs)* precompile crate ([#2413](https://github.com/bluealloy/revm/pull/2413)) +- bump stable tests, introduce lints ([#2403](https://github.com/bluealloy/revm/pull/2403)) + +## [19.0.0](https://github.com/bluealloy/revm/compare/revm-precompile-v18.0.0...revm-precompile-v19.0.0) - 2025-04-09 + +### Other + +- fixed `EIP` to `RIP` ([#2388](https://github.com/bluealloy/revm/pull/2388)) +- *(precompile)* remove unused dependencies ([#2378](https://github.com/bluealloy/revm/pull/2378)) +- add 0x prefix to b256! and address! calls ([#2345](https://github.com/bluealloy/revm/pull/2345)) +- alloy 0.13 and kzg v2.1.0 ([#2342](https://github.com/bluealloy/revm/pull/2342)) + +## [18.0.0](https://github.com/bluealloy/revm/compare/revm-precompile-v17.0.0...revm-precompile-v18.0.0) - 2025-03-28 + +### Added + +- Add arkworks wrapper for bls12-381 ([#2316](https://github.com/bluealloy/revm/pull/2316)) +- Add a wrapper for arkworks for EIP196 ([#2305](https://github.com/bluealloy/revm/pull/2305)) + +### Other + +- [**breaking**] Move modulus constant into blst wrapper ([#2336](https://github.com/bluealloy/revm/pull/2336)) +- Remove TODO for NBITS and remove NBITS from blst MSM API ([#2337](https://github.com/bluealloy/revm/pull/2337)) +- remove no-std method for bls ([#2338](https://github.com/bluealloy/revm/pull/2338)) +- Move all benchmarks into their own module like eip2537 ([#2335](https://github.com/bluealloy/revm/pull/2335)) +- add bls12-381 benchmarks ([#2327](https://github.com/bluealloy/revm/pull/2327)) +- add encode_fp function ([#2328](https://github.com/bluealloy/revm/pull/2328)) +- clean up blst wrapper doc comment and types ([#2314](https://github.com/bluealloy/revm/pull/2314)) +- Move all blst related methods into blst wrapper ([#2313](https://github.com/bluealloy/revm/pull/2313)) +- Remove LATEST variant from SpecId enum ([#2299](https://github.com/bluealloy/revm/pull/2299)) + +## [17.0.0](https://github.com/bluealloy/revm/compare/revm-precompile-v17.0.0-alpha.7...revm-precompile-v17.0.0) - 2025-03-24 + +### Added + +- add bn_mul benchmark ([#2287](https://github.com/bluealloy/revm/pull/2287)) + +### Other + +- *(op-precompiles)* Add missing g2 add tests ([#2253](https://github.com/bluealloy/revm/pull/2253)) + +## [17.0.0-alpha.7](https://github.com/bluealloy/revm/compare/revm-precompile-v17.0.0-alpha.6...revm-precompile-v17.0.0-alpha.7) - 2025-03-21 + +### Added + +- Return Fatal error on bls precompiles if in no_std ([#2249](https://github.com/bluealloy/revm/pull/2249)) +- bls special case G1/G2_MUL ([#2248](https://github.com/bluealloy/revm/pull/2248)) +- Remove PrecompileError from PrecompileProvider ([#2233](https://github.com/bluealloy/revm/pull/2233)) + +### Other + +- add early exit for no-ops in EIP1962 and EIP2537 ([#2271](https://github.com/bluealloy/revm/pull/2271)) +- *(op-precompiles)* Check subset of l1 precompiles in op ([#2204](https://github.com/bluealloy/revm/pull/2204)) +- Add `g1_mul`, `g1_add` and `read_scalar` methods into substrate wrapper for bn128 ([#2264](https://github.com/bluealloy/revm/pull/2264)) +- *(op-precompiles)* clean up op tx tests ([#2242](https://github.com/bluealloy/revm/pull/2242)) +- Adds a wrapper around substrate-bn for EIP196 ([#2258](https://github.com/bluealloy/revm/pull/2258)) +- add invariant test for G1/G2 Mul ([#2247](https://github.com/bluealloy/revm/pull/2247)) +- add documentation for the gas related constants for EIP2537 ([#2246](https://github.com/bluealloy/revm/pull/2246)) +- add a safe blst wrapper ([#2223](https://github.com/bluealloy/revm/pull/2223)) +- Remove redundant bls12-381 constants and cleanup naming ([#2235](https://github.com/bluealloy/revm/pull/2235)) +- Add some documentation for the bls12-381 precompile constants ([#2222](https://github.com/bluealloy/revm/pull/2222)) + +## [17.0.0-alpha.6](https://github.com/bluealloy/revm/compare/revm-precompile-v17.0.0-alpha.5...revm-precompile-v17.0.0-alpha.6) - 2025-03-16 + +### Added + +- *(docs)* MyEvm example and book cleanup ([#2218](https://github.com/bluealloy/revm/pull/2218)) + +## [17.0.0-alpha.5](https://github.com/bluealloy/revm/compare/revm-precompile-v17.0.0-alpha.4...revm-precompile-v17.0.0-alpha.5) - 2025-03-12 + +### Other + +- updated the following local packages: revm-context-interface + +## [17.0.0-alpha.4](https://github.com/bluealloy/revm/compare/revm-precompile-v17.0.0-alpha.3...revm-precompile-v17.0.0-alpha.4) - 2025-03-11 + +### Fixed + +- correct propagate features ([#2177](https://github.com/bluealloy/revm/pull/2177)) + +### Other + +- *(precompile)* refactor out msm helper ([#2179](https://github.com/bluealloy/revm/pull/2179)) + +## [17.0.0-alpha.3](https://github.com/bluealloy/revm/compare/revm-precompile-v17.0.0-alpha.2...revm-precompile-v17.0.0-alpha.3) - 2025-03-10 + +### Fixed + +- *(precompiles)* add portable flag for bls ([#2174](https://github.com/bluealloy/revm/pull/2174)) + +### Other + +- v59 release-plz update ([#2170](https://github.com/bluealloy/revm/pull/2170)) + +## [17.0.0-alpha.2](https://github.com/bluealloy/revm/compare/revm-precompile-v17.0.0-alpha.1...revm-precompile-v17.0.0-alpha.2) - 2025-03-10 + +### Added + +- remove specification crate ([#2165](https://github.com/bluealloy/revm/pull/2165)) + +### Fixed + +- *(blst)* Fix blst wrong constants values and usage ([#2102](https://github.com/bluealloy/revm/pull/2102)) + +### Other + +- simplify bn128::run_pair ([#2137](https://github.com/bluealloy/revm/pull/2137)) +- export eip2930 eip7702 types from one place ([#2097](https://github.com/bluealloy/revm/pull/2097)) +- PrecompileErrors to PrecompileError ([#2103](https://github.com/bluealloy/revm/pull/2103)) +- Update broken link secp256r1.rs ([#2099](https://github.com/bluealloy/revm/pull/2099)) +- G1_msm base gas fee const correction ([#2100](https://github.com/bluealloy/revm/pull/2100)) +- Split blst constants out to individual file #2085 +- *(deps)* bump breaking deps ([#2093](https://github.com/bluealloy/revm/pull/2093)) +- move all dependencies to workspace ([#2092](https://github.com/bluealloy/revm/pull/2092)) + +## [17.0.0-alpha.1](https://github.com/bluealloy/revm/compare/revm-precompile-v16.1.0...revm-precompile-v17.0.0-alpha.1) - 2025-02-16 + +### Added + +- *(eip7702)* apply latest EIP-7702 changes, backport from v52 (#1969) +- integrate codspeed (#1935) +- Restucturing Part7 Handler and Context rework (#1865) +- restructuring Part6 transaction crate (#1814) +- restructure Part2 database crate (#1784) +- project restructuring Part1 (#1776) +- introducing EvmWiring, a chain-specific configuration (#1672) + +### Fixed + +- *(Inspector)* frame_end called multiple times (#2037) + +### Other + +- backport op l1 fetch perf (#2076) +- Bump licence year to 2025 (#2058) +- bump kzg.rs (#2002) +- align crates versions (#1983) +- blst reprice, remove g1/g2 mul (#1981) +- integrate rust-secp256k1 (#1915) +- fix comments and docs into more sensible (#1920) +- Rename PRAGUE_EOF to OSAKA (#1903) +- *(precompile)* use secp256k1 global context for ecrecover (#1843) +- fix some typos (#1800) +- Replace `PrecompileError` variant ([#1797](https://github.com/bluealloy/revm/pull/1797)) +- *(deps)* bump once_cell from 1.19.0 to 1.20.0 (#1773) + +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [16.1.0](https://github.com/bluealloy/revm/compare/revm-precompile-v16.0.0...revm-precompile-v16.1.0) - 2025-02-11 + +### Other + +- revm v19.4.0 tag v54 + +## [16.0.0](https://github.com/bluealloy/revm/compare/revm-precompile-v15.0.0...revm-precompile-v16.0.0) - 2024-12-26 + +### Added + +- blst reprice, remove g1/g2 mul, eest test bump ([#1951](https://github.com/bluealloy/revm/pull/1951)) +- add Isthmus spec ([#1948](https://github.com/bluealloy/revm/pull/1948)) + +## [15.0.0](https://github.com/bluealloy/revm/compare/revm-precompile-v14.0.0...revm-precompile-v15.0.0) - 2024-11-06 + +### Other + +- bump alloy-eip7702 and remove `Parity` re-export ([#1842](https://github.com/bluealloy/revm/pull/1842)) +- *(precompile)* use secp256k1 global context for ecrecover ([#1845](https://github.com/bluealloy/revm/pull/1845)) + +## [14.0.0](https://github.com/bluealloy/revm/compare/revm-precompile-v13.0.0...revm-precompile-v14.0.0) - 2024-10-23 + +### Other + +- updated the following local packages: revm-primitives + +## [13.0.0](https://github.com/bluealloy/revm/compare/revm-precompile-v12.0.0...revm-precompile-v13.0.0) - 2024-10-17 + +### Other + +- updated the following local packages: revm-primitives + +## [12.0.0](https://github.com/bluealloy/revm/compare/revm-precompile-v11.0.3...revm-precompile-v12.0.0) - 2024-10-17 + +### Added + +- Rename PRAGUE_EOF to OSAKA ([#1822](https://github.com/bluealloy/revm/pull/1822)) + +## [11.0.3](https://github.com/bluealloy/revm/compare/revm-precompile-v11.0.2...revm-precompile-v11.0.3) - 2024-09-26 + +### Other + +- updated the following local packages: revm-primitives + +## [11.0.2](https://github.com/bluealloy/revm/compare/revm-precompile-v11.0.1...revm-precompile-v11.0.2) - 2024-09-18 + +### Other + +- make clippy happy ([#1755](https://github.com/bluealloy/revm/pull/1755)) + +## [11.0.1](https://github.com/bluealloy/revm/compare/revm-precompile-v11.0.0...revm-precompile-v11.0.1) - 2024-08-30 + +### Other +- Bump new logo ([#1735](https://github.com/bluealloy/revm/pull/1735)) +- bump kzg-rs version ([#1734](https://github.com/bluealloy/revm/pull/1734)) + +## [10.1.0](https://github.com/bluealloy/revm/compare/revm-precompile-v10.0.0...revm-precompile-v10.1.0) - 2024-08-29 + +### Added +- c-kzg bump, cleanup on kzgsetting ([#1719](https://github.com/bluealloy/revm/pull/1719)) + +### Other +- bump `kzg-rs` version ([#1726](https://github.com/bluealloy/revm/pull/1726)) +- switch gas check order in blake2 precompile ([#1718](https://github.com/bluealloy/revm/pull/1718)) + +## [9.3.0](https://github.com/bluealloy/revm/compare/revm-precompile-v9.2.0...revm-precompile-v9.3.0) - 2024-08-08 + +### Added +- use batch bn256 pair operation ([#1643](https://github.com/bluealloy/revm/pull/1643)) + +### Other +- Add OP-Granite hardfork, limiting bn256Pairing input size ([#1685](https://github.com/bluealloy/revm/pull/1685)) +- *(deps)* bump rstest from 0.21.0 to 0.22.0 ([#1681](https://github.com/bluealloy/revm/pull/1681)) +- *(deps)* bump blst from 0.3.12 to 0.3.13 ([#1669](https://github.com/bluealloy/revm/pull/1669)) +- *(clippy)* 1.80 rust clippy list paragraph ident ([#1661](https://github.com/bluealloy/revm/pull/1661)) +- use `is_zero` for `U256` and `B256` ([#1638](https://github.com/bluealloy/revm/pull/1638)) + +## [9.1.0](https://github.com/bluealloy/revm/compare/revm-precompile-v9.0.0...revm-precompile-v9.1.0) - 2024-07-16 + +### Added +- use `kzg-rs` for kzg point evaluation ([#1558](https://github.com/bluealloy/revm/pull/1558)) + +### Other +- main CHANGELOG ([#1592](https://github.com/bluealloy/revm/pull/1592)) + +## [9.0.0](https://github.com/bluealloy/revm/compare/revm-precompile-v8.0.0...revm-precompile-v8.1.0) - 2024-07-08 + +### Added +- *(Precompiles)* Throw fatal error if c-kzg is disabled ([#1589](https://github.com/bluealloy/revm/pull/1589)) + +## [8.0.0](https://github.com/bluealloy/revm/compare/revm-precompile-v7.0.0...revm-precompile-v8.0.0) - 2024-06-20 + +### Added +- *(precompiles)* fatal error for precompiles ([#1499](https://github.com/bluealloy/revm/pull/1499)) +- add ecAdd to precompile bench ([#1496](https://github.com/bluealloy/revm/pull/1496)) +- *(optimism)* Add secp256r1 precompile for Fjord ([#1436](https://github.com/bluealloy/revm/pull/1436)) + +### Fixed +- *(eof)* fixture 2 tests ([#1550](https://github.com/bluealloy/revm/pull/1550)) +- check canonical Fp elements ([#1434](https://github.com/bluealloy/revm/pull/1434)) +- *(precompile)* ignore infinity points in G1 MSM ([#1432](https://github.com/bluealloy/revm/pull/1432)) +- *(precompile)* BLS G2 MSM ([#1428](https://github.com/bluealloy/revm/pull/1428)) + +### Other +- avoid cloning precompiles ([#1486](https://github.com/bluealloy/revm/pull/1486)) +- *(precompiles)* Fix some nits in bls12_381 ([#1495](https://github.com/bluealloy/revm/pull/1495)) +- *(deps)* allow multiple versions of secp256k1 ([#1490](https://github.com/bluealloy/revm/pull/1490)) +- *(deps)* bump rstest from 0.19.0 to 0.21.0 ([#1482](https://github.com/bluealloy/revm/pull/1482)) +- *(deps)* bump blst from 0.3.11 to 0.3.12 ([#1481](https://github.com/bluealloy/revm/pull/1481)) +- add test for map_fp_to_g1 precompile ([#1465](https://github.com/bluealloy/revm/pull/1465)) +- add docs for BLS scalar input decoding ([#1446](https://github.com/bluealloy/revm/pull/1446)) + ## [7.0.0](https://github.com/bluealloy/revm/compare/revm-precompile-v6.0.0...revm-precompile-v7.0.0) - 2024-05-12 ### Added diff --git a/crates/precompile/Cargo.toml b/crates/precompile/Cargo.toml index 08abf55bb6..450736a400 100644 --- a/crates/precompile/Cargo.toml +++ b/crates/precompile/Cargo.toml @@ -1,103 +1,139 @@ [package] -authors = ["Dragan Rakita "] -description = "revm Precompiles - Ethereum compatible precompiled contracts" -edition = "2021" -keywords = ["no_std", "ethereum", "evm", "revm", "precompiles"] -license = "MIT" name = "revm-precompile" -repository = "https://github.com/bluealloy/revm" -version = "7.0.0" +description = "Revm Precompiles - Ethereum compatible precompiled contracts" +version = "25.0.0" +authors.workspace = true +edition.workspace = true +keywords.workspace = true +license.workspace = true +repository.workspace = true +readme.workspace = true [package.metadata.docs.rs] all-features = true rustdoc-args = ["--cfg", "docsrs"] -[lints.rust] -unreachable_pub = "warn" -unused_must_use = "deny" -rust_2018_idioms = "deny" - -[lints.rustdoc] -all = "warn" +[lints] +workspace = true [dependencies] -revm-primitives = { path = "../primitives", version = "4.0.0", default-features = false } -bn = { package = "substrate-bn", version = "0.6", default-features = false } -once_cell = { version = "1.19", default-features = false, features = ["alloc"] } -ripemd = { version = "0.1", default-features = false } -sha2 = { version = "0.10", default-features = false } -# modexp precompile -aurora-engine-modexp = { version = "1.1", default-features = false } - -# Optional KZG point evaluation precompile -c-kzg = { version = "1.0.2", default-features = false, optional = true } - -# ecRecover precompile -k256 = { version = "0.13.3", default-features = false, features = ["ecdsa"] } -secp256k1 = { version = "0.29.0", default-features = false, features = [ - "alloc", - "recovery", - "rand", - "global-context", +# revm +primitives.workspace = true + +# modexp precompiles +aurora-engine-modexp.workspace = true +# gmp wrapper +rug = { workspace = true, features = ["integer"], optional = true } + +# static precompile sets. +once_cell = { workspace = true, features = ["alloc"] } + +# ecRecover +k256 = { workspace = true, features = ["ecdsa"] } +secp256k1 = { workspace = true, features = [ + "alloc", + "recovery", + "rand", + "global-context", +], optional = true } +libsecp256k1 = { workspace = true, features = [ + "static-context", ], optional = true } -# BLS12-381 precompiles -blst = { version = "0.3.11", optional = true } +# SHA2-256 and RIPEMD-160 +sha2.workspace = true +ripemd.workspace = true + +# Optionally use substrate implementation for eip1962 +bn = { workspace = true, optional = true } + +# Use arkworks implementation for eip1962 +ark-bn254 = { workspace = true, features = ["curve"] } +ark-ec = { workspace = true } +ark-ff = { workspace = true, features = ["asm"] } +ark-serialize = { workspace = true } + +# KZG point evaluation precompile +c-kzg = { workspace = true, optional = true, features = [ + "ethereum_kzg_settings", +] } + +# Optionally use `kzg-rs` for a pure Rust implementation of KZG point evaluation. +kzg-rs = { workspace = true, optional = true } + +# Use the BLS12-381 implementation of blst for EIP2537 +blst = { workspace = true, optional = true } + +# Use the BLS12-381 implementation of arkworks for EIP2537 +ark-bls12-381 = { workspace = true, features = ["curve"] } # p256verify precompile -p256 = { version = "0.13.2", optional = true, default-features = false, features = ["ecdsa"] } +p256 = { workspace = true, features = ["ecdsa"] } + +# utils +cfg-if.workspace = true +arrayref = "0.3.6" [dev-dependencies] -criterion = { version = "0.5" } -rand = { version = "0.8", features = ["std"] } -eyre = "0.6.12" -rstest = "0.19.0" -serde = "1.0" -serde_json = "1.0" -serde_derive = "1.0" +criterion.workspace = true +rand = { workspace = true, features = ["std"] } +ark-std = { workspace = true } +rstest.workspace = true [features] default = ["std", "c-kzg", "secp256k1", "portable", "blst"] std = [ - "revm-primitives/std", - "k256/std", - "once_cell/std", - "ripemd/std", - "sha2/std", - "c-kzg?/std", - "secp256k1?/std", -] -hashbrown = ["revm-primitives/hashbrown"] -asm-keccak = ["revm-primitives/asm-keccak"] - -optimism = ["revm-primitives/optimism", "secp256r1"] -# Optimism default handler enabled Optimism handler register by default in EvmBuilder. -optimism-default-handler = [ - "optimism", - "revm-primitives/optimism-default-handler", + "primitives/std", + "k256/std", + "once_cell/std", + "ripemd/std", + "sha2/std", + "c-kzg?/std", + "secp256k1?/std", + "libsecp256k1?/std", + "ark-bn254/std", + "ark-bls12-381/std", + "aurora-engine-modexp/std", + "ark-ec/std", + "ark-ff/std", + "ark-serialize/std", + "ark-std/std", + "p256/std", + "rug?/std", ] -negate-optimism-default-handler = [ - "revm-primitives/negate-optimism-default-handler", -] - -# Enables the p256verify precompile. -secp256r1 = ["dep:p256"] +hashbrown = ["primitives/hashbrown"] +asm-keccak = ["primitives/asm-keccak"] +asm-sha2 = ["sha2/asm"] # These libraries may not work on all no_std platforms as they depend on C. # Enables the KZG point evaluation precompile. -c-kzg = ["dep:c-kzg", "revm-primitives/c-kzg"] -portable = ["revm-primitives/portable", "c-kzg?/portable"] +c-kzg = ["dep:c-kzg"] +# `kzg-rs` is not audited but useful for `no_std` environment, use it with causing and default to `c-kzg` if possible. +kzg-rs = ["dep:kzg-rs"] + +# Compile in portable mode, without ISA extensions. +# Binary can be executed on all systems. +portable = ["c-kzg?/portable", "blst?/portable"] # Use `secp256k1` as a faster alternative to `k256`. # The problem that `secp256k1` has is it fails to build for `wasm` target on Windows and Mac as it is c lib. # In Linux it passes. If you don't require to build wasm on win/mac, it is safe to use it and it is enabled by default. secp256k1 = ["dep:secp256k1"] +libsecp256k1 = ["dep:libsecp256k1"] -# Enables the BLS12-381 precompiles. +# Enables the blst implementation of the BLS12-381 precompile. blst = ["dep:blst"] +# Enables the substrate implementation of eip1962 +bn = ["dep:bn"] + +# Use rug (that wraps gmp) for modexp precompile. +# It is faster library but licences as GPL code, if enabled please make sure to follow the license. +gmp = ["dep:rug"] + [[bench]] name = "bench" -path = "benches/bench.rs" +path = "bench/main.rs" harness = false +required-features = ["secp256k1"] diff --git a/crates/precompile/LICENSE b/crates/precompile/LICENSE index ad98ff22cc..be6d350ebe 100644 --- a/crates/precompile/LICENSE +++ b/crates/precompile/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2021-2024 draganrakita +Copyright (c) 2021-2025 draganrakita Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/crates/precompile/bench/blake2.rs b/crates/precompile/bench/blake2.rs new file mode 100644 index 0000000000..053552fad4 --- /dev/null +++ b/crates/precompile/bench/blake2.rs @@ -0,0 +1,116 @@ +use criterion::{black_box, BenchmarkGroup}; +use primitives::hex; +use revm_precompile::blake2; + +pub fn add_benches(group: &mut BenchmarkGroup<'_, criterion::measurement::WallTime>) { + // Test vectors from the blake2 test + let inputs = [ + hex!("0000000248c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001"), // 2 rounds + hex!("0000000448c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b616162636465666768696a6b6c6d6e6f700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001"), // 4 rounds + hex!("0000004048c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001"), // 64 rounds + hex!("0000000a48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001"), // 10 rounds (Blake2s standard) + hex!("0000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001"), // 12 rounds (Blake2b standard) + hex!("0000020048c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001"), // 512 rounds + hex!("0000040048c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001"), // 1024 rounds + hex!("000186a048c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001"), // 100000 rounds (100K) + hex!("00030d4048c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001"), // 200000 rounds (200K) + ]; + + // Benchmark with 2 rounds + group.bench_function("blake2/2_rounds", |b| { + let input = &inputs[0]; // 2 rounds + b.iter(|| { + black_box(blake2::run(black_box(input), u64::MAX).unwrap()); + }); + }); + + // Benchmark with 4 rounds + group.bench_function("blake2/4_rounds", |b| { + let input = &inputs[1]; // 4 rounds + b.iter(|| { + black_box(blake2::run(black_box(input), u64::MAX).unwrap()); + }); + }); + + // Benchmark with 64 rounds + group.bench_function("blake2/64_rounds", |b| { + let input = &inputs[2]; // 64 rounds + b.iter(|| { + black_box(blake2::run(black_box(input), u64::MAX).unwrap()); + }); + }); + + // Benchmark with 10 rounds (Blake2s standard) + group.bench_function("blake2/10_rounds", |b| { + let input = &inputs[3]; // 10 rounds + b.iter(|| { + black_box(blake2::run(black_box(input), u64::MAX).unwrap()); + }); + }); + + // Benchmark with 12 rounds (Blake2b standard) + group.bench_function("blake2/12_rounds", |b| { + let input = &inputs[4]; // 12 rounds + b.iter(|| { + black_box(blake2::run(black_box(input), u64::MAX).unwrap()); + }); + }); + + // Benchmark with 512 rounds + group.bench_function("blake2/512_rounds", |b| { + let input = &inputs[5]; // 512 rounds + b.iter(|| { + black_box(blake2::run(black_box(input), u64::MAX).unwrap()); + }); + }); + + // Benchmark with 1024 rounds + group.bench_function("blake2/1024_rounds", |b| { + let input = &inputs[6]; // 1024 rounds + b.iter(|| { + black_box(blake2::run(black_box(input), u64::MAX).unwrap()); + }); + }); + + // Benchmark with 100K rounds + group.bench_function("blake2/100K_rounds", |b| { + let input = &inputs[7]; // 100000 rounds + b.iter(|| { + black_box(blake2::run(black_box(input), u64::MAX).unwrap()); + }); + }); + + // Benchmark with 200K rounds + group.bench_function("blake2/200K_rounds", |b| { + let input = &inputs[8]; // 200000 rounds + b.iter(|| { + black_box(blake2::run(black_box(input), u64::MAX).unwrap()); + }); + }); + + // Benchmark just the compression function with different round counts + group.bench_function("blake2/compress_12_rounds", |b| { + let h = [ + 0x6a09e667f3bcc908u64, + 0xbb67ae8584caa73bu64, + 0x3c6ef372fe94f82bu64, + 0xa54ff53a5f1d36f1u64, + 0x510e527fade682d1u64, + 0x9b05688c2b3e6c1fu64, + 0x1f83d9abfb41bd6bu64, + 0x5be0cd19137e2179u64, + ]; + let m = [0u64; 16]; + let t = [0u64, 0u64]; + b.iter(|| { + let mut h_copy = h; + blake2::algo::compress( + black_box(12), + &mut h_copy, + black_box(m), + black_box(t), + black_box(false), + ); + }); + }); +} diff --git a/crates/precompile/bench/ecrecover.rs b/crates/precompile/bench/ecrecover.rs new file mode 100644 index 0000000000..dd2ff2fa5c --- /dev/null +++ b/crates/precompile/bench/ecrecover.rs @@ -0,0 +1,32 @@ +//! Benchmarks for the ecrecover precompile +use criterion::{measurement::Measurement, BenchmarkGroup}; +use primitives::{hex, keccak256, Bytes, U256}; +use revm_precompile::secp256k1::ec_recover_run; +use secp256k1::{Message, SecretKey, SECP256K1}; + +/// Add benches for the ecrecover precompile +pub fn add_benches(group: &mut BenchmarkGroup<'_, M>) { + // Generate secp256k1 signature + let data = hex::decode("1337133713371337").unwrap(); + let hash = keccak256(data); + let secret_key = SecretKey::new(&mut secp256k1::rand::rng()); + + let message = Message::from_digest_slice(&hash[..]).unwrap(); + let s = SECP256K1.sign_ecdsa_recoverable(message, &secret_key); + let (rec_id, data) = s.serialize_compact(); + let rec_id = i32::from(rec_id) as u8 + 27; + + let mut message_and_signature = [0u8; 128]; + message_and_signature[0..32].copy_from_slice(&hash[..]); + + // Fit signature into format the precompile expects + let rec_id = U256::from(rec_id as u64); + message_and_signature[32..64].copy_from_slice(&rec_id.to_be_bytes::<32>()); + message_and_signature[64..128].copy_from_slice(&data); + + let message_and_signature = Bytes::from(message_and_signature); + + group.bench_function("ecrecover precompile", |b| { + b.iter(|| ec_recover_run(&message_and_signature, u64::MAX).unwrap()) + }); +} diff --git a/crates/precompile/bench/eip1962.rs b/crates/precompile/bench/eip1962.rs new file mode 100644 index 0000000000..92b547da95 --- /dev/null +++ b/crates/precompile/bench/eip1962.rs @@ -0,0 +1,76 @@ +//! Benchmarks for the BN128 precompiles +use criterion::{measurement::Measurement, BenchmarkGroup}; +use primitives::hex; +use primitives::Bytes; +use revm_precompile::bn128::{ + add::ISTANBUL_ADD_GAS_COST, + mul::ISTANBUL_MUL_GAS_COST, + pair::{ISTANBUL_PAIR_BASE, ISTANBUL_PAIR_PER_POINT}, + run_add, run_mul, run_pair, +}; + +/// Add benches for the BN128 add precompile +pub fn add_bn128_add_benches(group: &mut BenchmarkGroup<'_, M>) { + let ecadd_input = hex::decode( + "\ + 18b18acfb4c2c30276db5411368e7185b311dd124691610c5d3b74034e093dc9\ + 063c909c4720840cb5134cb9f59fa749755796819658d32efc0d288198f37266\ + 07c2b7f58a84bd6145f00c9c2bc0bb1a187f20ff2c92963a88019e7c6a014eed\ + 06614e20c147e940f2d70da3f74c9a17df361706a4485c742bd6788478fa17d7", + ) + .unwrap(); + let input = Bytes::from(ecadd_input); + + group.bench_function("bn128 add precompile", |b| { + b.iter(|| run_add(&input, ISTANBUL_ADD_GAS_COST, 150).unwrap()) + }); +} + +/// Add benches for the BN128 mul precompile +pub fn add_bn128_mul_benches(group: &mut BenchmarkGroup<'_, M>) { + let ecmul_input = hex::decode( + "\ + 18b18acfb4c2c30276db5411368e7185b311dd124691610c5d3b74034e093dc9\ + 063c909c4720840cb5134cb9f59fa749755796819658d32efc0d288198f37266\ + 06614e20c147e940f2d70da3f74c9a17df361706a4485c742bd6788478fa17d7", + ) + .unwrap(); + let input = Bytes::from(ecmul_input); + + group.bench_function("bn128 mul precompile", |b| { + b.iter(|| run_mul(&input, ISTANBUL_MUL_GAS_COST, 6000).unwrap()) + }); +} + +/// Add benches for the BN128 pair precompile +pub fn add_bn128_pair_benches(group: &mut BenchmarkGroup<'_, M>) { + let ecpair_input = hex::decode( + "\ + 1c76476f4def4bb94541d57ebba1193381ffa7aa76ada664dd31c16024c43f59\ + 3034dd2920f673e204fee2811c678745fc819b55d3e9d294e45c9b03a76aef41\ + 209dd15ebff5d46c4bd888e51a93cf99a7329636c63514396b4a452003a35bf7\ + 04bf11ca01483bfa8b34b43561848d28905960114c8ac04049af4b6315a41678\ + 2bb8324af6cfc93537a2ad1a445cfd0ca2a71acd7ac41fadbf933c2a51be344d\ + 120a2a4cf30c1bf9845f20c6fe39e07ea2cce61f0c9bb048165fe5e4de877550\ + 111e129f1cf1097710d41c4ac70fcdfa5ba2023c6ff1cbeac322de49d1b6df7c\ + 2032c61a830e3c17286de9462bf242fca2883585b93870a73853face6a6bf411\ + 198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2\ + 1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed\ + 090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b\ + 12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", + ) + .unwrap(); + let input = Bytes::from(ecpair_input); + + group.bench_function("ecpairing precompile", |b| { + b.iter(|| { + run_pair( + &input, + ISTANBUL_PAIR_PER_POINT, + ISTANBUL_PAIR_BASE, + u64::MAX, + ) + .unwrap() + }) + }); +} diff --git a/crates/precompile/bench/eip2537.rs b/crates/precompile/bench/eip2537.rs new file mode 100644 index 0000000000..124ed82427 --- /dev/null +++ b/crates/precompile/bench/eip2537.rs @@ -0,0 +1,316 @@ +//! Benchmarks for the BLS12-381 precompiles +use ark_bls12_381::{Fq, Fr, G1Affine, G2Affine}; +use ark_ec::AffineRepr; +use ark_std::rand::{rngs::StdRng, SeedableRng}; +use arkworks_general::{encode_base_field, encode_field_32_bytes, random_field, random_points}; +use criterion::{measurement::Measurement, BenchmarkGroup}; +use primitives::Bytes; +use revm_precompile::bls12_381_const::{PADDED_FP_LENGTH, PADDED_G1_LENGTH, PADDED_G2_LENGTH}; + +const RNG_SEED: u64 = 42; +const MAX_MSM_SIZE: usize = 256; +const MAX_PAIRING_PAIRS: usize = 16; + +type PrecompileInput = Vec; + +mod arkworks_general { + use super::StdRng; + use ark_bls12_381::Fq; + use ark_ec::AffineRepr; + use ark_ff::Field; + + use ark_serialize::CanonicalSerialize; + use revm_precompile::bls12_381_const::{FP_LENGTH, FP_PAD_BY, PADDED_FP_LENGTH}; + + pub(super) fn random_points(num_points: usize, rng: &mut StdRng) -> Vec

{ + let mut points = Vec::new(); + for _ in 0..num_points { + points.push(P::rand(rng)); + } + points + } + + pub(super) fn random_field(num_scalars: usize, rng: &mut StdRng) -> Vec { + let mut points = Vec::new(); + for _ in 0..num_scalars { + points.push(F::rand(rng)); + } + points + } + + // Note: This is kept separate from encode_base_field since it's for Fr scalars (32 bytes) + // while encode_base_field is for Fq field elements (padded to 64 bytes) + pub(super) fn encode_field_32_bytes(field: &F) -> Vec { + let mut bytes_be = vec![0u8; 32]; + field + .serialize_uncompressed(&mut bytes_be[..]) + .expect("Failed to serialize field element"); + bytes_be.reverse(); + + bytes_be + } + + // Add padding to Fq field element and convert it to big endian (BE) format + pub(super) fn encode_base_field(fp: &Fq) -> Vec { + let mut bytes = [0u8; FP_LENGTH]; + fp.serialize_uncompressed(&mut bytes[..]) + .expect("Failed to serialize field element"); + bytes.reverse(); // Convert to big endian + + // Add padding + let mut padded_bytes = vec![0; PADDED_FP_LENGTH]; + padded_bytes[FP_PAD_BY..PADDED_FP_LENGTH].copy_from_slice(&bytes); + + padded_bytes + } +} + +/// Encode a BLS12-381 G1 point +// Note: This has been copied in from precompile/src/bls12_381 since +// those are not public +pub fn encode_bls12381_g1_point(input: &G1Affine) -> [u8; PADDED_G1_LENGTH] { + let mut output = [0u8; PADDED_G1_LENGTH]; + + let Some((x, y)) = input.xy() else { + return output; // Point at infinity, return all zeros + }; + + let x_encoded = encode_base_field(&x); + let y_encoded = encode_base_field(&y); + + // Copy the encoded values to the output + output[..PADDED_FP_LENGTH].copy_from_slice(&x_encoded); + output[PADDED_FP_LENGTH..].copy_from_slice(&y_encoded); + + output +} + +/// Encode a BLS12-381 G2 point +pub fn encode_bls12381_g2_point(input: &G2Affine) -> [u8; PADDED_G2_LENGTH] { + let mut output = [0u8; PADDED_G2_LENGTH]; + + let Some((x, y)) = input.xy() else { + return output; // Point at infinity, return all zeros + }; + + let x_c0_encoded = encode_base_field(&x.c0); + let x_c1_encoded = encode_base_field(&x.c1); + let y_c0_encoded = encode_base_field(&y.c0); + let y_c1_encoded = encode_base_field(&y.c1); + + // Copy encoded values to output + output[..PADDED_FP_LENGTH].copy_from_slice(&x_c0_encoded); + output[PADDED_FP_LENGTH..2 * PADDED_FP_LENGTH].copy_from_slice(&x_c1_encoded); + output[2 * PADDED_FP_LENGTH..3 * PADDED_FP_LENGTH].copy_from_slice(&y_c0_encoded); + output[3 * PADDED_FP_LENGTH..4 * PADDED_FP_LENGTH].copy_from_slice(&y_c1_encoded); + + output +} + +fn g1_add_test_vectors(num_test_vectors: usize, rng: &mut StdRng) -> Vec { + let num_g1_points = num_test_vectors * 2; + let points: Vec = random_points(num_g1_points, rng); + + points + .chunks_exact(2) + .map(|chunk| { + let lhs = chunk[0]; + let rhs = chunk[1]; + let mut g1_add_input = Vec::new(); + g1_add_input.extend(encode_bls12381_g1_point(&lhs)); + g1_add_input.extend(encode_bls12381_g1_point(&rhs)); + g1_add_input + }) + .collect() +} + +fn g2_add_test_vectors(num_test_vectors: usize, rng: &mut StdRng) -> Vec { + let num_g2_points = num_test_vectors * 2; + let points: Vec = random_points(num_g2_points, rng); + + points + .chunks_exact(2) + .map(|chunk| { + let lhs = chunk[0]; + let rhs = chunk[1]; + let mut g2_add_input = Vec::new(); + g2_add_input.extend(encode_bls12381_g2_point(&lhs)); + g2_add_input.extend(encode_bls12381_g2_point(&rhs)); + g2_add_input + }) + .collect() +} + +/// Add benches for the BLS12-381 G1 add precompile +pub fn add_g1_add_benches(group: &mut BenchmarkGroup<'_, M>) { + use revm_precompile::bls12_381::g1_add::PRECOMPILE; + + let mut rng = StdRng::seed_from_u64(RNG_SEED); + let test_vectors = g1_add_test_vectors(1, &mut rng); + let input = Bytes::from(test_vectors[0].clone()); + + let precompile = *PRECOMPILE.precompile(); + + group.bench_function("g1_add", |b| { + b.iter(|| precompile(&input, u64::MAX).unwrap()); + }); +} + +/// Add benches for the BLS12-381 G2 add precompile +pub fn add_g2_add_benches(group: &mut BenchmarkGroup<'_, M>) { + use revm_precompile::bls12_381::g2_add::PRECOMPILE; + + let mut rng = StdRng::seed_from_u64(RNG_SEED); + let test_vectors = g2_add_test_vectors(1, &mut rng); + let input = Bytes::from(test_vectors[0].clone()); + + let precompile = *PRECOMPILE.precompile(); + + group.bench_function("g2_add", |b| { + b.iter(|| precompile(&input, u64::MAX).unwrap()); + }); +} + +/// Add benches for the BLS12-381 G1 msm precompile +pub fn add_g1_msm_benches(group: &mut BenchmarkGroup<'_, M>) { + use revm_precompile::bls12_381::g1_msm::PRECOMPILE; + + let precompile = *PRECOMPILE.precompile(); + + let sizes_to_bench = [MAX_MSM_SIZE, MAX_MSM_SIZE / 2, 2, 1]; + + for size in sizes_to_bench { + let mut rng = StdRng::seed_from_u64(RNG_SEED); + let test_vector = g1_msm_test_vectors(size, &mut rng); + let input = Bytes::from(test_vector); + + group.bench_function(format!("g1_msm (size {size})"), |b| { + b.iter(|| precompile(&input, u64::MAX).unwrap()); + }); + } +} + +fn g1_msm_test_vectors(msm_size: usize, rng: &mut StdRng) -> PrecompileInput { + let points: Vec = random_points(msm_size, rng); + let scalars: Vec = random_field(msm_size, rng); + + let mut input = Vec::new(); + for (point, scalar) in points.iter().zip(scalars.iter()) { + input.extend(encode_bls12381_g1_point(point)); + input.extend(encode_field_32_bytes(scalar)); + } + + input +} + +fn g2_msm_test_vectors(msm_size: usize, rng: &mut StdRng) -> PrecompileInput { + let points: Vec = random_points(msm_size, rng); + let scalars: Vec = random_field(msm_size, rng); + + let mut input = Vec::new(); + for (point, scalar) in points.iter().zip(scalars.iter()) { + input.extend(encode_bls12381_g2_point(point)); + input.extend(encode_field_32_bytes(scalar)); + } + + input +} + +/// Add benches for the BLS12-381 G2 msm precompile +pub fn add_g2_msm_benches(group: &mut BenchmarkGroup<'_, M>) { + use revm_precompile::bls12_381::g2_msm::PRECOMPILE; + + let precompile = *PRECOMPILE.precompile(); + + let sizes_to_bench = [MAX_MSM_SIZE, MAX_MSM_SIZE / 2, 2, 1]; + + for size in sizes_to_bench { + let mut rng = StdRng::seed_from_u64(RNG_SEED); + let test_vector = g2_msm_test_vectors(size, &mut rng); + let input = Bytes::from(test_vector); + + group.bench_function(format!("g2_msm (size {size})"), |b| { + b.iter(|| precompile(&input, u64::MAX).unwrap()); + }); + } +} + +fn pairing_test_vectors(num_pairs: usize, rng: &mut StdRng) -> PrecompileInput { + // Generate random G1 and G2 points for pairing + let g1_points: Vec = random_points(num_pairs, rng); + let g2_points: Vec = random_points(num_pairs, rng); + + let mut input = Vec::new(); + for (g1, g2) in g1_points.iter().zip(g2_points.iter()) { + input.extend(encode_bls12381_g1_point(g1)); + input.extend(encode_bls12381_g2_point(g2)); + } + + input +} + +/// Add benches for the BLS12-381 pairing precompile +pub fn add_pairing_benches(group: &mut BenchmarkGroup<'_, M>) { + use revm_precompile::bls12_381::pairing::PRECOMPILE; + + let precompile = *PRECOMPILE.precompile(); + + let sizes_to_bench = [MAX_PAIRING_PAIRS, MAX_PAIRING_PAIRS / 2, 2, 1]; + + for pairs in sizes_to_bench { + let mut rng = StdRng::seed_from_u64(RNG_SEED); + let test_vector = pairing_test_vectors(pairs, &mut rng); + let input = Bytes::from(test_vector); + + group.bench_function(format!("pairing ({pairs} pairs)"), |b| { + b.iter(|| precompile(&input, u64::MAX).unwrap()); + }); + } +} + +fn map_fp_to_g1_test_vectors(rng: &mut StdRng) -> PrecompileInput { + let fp: Fq = random_field(1, rng)[0]; + encode_base_field(&fp) +} + +/// Add benches for the BLS12-381 map fp to g1 precompiles +pub fn add_map_fp_to_g1_benches(group: &mut BenchmarkGroup<'_, M>) { + use revm_precompile::bls12_381::map_fp_to_g1::PRECOMPILE; + + let mut rng = StdRng::seed_from_u64(RNG_SEED); + let test_vector = map_fp_to_g1_test_vectors(&mut rng); + let input = Bytes::from(test_vector); + + let precompile = *PRECOMPILE.precompile(); + + group.bench_function("map_fp_to_g1", |b| { + b.iter(|| precompile(&input, u64::MAX).unwrap()); + }); +} + +fn map_fp2_to_g2_test_vectors(rng: &mut StdRng) -> PrecompileInput { + let fp_c0: Fq = random_field(1, rng)[0]; + let fp_c1: Fq = random_field(1, rng)[0]; + + let mut input = Vec::new(); + + input.extend(encode_base_field(&fp_c0)); + input.extend(encode_base_field(&fp_c1)); + + input +} + +/// Add benches for the BLS12-381 map fp2 to g2 precompiles +pub fn add_map_fp2_to_g2_benches(group: &mut BenchmarkGroup<'_, M>) { + use revm_precompile::bls12_381::map_fp2_to_g2::PRECOMPILE; + + let mut rng = StdRng::seed_from_u64(RNG_SEED); + let test_vector = map_fp2_to_g2_test_vectors(&mut rng); + let input = Bytes::from(test_vector); + + let precompile = *PRECOMPILE.precompile(); + + group.bench_function("map_fp2_to_g2", |b| { + b.iter(|| precompile(&input, u64::MAX).unwrap()); + }); +} diff --git a/crates/precompile/bench/eip4844.rs b/crates/precompile/bench/eip4844.rs new file mode 100644 index 0000000000..c9c4a65c6e --- /dev/null +++ b/crates/precompile/bench/eip4844.rs @@ -0,0 +1,23 @@ +//! Benchmarks for the KZG point evaluation precompile +use criterion::{measurement::Measurement, BenchmarkGroup}; +use primitives::{eip4844::VERSIONED_HASH_VERSION_KZG, hex}; +use revm_precompile::kzg_point_evaluation::run; +use sha2::{Digest, Sha256}; + +/// Add benches for the KZG point evaluation precompile +pub fn add_benches(group: &mut BenchmarkGroup<'_, M>) { + // KZG Point Evaluation Precompile + let commitment = hex!("8f59a8d2a1a625a17f3fea0fe5eb8c896db3764f3185481bc22f91b4aaffcca25f26936857bc3a7c2539ea8ec3a952b7").to_vec(); + let mut versioned_hash = Sha256::digest(&commitment).to_vec(); + versioned_hash[0] = VERSIONED_HASH_VERSION_KZG; + let z = hex!("73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000000").to_vec(); + let y = hex!("1522a4a7f34e1ea350ae07c29c96c7e79655aa926122e95fe69fcbd932ca49e9").to_vec(); + let proof = hex!("a62ad71d14c5719385c0686f1871430475bf3a00f0aa3f7b8dd99a9abc2160744faf0070725e00b60ad9a026a15b1a8c").to_vec(); + + let kzg_input = [versioned_hash, z, y, commitment, proof].concat(); + let gas = 50000; + + group.bench_function("kzg precompile", |b| { + b.iter(|| run(&kzg_input, gas).unwrap()) + }); +} diff --git a/crates/precompile/bench/main.rs b/crates/precompile/bench/main.rs new file mode 100644 index 0000000000..153dc40ad1 --- /dev/null +++ b/crates/precompile/bench/main.rs @@ -0,0 +1,46 @@ +#![allow(missing_docs)] +//! Benchmarks for the crypto precompiles + +pub mod blake2; +pub mod ecrecover; +pub mod eip1962; +pub mod eip2537; +pub mod eip4844; + +use criterion::{criterion_group, criterion_main, Criterion}; + +/// Benchmarks different cryptography-related precompiles. +pub fn benchmark_crypto_precompiles(c: &mut Criterion) { + let mut group = c.benchmark_group("Crypto Precompile benchmarks"); + + // Run BLS12-381 benchmarks (EIP-2537) + eip2537::add_g1_add_benches(&mut group); + eip2537::add_g2_add_benches(&mut group); + eip2537::add_g1_msm_benches(&mut group); + eip2537::add_g2_msm_benches(&mut group); + eip2537::add_pairing_benches(&mut group); + eip2537::add_map_fp_to_g1_benches(&mut group); + eip2537::add_map_fp2_to_g2_benches(&mut group); + + // Run BN128 benchmarks + eip1962::add_bn128_add_benches(&mut group); + eip1962::add_bn128_mul_benches(&mut group); + eip1962::add_bn128_pair_benches(&mut group); + + // Run secp256k1 benchmarks + ecrecover::add_benches(&mut group); + + // Run KZG point evaluation benchmarks + eip4844::add_benches(&mut group); + + // Run Blake2 benchmarks + blake2::add_benches(&mut group); +} + +criterion_group! { + name = benches; + config = Criterion::default(); + targets = benchmark_crypto_precompiles +} + +criterion_main!(benches); diff --git a/crates/precompile/benches/bench.rs b/crates/precompile/benches/bench.rs deleted file mode 100644 index 48452b4abb..0000000000 --- a/crates/precompile/benches/bench.rs +++ /dev/null @@ -1,127 +0,0 @@ -use criterion::{black_box, criterion_group, criterion_main, Criterion}; -use revm_precompile::{ - bn128::{ - pair::{ISTANBUL_PAIR_BASE, ISTANBUL_PAIR_PER_POINT}, - run_pair, - }, - kzg_point_evaluation::run, - secp256k1::ec_recover_run, - Bytes, -}; -use revm_primitives::{hex, keccak256, Env, U256, VERSIONED_HASH_VERSION_KZG}; -use secp256k1::{Message, SecretKey, SECP256K1}; -use sha2::{Digest, Sha256}; - -/// Benchmarks different cryptography-related precompiles. -pub fn benchmark_crypto_precompiles(c: &mut Criterion) { - let mut group = c.benchmark_group("Crypto Precompile benchmarks"); - let group_name = |description: &str| format!("precompile bench | {description}"); - - // === ECPAIRING === - - // set up ecpairing input - let input = hex::decode( - "\ - 1c76476f4def4bb94541d57ebba1193381ffa7aa76ada664dd31c16024c43f59\ - 3034dd2920f673e204fee2811c678745fc819b55d3e9d294e45c9b03a76aef41\ - 209dd15ebff5d46c4bd888e51a93cf99a7329636c63514396b4a452003a35bf7\ - 04bf11ca01483bfa8b34b43561848d28905960114c8ac04049af4b6315a41678\ - 2bb8324af6cfc93537a2ad1a445cfd0ca2a71acd7ac41fadbf933c2a51be344d\ - 120a2a4cf30c1bf9845f20c6fe39e07ea2cce61f0c9bb048165fe5e4de877550\ - 111e129f1cf1097710d41c4ac70fcdfa5ba2023c6ff1cbeac322de49d1b6df7c\ - 2032c61a830e3c17286de9462bf242fca2883585b93870a73853face6a6bf411\ - 198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2\ - 1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed\ - 090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b\ - 12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", - ) - .unwrap(); - - let res = run_pair( - &input, - ISTANBUL_PAIR_PER_POINT, - ISTANBUL_PAIR_BASE, - u64::MAX, - ) - .unwrap() - .0; - - println!("gas used by regular pairing call: {:?}", res); - - // === ECRECOVER === - - // generate secp256k1 signature - let data = hex::decode("1337133713371337").unwrap(); - let hash = keccak256(data); - let secret_key = SecretKey::new(&mut rand::thread_rng()); - - let message = Message::from_digest_slice(&hash[..]).unwrap(); - let s = SECP256K1.sign_ecdsa_recoverable(&message, &secret_key); - let (rec_id, data) = s.serialize_compact(); - let mut rec_id = rec_id.to_i32() as u8; - assert_eq!(rec_id, 0); - rec_id += 27; - - let mut message_and_signature = [0u8; 128]; - message_and_signature[0..32].copy_from_slice(&hash[..]); - - // fit signature into format the precompile expects - let rec_id = U256::from(rec_id as u64); - message_and_signature[32..64].copy_from_slice(&rec_id.to_be_bytes::<32>()); - message_and_signature[64..128].copy_from_slice(&data); - - let message_and_signature = Bytes::from(message_and_signature); - let gas = ec_recover_run(&message_and_signature, u64::MAX).unwrap(); - println!("gas used by ecrecover precompile: {:?}", gas); - - // === POINT_EVALUATION === - - // now check kzg precompile gas - let commitment = hex!("8f59a8d2a1a625a17f3fea0fe5eb8c896db3764f3185481bc22f91b4aaffcca25f26936857bc3a7c2539ea8ec3a952b7").to_vec(); - let mut versioned_hash = Sha256::digest(&commitment).to_vec(); - versioned_hash[0] = VERSIONED_HASH_VERSION_KZG; - let z = hex!("73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000000").to_vec(); - let y = hex!("1522a4a7f34e1ea350ae07c29c96c7e79655aa926122e95fe69fcbd932ca49e9").to_vec(); - let proof = hex!("a62ad71d14c5719385c0686f1871430475bf3a00f0aa3f7b8dd99a9abc2160744faf0070725e00b60ad9a026a15b1a8c").to_vec(); - - let kzg_input = [versioned_hash, z, y, commitment, proof].concat().into(); - - let gas = 50000; - let env = Env::default(); - let (actual_gas, _actual_output) = run(&kzg_input, gas, &env).unwrap(); - println!("gas used by kzg precompile: {:?}", actual_gas); - - group.bench_function(group_name("ecrecover precompile"), |b| { - b.iter(|| { - ec_recover_run(&message_and_signature, u64::MAX).unwrap(); - black_box(()) - }) - }); - - group.bench_function(group_name("ecpairing precompile"), |b| { - b.iter(|| { - run_pair( - &input, - ISTANBUL_PAIR_PER_POINT, - ISTANBUL_PAIR_BASE, - u64::MAX, - ) - .unwrap(); - black_box(()) - }) - }); - - group.bench_function(group_name("kzg precompile"), |b| { - b.iter(|| { - run(&kzg_input, gas, &env).unwrap(); - black_box(()) - }) - }); -} - -criterion_group! { - name = benches; - config = Criterion::default(); - targets = benchmark_crypto_precompiles -} -criterion_main!(benches); diff --git a/crates/precompile/src/blake2.rs b/crates/precompile/src/blake2.rs index 057bba74d4..6c446152a9 100644 --- a/crates/precompile/src/blake2.rs +++ b/crates/precompile/src/blake2.rs @@ -1,59 +1,68 @@ -use crate::{Error, Precompile, PrecompileResult, PrecompileWithAddress}; -use revm_primitives::Bytes; +//! Blake2 precompile. More details in [`run`] + +use crate::{PrecompileError, PrecompileOutput, PrecompileResult, PrecompileWithAddress}; const F_ROUND: u64 = 1; const INPUT_LENGTH: usize = 213; -pub const FUN: PrecompileWithAddress = - PrecompileWithAddress(crate::u64_to_address(9), Precompile::Standard(run)); +/// Blake2 precompile +pub const FUN: PrecompileWithAddress = PrecompileWithAddress(crate::u64_to_address(9), run); /// reference: /// input format: /// [4 bytes for rounds][64 bytes for h][128 bytes for m][8 bytes for t_0][8 bytes for t_1][1 byte for f] -pub fn run(input: &Bytes, gas_limit: u64) -> PrecompileResult { - let input = &input[..]; - +pub fn run(input: &[u8], gas_limit: u64) -> PrecompileResult { if input.len() != INPUT_LENGTH { - return Err(Error::Blake2WrongLength); + return Err(PrecompileError::Blake2WrongLength); } - let f = match input[212] { - 1 => true, - 0 => false, - _ => return Err(Error::Blake2WrongFinalIndicatorFlag), - }; - - // rounds 4 bytes + // Parse number of rounds (4 bytes) let rounds = u32::from_be_bytes(input[..4].try_into().unwrap()) as usize; let gas_used = rounds as u64 * F_ROUND; if gas_used > gas_limit { - return Err(Error::OutOfGas); + return Err(PrecompileError::OutOfGas); } + // Parse final block flag + let f = match input[212] { + 0 => false, + 1 => true, + _ => return Err(PrecompileError::Blake2WrongFinalIndicatorFlag), + }; + + // Parse state vector h (8 × u64) let mut h = [0u64; 8]; + input[4..68] + .chunks_exact(8) + .enumerate() + .for_each(|(i, chunk)| { + h[i] = u64::from_le_bytes(chunk.try_into().unwrap()); + }); + + // Parse message block m (16 × u64) let mut m = [0u64; 16]; + input[68..196] + .chunks_exact(8) + .enumerate() + .for_each(|(i, chunk)| { + m[i] = u64::from_le_bytes(chunk.try_into().unwrap()); + }); - for (i, pos) in (4..68).step_by(8).enumerate() { - h[i] = u64::from_le_bytes(input[pos..pos + 8].try_into().unwrap()); - } - for (i, pos) in (68..196).step_by(8).enumerate() { - m[i] = u64::from_le_bytes(input[pos..pos + 8].try_into().unwrap()); - } - let t = [ - u64::from_le_bytes(input[196..196 + 8].try_into().unwrap()), - u64::from_le_bytes(input[204..204 + 8].try_into().unwrap()), - ]; + // Parse offset counters + let t_0 = u64::from_le_bytes(input[196..204].try_into().unwrap()); + let t_1 = u64::from_le_bytes(input[204..212].try_into().unwrap()); - algo::compress(rounds, &mut h, m, t, f); + algo::compress(rounds, &mut h, m, [t_0, t_1], f); let mut out = [0u8; 64]; for (i, h) in (0..64).step_by(8).zip(h.iter()) { out[i..i + 8].copy_from_slice(&h.to_le_bytes()); } - Ok((gas_used, out.into())) + Ok(PrecompileOutput::new(gas_used, out.into())) } +/// Blake2 algorithm pub mod algo { /// SIGMA from spec: pub const SIGMA: [[usize; 16]; 10] = [ @@ -81,28 +90,60 @@ pub mod algo { 0x5be0cd19137e2179, ]; - #[inline] + #[inline(always)] #[allow(clippy::many_single_char_names)] /// G function: - pub fn g(v: &mut [u64], a: usize, b: usize, c: usize, d: usize, x: u64, y: u64) { - v[a] = v[a].wrapping_add(v[b]).wrapping_add(x); - v[d] = (v[d] ^ v[a]).rotate_right(32); - v[c] = v[c].wrapping_add(v[d]); - v[b] = (v[b] ^ v[c]).rotate_right(24); - v[a] = v[a].wrapping_add(v[b]).wrapping_add(y); - v[d] = (v[d] ^ v[a]).rotate_right(16); - v[c] = v[c].wrapping_add(v[d]); - v[b] = (v[b] ^ v[c]).rotate_right(63); - } - - // Compression function F takes as an argument the state vector "h", - // message block vector "m" (last block is padded with zeros to full - // block size, if required), 2w-bit offset counter "t", and final block - // indicator flag "f". Local vector v[0..15] is used in processing. F - // returns a new state vector. The number of rounds, "r", is 12 for - // BLAKE2b and 10 for BLAKE2s. Rounds are numbered from 0 to r - 1. + fn g(v: &mut [u64; 16], a: usize, b: usize, c: usize, d: usize, x: u64, y: u64) { + let mut va = v[a]; + let mut vb = v[b]; + let mut vc = v[c]; + let mut vd = v[d]; + + va = va.wrapping_add(vb).wrapping_add(x); + vd = (vd ^ va).rotate_right(32); + vc = vc.wrapping_add(vd); + vb = (vb ^ vc).rotate_right(24); + + va = va.wrapping_add(vb).wrapping_add(y); + vd = (vd ^ va).rotate_right(16); + vc = vc.wrapping_add(vd); + vb = (vb ^ vc).rotate_right(63); + + v[a] = va; + v[b] = vb; + v[c] = vc; + v[d] = vd; + } + + /// Compression function F takes as an argument the state vector "h", + /// message block vector "m" (last block is padded with zeros to full + /// block size, if required), 2w-bit offset counter "t", and final block + /// indicator flag "f". Local vector v[0..15] is used in processing. F + /// returns a new state vector. The number of rounds, "r", is 12 for + /// BLAKE2b and 10 for BLAKE2s. Rounds are numbered from 0 to r - 1. #[allow(clippy::many_single_char_names)] pub fn compress(rounds: usize, h: &mut [u64; 8], m: [u64; 16], t: [u64; 2], f: bool) { + #[cfg(all(target_feature = "avx2", feature = "std"))] + { + // only if it is compiled with avx2 flag and it is std, we can use avx2. + if std::is_x86_feature_detected!("avx2") { + // avx2 is 1.8x more performant than portable implementation. + unsafe { + super::avx2::compress_block( + rounds, + &m, + h, + ((t[1] as u128) << 64) | (t[0] as u128), + if f { !0 } else { 0 }, + 0, + ); + } + return; + } + } + + // if avx2 is not available, use the fallback portable implementation + let mut v = [0u64; 16]; v[..h.len()].copy_from_slice(h); // First half from state. v[h.len()..].copy_from_slice(&IV); // Second half from IV. @@ -114,21 +155,492 @@ pub mod algo { v[14] = !v[14] // Invert all bits if the last-block-flag is set. } for i in 0..rounds { - // Message word selection permutation for this round. - let s = &SIGMA[i % 10]; - g(&mut v, 0, 4, 8, 12, m[s[0]], m[s[1]]); - g(&mut v, 1, 5, 9, 13, m[s[2]], m[s[3]]); - g(&mut v, 2, 6, 10, 14, m[s[4]], m[s[5]]); - g(&mut v, 3, 7, 11, 15, m[s[6]], m[s[7]]); - - g(&mut v, 0, 5, 10, 15, m[s[8]], m[s[9]]); - g(&mut v, 1, 6, 11, 12, m[s[10]], m[s[11]]); - g(&mut v, 2, 7, 8, 13, m[s[12]], m[s[13]]); - g(&mut v, 3, 4, 9, 14, m[s[14]], m[s[15]]); + round(&mut v, &m, i); } for i in 0..8 { h[i] ^= v[i] ^ v[i + 8]; } } + + #[inline(always)] + fn round(v: &mut [u64; 16], m: &[u64; 16], r: usize) { + // Message word selection permutation for this round. + let s = &SIGMA[r % 10]; + // g1 + g(v, 0, 4, 8, 12, m[s[0]], m[s[1]]); + g(v, 1, 5, 9, 13, m[s[2]], m[s[3]]); + g(v, 2, 6, 10, 14, m[s[4]], m[s[5]]); + g(v, 3, 7, 11, 15, m[s[6]], m[s[7]]); + + // g2 + g(v, 0, 5, 10, 15, m[s[8]], m[s[9]]); + g(v, 1, 6, 11, 12, m[s[10]], m[s[11]]); + g(v, 2, 7, 8, 13, m[s[12]], m[s[13]]); + g(v, 3, 4, 9, 14, m[s[14]], m[s[15]]); + } +} + +// Adapted from https://github.com/rust-lang-nursery/stdsimd/pull/479. +macro_rules! _MM_SHUFFLE { + ($z:expr, $y:expr, $x:expr, $w:expr) => { + ($z << 6) | ($y << 4) | ($x << 2) | $w + }; +} + +/// Code adapted from https://github.com/oconnor663/blake2_simd/blob/82b3e2aee4d2384aabbeb146058301ff0dbd453f/blake2b/src/avx2.rs +#[cfg(all(target_feature = "avx2", feature = "std"))] +mod avx2 { + #[cfg(target_arch = "x86")] + use core::arch::x86::*; + #[cfg(target_arch = "x86_64")] + use core::arch::x86_64::*; + + use super::algo::IV; + use arrayref::{array_refs, mut_array_refs}; + + type Word = u64; + type Count = u128; + /// The number input bytes passed to each call to the compression function. Small benchmarks need + /// to use an even multiple of `BLOCKBYTES`, or else their apparent throughput will be low. + const BLOCKBYTES: usize = 16 * size_of::(); + + const DEGREE: usize = 4; + + /// Compress a block of data using the BLAKE2 algorithm. + #[inline(always)] + pub(crate) unsafe fn compress_block( + mut rounds: usize, + block: &[Word; 16], + words: &mut [Word; 8], + count: Count, + last_block: Word, + last_node: Word, + ) { + let (words_low, words_high) = mut_array_refs!(words, DEGREE, DEGREE); + let (iv_low, iv_high) = array_refs!(&IV, DEGREE, DEGREE); + let mut a = loadu(words_low); + let mut b = loadu(words_high); + let mut c = loadu(iv_low); + let flags = set4(count_low(count), count_high(count), last_block, last_node); + let mut d = xor(loadu(iv_high), flags); + + let block: &[u8; BLOCKBYTES] = std::mem::transmute(block); + let msg_chunks = array_refs!(block, 16, 16, 16, 16, 16, 16, 16, 16); + let m0 = _mm256_broadcastsi128_si256(loadu_128(msg_chunks.0)); + let m1 = _mm256_broadcastsi128_si256(loadu_128(msg_chunks.1)); + let m2 = _mm256_broadcastsi128_si256(loadu_128(msg_chunks.2)); + let m3 = _mm256_broadcastsi128_si256(loadu_128(msg_chunks.3)); + let m4 = _mm256_broadcastsi128_si256(loadu_128(msg_chunks.4)); + let m5 = _mm256_broadcastsi128_si256(loadu_128(msg_chunks.5)); + let m6 = _mm256_broadcastsi128_si256(loadu_128(msg_chunks.6)); + let m7 = _mm256_broadcastsi128_si256(loadu_128(msg_chunks.7)); + + let iv0 = a; + let iv1 = b; + let mut t0; + let mut t1; + let mut b0; + + loop { + if rounds == 0 { + break; + } + rounds -= 1; + + // round 1 + t0 = _mm256_unpacklo_epi64(m0, m1); + t1 = _mm256_unpacklo_epi64(m2, m3); + b0 = _mm256_blend_epi32(t0, t1, 0xF0); + g1(&mut a, &mut b, &mut c, &mut d, &mut b0); + t0 = _mm256_unpackhi_epi64(m0, m1); + t1 = _mm256_unpackhi_epi64(m2, m3); + b0 = _mm256_blend_epi32(t0, t1, 0xF0); + g2(&mut a, &mut b, &mut c, &mut d, &mut b0); + diagonalize(&mut a, &mut b, &mut c, &mut d); + t0 = _mm256_unpacklo_epi64(m7, m4); + t1 = _mm256_unpacklo_epi64(m5, m6); + b0 = _mm256_blend_epi32(t0, t1, 0xF0); + g1(&mut a, &mut b, &mut c, &mut d, &mut b0); + t0 = _mm256_unpackhi_epi64(m7, m4); + t1 = _mm256_unpackhi_epi64(m5, m6); + b0 = _mm256_blend_epi32(t0, t1, 0xF0); + g2(&mut a, &mut b, &mut c, &mut d, &mut b0); + undiagonalize(&mut a, &mut b, &mut c, &mut d); + + if rounds == 0 { + break; + } + rounds -= 1; + + // round 2 + t0 = _mm256_unpacklo_epi64(m7, m2); + t1 = _mm256_unpackhi_epi64(m4, m6); + b0 = _mm256_blend_epi32(t0, t1, 0xF0); + g1(&mut a, &mut b, &mut c, &mut d, &mut b0); + t0 = _mm256_unpacklo_epi64(m5, m4); + t1 = _mm256_alignr_epi8(m3, m7, 8); + b0 = _mm256_blend_epi32(t0, t1, 0xF0); + g2(&mut a, &mut b, &mut c, &mut d, &mut b0); + diagonalize(&mut a, &mut b, &mut c, &mut d); + t0 = _mm256_unpackhi_epi64(m2, m0); + t1 = _mm256_blend_epi32(m5, m0, 0x33); + b0 = _mm256_blend_epi32(t0, t1, 0xF0); + g1(&mut a, &mut b, &mut c, &mut d, &mut b0); + t0 = _mm256_alignr_epi8(m6, m1, 8); + t1 = _mm256_blend_epi32(m3, m1, 0x33); + b0 = _mm256_blend_epi32(t0, t1, 0xF0); + g2(&mut a, &mut b, &mut c, &mut d, &mut b0); + undiagonalize(&mut a, &mut b, &mut c, &mut d); + + if rounds == 0 { + break; + } + rounds -= 1; + + // round 3 + t0 = _mm256_alignr_epi8(m6, m5, 8); + t1 = _mm256_unpackhi_epi64(m2, m7); + b0 = _mm256_blend_epi32(t0, t1, 0xF0); + g1(&mut a, &mut b, &mut c, &mut d, &mut b0); + t0 = _mm256_unpacklo_epi64(m4, m0); + t1 = _mm256_blend_epi32(m6, m1, 0x33); + b0 = _mm256_blend_epi32(t0, t1, 0xF0); + g2(&mut a, &mut b, &mut c, &mut d, &mut b0); + diagonalize(&mut a, &mut b, &mut c, &mut d); + t0 = _mm256_alignr_epi8(m5, m4, 8); + t1 = _mm256_unpackhi_epi64(m1, m3); + b0 = _mm256_blend_epi32(t0, t1, 0xF0); + g1(&mut a, &mut b, &mut c, &mut d, &mut b0); + t0 = _mm256_unpacklo_epi64(m2, m7); + t1 = _mm256_blend_epi32(m0, m3, 0x33); + b0 = _mm256_blend_epi32(t0, t1, 0xF0); + g2(&mut a, &mut b, &mut c, &mut d, &mut b0); + undiagonalize(&mut a, &mut b, &mut c, &mut d); + + if rounds == 0 { + break; + } + rounds -= 1; + + // round 4 + t0 = _mm256_unpackhi_epi64(m3, m1); + t1 = _mm256_unpackhi_epi64(m6, m5); + b0 = _mm256_blend_epi32(t0, t1, 0xF0); + g1(&mut a, &mut b, &mut c, &mut d, &mut b0); + t0 = _mm256_unpackhi_epi64(m4, m0); + t1 = _mm256_unpacklo_epi64(m6, m7); + b0 = _mm256_blend_epi32(t0, t1, 0xF0); + g2(&mut a, &mut b, &mut c, &mut d, &mut b0); + diagonalize(&mut a, &mut b, &mut c, &mut d); + t0 = _mm256_alignr_epi8(m1, m7, 8); + t1 = _mm256_shuffle_epi32(m2, _MM_SHUFFLE!(1, 0, 3, 2)); + b0 = _mm256_blend_epi32(t0, t1, 0xF0); + g1(&mut a, &mut b, &mut c, &mut d, &mut b0); + t0 = _mm256_unpacklo_epi64(m4, m3); + t1 = _mm256_unpacklo_epi64(m5, m0); + b0 = _mm256_blend_epi32(t0, t1, 0xF0); + g2(&mut a, &mut b, &mut c, &mut d, &mut b0); + undiagonalize(&mut a, &mut b, &mut c, &mut d); + + if rounds == 0 { + break; + } + rounds -= 1; + + // round 5 + t0 = _mm256_unpackhi_epi64(m4, m2); + t1 = _mm256_unpacklo_epi64(m1, m5); + b0 = _mm256_blend_epi32(t0, t1, 0xF0); + g1(&mut a, &mut b, &mut c, &mut d, &mut b0); + t0 = _mm256_blend_epi32(m3, m0, 0x33); + t1 = _mm256_blend_epi32(m7, m2, 0x33); + b0 = _mm256_blend_epi32(t0, t1, 0xF0); + g2(&mut a, &mut b, &mut c, &mut d, &mut b0); + diagonalize(&mut a, &mut b, &mut c, &mut d); + t0 = _mm256_alignr_epi8(m7, m1, 8); + t1 = _mm256_alignr_epi8(m3, m5, 8); + b0 = _mm256_blend_epi32(t0, t1, 0xF0); + g1(&mut a, &mut b, &mut c, &mut d, &mut b0); + t0 = _mm256_unpackhi_epi64(m6, m0); + t1 = _mm256_unpacklo_epi64(m6, m4); + b0 = _mm256_blend_epi32(t0, t1, 0xF0); + g2(&mut a, &mut b, &mut c, &mut d, &mut b0); + undiagonalize(&mut a, &mut b, &mut c, &mut d); + + if rounds == 0 { + break; + } + rounds -= 1; + + // round 6 + t0 = _mm256_unpacklo_epi64(m1, m3); + t1 = _mm256_unpacklo_epi64(m0, m4); + b0 = _mm256_blend_epi32(t0, t1, 0xF0); + g1(&mut a, &mut b, &mut c, &mut d, &mut b0); + t0 = _mm256_unpacklo_epi64(m6, m5); + t1 = _mm256_unpackhi_epi64(m5, m1); + b0 = _mm256_blend_epi32(t0, t1, 0xF0); + g2(&mut a, &mut b, &mut c, &mut d, &mut b0); + diagonalize(&mut a, &mut b, &mut c, &mut d); + t0 = _mm256_alignr_epi8(m2, m0, 8); + t1 = _mm256_unpackhi_epi64(m3, m7); + b0 = _mm256_blend_epi32(t0, t1, 0xF0); + g1(&mut a, &mut b, &mut c, &mut d, &mut b0); + t0 = _mm256_unpackhi_epi64(m4, m6); + t1 = _mm256_alignr_epi8(m7, m2, 8); + b0 = _mm256_blend_epi32(t0, t1, 0xF0); + g2(&mut a, &mut b, &mut c, &mut d, &mut b0); + undiagonalize(&mut a, &mut b, &mut c, &mut d); + + if rounds == 0 { + break; + } + rounds -= 1; + + // round 7 + t0 = _mm256_blend_epi32(m0, m6, 0x33); + t1 = _mm256_unpacklo_epi64(m7, m2); + b0 = _mm256_blend_epi32(t0, t1, 0xF0); + g1(&mut a, &mut b, &mut c, &mut d, &mut b0); + t0 = _mm256_unpackhi_epi64(m2, m7); + t1 = _mm256_alignr_epi8(m5, m6, 8); + b0 = _mm256_blend_epi32(t0, t1, 0xF0); + g2(&mut a, &mut b, &mut c, &mut d, &mut b0); + diagonalize(&mut a, &mut b, &mut c, &mut d); + t0 = _mm256_unpacklo_epi64(m4, m0); + t1 = _mm256_blend_epi32(m4, m3, 0x33); + b0 = _mm256_blend_epi32(t0, t1, 0xF0); + g1(&mut a, &mut b, &mut c, &mut d, &mut b0); + t0 = _mm256_unpackhi_epi64(m5, m3); + t1 = _mm256_shuffle_epi32(m1, _MM_SHUFFLE!(1, 0, 3, 2)); + b0 = _mm256_blend_epi32(t0, t1, 0xF0); + g2(&mut a, &mut b, &mut c, &mut d, &mut b0); + undiagonalize(&mut a, &mut b, &mut c, &mut d); + + if rounds == 0 { + break; + } + rounds -= 1; + // round 8 + t0 = _mm256_unpackhi_epi64(m6, m3); + t1 = _mm256_blend_epi32(m1, m6, 0x33); + b0 = _mm256_blend_epi32(t0, t1, 0xF0); + g1(&mut a, &mut b, &mut c, &mut d, &mut b0); + t0 = _mm256_alignr_epi8(m7, m5, 8); + t1 = _mm256_unpackhi_epi64(m0, m4); + b0 = _mm256_blend_epi32(t0, t1, 0xF0); + g2(&mut a, &mut b, &mut c, &mut d, &mut b0); + diagonalize(&mut a, &mut b, &mut c, &mut d); + t0 = _mm256_blend_epi32(m2, m1, 0x33); + t1 = _mm256_alignr_epi8(m4, m7, 8); + b0 = _mm256_blend_epi32(t0, t1, 0xF0); + g1(&mut a, &mut b, &mut c, &mut d, &mut b0); + t0 = _mm256_unpacklo_epi64(m5, m0); + t1 = _mm256_unpacklo_epi64(m2, m3); + b0 = _mm256_blend_epi32(t0, t1, 0xF0); + g2(&mut a, &mut b, &mut c, &mut d, &mut b0); + undiagonalize(&mut a, &mut b, &mut c, &mut d); + + if rounds == 0 { + break; + } + rounds -= 1; + + // round 9 + t0 = _mm256_unpacklo_epi64(m3, m7); + t1 = _mm256_alignr_epi8(m0, m5, 8); + b0 = _mm256_blend_epi32(t0, t1, 0xF0); + g1(&mut a, &mut b, &mut c, &mut d, &mut b0); + t0 = _mm256_unpackhi_epi64(m7, m4); + t1 = _mm256_alignr_epi8(m4, m1, 8); + b0 = _mm256_blend_epi32(t0, t1, 0xF0); + g2(&mut a, &mut b, &mut c, &mut d, &mut b0); + diagonalize(&mut a, &mut b, &mut c, &mut d); + t0 = _mm256_unpacklo_epi64(m5, m6); + t1 = _mm256_unpackhi_epi64(m6, m0); + b0 = _mm256_blend_epi32(t0, t1, 0xF0); + g1(&mut a, &mut b, &mut c, &mut d, &mut b0); + t0 = _mm256_alignr_epi8(m1, m2, 8); + t1 = _mm256_alignr_epi8(m2, m3, 8); + b0 = _mm256_blend_epi32(t0, t1, 0xF0); + g2(&mut a, &mut b, &mut c, &mut d, &mut b0); + undiagonalize(&mut a, &mut b, &mut c, &mut d); + + if rounds == 0 { + break; + } + rounds -= 1; + + // round 10 + t0 = _mm256_unpacklo_epi64(m5, m4); + t1 = _mm256_unpackhi_epi64(m3, m0); + b0 = _mm256_blend_epi32(t0, t1, 0xF0); + g1(&mut a, &mut b, &mut c, &mut d, &mut b0); + t0 = _mm256_unpacklo_epi64(m1, m2); + t1 = _mm256_blend_epi32(m2, m3, 0x33); + b0 = _mm256_blend_epi32(t0, t1, 0xF0); + g2(&mut a, &mut b, &mut c, &mut d, &mut b0); + diagonalize(&mut a, &mut b, &mut c, &mut d); + t0 = _mm256_unpackhi_epi64(m6, m7); + t1 = _mm256_unpackhi_epi64(m4, m1); + b0 = _mm256_blend_epi32(t0, t1, 0xF0); + g1(&mut a, &mut b, &mut c, &mut d, &mut b0); + t0 = _mm256_blend_epi32(m5, m0, 0x33); + t1 = _mm256_unpacklo_epi64(m7, m6); + b0 = _mm256_blend_epi32(t0, t1, 0xF0); + g2(&mut a, &mut b, &mut c, &mut d, &mut b0); + undiagonalize(&mut a, &mut b, &mut c, &mut d); + + // last two rounds are removed + } + a = xor(a, c); + b = xor(b, d); + a = xor(a, iv0); + b = xor(b, iv1); + + storeu(a, words_low); + storeu(b, words_high); + } + + #[inline(always)] + pub(crate) fn count_low(count: Count) -> Word { + count as Word + } + + #[inline(always)] + pub(crate) fn count_high(count: Count) -> Word { + (count >> 8 * size_of::()) as Word + } + + #[inline(always)] + unsafe fn loadu(src: *const [Word; DEGREE]) -> __m256i { + // This is an unaligned load, so the pointer cast is allowed. + _mm256_loadu_si256(src as *const __m256i) + } + + #[inline(always)] + unsafe fn storeu(src: __m256i, dest: *mut [Word; DEGREE]) { + // This is an unaligned store, so the pointer cast is allowed. + _mm256_storeu_si256(dest as *mut __m256i, src) + } + + #[inline(always)] + unsafe fn loadu_128(mem_addr: &[u8; 16]) -> __m128i { + _mm_loadu_si128(mem_addr.as_ptr() as *const __m128i) + } + + #[inline(always)] + unsafe fn add(a: __m256i, b: __m256i) -> __m256i { + _mm256_add_epi64(a, b) + } + + #[inline(always)] + unsafe fn xor(a: __m256i, b: __m256i) -> __m256i { + _mm256_xor_si256(a, b) + } + + #[inline(always)] + unsafe fn set4(a: u64, b: u64, c: u64, d: u64) -> __m256i { + _mm256_setr_epi64x(a as i64, b as i64, c as i64, d as i64) + } + + // These rotations are the "simple version". For the "complicated version", see + // https://github.com/sneves/blake2-avx2/blob/b3723921f668df09ece52dcd225a36d4a4eea1d9/blake2b-common.h#L43-L46. + // For a discussion of the tradeoffs, see + // https://github.com/sneves/blake2-avx2/pull/5. In short: + // - Due to an LLVM bug (https://bugs.llvm.org/show_bug.cgi?id=44379), this + // version performs better on recent x86 chips. + // - LLVM is able to optimize this version to AVX-512 rotation instructions + // when those are enabled. + #[inline(always)] + unsafe fn rot32(x: __m256i) -> __m256i { + _mm256_or_si256(_mm256_srli_epi64(x, 32), _mm256_slli_epi64(x, 64 - 32)) + } + + #[inline(always)] + unsafe fn rot24(x: __m256i) -> __m256i { + _mm256_or_si256(_mm256_srli_epi64(x, 24), _mm256_slli_epi64(x, 64 - 24)) + } + + #[inline(always)] + unsafe fn rot16(x: __m256i) -> __m256i { + _mm256_or_si256(_mm256_srli_epi64(x, 16), _mm256_slli_epi64(x, 64 - 16)) + } + + #[inline(always)] + unsafe fn rot63(x: __m256i) -> __m256i { + _mm256_or_si256(_mm256_srli_epi64(x, 63), _mm256_slli_epi64(x, 64 - 63)) + } + + #[inline(always)] + unsafe fn g1( + a: &mut __m256i, + b: &mut __m256i, + c: &mut __m256i, + d: &mut __m256i, + m: &mut __m256i, + ) { + *a = add(*a, *m); + *a = add(*a, *b); + *d = xor(*d, *a); + *d = rot32(*d); + *c = add(*c, *d); + *b = xor(*b, *c); + *b = rot24(*b); + } + + #[inline(always)] + unsafe fn g2( + a: &mut __m256i, + b: &mut __m256i, + c: &mut __m256i, + d: &mut __m256i, + m: &mut __m256i, + ) { + *a = add(*a, *m); + *a = add(*a, *b); + *d = xor(*d, *a); + *d = rot16(*d); + *c = add(*c, *d); + *b = xor(*b, *c); + *b = rot63(*b); + } + + // Note the optimization here of leaving b as the unrotated row, rather than a. + // All the message loads below are adjusted to compensate for this. See + // discussion at https://github.com/sneves/blake2-avx2/pull/4 + #[inline(always)] + unsafe fn diagonalize(a: &mut __m256i, _b: &mut __m256i, c: &mut __m256i, d: &mut __m256i) { + *a = _mm256_permute4x64_epi64(*a, _MM_SHUFFLE!(2, 1, 0, 3)); + *d = _mm256_permute4x64_epi64(*d, _MM_SHUFFLE!(1, 0, 3, 2)); + *c = _mm256_permute4x64_epi64(*c, _MM_SHUFFLE!(0, 3, 2, 1)); + } + + #[inline(always)] + unsafe fn undiagonalize(a: &mut __m256i, _b: &mut __m256i, c: &mut __m256i, d: &mut __m256i) { + *a = _mm256_permute4x64_epi64(*a, _MM_SHUFFLE!(0, 3, 2, 1)); + *d = _mm256_permute4x64_epi64(*d, _MM_SHUFFLE!(1, 0, 3, 2)); + *c = _mm256_permute4x64_epi64(*c, _MM_SHUFFLE!(2, 1, 0, 3)); + } +} + +#[cfg(test)] +mod tests { + use super::*; + use primitives::hex; + use std::time::Instant; + + #[test] + fn perfblake2() { + let input = [hex!("0000040048c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b616162636465666768696a6b6c6d6e6f700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001") + ,hex!("0000020048c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001") + ,hex!("0000004048c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001")]; + + let time = Instant::now(); + for i in 0..3000 { + let _ = run(&input[i % 3], u64::MAX).unwrap(); + } + println!("duration: {:?}", time.elapsed()); + } } diff --git a/crates/precompile/src/bls12_381.rs b/crates/precompile/src/bls12_381.rs index a020e8b13a..879dcd60bc 100644 --- a/crates/precompile/src/bls12_381.rs +++ b/crates/precompile/src/bls12_381.rs @@ -1,16 +1,34 @@ +//! BLS12-381 precompiles added in [`EIP-2537`](https://eips.ethereum.org/EIPS/eip-2537) +//! For more details check modules for each precompile. use crate::PrecompileWithAddress; -mod g1; +cfg_if::cfg_if! { + if #[cfg(feature = "blst")]{ + mod blst; + use blst as crypto_backend; + } else { + mod arkworks; + use arkworks as crypto_backend; + } +} + +// Re-export type aliases for use in submodules +use crate::bls12_381_const::FP_LENGTH; +type G1Point = ([u8; FP_LENGTH], [u8; FP_LENGTH]); +type G2Point = ( + [u8; FP_LENGTH], + [u8; FP_LENGTH], + [u8; FP_LENGTH], + [u8; FP_LENGTH], +); +type PairingPair = (G1Point, G2Point); + pub mod g1_add; pub mod g1_msm; -pub mod g1_mul; -mod g2; pub mod g2_add; pub mod g2_msm; -pub mod g2_mul; pub mod map_fp2_to_g2; pub mod map_fp_to_g1; -mod msm; pub mod pairing; mod utils; @@ -18,10 +36,8 @@ mod utils; pub fn precompiles() -> impl Iterator { [ g1_add::PRECOMPILE, - g1_mul::PRECOMPILE, g1_msm::PRECOMPILE, g2_add::PRECOMPILE, - g2_mul::PRECOMPILE, g2_msm::PRECOMPILE, pairing::PRECOMPILE, map_fp_to_g1::PRECOMPILE, @@ -29,122 +45,3 @@ pub fn precompiles() -> impl Iterator { ] .into_iter() } - -#[cfg(test)] -mod test { - use super::g1_add; - use super::g1_msm; - use super::g1_mul; - use super::g2_add; - use super::g2_msm; - use super::g2_mul; - use super::map_fp2_to_g2; - use super::map_fp_to_g1; - use super::msm::msm_required_gas; - use super::pairing; - use eyre::Result; - use revm_primitives::{hex::FromHex, Bytes, PrecompileResult}; - use rstest::rstest; - use serde_derive::{Deserialize, Serialize}; - use std::{fs, path::Path}; - - /// Test vector structure for BLS12-381 precompile tests. - #[derive(Serialize, Deserialize, Debug)] - #[serde(rename_all = "PascalCase")] - struct TestVector { - input: String, - expected: Option, - name: String, - gas: Option, - expected_error: Option, - } - - #[derive(Serialize, Deserialize, Debug)] - struct TestVectors(Vec); - - fn load_test_vectors>(path: P) -> Result { - let file_contents = fs::read_to_string(path)?; - Ok(serde_json::from_str(&file_contents)?) - } - - #[rstest] - #[case::fail_g1_add(g1_add::g1_add, "fail-add_G1_bls.json")] - #[case::fail_g1_mul(g1_mul::g1_mul, "fail-mul_G1_bls.json")] - #[case::fail_g1_msm(g1_msm::g1_msm, "fail-multiexp_G1_bls.json")] - #[case::fail_g2_add(g2_add::g2_add, "fail-add_G2_bls.json")] - #[case::fail_g2_mul(g2_mul::g2_mul, "fail-mul_G2_bls.json")] - #[case::fail_g2_msm(g2_msm::g2_msm, "fail-multiexp_G2_bls.json")] - #[case::fail_pairing(pairing::pairing, "fail-pairing_check_bls.json")] - #[case::fail_map_fp_to_g1(map_fp_to_g1::map_fp_to_g1, "fail-map_fp_to_G1_bls.json")] - #[case::fail_map_fp2_to_g2(map_fp2_to_g2::map_fp2_to_g2, "fail-map_fp2_to_G2_bls.json")] - #[case::g1_add(g1_add::g1_add, "add_G1_bls.json")] - #[case::g1_mul(g1_mul::g1_mul, "mul_G1_bls.json")] - #[case::g1_msm(g1_msm::g1_msm, "multiexp_G1_bls.json")] - #[case::g2_add(g2_add::g2_add, "add_G2_bls.json")] - #[case::g2_mul(g2_mul::g2_mul, "mul_G2_bls.json")] - #[case::g2_msm(g2_msm::g2_msm, "multiexp_G2_bls.json")] - #[case::pairing(pairing::pairing, "pairing_check_bls.json")] - #[case::map_fp_to_g1(map_fp_to_g1::map_fp_to_g1, "map_fp_to_G1_bls.json")] - #[case::map_fp2_to_g2(map_fp2_to_g2::map_fp2_to_g2, "map_fp2_to_G2_bls.json")] - fn test_bls( - #[case] precompile: fn(input: &Bytes, gas_limit: u64) -> PrecompileResult, - #[case] file_name: &str, - ) { - let test_vectors = load_test_vectors(format!("test-vectors/{file_name}")) - .unwrap_or_else(|e| panic!("Failed to load test vectors from {file_name}: {e}")); - - for vector in test_vectors.0 { - let test_name = format!("{file_name}/{}", vector.name); - let input = Bytes::from_hex(vector.input.clone()).unwrap_or_else(|e| { - panic!( - "could not deserialize input {} as hex in {test_name}: {e}", - &vector.input - ) - }); - let target_gas: u64 = 30_000_000; - let res = precompile(&input, target_gas); - if let Some(expected_error) = vector.expected_error { - assert!(res.is_err(), "expected error {expected_error} didn't happen in {test_name}, got result {res:?}"); - } else { - let Some(gas) = vector.gas else { - panic!("gas is missing in {test_name}"); - }; - let (actual_gas, actual_output) = - res.unwrap_or_else(|e| panic!("precompile call failed for {test_name}: {e}")); - assert_eq!( - gas, actual_gas, - "expected gas: {}, actual gas: {} in {test_name}", - gas, actual_gas - ); - let Some(expected) = vector.expected else { - panic!("expected output is missing in {test_name}"); - }; - let expected_output = Bytes::from_hex(expected).unwrap(); - assert_eq!( - expected_output, actual_output, - "expected output: {expected_output}, actual output: {actual_output} in {test_name}"); - } - } - } - - #[rstest] - #[case::g1_empty(0, g1_mul::BASE_GAS_FEE, 0)] - #[case::g1_one_item(160, g1_mul::BASE_GAS_FEE, 14400)] - #[case::g1_two_items(320, g1_mul::BASE_GAS_FEE, 21312)] - #[case::g1_ten_items(1600, g1_mul::BASE_GAS_FEE, 50760)] - #[case::g1_sixty_four_items(10240, g1_mul::BASE_GAS_FEE, 170496)] - #[case::g1_one_hundred_twenty_eight_items(20480, g1_mul::BASE_GAS_FEE, 267264)] - #[case::g1_one_hundred_twenty_nine_items(20640, g1_mul::BASE_GAS_FEE, 269352)] - #[case::g1_two_hundred_fifty_six_items(40960, g1_mul::BASE_GAS_FEE, 534528)] - fn test_g1_msm_required_gas( - #[case] input_len: usize, - #[case] multiplication_cost: u64, - #[case] expected_output: u64, - ) { - let k = input_len / g1_mul::INPUT_LENGTH; - - let actual_output = msm_required_gas(k, multiplication_cost); - - assert_eq!(expected_output, actual_output); - } -} diff --git a/crates/precompile/src/bls12_381/arkworks.rs b/crates/precompile/src/bls12_381/arkworks.rs new file mode 100644 index 0000000000..b8eb0a437a --- /dev/null +++ b/crates/precompile/src/bls12_381/arkworks.rs @@ -0,0 +1,541 @@ +use super::{G1Point, G2Point, PairingPair}; +use crate::{ + bls12_381_const::{FP_LENGTH, G1_LENGTH, G2_LENGTH, SCALAR_LENGTH}, + PrecompileError, +}; +use ark_bls12_381::{Bls12_381, Fq, Fq2, Fr, G1Affine, G1Projective, G2Affine, G2Projective}; +use ark_ec::{ + hashing::{curve_maps::wb::WBMap, map_to_curve_hasher::MapToCurve}, + pairing::Pairing, + AffineRepr, CurveGroup, VariableBaseMSM, +}; +use ark_ff::{One, PrimeField, Zero}; + +use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; +use std::{string::ToString, vec::Vec}; + +/// Reads a single `Fp` field element from the input slice. +/// +/// Takes a byte slice in Big Endian format and attempts to interpret it as an +/// elliptic curve field element. Returns an error if the bytes do not form +/// a valid field element. +/// +/// # Panics +/// +/// Panics if the input is not exactly 48 bytes long. +#[inline] +fn read_fp(input_be: &[u8]) -> Result { + assert_eq!(input_be.len(), FP_LENGTH, "input must be {FP_LENGTH} bytes"); + + let mut input_le = [0u8; FP_LENGTH]; + input_le.copy_from_slice(input_be); + + // Reverse in-place to convert from big-endian to little-endian. + input_le.reverse(); + + Fq::deserialize_uncompressed(&input_le[..]) + .map_err(|_| PrecompileError::Other("non-canonical fp value".to_string())) +} + +/// Encodes an `Fp` field element into a big-endian byte array. +/// +/// # Panics +/// +/// Panics if serialization fails, which should not occur for a valid field element. +fn encode_fp(fp: &Fq) -> [u8; FP_LENGTH] { + let mut bytes = [0u8; FP_LENGTH]; + fp.serialize_uncompressed(&mut bytes[..]) + .expect("Failed to serialize field element"); + bytes.reverse(); + bytes +} + +/// Reads a Fp2 (quadratic extension field element) from the input slices. +/// +/// Parses two Fp field elements in Big Endian format for the Fp2 element. +/// +/// # Panics +/// +/// Panics if either input is not exactly 48 bytes long. +#[inline] +fn read_fp2(input_1: &[u8; FP_LENGTH], input_2: &[u8; FP_LENGTH]) -> Result { + let fp_1 = read_fp(input_1)?; + let fp_2 = read_fp(input_2)?; + + Ok(Fq2::new(fp_1, fp_2)) +} + +/// Creates a new `G1` point from the given `x` and `y` coordinates. +/// +/// Constructs a point on the G1 curve from its affine coordinates. +/// +/// Note: The point at infinity which is represented as (0,0) is +/// handled specifically. +#[inline] +fn new_g1_point_no_subgroup_check(px: Fq, py: Fq) -> Result { + if px.is_zero() && py.is_zero() { + Ok(G1Affine::zero()) + } else { + // We cannot use `G1Affine::new` because that triggers an assert if the point is not on the curve. + let point = G1Affine::new_unchecked(px, py); + if !point.is_on_curve() { + return Err(PrecompileError::Other( + "Element not on G1 curve".to_string(), + )); + } + Ok(point) + } +} + +/// Creates a new `G2` point from the given Fq2 coordinates. +/// +/// G2 points in BLS12_381 are defined over a quadratic extension field Fq2. +/// This function takes two Fq2 elements representing the x and y coordinates +/// and creates a G2 point. +/// +/// Note: The point at infinity which is represented as (0,0) is +/// handled specifically. +#[inline] +fn new_g2_point_no_subgroup_check(x: Fq2, y: Fq2) -> Result { + let point = if x.is_zero() && y.is_zero() { + G2Affine::zero() + } else { + // We cannot use `G2Affine::new` because that triggers an assert if the point is not on the curve. + let point = G2Affine::new_unchecked(x, y); + if !point.is_on_curve() { + return Err(PrecompileError::Other( + "Element not on G2 curve".to_string(), + )); + } + point + }; + + Ok(point) +} + +/// Reads a G1 point from the input slices. +/// +/// Parses a G1 point from byte slices by reading two field elements +/// representing the x and y coordinates in Big Endian format. +/// Also performs a subgroup check to ensure the point is in the correct subgroup. +/// +/// # Panics +/// +/// Panics if the inputs are not exactly 48 bytes long. +#[inline] +fn read_g1(x: &[u8; FP_LENGTH], y: &[u8; FP_LENGTH]) -> Result { + let point = read_g1_no_subgroup_check(x, y)?; + if !point.is_in_correct_subgroup_assuming_on_curve() { + return Err(PrecompileError::Other( + "Element not in the correct subgroup".to_string(), + )); + } + Ok(point) +} + +/// Reads a G1 point without performing a subgroup check. +/// +/// Note: Skipping subgroup checks can introduce security issues. +/// This method should only be called if: +/// - The EIP specifies that no subgroup check should be performed +/// - One can be certain that the point is in the correct subgroup. +#[inline] +fn read_g1_no_subgroup_check( + x: &[u8; FP_LENGTH], + y: &[u8; FP_LENGTH], +) -> Result { + let px = read_fp(x)?; + let py = read_fp(y)?; + new_g1_point_no_subgroup_check(px, py) +} + +/// Encodes a G1 point into a byte array. +/// +/// Converts a G1 point to affine coordinates and serializes the x and y coordinates +/// as big-endian byte arrays. +#[inline] +fn encode_g1_point(input: &G1Affine) -> [u8; G1_LENGTH] { + let mut output = [0u8; G1_LENGTH]; + + let Some((x, y)) = input.xy() else { + return output; // Point at infinity, return all zeros + }; + + let x_encoded = encode_fp(&x); + let y_encoded = encode_fp(&y); + + // Copy the encoded values to the output + output[..FP_LENGTH].copy_from_slice(&x_encoded); + output[FP_LENGTH..].copy_from_slice(&y_encoded); + + output +} + +/// Reads a G2 point from the input slices. +/// +/// Parses a G2 point from byte slices by reading four field elements +/// representing the x and y coordinates in Big Endian format. +/// Also performs a subgroup check to ensure the point is in the correct subgroup. +#[inline] +fn read_g2( + a_x_0: &[u8; FP_LENGTH], + a_x_1: &[u8; FP_LENGTH], + a_y_0: &[u8; FP_LENGTH], + a_y_1: &[u8; FP_LENGTH], +) -> Result { + let point = read_g2_no_subgroup_check(a_x_0, a_x_1, a_y_0, a_y_1)?; + if !point.is_in_correct_subgroup_assuming_on_curve() { + return Err(PrecompileError::Other( + "Element not in the correct subgroup".to_string(), + )); + } + Ok(point) +} + +/// Reads a G2 point without performing a subgroup check. +/// +/// Note: Skipping subgroup checks can introduce security issues. +/// This method should only be called if: +/// - The EIP specifies that no subgroup check should be performed +/// - One can be certain that the point is in the correct subgroup. +#[inline] +fn read_g2_no_subgroup_check( + a_x_0: &[u8; FP_LENGTH], + a_x_1: &[u8; FP_LENGTH], + a_y_0: &[u8; FP_LENGTH], + a_y_1: &[u8; FP_LENGTH], +) -> Result { + let x = read_fp2(a_x_0, a_x_1)?; + let y = read_fp2(a_y_0, a_y_1)?; + new_g2_point_no_subgroup_check(x, y) +} + +/// Encodes a G2 point into a byte array. +/// +/// Converts a G2 point to affine coordinates and serializes the coordinates +/// as big-endian byte arrays. +#[inline] +fn encode_g2_point(input: &G2Affine) -> [u8; G2_LENGTH] { + let mut output = [0u8; G2_LENGTH]; + + let Some((x, y)) = input.xy() else { + return output; // Point at infinity, return all zeros + }; + + let x_c0_encoded = encode_fp(&x.c0); + let x_c1_encoded = encode_fp(&x.c1); + let y_c0_encoded = encode_fp(&y.c0); + let y_c1_encoded = encode_fp(&y.c1); + + output[..FP_LENGTH].copy_from_slice(&x_c0_encoded); + output[FP_LENGTH..2 * FP_LENGTH].copy_from_slice(&x_c1_encoded); + output[2 * FP_LENGTH..3 * FP_LENGTH].copy_from_slice(&y_c0_encoded); + output[3 * FP_LENGTH..4 * FP_LENGTH].copy_from_slice(&y_c1_encoded); + + output +} + +/// Extracts a scalar from a byte slice representation, decoding the input as a Big Endian +/// unsigned integer. +/// +/// Note: We do not check that the scalar is a canonical Fr element, because the EIP specifies: +/// * The corresponding integer is not required to be less than or equal than main subgroup order. +#[inline] +fn read_scalar(input: &[u8]) -> Result { + if input.len() != SCALAR_LENGTH { + return Err(PrecompileError::Other(format!( + "Input should be {SCALAR_LENGTH} bytes, was {}", + input.len() + ))); + } + + Ok(Fr::from_be_bytes_mod_order(input)) +} + +/// Performs point addition on two G1 points. +#[inline] +fn p1_add_affine(p1: &G1Affine, p2: &G1Affine) -> G1Affine { + let p1_proj: G1Projective = (*p1).into(); + let p3 = p1_proj + p2; + p3.into_affine() +} + +/// Performs point addition on two G2 points. +#[inline] +fn p2_add_affine(p1: &G2Affine, p2: &G2Affine) -> G2Affine { + let p1_proj: G2Projective = (*p1).into(); + let p3 = p1_proj + p2; + p3.into_affine() +} + +/// Performs multi-scalar multiplication (MSM) for G1 points +/// +/// Takes a vector of G1 points and corresponding scalars, and returns their weighted sum +/// +/// Note: This method assumes that `g1_points` does not contain any points at infinity. +#[inline] +fn p1_msm(g1_points: Vec, scalars: Vec) -> G1Affine { + assert_eq!( + g1_points.len(), + scalars.len(), + "number of scalars should equal the number of g1 points" + ); + + if g1_points.is_empty() { + return G1Affine::zero(); + } + + if g1_points.len() == 1 { + let big_int = scalars[0].into_bigint(); + return g1_points[0].mul_bigint(big_int).into_affine(); + } + + // Perform multi-scalar multiplication + G1Projective::msm(&g1_points, &scalars) + .expect("MSM should succeed") + .into_affine() +} + +/// Performs multi-scalar multiplication (MSM) for G2 points +/// +/// Takes a vector of G2 points and corresponding scalars, and returns their weighted sum +/// +/// Note: This method assumes that `g2_points` does not contain any points at infinity. +#[inline] +fn p2_msm(g2_points: Vec, scalars: Vec) -> G2Affine { + assert_eq!( + g2_points.len(), + scalars.len(), + "number of scalars should equal the number of g2 points" + ); + + if g2_points.is_empty() { + return G2Affine::zero(); + } + + if g2_points.len() == 1 { + let big_int = scalars[0].into_bigint(); + return g2_points[0].mul_bigint(big_int).into_affine(); + } + + // Perform multi-scalar multiplication + G2Projective::msm(&g2_points, &scalars) + .expect("MSM should succeed") + .into_affine() +} + +/// Maps a field element to a G1 point +/// +/// Takes a field element (Fq) and returns the corresponding G1 point in affine form +#[inline] +fn map_fp_to_g1(fp: &Fq) -> G1Affine { + WBMap::map_to_curve(*fp) + .expect("map_to_curve is infallible") + .clear_cofactor() +} + +/// Maps a field element to a G2 point +/// +/// Takes a field element (Fq2) and returns the corresponding G2 point in affine form +#[inline] +fn map_fp2_to_g2(fp2: &Fq2) -> G2Affine { + WBMap::map_to_curve(*fp2) + .expect("map_to_curve is infallible") + .clear_cofactor() +} + +/// pairing_check performs a pairing check on a list of G1 and G2 point pairs and +/// returns true if the result is equal to the identity element. +#[inline] +fn pairing_check(pairs: &[(G1Affine, G2Affine)]) -> bool { + if pairs.is_empty() { + return true; + } + + let (g1_points, g2_points): (Vec, Vec) = pairs.iter().copied().unzip(); + + let pairing_result = Bls12_381::multi_pairing(&g1_points, &g2_points); + pairing_result.0.is_one() +} + +/// pairing_check_bytes performs a pairing check on a list of G1 and G2 point pairs taking byte inputs. +#[inline] +pub(super) fn pairing_check_bytes(pairs: &[PairingPair]) -> Result { + if pairs.is_empty() { + return Ok(true); + } + + let mut parsed_pairs = Vec::with_capacity(pairs.len()); + for ((g1_x, g1_y), (g2_x_0, g2_x_1, g2_y_0, g2_y_1)) in pairs { + // Check if G1 point is zero (point at infinity) + let g1_is_zero = g1_x.iter().all(|&b| b == 0) && g1_y.iter().all(|&b| b == 0); + + // Check if G2 point is zero (point at infinity) + let g2_is_zero = g2_x_0.iter().all(|&b| b == 0) + && g2_x_1.iter().all(|&b| b == 0) + && g2_y_0.iter().all(|&b| b == 0) + && g2_y_1.iter().all(|&b| b == 0); + + // Skip this pair if either point is at infinity as it's a no-op + if g1_is_zero || g2_is_zero { + // Still need to validate the non-zero point if one exists + if !g1_is_zero { + let _ = read_g1(g1_x, g1_y)?; + } + if !g2_is_zero { + let _ = read_g2(g2_x_0, g2_x_1, g2_y_0, g2_y_1)?; + } + continue; + } + + let g1_point = read_g1(g1_x, g1_y)?; + let g2_point = read_g2(g2_x_0, g2_x_1, g2_y_0, g2_y_1)?; + parsed_pairs.push((g1_point, g2_point)); + } + + // If all pairs were filtered out, return true (identity element) + if parsed_pairs.is_empty() { + return Ok(true); + } + + Ok(pairing_check(&parsed_pairs)) +} + +// Byte-oriented versions of the functions for external API compatibility + +/// Performs point addition on two G1 points taking byte coordinates. +#[inline] +pub(super) fn p1_add_affine_bytes( + a: G1Point, + b: G1Point, +) -> Result<[u8; G1_LENGTH], PrecompileError> { + let (a_x, a_y) = a; + let (b_x, b_y) = b; + // Parse first point + let p1 = read_g1_no_subgroup_check(&a_x, &a_y)?; + + // Parse second point + let p2 = read_g1_no_subgroup_check(&b_x, &b_y)?; + + // Perform addition + let result = p1_add_affine(&p1, &p2); + + // Encode result + Ok(encode_g1_point(&result)) +} + +/// Performs point addition on two G2 points taking byte coordinates. +#[inline] +pub(super) fn p2_add_affine_bytes( + a: G2Point, + b: G2Point, +) -> Result<[u8; G2_LENGTH], PrecompileError> { + let (a_x_0, a_x_1, a_y_0, a_y_1) = a; + let (b_x_0, b_x_1, b_y_0, b_y_1) = b; + // Parse first point + let p1 = read_g2_no_subgroup_check(&a_x_0, &a_x_1, &a_y_0, &a_y_1)?; + + // Parse second point + let p2 = read_g2_no_subgroup_check(&b_x_0, &b_x_1, &b_y_0, &b_y_1)?; + + // Perform addition + let result = p2_add_affine(&p1, &p2); + + // Encode result + Ok(encode_g2_point(&result)) +} + +/// Maps a field element to a G1 point from bytes +#[inline] +pub(super) fn map_fp_to_g1_bytes( + fp_bytes: &[u8; FP_LENGTH], +) -> Result<[u8; G1_LENGTH], PrecompileError> { + let fp = read_fp(fp_bytes)?; + let result = map_fp_to_g1(&fp); + Ok(encode_g1_point(&result)) +} + +/// Maps field elements to a G2 point from bytes +#[inline] +pub(super) fn map_fp2_to_g2_bytes( + fp2_x: &[u8; FP_LENGTH], + fp2_y: &[u8; FP_LENGTH], +) -> Result<[u8; G2_LENGTH], PrecompileError> { + let fp2 = read_fp2(fp2_x, fp2_y)?; + let result = map_fp2_to_g2(&fp2); + Ok(encode_g2_point(&result)) +} + +/// Performs multi-scalar multiplication (MSM) for G1 points taking byte inputs. +#[inline] +pub(super) fn p1_msm_bytes( + point_scalar_pairs: impl Iterator>, +) -> Result<[u8; G1_LENGTH], PrecompileError> { + let mut g1_points = Vec::new(); + let mut scalars = Vec::new(); + + // Parse all points and scalars + for pair_result in point_scalar_pairs { + let ((x, y), scalar_bytes) = pair_result?; + + // NB: MSM requires subgroup check + let point = read_g1(&x, &y)?; + + // Skip zero scalars after validating the point + if scalar_bytes.iter().all(|&b| b == 0) { + continue; + } + + let scalar = read_scalar(&scalar_bytes)?; + g1_points.push(point); + scalars.push(scalar); + } + + // Return point at infinity if no pairs were provided or all scalars were zero + if g1_points.is_empty() { + return Ok([0u8; G1_LENGTH]); + } + + // Perform MSM + let result = p1_msm(g1_points, scalars); + + // Encode result + Ok(encode_g1_point(&result)) +} + +/// Performs multi-scalar multiplication (MSM) for G2 points taking byte inputs. +#[inline] +pub(super) fn p2_msm_bytes( + point_scalar_pairs: impl Iterator>, +) -> Result<[u8; G2_LENGTH], PrecompileError> { + let mut g2_points = Vec::new(); + let mut scalars = Vec::new(); + + // Parse all points and scalars + for pair_result in point_scalar_pairs { + let ((x_0, x_1, y_0, y_1), scalar_bytes) = pair_result?; + + // NB: MSM requires subgroup check + let point = read_g2(&x_0, &x_1, &y_0, &y_1)?; + + // Skip zero scalars after validating the point + if scalar_bytes.iter().all(|&b| b == 0) { + continue; + } + + let scalar = read_scalar(&scalar_bytes)?; + g2_points.push(point); + scalars.push(scalar); + } + + // Return point at infinity if no pairs were provided or all scalars were zero + if g2_points.is_empty() { + return Ok([0u8; G2_LENGTH]); + } + + // Perform MSM + let result = p2_msm(g2_points, scalars); + + // Encode result + Ok(encode_g2_point(&result)) +} diff --git a/crates/precompile/src/bls12_381/blst.rs b/crates/precompile/src/bls12_381/blst.rs new file mode 100644 index 0000000000..822eed35ba --- /dev/null +++ b/crates/precompile/src/bls12_381/blst.rs @@ -0,0 +1,805 @@ +// This module contains a safe wrapper around the blst library. + +use super::{G1Point, G2Point, PairingPair}; +use crate::{ + bls12_381_const::{FP_LENGTH, G1_LENGTH, G2_LENGTH, SCALAR_LENGTH, SCALAR_LENGTH_BITS}, + PrecompileError, +}; +use blst::{ + blst_bendian_from_fp, blst_final_exp, blst_fp, blst_fp12, blst_fp12_is_one, blst_fp12_mul, + blst_fp2, blst_fp_from_bendian, blst_map_to_g1, blst_map_to_g2, blst_miller_loop, blst_p1, + blst_p1_add_or_double_affine, blst_p1_affine, blst_p1_affine_in_g1, blst_p1_affine_on_curve, + blst_p1_from_affine, blst_p1_mult, blst_p1_to_affine, blst_p2, blst_p2_add_or_double_affine, + blst_p2_affine, blst_p2_affine_in_g2, blst_p2_affine_on_curve, blst_p2_from_affine, + blst_p2_mult, blst_p2_to_affine, blst_scalar, blst_scalar_from_bendian, MultiPoint, +}; +use std::string::ToString; +use std::vec::Vec; + +// Big-endian non-Montgomery form. +const MODULUS_REPR: [u8; 48] = [ + 0x1a, 0x01, 0x11, 0xea, 0x39, 0x7f, 0xe6, 0x9a, 0x4b, 0x1b, 0xa7, 0xb6, 0x43, 0x4b, 0xac, 0xd7, + 0x64, 0x77, 0x4b, 0x84, 0xf3, 0x85, 0x12, 0xbf, 0x67, 0x30, 0xd2, 0xa0, 0xf6, 0xb0, 0xf6, 0x24, + 0x1e, 0xab, 0xff, 0xfe, 0xb1, 0x53, 0xff, 0xff, 0xb9, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xaa, 0xab, +]; + +#[inline] +fn p1_to_affine(p: &blst_p1) -> blst_p1_affine { + let mut p_affine = blst_p1_affine::default(); + // SAFETY: both inputs are valid blst types + unsafe { blst_p1_to_affine(&mut p_affine, p) }; + p_affine +} + +#[inline] +fn p1_from_affine(p_affine: &blst_p1_affine) -> blst_p1 { + let mut p = blst_p1::default(); + // SAFETY: both inputs are valid blst types + unsafe { blst_p1_from_affine(&mut p, p_affine) }; + p +} + +#[inline] +fn p1_add_or_double(p: &blst_p1, p_affine: &blst_p1_affine) -> blst_p1 { + let mut result = blst_p1::default(); + // SAFETY: all inputs are valid blst types + unsafe { blst_p1_add_or_double_affine(&mut result, p, p_affine) }; + result +} + +#[inline] +fn p2_to_affine(p: &blst_p2) -> blst_p2_affine { + let mut p_affine = blst_p2_affine::default(); + // SAFETY: both inputs are valid blst types + unsafe { blst_p2_to_affine(&mut p_affine, p) }; + p_affine +} + +#[inline] +fn p2_from_affine(p_affine: &blst_p2_affine) -> blst_p2 { + let mut p = blst_p2::default(); + // SAFETY: both inputs are valid blst types + unsafe { blst_p2_from_affine(&mut p, p_affine) }; + p +} + +#[inline] +fn p2_add_or_double(p: &blst_p2, p_affine: &blst_p2_affine) -> blst_p2 { + let mut result = blst_p2::default(); + // SAFETY: all inputs are valid blst types + unsafe { blst_p2_add_or_double_affine(&mut result, p, p_affine) }; + result +} + +/// p1_add_affine adds two G1 points in affine form, returning the result in affine form +/// +/// Note: `a` and `b` can be the same, ie this method is safe to call if one wants +/// to essentially double a point +#[inline] +fn p1_add_affine(a: &blst_p1_affine, b: &blst_p1_affine) -> blst_p1_affine { + // Convert first point to Jacobian coordinates + let a_jacobian = p1_from_affine(a); + + // Add second point (in affine) to first point (in Jacobian) + let sum_jacobian = p1_add_or_double(&a_jacobian, b); + + // Convert result back to affine coordinates + p1_to_affine(&sum_jacobian) +} + +/// Add two G2 points in affine form, returning the result in affine form +#[inline] +fn p2_add_affine(a: &blst_p2_affine, b: &blst_p2_affine) -> blst_p2_affine { + // Convert first point to Jacobian coordinates + let a_jacobian = p2_from_affine(a); + + // Add second point (in affine) to first point (in Jacobian) + let sum_jacobian = p2_add_or_double(&a_jacobian, b); + + // Convert result back to affine coordinates + p2_to_affine(&sum_jacobian) +} + +/// Performs a G1 scalar multiplication +/// +/// Takes a G1 point in affine form and a scalar, and returns the result +/// of the scalar multiplication in affine form +/// +/// Note: The scalar is expected to be in Big Endian format. +#[inline] +fn p1_scalar_mul(p: &blst_p1_affine, scalar: &blst_scalar) -> blst_p1_affine { + // Convert point to Jacobian coordinates + let p_jacobian = p1_from_affine(p); + + let mut result = blst_p1::default(); + + // SAFETY: all inputs are valid blst types + unsafe { + blst_p1_mult( + &mut result, + &p_jacobian, + scalar.b.as_ptr(), + scalar.b.len() * 8, + ) + }; + + // Convert result back to affine coordinates + p1_to_affine(&result) +} + +/// Performs a G2 scalar multiplication +/// +/// Takes a G2 point in affine form and a scalar, and returns the result +/// of the scalar multiplication in affine form +/// +/// Note: The scalar is expected to be in Big Endian format. +#[inline] +fn p2_scalar_mul(p: &blst_p2_affine, scalar: &blst_scalar) -> blst_p2_affine { + // Convert point to Jacobian coordinates + let p_jacobian = p2_from_affine(p); + + let mut result = blst_p2::default(); + // SAFETY: all inputs are valid blst types + unsafe { + blst_p2_mult( + &mut result, + &p_jacobian, + scalar.b.as_ptr(), + scalar.b.len() * 8, + ) + }; + + // Convert result back to affine coordinates + p2_to_affine(&result) +} + +/// Performs multi-scalar multiplication (MSM) for G1 points +/// +/// Takes a vector of G1 points and corresponding scalars, and returns their weighted sum +/// +/// Note: This method assumes that `g1_points` does not contain any points at infinity. +#[inline] +fn p1_msm(g1_points: Vec, scalars: Vec) -> blst_p1_affine { + assert_eq!( + g1_points.len(), + scalars.len(), + "number of scalars should equal the number of g1 points" + ); + + // When no inputs are given, we return the point at infinity. + // This case can only trigger, if the initial MSM pairs + // all had, either a zero scalar or the point at infinity. + // + // The precompile will return an error, if the initial input + // was empty, in accordance with EIP-2537. + if g1_points.is_empty() { + return blst_p1_affine::default(); + } + + // When there is only a single point, we use a simpler scalar multiplication + // procedure + if g1_points.len() == 1 { + return p1_scalar_mul(&g1_points[0], &scalars[0]); + } + + let scalars_bytes: Vec<_> = scalars.into_iter().flat_map(|s| s.b).collect(); + // Perform multi-scalar multiplication + let multiexp = g1_points.mult(&scalars_bytes, SCALAR_LENGTH_BITS); + + // Convert result back to affine coordinates + p1_to_affine(&multiexp) +} + +/// Performs multi-scalar multiplication (MSM) for G2 points +/// +/// Takes a vector of G2 points and corresponding scalars, and returns their weighted sum +/// +/// Note: Scalars are expected to be in Big Endian format. +/// This method assumes that `g2_points` does not contain any points at infinity. +#[inline] +fn p2_msm(g2_points: Vec, scalars: Vec) -> blst_p2_affine { + assert_eq!( + g2_points.len(), + scalars.len(), + "number of scalars should equal the number of g2 points" + ); + + // When no inputs are given, we return the point at infinity. + // This case can only trigger, if the initial MSM pairs + // all had, either a zero scalar or the point at infinity. + // + // The precompile will return an error, if the initial input + // was empty, in accordance with EIP-2537. + if g2_points.is_empty() { + return blst_p2_affine::default(); + } + + // When there is only a single point, we use a simpler scalar multiplication + // procedure + if g2_points.len() == 1 { + return p2_scalar_mul(&g2_points[0], &scalars[0]); + } + + let scalars_bytes: Vec<_> = scalars.into_iter().flat_map(|s| s.b).collect(); + + // Perform multi-scalar multiplication + let multiexp = g2_points.mult(&scalars_bytes, SCALAR_LENGTH_BITS); + + // Convert result back to affine coordinates + p2_to_affine(&multiexp) +} + +/// Maps a field element to a G1 point +/// +/// Takes a field element (blst_fp) and returns the corresponding G1 point in affine form +#[inline] +fn map_fp_to_g1(fp: &blst_fp) -> blst_p1_affine { + // Create a new G1 point in Jacobian coordinates + let mut p = blst_p1::default(); + + // Map the field element to a point on the curve + // SAFETY: `p` and `fp` are blst values + // Third argument is unused if null + unsafe { blst_map_to_g1(&mut p, fp, core::ptr::null()) }; + + // Convert to affine coordinates + p1_to_affine(&p) +} + +/// Maps a field element to a G2 point +/// +/// Takes a field element (blst_fp2) and returns the corresponding G2 point in affine form +#[inline] +fn map_fp2_to_g2(fp2: &blst_fp2) -> blst_p2_affine { + // Create a new G2 point in Jacobian coordinates + let mut p = blst_p2::default(); + + // Map the field element to a point on the curve + // SAFETY: `p` and `fp2` are blst values + // Third argument is unused if null + unsafe { blst_map_to_g2(&mut p, fp2, core::ptr::null()) }; + + // Convert to affine coordinates + p2_to_affine(&p) +} + +/// Computes a single miller loop for a given G1, G2 pair +#[inline] +fn compute_miller_loop(g1: &blst_p1_affine, g2: &blst_p2_affine) -> blst_fp12 { + let mut result = blst_fp12::default(); + + // SAFETY: All arguments are valid blst types + unsafe { blst_miller_loop(&mut result, g2, g1) } + + result +} + +/// multiply_fp12 multiplies two fp12 elements +#[inline] +fn multiply_fp12(a: &blst_fp12, b: &blst_fp12) -> blst_fp12 { + let mut result = blst_fp12::default(); + + // SAFETY: All arguments are valid blst types + unsafe { blst_fp12_mul(&mut result, a, b) } + + result +} + +/// final_exp computes the final exponentiation on an fp12 element +#[inline] +fn final_exp(f: &blst_fp12) -> blst_fp12 { + let mut result = blst_fp12::default(); + + // SAFETY: All arguments are valid blst types + unsafe { blst_final_exp(&mut result, f) } + + result +} + +/// is_fp12_one checks if an fp12 element equals +/// multiplicative identity element, one +#[inline] +fn is_fp12_one(f: &blst_fp12) -> bool { + // SAFETY: argument is a valid blst type + unsafe { blst_fp12_is_one(f) } +} + +/// pairing_check performs a pairing check on a list of G1 and G2 point pairs and +/// returns true if the result is equal to the identity element. +#[inline] +fn pairing_check(pairs: &[(blst_p1_affine, blst_p2_affine)]) -> bool { + // When no inputs are given, we return true + // This case can only trigger, if the initial pairing components + // all had, either the G1 element as the point at infinity + // or the G2 element as the point at infinity. + // + // The precompile will return an error, if the initial input + // was empty, in accordance with EIP-2537. + if pairs.is_empty() { + return true; + } + // Compute the miller loop for the first pair + let (first_g1, first_g2) = &pairs[0]; + let mut acc = compute_miller_loop(first_g1, first_g2); + + // For the remaining pairs, compute miller loop and multiply with the accumulated result + for (g1, g2) in pairs.iter().skip(1) { + let ml = compute_miller_loop(g1, g2); + acc = multiply_fp12(&acc, &ml); + } + + // Apply final exponentiation and check if result is 1 + let final_result = final_exp(&acc); + + // Check if the result is one (identity element) + is_fp12_one(&final_result) +} + +/// Encodes a G1 point in affine format into byte slice. +/// +/// Note: The encoded bytes are in Big Endian format. +fn encode_g1_point(input: &blst_p1_affine) -> [u8; G1_LENGTH] { + let mut out = [0u8; G1_LENGTH]; + fp_to_bytes(&mut out[..FP_LENGTH], &input.x); + fp_to_bytes(&mut out[FP_LENGTH..], &input.y); + out +} + +/// Encodes a single finite field element into byte slice. +/// +/// Note: The encoded bytes are in Big Endian format. +fn fp_to_bytes(out: &mut [u8], input: &blst_fp) { + if out.len() != FP_LENGTH { + return; + } + // SAFETY: Out length is checked previously, `input` is a blst value. + unsafe { blst_bendian_from_fp(out.as_mut_ptr(), input) }; +} + +/// Returns a `blst_p1_affine` from the provided byte slices, which represent the x and y +/// affine coordinates of the point. +/// +/// Note: Coordinates are expected to be in Big Endian format. +/// +/// - If the x or y coordinate do not represent a canonical field element, an error is returned. +/// See [read_fp] for more information. +/// - If the point is not on the curve, an error is returned. +fn decode_g1_on_curve( + p0_x: &[u8; FP_LENGTH], + p0_y: &[u8; FP_LENGTH], +) -> Result { + let out = blst_p1_affine { + x: read_fp(p0_x)?, + y: read_fp(p0_y)?, + }; + + // From EIP-2537: + // + // Error cases: + // + // * An input is neither a point on the G1 elliptic curve nor the infinity point + // + // SAFETY: Out is a blst value. + if unsafe { !blst_p1_affine_on_curve(&out) } { + return Err(PrecompileError::Other( + "Element not on G1 curve".to_string(), + )); + } + + Ok(out) +} + +/// Extracts a G1 point in Affine format from the x and y coordinates. +/// +/// Note: Coordinates are expected to be in Big Endian format. +/// By default, subgroup checks are performed. +fn read_g1(x: &[u8; FP_LENGTH], y: &[u8; FP_LENGTH]) -> Result { + _extract_g1_input(x, y, true) +} +/// Extracts a G1 point in Affine format from the x and y coordinates +/// without performing a subgroup check. +/// +/// Note: Coordinates are expected to be in Big Endian format. +/// Skipping subgroup checks can introduce security issues. +/// This method should only be called if: +/// - The EIP specifies that no subgroup check should be performed +/// - One can be certain that the point is in the correct subgroup. +fn read_g1_no_subgroup_check( + x: &[u8; FP_LENGTH], + y: &[u8; FP_LENGTH], +) -> Result { + _extract_g1_input(x, y, false) +} +/// Extracts a G1 point in Affine format from the x and y coordinates. +/// +/// Note: Coordinates are expected to be in Big Endian format. +/// This function will perform a G1 subgroup check if `subgroup_check` is set to `true`. +fn _extract_g1_input( + x: &[u8; FP_LENGTH], + y: &[u8; FP_LENGTH], + subgroup_check: bool, +) -> Result { + let out = decode_g1_on_curve(x, y)?; + + if subgroup_check { + // NB: Subgroup checks + // + // Scalar multiplications, MSMs and pairings MUST perform a subgroup check. + // + // Implementations SHOULD use the optimized subgroup check method: + // + // https://eips.ethereum.org/assets/eip-2537/fast_subgroup_checks + // + // On any input that fail the subgroup check, the precompile MUST return an error. + // + // As endomorphism acceleration requires input on the correct subgroup, implementers MAY + // use endomorphism acceleration. + if unsafe { !blst_p1_affine_in_g1(&out) } { + return Err(PrecompileError::Other("Element not in G1".to_string())); + } + } + Ok(out) +} + +/// Encodes a G2 point in affine format into byte slice. +/// +/// Note: The encoded bytes are in Big Endian format. +fn encode_g2_point(input: &blst_p2_affine) -> [u8; G2_LENGTH] { + let mut out = [0u8; G2_LENGTH]; + fp_to_bytes(&mut out[..FP_LENGTH], &input.x.fp[0]); + fp_to_bytes(&mut out[FP_LENGTH..2 * FP_LENGTH], &input.x.fp[1]); + fp_to_bytes(&mut out[2 * FP_LENGTH..3 * FP_LENGTH], &input.y.fp[0]); + fp_to_bytes(&mut out[3 * FP_LENGTH..4 * FP_LENGTH], &input.y.fp[1]); + out +} + +/// Returns a `blst_p2_affine` from the provided byte slices, which represent the x and y +/// affine coordinates of the point. +/// +/// Note: Coordinates are expected to be in Big Endian format. +/// +/// - If the x or y coordinate do not represent a canonical field element, an error is returned. +/// See [read_fp2] for more information. +/// - If the point is not on the curve, an error is returned. +fn decode_g2_on_curve( + x1: &[u8; FP_LENGTH], + x2: &[u8; FP_LENGTH], + y1: &[u8; FP_LENGTH], + y2: &[u8; FP_LENGTH], +) -> Result { + let out = blst_p2_affine { + x: read_fp2(x1, x2)?, + y: read_fp2(y1, y2)?, + }; + + // From EIP-2537: + // + // Error cases: + // + // * An input is neither a point on the G2 elliptic curve nor the infinity point + // + // SAFETY: Out is a blst value. + if unsafe { !blst_p2_affine_on_curve(&out) } { + return Err(PrecompileError::Other( + "Element not on G2 curve".to_string(), + )); + } + + Ok(out) +} + +/// Creates a blst_fp2 element from two field elements. +/// +/// Field elements are expected to be in Big Endian format. +/// Returns an error if either of the input field elements is not canonical. +fn read_fp2( + input_1: &[u8; FP_LENGTH], + input_2: &[u8; FP_LENGTH], +) -> Result { + let fp_1 = read_fp(input_1)?; + let fp_2 = read_fp(input_2)?; + + let fp2 = blst_fp2 { fp: [fp_1, fp_2] }; + + Ok(fp2) +} +/// Extracts a G2 point in Affine format from the x and y coordinates. +/// +/// Note: Coordinates are expected to be in Big Endian format. +/// By default, subgroup checks are performed. +fn read_g2( + a_x_0: &[u8; FP_LENGTH], + a_x_1: &[u8; FP_LENGTH], + a_y_0: &[u8; FP_LENGTH], + a_y_1: &[u8; FP_LENGTH], +) -> Result { + _extract_g2_input(a_x_0, a_x_1, a_y_0, a_y_1, true) +} +/// Extracts a G2 point in Affine format from the x and y coordinates +/// without performing a subgroup check. +/// +/// Note: Coordinates are expected to be in Big Endian format. +/// Skipping subgroup checks can introduce security issues. +/// This method should only be called if: +/// - The EIP specifies that no subgroup check should be performed +/// - One can be certain that the point is in the correct subgroup. +fn read_g2_no_subgroup_check( + a_x_0: &[u8; FP_LENGTH], + a_x_1: &[u8; FP_LENGTH], + a_y_0: &[u8; FP_LENGTH], + a_y_1: &[u8; FP_LENGTH], +) -> Result { + _extract_g2_input(a_x_0, a_x_1, a_y_0, a_y_1, false) +} +/// Extracts a G2 point in Affine format from the x and y coordinates. +/// +/// Note: Coordinates are expected to be in Big Endian format. +/// This function will perform a G2 subgroup check if `subgroup_check` is set to `true`. +fn _extract_g2_input( + a_x_0: &[u8; FP_LENGTH], + a_x_1: &[u8; FP_LENGTH], + a_y_0: &[u8; FP_LENGTH], + a_y_1: &[u8; FP_LENGTH], + subgroup_check: bool, +) -> Result { + let out = decode_g2_on_curve(a_x_0, a_x_1, a_y_0, a_y_1)?; + + if subgroup_check { + // NB: Subgroup checks + // + // Scalar multiplications, MSMs and pairings MUST perform a subgroup check. + // + // Implementations SHOULD use the optimized subgroup check method: + // + // https://eips.ethereum.org/assets/eip-2537/fast_subgroup_checks + // + // On any input that fail the subgroup check, the precompile MUST return an error. + // + // As endomorphism acceleration requires input on the correct subgroup, implementers MAY + // use endomorphism acceleration. + if unsafe { !blst_p2_affine_in_g2(&out) } { + return Err(PrecompileError::Other("Element not in G2".to_string())); + } + } + Ok(out) +} + +/// Checks whether or not the input represents a canonical field element +/// returning the field element if successful. +/// +/// Note: The field element is expected to be in big endian format. +fn read_fp(input: &[u8; FP_LENGTH]) -> Result { + if !is_valid_be(input) { + return Err(PrecompileError::Other("non-canonical fp value".to_string())); + } + let mut fp = blst_fp::default(); + // SAFETY: `input` has fixed length, and `fp` is a blst value. + unsafe { + // This performs the check for canonical field elements + blst_fp_from_bendian(&mut fp, input.as_ptr()); + } + + Ok(fp) +} + +/// Extracts a scalar from a 32 byte slice representation, decoding the input as a Big Endian +/// unsigned integer. If the input is not exactly 32 bytes long, an error is returned. +/// +/// From [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537): +/// * A scalar for the multiplication operation is encoded as 32 bytes by performing BigEndian +/// encoding of the corresponding (unsigned) integer. +/// +/// We do not check that the scalar is a canonical Fr element, because the EIP specifies: +/// * The corresponding integer is not required to be less than or equal than main subgroup order +/// `q`. +fn read_scalar(input: &[u8]) -> Result { + if input.len() != SCALAR_LENGTH { + return Err(PrecompileError::Other(format!( + "Input should be {SCALAR_LENGTH} bytes, was {}", + input.len() + ))); + } + + let mut out = blst_scalar::default(); + // SAFETY: `input` length is checked previously, out is a blst value. + unsafe { + // Note: We do not use `blst_scalar_fr_check` here because, from EIP-2537: + // + // * The corresponding integer is not required to be less than or equal than main subgroup + // order `q`. + blst_scalar_from_bendian(&mut out, input.as_ptr()) + }; + + Ok(out) +} + +/// Checks if the input is a valid big-endian representation of a field element. +fn is_valid_be(input: &[u8; 48]) -> bool { + *input < MODULUS_REPR +} + +// Byte-oriented versions of the functions for external API compatibility + +/// Performs point addition on two G1 points taking byte coordinates. +#[inline] +pub(super) fn p1_add_affine_bytes( + a: G1Point, + b: G1Point, +) -> Result<[u8; G1_LENGTH], crate::PrecompileError> { + let (a_x, a_y) = a; + let (b_x, b_y) = b; + // Parse first point + let p1 = read_g1_no_subgroup_check(&a_x, &a_y)?; + + // Parse second point + let p2 = read_g1_no_subgroup_check(&b_x, &b_y)?; + + // Perform addition + let result = p1_add_affine(&p1, &p2); + + // Encode result + Ok(encode_g1_point(&result)) +} + +/// Performs point addition on two G2 points taking byte coordinates. +#[inline] +pub(super) fn p2_add_affine_bytes( + a: G2Point, + b: G2Point, +) -> Result<[u8; G2_LENGTH], crate::PrecompileError> { + let (a_x_0, a_x_1, a_y_0, a_y_1) = a; + let (b_x_0, b_x_1, b_y_0, b_y_1) = b; + // Parse first point + let p1 = read_g2_no_subgroup_check(&a_x_0, &a_x_1, &a_y_0, &a_y_1)?; + + // Parse second point + let p2 = read_g2_no_subgroup_check(&b_x_0, &b_x_1, &b_y_0, &b_y_1)?; + + // Perform addition + let result = p2_add_affine(&p1, &p2); + + // Encode result + Ok(encode_g2_point(&result)) +} + +/// Maps a field element to a G1 point from bytes +#[inline] +pub(super) fn map_fp_to_g1_bytes( + fp_bytes: &[u8; FP_LENGTH], +) -> Result<[u8; G1_LENGTH], crate::PrecompileError> { + let fp = read_fp(fp_bytes)?; + let result = map_fp_to_g1(&fp); + Ok(encode_g1_point(&result)) +} + +/// Maps field elements to a G2 point from bytes +#[inline] +pub(super) fn map_fp2_to_g2_bytes( + fp2_x: &[u8; FP_LENGTH], + fp2_y: &[u8; FP_LENGTH], +) -> Result<[u8; G2_LENGTH], crate::PrecompileError> { + let fp2 = read_fp2(fp2_x, fp2_y)?; + let result = map_fp2_to_g2(&fp2); + Ok(encode_g2_point(&result)) +} + +/// Performs multi-scalar multiplication (MSM) for G1 points taking byte inputs. +#[inline] +pub(super) fn p1_msm_bytes( + point_scalar_pairs: impl Iterator< + Item = Result<(G1Point, [u8; SCALAR_LENGTH]), crate::PrecompileError>, + >, +) -> Result<[u8; G1_LENGTH], crate::PrecompileError> { + let mut g1_points = Vec::new(); + let mut scalars = Vec::new(); + + // Parse all points and scalars + for pair_result in point_scalar_pairs { + let ((x, y), scalar_bytes) = pair_result?; + + // NB: MSM requires subgroup check + let point = read_g1(&x, &y)?; + + // Skip zero scalars after validating the point + if scalar_bytes.iter().all(|&b| b == 0) { + continue; + } + + let scalar = read_scalar(&scalar_bytes)?; + g1_points.push(point); + scalars.push(scalar); + } + + // Return point at infinity if no pairs were provided or all scalars were zero + if g1_points.is_empty() { + return Ok([0u8; G1_LENGTH]); + } + + // Perform MSM + let result = p1_msm(g1_points, scalars); + + // Encode result + Ok(encode_g1_point(&result)) +} + +/// Performs multi-scalar multiplication (MSM) for G2 points taking byte inputs. +#[inline] +pub(super) fn p2_msm_bytes( + point_scalar_pairs: impl Iterator< + Item = Result<(G2Point, [u8; SCALAR_LENGTH]), crate::PrecompileError>, + >, +) -> Result<[u8; G2_LENGTH], crate::PrecompileError> { + let mut g2_points = Vec::new(); + let mut scalars = Vec::new(); + + // Parse all points and scalars + for pair_result in point_scalar_pairs { + let ((x_0, x_1, y_0, y_1), scalar_bytes) = pair_result?; + + // NB: MSM requires subgroup check + let point = read_g2(&x_0, &x_1, &y_0, &y_1)?; + + // Skip zero scalars after validating the point + if scalar_bytes.iter().all(|&b| b == 0) { + continue; + } + + let scalar = read_scalar(&scalar_bytes)?; + g2_points.push(point); + scalars.push(scalar); + } + + // Return point at infinity if no pairs were provided or all scalars were zero + if g2_points.is_empty() { + return Ok([0u8; G2_LENGTH]); + } + + // Perform MSM + let result = p2_msm(g2_points, scalars); + + // Encode result + Ok(encode_g2_point(&result)) +} + +/// pairing_check_bytes performs a pairing check on a list of G1 and G2 point pairs taking byte inputs. +#[inline] +pub(super) fn pairing_check_bytes(pairs: &[PairingPair]) -> Result { + if pairs.is_empty() { + return Ok(true); + } + + let mut parsed_pairs = Vec::with_capacity(pairs.len()); + for ((g1_x, g1_y), (g2_x_0, g2_x_1, g2_y_0, g2_y_1)) in pairs { + // Check if G1 point is zero (point at infinity) + let g1_is_zero = g1_x.iter().all(|&b| b == 0) && g1_y.iter().all(|&b| b == 0); + + // Check if G2 point is zero (point at infinity) + let g2_is_zero = g2_x_0.iter().all(|&b| b == 0) + && g2_x_1.iter().all(|&b| b == 0) + && g2_y_0.iter().all(|&b| b == 0) + && g2_y_1.iter().all(|&b| b == 0); + + // Skip this pair if either point is at infinity as it's a no-op + if g1_is_zero || g2_is_zero { + // Still need to validate the non-zero point if one exists + if !g1_is_zero { + let _ = read_g1(g1_x, g1_y)?; + } + if !g2_is_zero { + let _ = read_g2(g2_x_0, g2_x_1, g2_y_0, g2_y_1)?; + } + continue; + } + + let g1_point = read_g1(g1_x, g1_y)?; + let g2_point = read_g2(g2_x_0, g2_x_1, g2_y_0, g2_y_1)?; + parsed_pairs.push((g1_point, g2_point)); + } + + // If all pairs were filtered out, return true (identity element) + if parsed_pairs.is_empty() { + return Ok(true); + } + + Ok(pairing_check(&parsed_pairs)) +} diff --git a/crates/precompile/src/bls12_381/g1.rs b/crates/precompile/src/bls12_381/g1.rs deleted file mode 100644 index 6e4b73faab..0000000000 --- a/crates/precompile/src/bls12_381/g1.rs +++ /dev/null @@ -1,95 +0,0 @@ -use super::utils::{fp_from_bendian, fp_to_bytes, remove_padding, PADDED_FP_LENGTH}; -use crate::primitives::{Bytes, PrecompileError}; -use blst::{blst_p1_affine, blst_p1_affine_in_g1, blst_p1_affine_on_curve}; - -/// Length of each of the elements in a g1 operation input. -pub(super) const G1_INPUT_ITEM_LENGTH: usize = 128; - -/// Output length of a g1 operation. -const G1_OUTPUT_LENGTH: usize = 128; - -/// Encodes a G1 point in affine format into byte slice with padded elements. -pub(super) fn encode_g1_point(input: *const blst_p1_affine) -> Bytes { - let mut out = vec![0u8; G1_OUTPUT_LENGTH]; - // SAFETY: out comes from fixed length array, input is a blst value. - unsafe { - fp_to_bytes(&mut out[..PADDED_FP_LENGTH], &(*input).x); - fp_to_bytes(&mut out[PADDED_FP_LENGTH..], &(*input).y); - } - out.into() -} - -/// Returns a `blst_p1_affine` from the provided byte slices, which represent the x and y -/// affine coordinates of the point. -/// -/// If the x or y coordinate do not represent a canonical field element, an error is returned. -/// -/// See [fp_from_bendian] for more information. -pub(super) fn decode_and_check_g1( - p0_x: &[u8; 48], - p0_y: &[u8; 48], -) -> Result { - let out = blst_p1_affine { - x: fp_from_bendian(p0_x)?, - y: fp_from_bendian(p0_y)?, - }; - - Ok(out) -} - -/// Extracts a G1 point in Affine format from a 128 byte slice representation. -/// -/// NOTE: This function will perform a G1 subgroup check if `subgroup_check` is set to `true`. -pub(super) fn extract_g1_input( - input: &[u8], - subgroup_check: bool, -) -> Result { - if input.len() != G1_INPUT_ITEM_LENGTH { - return Err(PrecompileError::Other(format!( - "Input should be {G1_INPUT_ITEM_LENGTH} bytes, was {}", - input.len() - ))); - } - - let input_p0_x = remove_padding(&input[..PADDED_FP_LENGTH])?; - let input_p0_y = remove_padding(&input[PADDED_FP_LENGTH..G1_INPUT_ITEM_LENGTH])?; - let out = decode_and_check_g1(input_p0_x, input_p0_y)?; - - if subgroup_check { - // NB: Subgroup checks - // - // Scalar multiplications, MSMs and pairings MUST perform a subgroup check. - // - // Implementations SHOULD use the optimized subgroup check method: - // - // https://eips.ethereum.org/assets/eip-2537/fast_subgroup_checks - // - // On any input that fail the subgroup check, the precompile MUST return an error. - // - // As endomorphism acceleration requires input on the correct subgroup, implementers MAY - // use endomorphism acceleration. - if unsafe { !blst_p1_affine_in_g1(&out) } { - return Err(PrecompileError::Other("Element not in G2".to_string())); - } - } else { - // From EIP-2537: - // - // Error cases: - // - // * An input is neither a point on the G1 elliptic curve nor the infinity point - // - // NB: There is no subgroup check for the G1 addition precompile. - // - // We use blst_p1_affine_on_curve instead of blst_p1_affine_in_g2 because the latter performs - // the subgroup check. - // - // SAFETY: out is a blst value. - if unsafe { !blst_p1_affine_on_curve(&out) } { - return Err(PrecompileError::Other( - "Element not on G2 curve".to_string(), - )); - } - } - - Ok(out) -} diff --git a/crates/precompile/src/bls12_381/g1_add.rs b/crates/precompile/src/bls12_381/g1_add.rs index 9fed002dfc..c8aa2f80f0 100644 --- a/crates/precompile/src/bls12_381/g1_add.rs +++ b/crates/precompile/src/bls12_381/g1_add.rs @@ -1,56 +1,46 @@ -use super::g1::{encode_g1_point, extract_g1_input, G1_INPUT_ITEM_LENGTH}; -use crate::{u64_to_address, PrecompileWithAddress}; -use blst::{ - blst_p1, blst_p1_add_or_double_affine, blst_p1_affine, blst_p1_from_affine, blst_p1_to_affine, +//! BLS12-381 G1 add precompile. More details in [`g1_add`] +use super::crypto_backend::p1_add_affine_bytes; +use super::utils::{pad_g1_point, remove_g1_padding}; +use crate::bls12_381_const::{ + G1_ADD_ADDRESS, G1_ADD_BASE_GAS_FEE, G1_ADD_INPUT_LENGTH, PADDED_G1_LENGTH, }; -use revm_primitives::{Bytes, Precompile, PrecompileError, PrecompileResult}; +use crate::{PrecompileError, PrecompileOutput, PrecompileResult, PrecompileWithAddress}; /// [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537#specification) BLS12_G1ADD precompile. -pub const PRECOMPILE: PrecompileWithAddress = - PrecompileWithAddress(u64_to_address(ADDRESS), Precompile::Standard(g1_add)); -/// BLS12_G1ADD precompile address. -pub const ADDRESS: u64 = 0x0b; -/// Base gas fee for BLS12-381 g1_add operation. -const BASE_GAS_FEE: u64 = 500; - -/// Input length of g1_add operation. -const INPUT_LENGTH: usize = 256; +pub const PRECOMPILE: PrecompileWithAddress = PrecompileWithAddress(G1_ADD_ADDRESS, g1_add); /// G1 addition call expects `256` bytes as an input that is interpreted as byte /// concatenation of two G1 points (`128` bytes each). /// Output is an encoding of addition operation result - single G1 point (`128` /// bytes). /// See also: -pub(super) fn g1_add(input: &Bytes, gas_limit: u64) -> PrecompileResult { - if BASE_GAS_FEE > gas_limit { +pub fn g1_add(input: &[u8], gas_limit: u64) -> PrecompileResult { + if G1_ADD_BASE_GAS_FEE > gas_limit { return Err(PrecompileError::OutOfGas); } - if input.len() != INPUT_LENGTH { + if input.len() != G1_ADD_INPUT_LENGTH { return Err(PrecompileError::Other(format!( - "G1ADD input should be {INPUT_LENGTH} bytes, was {}", + "G1ADD input should be {G1_ADD_INPUT_LENGTH} bytes, was {}", input.len() ))); } - // NB: There is no subgroup check for the G1 addition precompile. - // - // So we set the subgroup checks here to `false` - let a_aff = &extract_g1_input(&input[..G1_INPUT_ITEM_LENGTH], false)?; - let b_aff = &extract_g1_input(&input[G1_INPUT_ITEM_LENGTH..], false)?; + // Extract coordinates from padded input + let [a_x, a_y] = remove_g1_padding(&input[..PADDED_G1_LENGTH])?; + let [b_x, b_y] = remove_g1_padding(&input[PADDED_G1_LENGTH..])?; - let mut b = blst_p1::default(); - // SAFETY: b and b_aff are blst values. - unsafe { blst_p1_from_affine(&mut b, b_aff) }; + let a = (*a_x, *a_y); + let b = (*b_x, *b_y); - let mut p = blst_p1::default(); - // SAFETY: p, b and a_aff are blst values. - unsafe { blst_p1_add_or_double_affine(&mut p, &b, a_aff) }; + // Get unpadded result from crypto backend + let unpadded_result = p1_add_affine_bytes(a, b)?; - let mut p_aff = blst_p1_affine::default(); - // SAFETY: p_aff and p are blst values. - unsafe { blst_p1_to_affine(&mut p_aff, &p) }; + // Pad the result for EVM compatibility + let padded_result = pad_g1_point(&unpadded_result); - let out = encode_g1_point(&p_aff); - Ok((BASE_GAS_FEE, out)) + Ok(PrecompileOutput::new( + G1_ADD_BASE_GAS_FEE, + padded_result.into(), + )) } diff --git a/crates/precompile/src/bls12_381/g1_msm.rs b/crates/precompile/src/bls12_381/g1_msm.rs index f0003a3295..f47802ef4b 100644 --- a/crates/precompile/src/bls12_381/g1_msm.rs +++ b/crates/precompile/src/bls12_381/g1_msm.rs @@ -1,19 +1,16 @@ -use super::{ - g1::{encode_g1_point, extract_g1_input, G1_INPUT_ITEM_LENGTH}, - g1_mul, - msm::msm_required_gas, - utils::{extract_scalar_input, NBITS, SCALAR_LENGTH}, +//! BLS12-381 G1 msm precompile. More details in [`g1_msm`] +use super::crypto_backend::p1_msm_bytes; +use super::G1Point; +use crate::bls12_381::utils::{pad_g1_point, remove_g1_padding}; +use crate::bls12_381_const::{ + DISCOUNT_TABLE_G1_MSM, G1_MSM_ADDRESS, G1_MSM_BASE_GAS_FEE, G1_MSM_INPUT_LENGTH, + PADDED_G1_LENGTH, SCALAR_LENGTH, }; -use crate::{u64_to_address, PrecompileWithAddress}; -use blst::{blst_p1, blst_p1_affine, blst_p1_from_affine, blst_p1_to_affine, p1_affines}; -use revm_primitives::{Bytes, Precompile, PrecompileError, PrecompileResult}; +use crate::bls12_381_utils::msm_required_gas; +use crate::{PrecompileError, PrecompileOutput, PrecompileResult, PrecompileWithAddress}; /// [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537#specification) BLS12_G1MSM precompile. -pub const PRECOMPILE: PrecompileWithAddress = - PrecompileWithAddress(u64_to_address(ADDRESS), Precompile::Standard(g1_msm)); - -/// BLS12_G1MSM precompile address. -pub const ADDRESS: u64 = 0x0d; +pub const PRECOMPILE: PrecompileWithAddress = PrecompileWithAddress(G1_MSM_ADDRESS, g1_msm); /// Implements EIP-2537 G1MSM precompile. /// G1 multi-scalar-multiplication call expects `160*k` bytes as an input that is interpreted @@ -23,65 +20,55 @@ pub const ADDRESS: u64 = 0x0d; /// Output is an encoding of multi-scalar-multiplication operation result - single G1 /// point (`128` bytes). /// See also: -pub(super) fn g1_msm(input: &Bytes, gas_limit: u64) -> PrecompileResult { +pub fn g1_msm(input: &[u8], gas_limit: u64) -> PrecompileResult { let input_len = input.len(); - if input_len == 0 || input_len % g1_mul::INPUT_LENGTH != 0 { + if input_len == 0 || input_len % G1_MSM_INPUT_LENGTH != 0 { return Err(PrecompileError::Other(format!( - "G1MSM input length should be multiple of {}, was {}", - g1_mul::INPUT_LENGTH, - input_len + "G1MSM input length should be multiple of {G1_MSM_INPUT_LENGTH}, was {input_len}", ))); } - let k = input_len / g1_mul::INPUT_LENGTH; - let required_gas = msm_required_gas(k, g1_mul::BASE_GAS_FEE); + let k = input_len / G1_MSM_INPUT_LENGTH; + let required_gas = msm_required_gas(k, &DISCOUNT_TABLE_G1_MSM, G1_MSM_BASE_GAS_FEE); if required_gas > gas_limit { return Err(PrecompileError::OutOfGas); } - let mut g1_points: Vec = Vec::with_capacity(k); - let mut scalars: Vec = Vec::with_capacity(k * SCALAR_LENGTH); - for i in 0..k { - let slice = - &input[i * g1_mul::INPUT_LENGTH..i * g1_mul::INPUT_LENGTH + G1_INPUT_ITEM_LENGTH]; - - // BLST batch API for p1_affines blows up when you pass it a point at infinity and returns - // point at infinity so we just skip the element, and return 128 bytes in the response - if slice.iter().all(|i| *i == 0) { - continue; - } + let valid_pairs_iter = (0..k).map(|i| { + let start = i * G1_MSM_INPUT_LENGTH; + let padded_g1 = &input[start..start + PADDED_G1_LENGTH]; + let scalar_bytes = &input[start + PADDED_G1_LENGTH..start + G1_MSM_INPUT_LENGTH]; - // NB: Scalar multiplications, MSMs and pairings MUST perform a subgroup check. - // - // So we set the subgroup_check flag to `true` - let p0_aff = &extract_g1_input(slice, true)?; + // Remove padding from G1 point - this validates padding format + let [x, y] = remove_g1_padding(padded_g1)?; + let scalar_array: [u8; SCALAR_LENGTH] = scalar_bytes.try_into().unwrap(); - let mut p0 = blst_p1::default(); - // SAFETY: p0 and p0_aff are blst values. - unsafe { blst_p1_from_affine(&mut p0, p0_aff) }; - g1_points.push(p0); + let point: G1Point = (*x, *y); + Ok((point, scalar_array)) + }); - scalars.extend_from_slice( - &extract_scalar_input( - &input[i * g1_mul::INPUT_LENGTH + G1_INPUT_ITEM_LENGTH - ..i * g1_mul::INPUT_LENGTH + G1_INPUT_ITEM_LENGTH + SCALAR_LENGTH], - )? - .b, - ); - } + let unpadded_result = p1_msm_bytes(valid_pairs_iter)?; - // return infinity point if all points are infinity - if g1_points.is_empty() { - return Ok((required_gas, [0; 128].into())); - } + // Pad the result for EVM compatibility + let padded_result = pad_g1_point(&unpadded_result); - let points = p1_affines::from(&g1_points); - let multiexp = points.mult(&scalars, NBITS); + Ok(PrecompileOutput::new(required_gas, padded_result.into())) +} - let mut multiexp_aff = blst_p1_affine::default(); - // SAFETY: multiexp_aff and multiexp are blst values. - unsafe { blst_p1_to_affine(&mut multiexp_aff, &multiexp) }; +#[cfg(test)] +mod test { + use super::*; + use primitives::{hex, Bytes}; - let out = encode_g1_point(&multiexp_aff); - Ok((required_gas, out)) + #[test] + fn bls_g1multiexp_g1_not_on_curve_but_in_subgroup() { + let input = Bytes::from(hex!("000000000000000000000000000000000a2833e497b38ee3ca5c62828bf4887a9f940c9e426c7890a759c20f248c23a7210d2432f4c98a514e524b5184a0ddac00000000000000000000000000000000150772d56bf9509469f9ebcd6e47570429fd31b0e262b66d512e245c38ec37255529f2271fd70066473e393a8bead0c30000000000000000000000000000000000000000000000000000000000000000")); + let fail = g1_msm(&input, G1_MSM_BASE_GAS_FEE); + assert_eq!( + fail, + Err(PrecompileError::Other( + "Element not on G1 curve".to_string() + )) + ); + } } diff --git a/crates/precompile/src/bls12_381/g1_mul.rs b/crates/precompile/src/bls12_381/g1_mul.rs deleted file mode 100644 index 2b62a39c1d..0000000000 --- a/crates/precompile/src/bls12_381/g1_mul.rs +++ /dev/null @@ -1,59 +0,0 @@ -use super::{ - g1::{encode_g1_point, extract_g1_input, G1_INPUT_ITEM_LENGTH}, - utils::{extract_scalar_input, NBITS}, -}; -use crate::{u64_to_address, PrecompileWithAddress}; -use blst::{blst_p1, blst_p1_affine, blst_p1_from_affine, blst_p1_mult, blst_p1_to_affine}; -use revm_primitives::{Bytes, Precompile, PrecompileError, PrecompileResult}; - -/// [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537#specification) BLS12_G1MUL precompile. -pub const PRECOMPILE: PrecompileWithAddress = - PrecompileWithAddress(u64_to_address(ADDRESS), Precompile::Standard(g1_mul)); -/// BLS12_G1MUL precompile address. -pub const ADDRESS: u64 = 0x0c; -/// Base gas fee for BLS12-381 g1_mul operation. -pub(super) const BASE_GAS_FEE: u64 = 12000; - -/// Input length of g1_mul operation. -pub(super) const INPUT_LENGTH: usize = 160; - -/// G1 multiplication call expects `160` bytes as an input that is interpreted as -/// byte concatenation of encoding of G1 point (`128` bytes) and encoding of a -/// scalar value (`32` bytes). -/// Output is an encoding of multiplication operation result - single G1 point -/// (`128` bytes). -/// See also: -pub(super) fn g1_mul(input: &Bytes, gas_limit: u64) -> PrecompileResult { - if BASE_GAS_FEE > gas_limit { - return Err(PrecompileError::OutOfGas); - } - if input.len() != INPUT_LENGTH { - return Err(PrecompileError::Other(format!( - "G1MUL input should be {INPUT_LENGTH} bytes, was {}", - input.len() - ))); - } - - // NB: Scalar multiplications, MSMs and pairings MUST perform a subgroup check. - // - // So we set the subgroup_check flag to `true` - let slice = &input[..G1_INPUT_ITEM_LENGTH]; - let p0_aff = &extract_g1_input(slice, true)?; - - let mut p0 = blst_p1::default(); - - // SAFETY: p0 and p0_aff are blst values. - unsafe { blst_p1_from_affine(&mut p0, p0_aff) }; - - let input_scalar0 = extract_scalar_input(&input[G1_INPUT_ITEM_LENGTH..])?; - - let mut p = blst_p1::default(); - // SAFETY: input_scalar0.b has fixed size, p and p0 are blst values. - unsafe { blst_p1_mult(&mut p, &p0, input_scalar0.b.as_ptr(), NBITS) }; - let mut p_aff = blst_p1_affine::default(); - // SAFETY: p_aff and p are blst values. - unsafe { blst_p1_to_affine(&mut p_aff, &p) }; - - let out = encode_g1_point(&p_aff); - Ok((BASE_GAS_FEE, out)) -} diff --git a/crates/precompile/src/bls12_381/g2.rs b/crates/precompile/src/bls12_381/g2.rs deleted file mode 100644 index 585368959e..0000000000 --- a/crates/precompile/src/bls12_381/g2.rs +++ /dev/null @@ -1,115 +0,0 @@ -use super::utils::{fp_from_bendian, fp_to_bytes, remove_padding, FP_LENGTH, PADDED_FP_LENGTH}; -use crate::primitives::{Bytes, PrecompileError}; -use blst::{blst_fp2, blst_p2_affine, blst_p2_affine_in_g2, blst_p2_affine_on_curve}; - -/// Length of each of the elements in a g2 operation input. -pub(super) const G2_INPUT_ITEM_LENGTH: usize = 256; - -/// Output length of a g2 operation. -const G2_OUTPUT_LENGTH: usize = 256; - -/// Encodes a G2 point in affine format into byte slice with padded elements. -pub(super) fn encode_g2_point(input: &blst_p2_affine) -> Bytes { - let mut out = vec![0u8; G2_OUTPUT_LENGTH]; - fp_to_bytes(&mut out[..PADDED_FP_LENGTH], &input.x.fp[0]); - fp_to_bytes( - &mut out[PADDED_FP_LENGTH..2 * PADDED_FP_LENGTH], - &input.x.fp[1], - ); - fp_to_bytes( - &mut out[2 * PADDED_FP_LENGTH..3 * PADDED_FP_LENGTH], - &input.y.fp[0], - ); - fp_to_bytes( - &mut out[3 * PADDED_FP_LENGTH..4 * PADDED_FP_LENGTH], - &input.y.fp[1], - ); - out.into() -} - -/// Convert the following field elements from byte slices into a `blst_p2_affine` point. -pub(super) fn decode_and_check_g2( - x1: &[u8; 48], - x2: &[u8; 48], - y1: &[u8; 48], - y2: &[u8; 48], -) -> Result { - Ok(blst_p2_affine { - x: check_canonical_fp2(x1, x2)?, - y: check_canonical_fp2(y1, y2)?, - }) -} - -/// Checks whether or not the input represents a canonical fp2 field element, returning the field -/// element if successful. -pub(super) fn check_canonical_fp2( - input_1: &[u8; 48], - input_2: &[u8; 48], -) -> Result { - let fp_1 = fp_from_bendian(input_1)?; - let fp_2 = fp_from_bendian(input_2)?; - - let fp2 = blst_fp2 { fp: [fp_1, fp_2] }; - - Ok(fp2) -} - -/// Extracts a G2 point in Affine format from a 256 byte slice representation. -/// -/// NOTE: This function will perform a G2 subgroup check if `subgroup_check` is set to `true`. -pub(super) fn extract_g2_input( - input: &[u8], - subgroup_check: bool, -) -> Result { - if input.len() != G2_INPUT_ITEM_LENGTH { - return Err(PrecompileError::Other(format!( - "Input should be {G2_INPUT_ITEM_LENGTH} bytes, was {}", - input.len() - ))); - } - - let mut input_fps: [&[u8; FP_LENGTH]; 4] = [&[0; FP_LENGTH]; 4]; - for i in 0..4 { - input_fps[i] = remove_padding(&input[i * PADDED_FP_LENGTH..(i + 1) * PADDED_FP_LENGTH])?; - } - - let out = decode_and_check_g2(input_fps[0], input_fps[1], input_fps[2], input_fps[3])?; - - if subgroup_check { - // NB: Subgroup checks - // - // Scalar multiplications, MSMs and pairings MUST perform a subgroup check. - // - // Implementations SHOULD use the optimized subgroup check method: - // - // https://eips.ethereum.org/assets/eip-2537/fast_subgroup_checks - // - // On any input that fail the subgroup check, the precompile MUST return an error. - // - // As endomorphism acceleration requires input on the correct subgroup, implementers MAY - // use endomorphism acceleration. - if unsafe { !blst_p2_affine_in_g2(&out) } { - return Err(PrecompileError::Other("Element not in G2".to_string())); - } - } else { - // From EIP-2537: - // - // Error cases: - // - // * An input is neither a point on the G2 elliptic curve nor the infinity point - // - // NB: There is no subgroup check for the G2 addition precompile. - // - // We use blst_p2_affine_on_curve instead of blst_p2_affine_in_g2 because the latter performs - // the subgroup check. - // - // SAFETY: out is a blst value. - if unsafe { !blst_p2_affine_on_curve(&out) } { - return Err(PrecompileError::Other( - "Element not on G2 curve".to_string(), - )); - } - } - - Ok(out) -} diff --git a/crates/precompile/src/bls12_381/g2_add.rs b/crates/precompile/src/bls12_381/g2_add.rs index a8f5b85a8e..bcd4f7984e 100644 --- a/crates/precompile/src/bls12_381/g2_add.rs +++ b/crates/precompile/src/bls12_381/g2_add.rs @@ -1,20 +1,13 @@ -use super::g2::{encode_g2_point, extract_g2_input, G2_INPUT_ITEM_LENGTH}; -use crate::{u64_to_address, PrecompileWithAddress}; -use blst::{ - blst_p2, blst_p2_add_or_double_affine, blst_p2_affine, blst_p2_from_affine, blst_p2_to_affine, +//! BLS12-381 G2 add precompile. More details in [`g2_add`] +use super::crypto_backend::p2_add_affine_bytes; +use super::utils::{pad_g2_point, remove_g2_padding}; +use crate::bls12_381_const::{ + G2_ADD_ADDRESS, G2_ADD_BASE_GAS_FEE, G2_ADD_INPUT_LENGTH, PADDED_G2_LENGTH, }; -use revm_primitives::{Bytes, Precompile, PrecompileError, PrecompileResult}; +use crate::{PrecompileError, PrecompileOutput, PrecompileResult, PrecompileWithAddress}; /// [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537#specification) BLS12_G2ADD precompile. -pub const PRECOMPILE: PrecompileWithAddress = - PrecompileWithAddress(u64_to_address(ADDRESS), Precompile::Standard(g2_add)); -/// BLS12_G2ADD precompile address. -pub const ADDRESS: u64 = 0x0e; -/// Base gas fee for BLS12-381 g2_add operation. -const BASE_GAS_FEE: u64 = 800; - -/// Input length of g2_add operation. -const INPUT_LENGTH: usize = 512; +pub const PRECOMPILE: PrecompileWithAddress = PrecompileWithAddress(G2_ADD_ADDRESS, g2_add); /// G2 addition call expects `512` bytes as an input that is interpreted as byte /// concatenation of two G2 points (`256` bytes each). @@ -22,36 +15,33 @@ const INPUT_LENGTH: usize = 512; /// Output is an encoding of addition operation result - single G2 point (`256` /// bytes). /// See also -pub(super) fn g2_add(input: &Bytes, gas_limit: u64) -> PrecompileResult { - if BASE_GAS_FEE > gas_limit { +pub fn g2_add(input: &[u8], gas_limit: u64) -> PrecompileResult { + if G2_ADD_BASE_GAS_FEE > gas_limit { return Err(PrecompileError::OutOfGas); } - if input.len() != INPUT_LENGTH { + if input.len() != G2_ADD_INPUT_LENGTH { return Err(PrecompileError::Other(format!( - "G2ADD input should be {INPUT_LENGTH} bytes, was {}", + "G2ADD input should be {G2_ADD_INPUT_LENGTH} bytes, was {}", input.len() ))); } - // NB: There is no subgroup check for the G2 addition precompile. - // - // So we set the subgroup checks here to `false` - let a_aff = &extract_g2_input(&input[..G2_INPUT_ITEM_LENGTH], false)?; - let b_aff = &extract_g2_input(&input[G2_INPUT_ITEM_LENGTH..], false)?; + // Extract coordinates from padded input + let [a_x_0, a_x_1, a_y_0, a_y_1] = remove_g2_padding(&input[..PADDED_G2_LENGTH])?; + let [b_x_0, b_x_1, b_y_0, b_y_1] = remove_g2_padding(&input[PADDED_G2_LENGTH..])?; - let mut b = blst_p2::default(); - // SAFETY: b and b_aff are blst values. - unsafe { blst_p2_from_affine(&mut b, b_aff) }; + let a = (*a_x_0, *a_x_1, *a_y_0, *a_y_1); + let b = (*b_x_0, *b_x_1, *b_y_0, *b_y_1); - let mut p = blst_p2::default(); - // SAFETY: p, b and a_aff are blst values. - unsafe { blst_p2_add_or_double_affine(&mut p, &b, a_aff) }; + // Get unpadded result from crypto backend + let unpadded_result = p2_add_affine_bytes(a, b)?; - let mut p_aff = blst_p2_affine::default(); - // SAFETY: p_aff and p are blst values. - unsafe { blst_p2_to_affine(&mut p_aff, &p) }; + // Pad the result for EVM compatibility + let padded_result = pad_g2_point(&unpadded_result); - let out = encode_g2_point(&p_aff); - Ok((BASE_GAS_FEE, out)) + Ok(PrecompileOutput::new( + G2_ADD_BASE_GAS_FEE, + padded_result.into(), + )) } diff --git a/crates/precompile/src/bls12_381/g2_msm.rs b/crates/precompile/src/bls12_381/g2_msm.rs index cedc73a147..98dfa71768 100644 --- a/crates/precompile/src/bls12_381/g2_msm.rs +++ b/crates/precompile/src/bls12_381/g2_msm.rs @@ -1,19 +1,16 @@ -use super::{ - g2::{encode_g2_point, extract_g2_input, G2_INPUT_ITEM_LENGTH}, - g2_mul, - msm::msm_required_gas, - utils::{extract_scalar_input, NBITS, SCALAR_LENGTH}, +//! BLS12-381 G2 msm precompile. More details in [`g2_msm`] +use super::crypto_backend::p2_msm_bytes; +use super::utils::{pad_g2_point, remove_g2_padding}; +use super::G2Point; +use crate::bls12_381_const::{ + DISCOUNT_TABLE_G2_MSM, G2_MSM_ADDRESS, G2_MSM_BASE_GAS_FEE, G2_MSM_INPUT_LENGTH, + PADDED_G2_LENGTH, SCALAR_LENGTH, }; -use crate::{u64_to_address, PrecompileWithAddress}; -use blst::{blst_p2, blst_p2_affine, blst_p2_from_affine, blst_p2_to_affine, p2_affines}; -use revm_primitives::{Bytes, Precompile, PrecompileError, PrecompileResult}; +use crate::bls12_381_utils::msm_required_gas; +use crate::{PrecompileError, PrecompileOutput, PrecompileResult, PrecompileWithAddress}; /// [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537#specification) BLS12_G2MSM precompile. -pub const PRECOMPILE: PrecompileWithAddress = - PrecompileWithAddress(u64_to_address(ADDRESS), Precompile::Standard(g2_msm)); - -/// BLS12_G2MSM precompile address. -pub const ADDRESS: u64 = 0x10; +pub const PRECOMPILE: PrecompileWithAddress = PrecompileWithAddress(G2_MSM_ADDRESS, g2_msm); /// Implements EIP-2537 G2MSM precompile. /// G2 multi-scalar-multiplication call expects `288*k` bytes as an input that is interpreted @@ -23,65 +20,37 @@ pub const ADDRESS: u64 = 0x10; /// Output is an encoding of multi-scalar-multiplication operation result - single G2 /// point (`256` bytes). /// See also: -pub(super) fn g2_msm(input: &Bytes, gas_limit: u64) -> PrecompileResult { +pub fn g2_msm(input: &[u8], gas_limit: u64) -> PrecompileResult { let input_len = input.len(); - if input_len == 0 || input_len % g2_mul::INPUT_LENGTH != 0 { + if input_len == 0 || input_len % G2_MSM_INPUT_LENGTH != 0 { return Err(PrecompileError::Other(format!( - "G2MSM input length should be multiple of {}, was {}", - g2_mul::INPUT_LENGTH, - input_len + "G2MSM input length should be multiple of {G2_MSM_INPUT_LENGTH}, was {input_len}", ))); } - let k = input_len / g2_mul::INPUT_LENGTH; - let required_gas = msm_required_gas(k, g2_mul::BASE_GAS_FEE); + let k = input_len / G2_MSM_INPUT_LENGTH; + let required_gas = msm_required_gas(k, &DISCOUNT_TABLE_G2_MSM, G2_MSM_BASE_GAS_FEE); if required_gas > gas_limit { return Err(PrecompileError::OutOfGas); } - let mut g2_points: Vec = Vec::with_capacity(k); - let mut scalars: Vec = Vec::with_capacity(k * SCALAR_LENGTH); - for i in 0..k { - let slice = - &input[i * g2_mul::INPUT_LENGTH..i * g2_mul::INPUT_LENGTH + G2_INPUT_ITEM_LENGTH]; - // BLST batch API for p2_affines blows up when you pass it a point at infinity and returns - // point at infinity so we just skip the element, and return 256 bytes in the response - if slice.iter().all(|i| *i == 0) { - continue; - } - - // NB: Scalar multiplications, MSMs and pairings MUST perform a subgroup check. - // - // So we set the subgroup_check flag to `true` - let p0_aff = &extract_g2_input(slice, true)?; - - let mut p0 = blst_p2::default(); - // SAFETY: p0 and p0_aff are blst values. - unsafe { blst_p2_from_affine(&mut p0, p0_aff) }; + let valid_pairs_iter = (0..k).map(|i| { + let start = i * G2_MSM_INPUT_LENGTH; + let padded_g2 = &input[start..start + PADDED_G2_LENGTH]; + let scalar_bytes = &input[start + PADDED_G2_LENGTH..start + G2_MSM_INPUT_LENGTH]; - g2_points.push(p0); + // Remove padding from G2 point - this validates padding format + let [x_0, x_1, y_0, y_1] = remove_g2_padding(padded_g2)?; + let scalar_array: [u8; SCALAR_LENGTH] = scalar_bytes.try_into().unwrap(); - scalars.extend_from_slice( - &extract_scalar_input( - &input[i * g2_mul::INPUT_LENGTH + G2_INPUT_ITEM_LENGTH - ..i * g2_mul::INPUT_LENGTH + G2_INPUT_ITEM_LENGTH + SCALAR_LENGTH], - )? - .b, - ); - } - - // return infinity point if all points are infinity - if g2_points.is_empty() { - return Ok((required_gas, [0; 256].into())); - } + let point: G2Point = (*x_0, *x_1, *y_0, *y_1); + Ok((point, scalar_array)) + }); - let points = p2_affines::from(&g2_points); - let multiexp = points.mult(&scalars, NBITS); + let unpadded_result = p2_msm_bytes(valid_pairs_iter)?; - let mut multiexp_aff = blst_p2_affine::default(); - // SAFETY: multiexp_aff and multiexp are blst values. - unsafe { blst_p2_to_affine(&mut multiexp_aff, &multiexp) }; + // Pad the result for EVM compatibility + let padded_result = pad_g2_point(&unpadded_result); - let out = encode_g2_point(&multiexp_aff); - Ok((required_gas, out)) + Ok(PrecompileOutput::new(required_gas, padded_result.into())) } diff --git a/crates/precompile/src/bls12_381/g2_mul.rs b/crates/precompile/src/bls12_381/g2_mul.rs deleted file mode 100644 index 62cb903e9b..0000000000 --- a/crates/precompile/src/bls12_381/g2_mul.rs +++ /dev/null @@ -1,56 +0,0 @@ -use super::{ - g2::{encode_g2_point, extract_g2_input, G2_INPUT_ITEM_LENGTH}, - utils::{extract_scalar_input, NBITS}, -}; -use crate::{u64_to_address, PrecompileWithAddress}; -use blst::{blst_p2, blst_p2_affine, blst_p2_from_affine, blst_p2_mult, blst_p2_to_affine}; -use revm_primitives::{Bytes, Precompile, PrecompileError, PrecompileResult}; - -/// [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537#specification) BLS12_G2MUL precompile. -pub const PRECOMPILE: PrecompileWithAddress = - PrecompileWithAddress(u64_to_address(ADDRESS), Precompile::Standard(g2_mul)); -/// BLS12_G2MUL precompile address. -pub const ADDRESS: u64 = 0x0f; -/// Base gas fee for BLS12-381 g2_mul operation. -pub(super) const BASE_GAS_FEE: u64 = 45000; - -/// Input length of g2_mul operation. -pub(super) const INPUT_LENGTH: usize = 288; - -/// G2 multiplication call expects `288` bytes as an input that is interpreted as -/// byte concatenation of encoding of G2 point (`256` bytes) and encoding of a -/// scalar value (`32` bytes). -/// Output is an encoding of multiplication operation result - single G2 point -/// (`256` bytes). -/// See also: -pub(super) fn g2_mul(input: &Bytes, gas_limit: u64) -> PrecompileResult { - if BASE_GAS_FEE > gas_limit { - return Err(PrecompileError::OutOfGas); - } - if input.len() != INPUT_LENGTH { - return Err(PrecompileError::Other(format!( - "G2MUL input should be {INPUT_LENGTH} bytes, was {}", - input.len() - ))); - } - - // NB: Scalar multiplications, MSMs and pairings MUST perform a subgroup check. - // - // So we set the subgroup_check flag to `true` - let p0_aff = &extract_g2_input(&input[..G2_INPUT_ITEM_LENGTH], true)?; - let mut p0 = blst_p2::default(); - // SAFETY: p0 and p0_aff are blst values. - unsafe { blst_p2_from_affine(&mut p0, p0_aff) }; - - let input_scalar0 = extract_scalar_input(&input[G2_INPUT_ITEM_LENGTH..])?; - - let mut p = blst_p2::default(); - // SAFETY: input_scalar0.b has fixed size, p and p0 are blst values. - unsafe { blst_p2_mult(&mut p, &p0, input_scalar0.b.as_ptr(), NBITS) }; - let mut p_aff = blst_p2_affine::default(); - // SAFETY: p_aff and p are blst values. - unsafe { blst_p2_to_affine(&mut p_aff, &p) }; - - let out = encode_g2_point(&p_aff); - Ok((BASE_GAS_FEE, out)) -} diff --git a/crates/precompile/src/bls12_381/map_fp2_to_g2.rs b/crates/precompile/src/bls12_381/map_fp2_to_g2.rs index 30c3ab5b63..50f67a32cb 100644 --- a/crates/precompile/src/bls12_381/map_fp2_to_g2.rs +++ b/crates/precompile/src/bls12_381/map_fp2_to_g2.rs @@ -1,28 +1,24 @@ +//! BLS12-381 map fp2 to g2 precompile. More details in [`map_fp2_to_g2`] use super::{ - g2::check_canonical_fp2, - g2::encode_g2_point, - utils::{remove_padding, PADDED_FP2_LENGTH, PADDED_FP_LENGTH}, + crypto_backend::map_fp2_to_g2_bytes, + utils::{pad_g2_point, remove_fp_padding}, }; -use crate::{u64_to_address, PrecompileWithAddress}; -use blst::{blst_map_to_g2, blst_p2, blst_p2_affine, blst_p2_to_affine}; -use revm_primitives::{Bytes, Precompile, PrecompileError, PrecompileResult}; +use crate::bls12_381_const::{ + MAP_FP2_TO_G2_ADDRESS, MAP_FP2_TO_G2_BASE_GAS_FEE, PADDED_FP2_LENGTH, PADDED_FP_LENGTH, +}; +use crate::PrecompileWithAddress; +use crate::{PrecompileError, PrecompileOutput, PrecompileResult}; /// [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537#specification) BLS12_MAP_FP2_TO_G2 precompile. pub const PRECOMPILE: PrecompileWithAddress = - PrecompileWithAddress(u64_to_address(ADDRESS), Precompile::Standard(map_fp2_to_g2)); - -/// BLS12_MAP_FP2_TO_G2 precompile address. -pub const ADDRESS: u64 = 0x13; - -/// Base gas fee for BLS12-381 map_fp2_to_g2 operation. -const BASE_GAS_FEE: u64 = 75000; + PrecompileWithAddress(MAP_FP2_TO_G2_ADDRESS, map_fp2_to_g2); -/// Field-to-curve call expects 128 bytes as an input that is interpreted as a +/// Field-to-curve call expects 128 bytes as an input that is interpreted as /// an element of Fp2. Output of this call is 256 bytes and is an encoded G2 /// point. /// See also: -pub(super) fn map_fp2_to_g2(input: &Bytes, gas_limit: u64) -> PrecompileResult { - if BASE_GAS_FEE > gas_limit { +pub fn map_fp2_to_g2(input: &[u8], gas_limit: u64) -> PrecompileResult { + if MAP_FP2_TO_G2_BASE_GAS_FEE > gas_limit { return Err(PrecompileError::OutOfGas); } @@ -33,19 +29,17 @@ pub(super) fn map_fp2_to_g2(input: &Bytes, gas_limit: u64) -> PrecompileResult { ))); } - let input_p0_x = remove_padding(&input[..PADDED_FP_LENGTH])?; - let input_p0_y = remove_padding(&input[PADDED_FP_LENGTH..PADDED_FP2_LENGTH])?; - let fp2 = check_canonical_fp2(input_p0_x, input_p0_y)?; + let input_p0_x = remove_fp_padding(&input[..PADDED_FP_LENGTH])?; + let input_p0_y = remove_fp_padding(&input[PADDED_FP_LENGTH..PADDED_FP2_LENGTH])?; - let mut p = blst_p2::default(); - // SAFETY: p and fp2 are blst values. - // third argument is unused if null. - unsafe { blst_map_to_g2(&mut p, &fp2, core::ptr::null()) }; + // Get unpadded result from crypto backend + let unpadded_result = map_fp2_to_g2_bytes(input_p0_x, input_p0_y)?; - let mut p_aff = blst_p2_affine::default(); - // SAFETY: p_aff and p are blst values. - unsafe { blst_p2_to_affine(&mut p_aff, &p) }; + // Pad the result for EVM compatibility + let padded_result = pad_g2_point(&unpadded_result); - let out = encode_g2_point(&p_aff); - Ok((BASE_GAS_FEE, out)) + Ok(PrecompileOutput::new( + MAP_FP2_TO_G2_BASE_GAS_FEE, + padded_result.into(), + )) } diff --git a/crates/precompile/src/bls12_381/map_fp_to_g1.rs b/crates/precompile/src/bls12_381/map_fp_to_g1.rs index 26b5987322..de4ee4503e 100644 --- a/crates/precompile/src/bls12_381/map_fp_to_g1.rs +++ b/crates/precompile/src/bls12_381/map_fp_to_g1.rs @@ -1,26 +1,20 @@ +//! BLS12-381 map fp to g1 precompile. More details in [`map_fp_to_g1`] use super::{ - g1::encode_g1_point, - utils::{fp_from_bendian, remove_padding, PADDED_FP_LENGTH}, + crypto_backend::map_fp_to_g1_bytes, + utils::{pad_g1_point, remove_fp_padding}, }; -use crate::{u64_to_address, PrecompileWithAddress}; -use blst::{blst_map_to_g1, blst_p1, blst_p1_affine, blst_p1_to_affine}; -use revm_primitives::{Bytes, Precompile, PrecompileError, PrecompileResult}; +use crate::bls12_381_const::{MAP_FP_TO_G1_ADDRESS, MAP_FP_TO_G1_BASE_GAS_FEE, PADDED_FP_LENGTH}; +use crate::{PrecompileError, PrecompileOutput, PrecompileResult, PrecompileWithAddress}; /// [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537#specification) BLS12_MAP_FP_TO_G1 precompile. pub const PRECOMPILE: PrecompileWithAddress = - PrecompileWithAddress(u64_to_address(ADDRESS), Precompile::Standard(map_fp_to_g1)); - -/// BLS12_MAP_FP_TO_G1 precompile address. -pub const ADDRESS: u64 = 0x12; - -/// Base gas fee for BLS12-381 map_fp_to_g1 operation. -const MAP_FP_TO_G1_BASE: u64 = 5500; + PrecompileWithAddress(MAP_FP_TO_G1_ADDRESS, map_fp_to_g1); /// Field-to-curve call expects 64 bytes as an input that is interpreted as an /// element of Fp. Output of this call is 128 bytes and is an encoded G1 point. /// See also: -pub(super) fn map_fp_to_g1(input: &Bytes, gas_limit: u64) -> PrecompileResult { - if MAP_FP_TO_G1_BASE > gas_limit { +pub fn map_fp_to_g1(input: &[u8], gas_limit: u64) -> PrecompileResult { + if MAP_FP_TO_G1_BASE_GAS_FEE > gas_limit { return Err(PrecompileError::OutOfGas); } @@ -31,31 +25,29 @@ pub(super) fn map_fp_to_g1(input: &Bytes, gas_limit: u64) -> PrecompileResult { ))); } - let input_p0 = remove_padding(input)?; - let fp = fp_from_bendian(input_p0)?; + let input_p0 = remove_fp_padding(input)?; - let mut p = blst_p1::default(); - // SAFETY: p and fp are blst values. - // third argument is unused if null. - unsafe { blst_map_to_g1(&mut p, &fp, core::ptr::null()) }; + // Get unpadded result from crypto backend + let unpadded_result = map_fp_to_g1_bytes(input_p0)?; - let mut p_aff = blst_p1_affine::default(); - // SAFETY: p_aff and p are blst values. - unsafe { blst_p1_to_affine(&mut p_aff, &p) }; + // Pad the result for EVM compatibility + let padded_result = pad_g1_point(&unpadded_result); - let out = encode_g1_point(&p_aff); - Ok((MAP_FP_TO_G1_BASE, out)) + Ok(PrecompileOutput::new( + MAP_FP_TO_G1_BASE_GAS_FEE, + padded_result.into(), + )) } #[cfg(test)] mod test { use super::*; - use crate::primitives::hex; + use primitives::{hex, Bytes}; #[test] fn sanity_test() { let input = Bytes::from(hex!("000000000000000000000000000000006900000000000000636f6e7472616374595a603f343061cd305a03f40239f5ffff31818185c136bc2595f2aa18e08f17")); - let fail = map_fp_to_g1(&input, MAP_FP_TO_G1_BASE); + let fail = map_fp_to_g1(&input, MAP_FP_TO_G1_BASE_GAS_FEE); assert_eq!( fail, Err(PrecompileError::Other("non-canonical fp value".to_string())) diff --git a/crates/precompile/src/bls12_381/msm.rs b/crates/precompile/src/bls12_381/msm.rs deleted file mode 100644 index 9ddeedc015..0000000000 --- a/crates/precompile/src/bls12_381/msm.rs +++ /dev/null @@ -1,26 +0,0 @@ -/// Amount used to calculate the multi-scalar-multiplication discount. -const MSM_MULTIPLIER: u64 = 1000; - -/// Table of gas discounts for multi-scalar-multiplication operations. -static MSM_DISCOUNT_TABLE: [u16; 128] = [ - 1200, 888, 764, 641, 594, 547, 500, 453, 438, 423, 408, 394, 379, 364, 349, 334, 330, 326, 322, - 318, 314, 310, 306, 302, 298, 294, 289, 285, 281, 277, 273, 269, 268, 266, 265, 263, 262, 260, - 259, 257, 256, 254, 253, 251, 250, 248, 247, 245, 244, 242, 241, 239, 238, 236, 235, 233, 232, - 231, 229, 228, 226, 225, 223, 222, 221, 220, 219, 219, 218, 217, 216, 216, 215, 214, 213, 213, - 212, 211, 211, 210, 209, 208, 208, 207, 206, 205, 205, 204, 203, 202, 202, 201, 200, 199, 199, - 198, 197, 196, 196, 195, 194, 193, 193, 192, 191, 191, 190, 189, 188, 188, 187, 186, 185, 185, - 184, 183, 182, 182, 181, 180, 179, 179, 178, 177, 176, 176, 175, 174, -]; - -/// Implements the gas schedule for G1/G2 Multiscalar-multiplication assuming 30 -/// MGas/second, see also: -pub(super) fn msm_required_gas(k: usize, multiplication_cost: u64) -> u64 { - if k == 0 { - return 0; - } - - let index = core::cmp::min(k - 1, MSM_DISCOUNT_TABLE.len() - 1); - let discount = MSM_DISCOUNT_TABLE[index] as u64; - - (k as u64 * discount * multiplication_cost) / MSM_MULTIPLIER -} diff --git a/crates/precompile/src/bls12_381/pairing.rs b/crates/precompile/src/bls12_381/pairing.rs index 2a699a0859..6f9a59bcbd 100644 --- a/crates/precompile/src/bls12_381/pairing.rs +++ b/crates/precompile/src/bls12_381/pairing.rs @@ -1,102 +1,63 @@ -use super::{ - g1::{extract_g1_input, G1_INPUT_ITEM_LENGTH}, - g2::{extract_g2_input, G2_INPUT_ITEM_LENGTH}, +//! BLS12-381 pairing precompile. More details in [`pairing`] +use super::crypto_backend::pairing_check_bytes; +use super::utils::{remove_g1_padding, remove_g2_padding}; +use super::PairingPair; +use crate::bls12_381_const::{ + PADDED_G1_LENGTH, PADDED_G2_LENGTH, PAIRING_ADDRESS, PAIRING_INPUT_LENGTH, + PAIRING_MULTIPLIER_BASE, PAIRING_OFFSET_BASE, }; -use crate::{u64_to_address, PrecompileWithAddress}; -use blst::{blst_final_exp, blst_fp12, blst_fp12_is_one, blst_fp12_mul, blst_miller_loop}; -use revm_primitives::{Bytes, Precompile, PrecompileError, PrecompileResult, B256}; +use crate::{PrecompileError, PrecompileOutput, PrecompileResult, PrecompileWithAddress}; +use primitives::B256; +use std::vec::Vec; /// [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537#specification) BLS12_PAIRING precompile. -pub const PRECOMPILE: PrecompileWithAddress = - PrecompileWithAddress(u64_to_address(ADDRESS), Precompile::Standard(pairing)); -/// BLS12_PAIRING precompile address. -pub const ADDRESS: u64 = 0x11; - -/// Multiplier gas fee for BLS12-381 pairing operation. -const PAIRING_MULTIPLIER_BASE: u64 = 43000; -/// Offset gas fee for BLS12-381 pairing operation. -const PAIRING_OFFSET_BASE: u64 = 65000; -/// Input length of paitring operation. -const INPUT_LENGTH: usize = 384; +pub const PRECOMPILE: PrecompileWithAddress = PrecompileWithAddress(PAIRING_ADDRESS, pairing); /// Pairing call expects 384*k (k being a positive integer) bytes as an inputs /// that is interpreted as byte concatenation of k slices. Each slice has the /// following structure: /// * 128 bytes of G1 point encoding /// * 256 bytes of G2 point encoding +/// /// Each point is expected to be in the subgroup of order q. -/// Output is a 32 bytes where first 31 bytes are equal to 0x00 and the last byte +/// Output is 32 bytes where first 31 bytes are equal to 0x00 and the last byte /// is 0x01 if pairing result is equal to the multiplicative identity in a pairing /// target field and 0x00 otherwise. +/// /// See also: -pub(super) fn pairing(input: &Bytes, gas_limit: u64) -> PrecompileResult { +pub fn pairing(input: &[u8], gas_limit: u64) -> PrecompileResult { let input_len = input.len(); - if input_len == 0 || input_len % INPUT_LENGTH != 0 { + if input_len == 0 || input_len % PAIRING_INPUT_LENGTH != 0 { return Err(PrecompileError::Other(format!( - "Pairing input length should be multiple of {INPUT_LENGTH}, was {input_len}" + "Pairing input length should be multiple of {PAIRING_INPUT_LENGTH}, was {input_len}" ))); } - let k = input_len / INPUT_LENGTH; + let k = input_len / PAIRING_INPUT_LENGTH; let required_gas: u64 = PAIRING_MULTIPLIER_BASE * k as u64 + PAIRING_OFFSET_BASE; if required_gas > gas_limit { return Err(PrecompileError::OutOfGas); } - // accumulator for the fp12 multiplications of the miller loops. - let mut acc = blst_fp12::default(); + // Collect pairs of points for the pairing check + let mut pairs: Vec = Vec::with_capacity(k); for i in 0..k { - // NB: Scalar multiplications, MSMs and pairings MUST perform a subgroup check. - // - // So we set the subgroup_check flag to `true` - let p1_aff = &extract_g1_input( - &input[i * INPUT_LENGTH..i * INPUT_LENGTH + G1_INPUT_ITEM_LENGTH], - true, - )?; + let encoded_g1_element = + &input[i * PAIRING_INPUT_LENGTH..i * PAIRING_INPUT_LENGTH + PADDED_G1_LENGTH]; + let encoded_g2_element = &input[i * PAIRING_INPUT_LENGTH + PADDED_G1_LENGTH + ..i * PAIRING_INPUT_LENGTH + PADDED_G1_LENGTH + PADDED_G2_LENGTH]; - // NB: Scalar multiplications, MSMs and pairings MUST perform a subgroup check. - // - // So we set the subgroup_check flag to `true` - let p2_aff = &extract_g2_input( - &input[i * INPUT_LENGTH + G1_INPUT_ITEM_LENGTH - ..i * INPUT_LENGTH + G1_INPUT_ITEM_LENGTH + G2_INPUT_ITEM_LENGTH], - true, - )?; + let [a_x, a_y] = remove_g1_padding(encoded_g1_element)?; + let [b_x_0, b_x_1, b_y_0, b_y_1] = remove_g2_padding(encoded_g2_element)?; - if i > 0 { - // after the first slice (i>0) we use cur_ml to store the current - // miller loop and accumulate with the previous results using a fp12 - // multiplication. - let mut cur_ml = blst_fp12::default(); - let mut res = blst_fp12::default(); - // SAFETY: res, acc, cur_ml, p1_aff and p2_aff are blst values. - unsafe { - blst_miller_loop(&mut cur_ml, p2_aff, p1_aff); - blst_fp12_mul(&mut res, &acc, &cur_ml); - } - acc = res; - } else { - // on the first slice (i==0) there is no previous results and no need - // to accumulate. - // SAFETY: acc, p1_aff and p2_aff are blst values. - unsafe { - blst_miller_loop(&mut acc, p2_aff, p1_aff); - } - } + pairs.push(((*a_x, *a_y), (*b_x_0, *b_x_1, *b_y_0, *b_y_1))); } - // SAFETY: ret and acc are blst values. - let mut ret = blst_fp12::default(); - unsafe { - blst_final_exp(&mut ret, &acc); - } + let result = pairing_check_bytes(&pairs)?; + let result = if result { 1 } else { 0 }; - let mut result: u8 = 0; - // SAFETY: ret is a blst value. - unsafe { - if blst_fp12_is_one(&ret) { - result = 1; - } - } - Ok((required_gas, B256::with_last_byte(result).into())) + Ok(PrecompileOutput::new( + required_gas, + B256::with_last_byte(result).into(), + )) } diff --git a/crates/precompile/src/bls12_381/utils.rs b/crates/precompile/src/bls12_381/utils.rs index ba18475c67..c53f0cae5e 100644 --- a/crates/precompile/src/bls12_381/utils.rs +++ b/crates/precompile/src/bls12_381/utils.rs @@ -1,113 +1,142 @@ -use core::cmp::Ordering; - -use blst::{ - blst_bendian_from_fp, blst_fp, blst_fp_from_bendian, blst_scalar, blst_scalar_from_bendian, +//! BLS12-381 utilities for padding and unpadding of input. +use crate::bls12_381_const::{ + FP_LENGTH, FP_PAD_BY, G1_LENGTH, PADDED_FP_LENGTH, PADDED_G1_LENGTH, PADDED_G2_LENGTH, }; -use revm_primitives::PrecompileError; - -/// Number of bits used in the BLS12-381 curve finite field elements. -pub(super) const NBITS: usize = 256; -/// Finite field element input length. -pub(super) const FP_LENGTH: usize = 48; -/// Finite field element padded input length. -pub(super) const PADDED_FP_LENGTH: usize = 64; -/// Quadratic extension of finite field element input length. -pub(super) const PADDED_FP2_LENGTH: usize = 128; -/// Input elements padding length. -pub(super) const PADDING_LENGTH: usize = 16; -/// Scalar length. -pub(super) const SCALAR_LENGTH: usize = 32; -// Big-endian non-Montgomery form. -pub(super) const MODULUS_REPR: [u8; 48] = [ - 0x1a, 0x01, 0x11, 0xea, 0x39, 0x7f, 0xe6, 0x9a, 0x4b, 0x1b, 0xa7, 0xb6, 0x43, 0x4b, 0xac, 0xd7, - 0x64, 0x77, 0x4b, 0x84, 0xf3, 0x85, 0x12, 0xbf, 0x67, 0x30, 0xd2, 0xa0, 0xf6, 0xb0, 0xf6, 0x24, - 0x1e, 0xab, 0xff, 0xfe, 0xb1, 0x53, 0xff, 0xff, 0xb9, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xaa, 0xab, -]; - -/// Encodes a single finite field element into byte slice with padding. -pub(super) fn fp_to_bytes(out: &mut [u8], input: *const blst_fp) { - if out.len() != PADDED_FP_LENGTH { - return; - } - let (padding, rest) = out.split_at_mut(PADDING_LENGTH); - padding.fill(0); - // SAFETY: out length is checked previously, input is a blst value. - unsafe { blst_bendian_from_fp(rest.as_mut_ptr(), input) }; -} +use crate::PrecompileError; /// Removes zeros with which the precompile inputs are left padded to 64 bytes. -pub(super) fn remove_padding(input: &[u8]) -> Result<&[u8; FP_LENGTH], PrecompileError> { +pub(super) fn remove_fp_padding(input: &[u8]) -> Result<&[u8; FP_LENGTH], PrecompileError> { if input.len() != PADDED_FP_LENGTH { return Err(PrecompileError::Other(format!( "Padded input should be {PADDED_FP_LENGTH} bytes, was {}", input.len() ))); } - let (padding, unpadded) = input.split_at(PADDING_LENGTH); + let (padding, unpadded) = input.split_at(FP_PAD_BY); if !padding.iter().all(|&x| x == 0) { return Err(PrecompileError::Other(format!( - "{PADDING_LENGTH} top bytes of input are not zero", + "{FP_PAD_BY} top bytes of input are not zero", ))); } Ok(unpadded.try_into().unwrap()) } +/// remove_g1_padding removes the padding applied to the Fp elements that constitute the +/// encoded G1 element. +pub(super) fn remove_g1_padding(input: &[u8]) -> Result<[&[u8; FP_LENGTH]; 2], PrecompileError> { + if input.len() != PADDED_G1_LENGTH { + return Err(PrecompileError::Other(format!( + "Input should be {PADDED_G1_LENGTH} bytes, was {}", + input.len() + ))); + } -/// Extracts a scalar from a 32 byte slice representation, decoding the input as a big endian -/// unsigned integer. If the input is not exactly 32 bytes long, an error is returned. -/// -/// From [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537): -/// * A scalar for the multiplication operation is encoded as 32 bytes by performing BigEndian -/// encoding of the corresponding (unsigned) integer. -/// -/// We do not check that the scalar is a canonical Fr element, because the EIP specifies: -/// * The corresponding integer is not required to be less than or equal than main subgroup order -/// `q`. -pub(super) fn extract_scalar_input(input: &[u8]) -> Result { - if input.len() != SCALAR_LENGTH { + let x = remove_fp_padding(&input[..PADDED_FP_LENGTH])?; + let y = remove_fp_padding(&input[PADDED_FP_LENGTH..PADDED_G1_LENGTH])?; + Ok([x, y]) +} + +/// remove_g2_padding removes the padding applied to the Fp elements that constitute the +/// encoded G2 element. +pub(super) fn remove_g2_padding(input: &[u8]) -> Result<[&[u8; FP_LENGTH]; 4], PrecompileError> { + if input.len() != PADDED_G2_LENGTH { return Err(PrecompileError::Other(format!( - "Input should be {SCALAR_LENGTH} bytes, was {}", + "Input should be {PADDED_G2_LENGTH} bytes, was {}", input.len() ))); } - let mut out = blst_scalar::default(); - // SAFETY: input length is checked previously, out is a blst value. - unsafe { - // NOTE: we do not use `blst_scalar_fr_check` here because, from EIP-2537: - // - // * The corresponding integer is not required to be less than or equal than main subgroup - // order `q`. - blst_scalar_from_bendian(&mut out, input.as_ptr()) - }; - - Ok(out) + let mut input_fps = [&[0; FP_LENGTH]; 4]; + for i in 0..4 { + input_fps[i] = remove_fp_padding(&input[i * PADDED_FP_LENGTH..(i + 1) * PADDED_FP_LENGTH])?; + } + Ok(input_fps) } -/// Checks if the input is a valid big-endian representation of a field element. -fn is_valid_be(input: &[u8; 48]) -> bool { - for (i, modul) in input.iter().zip(MODULUS_REPR.iter()) { - match i.cmp(modul) { - Ordering::Greater => return false, - Ordering::Less => return true, - Ordering::Equal => continue, - } +/// Pads an unpadded G1 point (96 bytes) to the EVM-compatible format (128 bytes). +/// +/// Takes a G1 point with 2 field elements of 48 bytes each and adds 16 bytes of +/// zero padding before each field element. +pub(super) fn pad_g1_point(unpadded: &[u8]) -> [u8; PADDED_G1_LENGTH] { + assert_eq!( + unpadded.len(), + G1_LENGTH, + "Invalid unpadded G1 point length" + ); + + let mut padded = [0u8; PADDED_G1_LENGTH]; + + // Copy each field element (x, y) with padding + for i in 0..2 { + padded[i * PADDED_FP_LENGTH + FP_PAD_BY..(i + 1) * PADDED_FP_LENGTH] + .copy_from_slice(&unpadded[i * FP_LENGTH..(i + 1) * FP_LENGTH]); } - // false if matching the modulus - false + + padded } -/// Checks whether or not the input represents a canonical field element, returning the field -/// element if successful. -pub(super) fn fp_from_bendian(input: &[u8; 48]) -> Result { - if !is_valid_be(input) { - return Err(PrecompileError::Other("non-canonical fp value".to_string())); +/// Pads an unpadded G2 point (192 bytes) to the EVM-compatible format (256 bytes). +/// +/// Takes a G2 point with 4 field elements of 48 bytes each and adds 16 bytes of +/// zero padding before each field element. +pub(super) fn pad_g2_point(unpadded: &[u8]) -> [u8; PADDED_G2_LENGTH] { + assert_eq!( + unpadded.len(), + 4 * FP_LENGTH, + "Invalid unpadded G2 point length" + ); + + let mut padded = [0u8; PADDED_G2_LENGTH]; + + // Copy each field element (x.c0, x.c1, y.c0, y.c1) with padding + for i in 0..4 { + padded[i * PADDED_FP_LENGTH + FP_PAD_BY..(i + 1) * PADDED_FP_LENGTH] + .copy_from_slice(&unpadded[i * FP_LENGTH..(i + 1) * FP_LENGTH]); } - let mut fp = blst_fp::default(); - // SAFETY: input has fixed length, and fp is a blst value. - unsafe { - // This performs the check for canonical field elements - blst_fp_from_bendian(&mut fp, input.as_ptr()); + + padded +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_pad_g1_point_roundtrip() { + // Create test data + let mut unpadded = [0u8; G1_LENGTH]; + for (i, byte) in unpadded.iter_mut().enumerate() { + *byte = (i * 2 + 1) as u8; + } + + // Pad the point + let padded = pad_g1_point(&unpadded); + + // Remove padding + let result = remove_g1_padding(&padded).unwrap(); + + // Verify roundtrip + assert_eq!(result[0], &unpadded[0..FP_LENGTH]); + assert_eq!(result[1], &unpadded[FP_LENGTH..G1_LENGTH]); } - Ok(fp) + #[test] + fn test_pad_g2_point_roundtrip() { + // Create test data for G2 point (192 bytes = 4 * 48) + let mut unpadded = [0u8; 4 * FP_LENGTH]; + for (i, byte) in unpadded.iter_mut().enumerate() { + *byte = (i * 2 + 1) as u8; + } + + // Pad the point + let padded = pad_g2_point(&unpadded); + + // Remove padding + let result = remove_g2_padding(&padded).unwrap(); + + // Verify roundtrip - G2 has 4 field elements + assert_eq!(result[0], &unpadded[0..FP_LENGTH]); + assert_eq!(result[1], &unpadded[FP_LENGTH..2 * FP_LENGTH]); + assert_eq!(result[2], &unpadded[2 * FP_LENGTH..3 * FP_LENGTH]); + assert_eq!(result[3], &unpadded[3 * FP_LENGTH..4 * FP_LENGTH]); + } } diff --git a/crates/precompile/src/bls12_381_const.rs b/crates/precompile/src/bls12_381_const.rs new file mode 100644 index 0000000000..9898aac258 --- /dev/null +++ b/crates/precompile/src/bls12_381_const.rs @@ -0,0 +1,210 @@ +//! Constants specifying the precompile addresses for each precompile in EIP-2537 + +use crate::u64_to_address; +use primitives::Address; + +/// G1 add precompile address +pub const G1_ADD_ADDRESS: Address = u64_to_address(0x0b); +/// G1 msm precompile address +pub const G1_MSM_ADDRESS: Address = u64_to_address(0x0c); +/// G2 add precompile address +pub const G2_ADD_ADDRESS: Address = u64_to_address(0x0d); +/// G2 msm precompile address +pub const G2_MSM_ADDRESS: Address = u64_to_address(0x0e); +/// Pairing precompile address +pub const PAIRING_ADDRESS: Address = u64_to_address(0x0f); +/// Map fp to g1 precompile address +pub const MAP_FP_TO_G1_ADDRESS: Address = u64_to_address(0x10); +/// Map fp2 to g2 precompile address +pub const MAP_FP2_TO_G2_ADDRESS: Address = u64_to_address(0x11); + +/// G1_ADD_BASE_GAS_FEE specifies the amount of gas needed +/// to perform the G1_ADD precompile. +pub const G1_ADD_BASE_GAS_FEE: u64 = 375; +/// G1_MSM_BASE_GAS_FEE specifies the base amount of gas needed to +/// perform the G1_MSM precompile. +/// +/// The cost to do an MSM is determined by the formula: +/// (k * G1_MSM_BASE_GAS_FEE * DISCOUNT\[k\]) // MSM_MULTIPLIER +/// where k is the number of point-scalar pairs. +/// +/// Note: If one wants to do a G1 scalar multiplication, they would call +/// this precompile with a single point and a scalar. +pub const G1_MSM_BASE_GAS_FEE: u64 = 12000; +/// MSM_MULTIPLIER specifies the division constant that is used to determine the +/// gas needed to compute an MSM. +/// +/// The cost to do an MSM is determined by the formula: +/// (k * MSM_BASE_GAS_FEE * DISCOUNT\[k\]) // MSM_MULTIPLIER +/// where k is the number of point-scalar pairs. +/// +/// Note: If `k` is more than the size of the discount table, then +/// the last value in the discount table is chosen. +pub const MSM_MULTIPLIER: u64 = 1000; +/// MAP_FP_TO_G1_BASE_GAS_FEE specifies the amount of gas needed +/// to perform the MAP_FP_TO_G1 precompile. +pub const MAP_FP_TO_G1_BASE_GAS_FEE: u64 = 5500; +/// MAP_FP2_TO_G2_BASE_GAS_FEE specifies the amount of gas needed +/// to perform the MAP_FP2_TO_G2 precompile. +pub const MAP_FP2_TO_G2_BASE_GAS_FEE: u64 = 23800; +/// G2_ADD_BASE_GAS_FEE specifies the amount of gas needed +/// to perform the G2_ADD precompile. +pub const G2_ADD_BASE_GAS_FEE: u64 = 600; +/// G2_MSM_BASE_GAS_FEE specifies the base amount of gas needed to +/// perform the G2_MSM precompile. +/// +/// The cost to do an MSM is determined by the formula: +/// (k * G2_MSM_BASE_GAS_FEE * DISCOUNT\[k\]) // MSM_MULTIPLIER +/// where k is the number of point-scalar pairs. +/// +/// Note: If one wants to do a G2 scalar multiplication, they would call +/// this precompile with a single point and a scalar. +pub const G2_MSM_BASE_GAS_FEE: u64 = 22500; +/// PAIRING_OFFSET_BASE specifies the y-intercept for the linear expression to determine +/// the amount of gas needed to perform a pairing. +/// +/// The cost to do a pairing is determined by the formula: +/// cost = PAIRING_MULTIPLIER_BASE * number_of_pairs + PAIRING_OFFSET_BASE +pub const PAIRING_OFFSET_BASE: u64 = 37700; +/// PAIRING_MULTIPLIER_BASE specifies the slope/gradient for the linear expression to determine +/// the amount of gas needed to perform a pairing. +/// +/// The cost to do a pairing is determined by the formula: +/// PAIRING_MULTIPLIER_BASE * number_of_pairs + PAIRING_OFFSET_BASE +pub const PAIRING_MULTIPLIER_BASE: u64 = 32600; + +/// Discounts table for G1 MSM as a vector of pairs `[k, discount]`. +pub static DISCOUNT_TABLE_G1_MSM: [u16; 128] = [ + 1000, 949, 848, 797, 764, 750, 738, 728, 719, 712, 705, 698, 692, 687, 682, 677, 673, 669, 665, + 661, 658, 654, 651, 648, 645, 642, 640, 637, 635, 632, 630, 627, 625, 623, 621, 619, 617, 615, + 613, 611, 609, 608, 606, 604, 603, 601, 599, 598, 596, 595, 593, 592, 591, 589, 588, 586, 585, + 584, 582, 581, 580, 579, 577, 576, 575, 574, 573, 572, 570, 569, 568, 567, 566, 565, 564, 563, + 562, 561, 560, 559, 558, 557, 556, 555, 554, 553, 552, 551, 550, 549, 548, 547, 547, 546, 545, + 544, 543, 542, 541, 540, 540, 539, 538, 537, 536, 536, 535, 534, 533, 532, 532, 531, 530, 529, + 528, 528, 527, 526, 525, 525, 524, 523, 522, 522, 521, 520, 520, 519, +]; +/// Discounts table for G2 MSM as a vector of pairs `[k, discount]`: +pub static DISCOUNT_TABLE_G2_MSM: [u16; 128] = [ + 1000, 1000, 923, 884, 855, 832, 812, 796, 782, 770, 759, 749, 740, 732, 724, 717, 711, 704, + 699, 693, 688, 683, 679, 674, 670, 666, 663, 659, 655, 652, 649, 646, 643, 640, 637, 634, 632, + 629, 627, 624, 622, 620, 618, 615, 613, 611, 609, 607, 606, 604, 602, 600, 598, 597, 595, 593, + 592, 590, 589, 587, 586, 584, 583, 582, 580, 579, 578, 576, 575, 574, 573, 571, 570, 569, 568, + 567, 566, 565, 563, 562, 561, 560, 559, 558, 557, 556, 555, 554, 553, 552, 552, 551, 550, 549, + 548, 547, 546, 545, 545, 544, 543, 542, 541, 541, 540, 539, 538, 537, 537, 536, 535, 535, 534, + 533, 532, 532, 531, 530, 530, 529, 528, 528, 527, 526, 526, 525, 524, 524, +]; + +// Constants related to the bls12-381 precompile inputs and outputs + +/// FP_LENGTH specifies the number of bytes needed to represent an +/// Fp element. This is an element in the base field of BLS12-381. +/// +/// Note: The base field is used to define G1 and G2 elements. +pub const FP_LENGTH: usize = 48; +/// PADDED_FP_LENGTH specifies the number of bytes that the EVM will use +/// to represent an Fp element according to EIP-2537. +/// +/// Note: We only need FP_LENGTH number of bytes to represent it, +/// but we pad the byte representation to be 32 byte aligned as specified in EIP 2537. +pub const PADDED_FP_LENGTH: usize = 64; + +/// G1_LENGTH specifies the number of bytes needed to represent a G1 element. +/// +/// Note: A G1 element contains 2 Fp elements. +pub const G1_LENGTH: usize = 2 * FP_LENGTH; +/// PADDED_G1_LENGTH specifies the number of bytes that the EVM will use to represent +/// a G1 element according to padding rules specified in EIP-2537. +pub const PADDED_G1_LENGTH: usize = 2 * PADDED_FP_LENGTH; + +/// FP2_LENGTH specifies the number of bytes needed to represent a Fp^2 element. +/// +/// Note: This is the quadratic extension of Fp, and by definition +/// means we need 2 Fp elements. +pub const FP2_LENGTH: usize = 2 * FP_LENGTH; + +/// PADDED_FP2_LENGTH specifies the number of bytes that the EVM will use to represent +/// a Fp^2 element according to the padding rules specified in EIP-2537. +/// +/// Note: This is the quadratic extension of Fp, and by definition +/// means we need 2 Fp elements. +pub const PADDED_FP2_LENGTH: usize = 2 * PADDED_FP_LENGTH; + +/// SCALAR_LENGTH specifies the number of bytes needed to represent an Fr element. +/// This is an element in the scalar field of BLS12-381. +/// +/// Note: Since it is already 32 byte aligned, there is no padded version of this constant. +pub const SCALAR_LENGTH: usize = 32; +/// SCALAR_LENGTH_BITS specifies the number of bits needed to represent an Fr element. +/// This is an element in the scalar field of BLS12-381. +pub const SCALAR_LENGTH_BITS: usize = SCALAR_LENGTH * 8; + +/// G1_ADD_INPUT_LENGTH specifies the number of bytes that the input to G1ADD +/// must use. +/// +/// Note: The input to the G1 addition precompile is 2 G1 elements. +pub const G1_ADD_INPUT_LENGTH: usize = 2 * PADDED_G1_LENGTH; +/// G1_MSM_INPUT_LENGTH specifies the number of bytes that each MSM input pair should have. +/// +/// Note: An MSM pair is a G1 element and a scalar. The input to the MSM precompile will have `n` +/// of these pairs. +pub const G1_MSM_INPUT_LENGTH: usize = PADDED_G1_LENGTH + SCALAR_LENGTH; + +/// G2_LENGTH specifies the number of bytes needed to represent a G2 element. +/// +/// Note: A G2 element contains 2 Fp^2 elements. +pub const G2_LENGTH: usize = 2 * FP2_LENGTH; + +/// PADDED_G2_LENGTH specifies the number of bytes that the EVM will use to represent +/// a G2 element. +/// +/// Note: A G2 element can be represented using 2 Fp^2 elements. +pub const PADDED_G2_LENGTH: usize = 2 * PADDED_FP2_LENGTH; + +/// G2_ADD_INPUT_LENGTH specifies the number of bytes that the input to G2ADD +/// must occupy. +/// +/// Note: The input to the G2 addition precompile is 2 G2 elements. +pub const G2_ADD_INPUT_LENGTH: usize = 2 * PADDED_G2_LENGTH; +/// G2_MSM_INPUT_LENGTH specifies the number of bytes that each MSM input pair should have. +/// +/// Note: An MSM pair is a G2 element and a scalar. The input to the MSM will have `n` +/// of these pairs. +pub const G2_MSM_INPUT_LENGTH: usize = PADDED_G2_LENGTH + SCALAR_LENGTH; + +/// PAIRING_INPUT_LENGTH specifies the number of bytes that each Pairing input pair should have. +/// +/// Note: An Pairing input-pair is a G2 element and a G1 element. The input to the Pairing will have `n` +/// of these pairs. +pub const PAIRING_INPUT_LENGTH: usize = PADDED_G1_LENGTH + PADDED_G2_LENGTH; + +/// FP_PAD_BY specifies the number of bytes that an FP_ELEMENT is padded by to make it 32 byte aligned. +/// +/// Note: This should be equal to PADDED_FP_LENGTH - FP_LENGTH. +pub const FP_PAD_BY: usize = 16; + +#[test] +fn check_discount_table_invariant_holds() { + // Currently EIP-2537 specifies the cost for a G1/G2 scalar multiplication in two places + // in two different ways. + // + // First it explicitly says that G1 Multiplication costs 12000 Gas and G2 Multiplication costs 22500. + // + // Then it implies the above constants for G1_MSM and G2_MSM via the MSM formula: + // MSM_COST = k * MSM_BASE_GAS_FEE * DISCOUNT[k-1] // MSM_MULTIPLIER + // + // Note that when the MSM has only one point-scalar pair (scalar multiplication), we get: + // MSM_COST = MSM_BASE_GAS_FEE * DISCOUNT[0] // MSM_MULTIPLIER + // (This is because k==1) + // + // The 0th entry in the discount table for G1_MSM and G2_MSM is equal to MSM_MULTIPLIER + // so for k==1, MSM_COST = MSM_BASE_GAS_FEE + // + // For G1, MSM_BASE_GAS_FEE matches 12000 and for G2 MSM_BASE_GAS_FEE matches 22500. + // + // In this test, we check that this invariant does not change by asserting that the first value + // in the discount table is equal to the MULTIPLIER. + assert_eq!(DISCOUNT_TABLE_G1_MSM[0], MSM_MULTIPLIER as u16); + assert_eq!(DISCOUNT_TABLE_G2_MSM[0], MSM_MULTIPLIER as u16); + // Note: We could also more robustly check this by defining the G1/G2 Scalar multiplication constants + // from the EIP and checking that they equal to the value computed by `msm_required_gas` when k==1 +} diff --git a/crates/precompile/src/bls12_381_utils.rs b/crates/precompile/src/bls12_381_utils.rs new file mode 100644 index 0000000000..4b0e41c3ce --- /dev/null +++ b/crates/precompile/src/bls12_381_utils.rs @@ -0,0 +1,16 @@ +//! Utility functions for the BLS12-381 precompiles +use crate::bls12_381_const::MSM_MULTIPLIER; + +/// Implements the gas schedule for G1/G2 Multiscalar-multiplication assuming 30 +/// MGas/second, see also: +#[inline] +pub fn msm_required_gas(k: usize, discount_table: &[u16], multiplication_cost: u64) -> u64 { + if k == 0 { + return 0; + } + + let index = core::cmp::min(k - 1, discount_table.len() - 1); + let discount = discount_table[index] as u64; + + (k as u64 * discount * multiplication_cost) / MSM_MULTIPLIER +} diff --git a/crates/precompile/src/bn128.rs b/crates/precompile/src/bn128.rs index ce08da7994..3cad806801 100644 --- a/crates/precompile/src/bn128.rs +++ b/crates/precompile/src/bn128.rs @@ -1,163 +1,184 @@ +//! BN128 precompiles added in [`EIP-1962`](https://eips.ethereum.org/EIPS/eip-1962) use crate::{ utilities::{bool_to_bytes32, right_pad}, - Address, Error, Precompile, PrecompileResult, PrecompileWithAddress, + Address, PrecompileError, PrecompileOutput, PrecompileResult, PrecompileWithAddress, }; -use bn::{AffineG1, AffineG2, Fq, Fq2, Group, Gt, G1, G2}; +use std::vec::Vec; +cfg_if::cfg_if! { + if #[cfg(feature = "bn")]{ + mod substrate; + use substrate::{g1_point_add, g1_point_mul, pairing_check}; + } else { + mod arkworks; + use arkworks::{g1_point_add, g1_point_mul, pairing_check}; + } +} + +/// Bn128 add precompile pub mod add { use super::*; - const ADDRESS: Address = crate::u64_to_address(6); + /// Bn128 add precompile address + pub const ADDRESS: Address = crate::u64_to_address(6); + /// Bn128 add precompile with ISTANBUL gas rules pub const ISTANBUL_ADD_GAS_COST: u64 = 150; - pub const ISTANBUL: PrecompileWithAddress = PrecompileWithAddress( - ADDRESS, - Precompile::Standard(|input, gas_limit| run_add(input, ISTANBUL_ADD_GAS_COST, gas_limit)), - ); + /// Bn128 add precompile with ISTANBUL gas rules + pub const ISTANBUL: PrecompileWithAddress = + PrecompileWithAddress(ADDRESS, |input, gas_limit| { + run_add(input, ISTANBUL_ADD_GAS_COST, gas_limit) + }); + + /// Bn128 add precompile with BYZANTIUM gas rules pub const BYZANTIUM_ADD_GAS_COST: u64 = 500; - pub const BYZANTIUM: PrecompileWithAddress = PrecompileWithAddress( - ADDRESS, - Precompile::Standard(|input, gas_limit| run_add(input, BYZANTIUM_ADD_GAS_COST, gas_limit)), - ); + + /// Bn128 add precompile with BYZANTIUM gas rules + pub const BYZANTIUM: PrecompileWithAddress = + PrecompileWithAddress(ADDRESS, |input, gas_limit| { + run_add(input, BYZANTIUM_ADD_GAS_COST, gas_limit) + }); } +/// Bn128 mul precompile pub mod mul { use super::*; - const ADDRESS: Address = crate::u64_to_address(7); + /// Bn128 mul precompile address + pub const ADDRESS: Address = crate::u64_to_address(7); + /// Bn128 mul precompile with ISTANBUL gas rules pub const ISTANBUL_MUL_GAS_COST: u64 = 6_000; - pub const ISTANBUL: PrecompileWithAddress = PrecompileWithAddress( - ADDRESS, - Precompile::Standard(|input, gas_limit| run_mul(input, ISTANBUL_MUL_GAS_COST, gas_limit)), - ); + /// Bn128 mul precompile with ISTANBUL gas rules + pub const ISTANBUL: PrecompileWithAddress = + PrecompileWithAddress(ADDRESS, |input, gas_limit| { + run_mul(input, ISTANBUL_MUL_GAS_COST, gas_limit) + }); + + /// Bn128 mul precompile with BYZANTIUM gas rules pub const BYZANTIUM_MUL_GAS_COST: u64 = 40_000; - pub const BYZANTIUM: PrecompileWithAddress = PrecompileWithAddress( - ADDRESS, - Precompile::Standard(|input, gas_limit| run_mul(input, BYZANTIUM_MUL_GAS_COST, gas_limit)), - ); + + /// Bn128 mul precompile with BYZANTIUM gas rules + pub const BYZANTIUM: PrecompileWithAddress = + PrecompileWithAddress(ADDRESS, |input, gas_limit| { + run_mul(input, BYZANTIUM_MUL_GAS_COST, gas_limit) + }); } +/// Bn128 pair precompile pub mod pair { use super::*; - const ADDRESS: Address = crate::u64_to_address(8); + /// Bn128 pair precompile address + pub const ADDRESS: Address = crate::u64_to_address(8); + /// Bn128 pair precompile with ISTANBUL gas rules pub const ISTANBUL_PAIR_PER_POINT: u64 = 34_000; + + /// Bn128 pair precompile with ISTANBUL gas rules pub const ISTANBUL_PAIR_BASE: u64 = 45_000; - pub const ISTANBUL: PrecompileWithAddress = PrecompileWithAddress( - ADDRESS, - Precompile::Standard(|input, gas_limit| { + + /// Bn128 pair precompile with ISTANBUL gas rules + pub const ISTANBUL: PrecompileWithAddress = + PrecompileWithAddress(ADDRESS, |input, gas_limit| { run_pair( input, ISTANBUL_PAIR_PER_POINT, ISTANBUL_PAIR_BASE, gas_limit, ) - }), - ); + }); + /// Bn128 pair precompile with BYZANTIUM gas rules pub const BYZANTIUM_PAIR_PER_POINT: u64 = 80_000; + + /// Bn128 pair precompile with BYZANTIUM gas rules pub const BYZANTIUM_PAIR_BASE: u64 = 100_000; - pub const BYZANTIUM: PrecompileWithAddress = PrecompileWithAddress( - ADDRESS, - Precompile::Standard(|input, gas_limit| { + + /// Bn128 pair precompile with BYZANTIUM gas rules + pub const BYZANTIUM: PrecompileWithAddress = + PrecompileWithAddress(ADDRESS, |input, gas_limit| { run_pair( input, BYZANTIUM_PAIR_PER_POINT, BYZANTIUM_PAIR_BASE, gas_limit, ) - }), - ); + }); } +/// FQ_LEN specifies the number of bytes needed to represent an +/// Fq element. This is an element in the base field of BN254. +/// +/// Note: The base field is used to define G1 and G2 elements. +const FQ_LEN: usize = 32; + +/// SCALAR_LEN specifies the number of bytes needed to represent an Fr element. +/// This is an element in the scalar field of BN254. +const SCALAR_LEN: usize = 32; + +/// FQ2_LEN specifies the number of bytes needed to represent an +/// Fq^2 element. +/// +/// Note: This is the quadratic extension of Fq, and by definition +/// means we need 2 Fq elements. +const FQ2_LEN: usize = 2 * FQ_LEN; + +/// G1_LEN specifies the number of bytes needed to represent a G1 element. +/// +/// Note: A G1 element contains 2 Fq elements. +const G1_LEN: usize = 2 * FQ_LEN; +/// G2_LEN specifies the number of bytes needed to represent a G2 element. +/// +/// Note: A G2 element contains 2 Fq^2 elements. +const G2_LEN: usize = 2 * FQ2_LEN; + /// Input length for the add operation. /// `ADD` takes two uncompressed G1 points (64 bytes each). -pub const ADD_INPUT_LEN: usize = 64 + 64; +pub const ADD_INPUT_LEN: usize = 2 * G1_LEN; /// Input length for the multiplication operation. /// `MUL` takes an uncompressed G1 point (64 bytes) and scalar (32 bytes). -pub const MUL_INPUT_LEN: usize = 64 + 32; +pub const MUL_INPUT_LEN: usize = G1_LEN + SCALAR_LEN; /// Pair element length. /// `PAIR` elements are composed of an uncompressed G1 point (64 bytes) and an uncompressed G2 point /// (128 bytes). -pub const PAIR_ELEMENT_LEN: usize = 64 + 128; - -/// Reads a single `Fq` from the input slice. -/// -/// # Panics -/// -/// Panics if the input is not at least 32 bytes long. -#[inline] -pub fn read_fq(input: &[u8]) -> Result { - Fq::from_slice(&input[..32]).map_err(|_| Error::Bn128FieldPointNotAMember) -} - -/// Reads the `x` and `y` points from the input slice. -/// -/// # Panics -/// -/// Panics if the input is not at least 64 bytes long. -#[inline] -pub fn read_point(input: &[u8]) -> Result { - let px = read_fq(&input[0..32])?; - let py = read_fq(&input[32..64])?; - new_g1_point(px, py) -} - -/// Creates a new `G1` point from the given `x` and `y` coordinates. -pub fn new_g1_point(px: Fq, py: Fq) -> Result { - if px == Fq::zero() && py == Fq::zero() { - Ok(G1::zero()) - } else { - AffineG1::new(px, py) - .map(Into::into) - .map_err(|_| Error::Bn128AffineGFailedToCreate) - } -} +pub const PAIR_ELEMENT_LEN: usize = G1_LEN + G2_LEN; +/// Run the Bn128 add precompile pub fn run_add(input: &[u8], gas_cost: u64, gas_limit: u64) -> PrecompileResult { if gas_cost > gas_limit { - return Err(Error::OutOfGas); + return Err(PrecompileError::OutOfGas); } let input = right_pad::(input); - let p1 = read_point(&input[..64])?; - let p2 = read_point(&input[64..])?; + let p1_bytes = &input[..G1_LEN]; + let p2_bytes = &input[G1_LEN..]; + let output = g1_point_add(p1_bytes, p2_bytes)?; - let mut output = [0u8; 64]; - if let Some(sum) = AffineG1::from_jacobian(p1 + p2) { - sum.x().to_big_endian(&mut output[..32]).unwrap(); - sum.y().to_big_endian(&mut output[32..]).unwrap(); - } - Ok((gas_cost, output.into())) + Ok(PrecompileOutput::new(gas_cost, output.into())) } +/// Run the Bn128 mul precompile pub fn run_mul(input: &[u8], gas_cost: u64, gas_limit: u64) -> PrecompileResult { if gas_cost > gas_limit { - return Err(Error::OutOfGas); + return Err(PrecompileError::OutOfGas); } let input = right_pad::(input); - let p = read_point(&input[..64])?; - - // `Fr::from_slice` can only fail when the length is not 32. - let fr = bn::Fr::from_slice(&input[64..96]).unwrap(); + let point_bytes = &input[..G1_LEN]; + let scalar_bytes = &input[G1_LEN..G1_LEN + SCALAR_LEN]; + let output = g1_point_mul(point_bytes, scalar_bytes)?; - let mut output = [0u8; 64]; - if let Some(mul) = AffineG1::from_jacobian(p * fr) { - mul.x().to_big_endian(&mut output[..32]).unwrap(); - mul.y().to_big_endian(&mut output[32..]).unwrap(); - } - Ok((gas_cost, output.into())) + Ok(PrecompileOutput::new(gas_cost, output.into())) } +/// Run the Bn128 pair precompile pub fn run_pair( input: &[u8], pair_per_point_cost: u64, @@ -166,60 +187,49 @@ pub fn run_pair( ) -> PrecompileResult { let gas_used = (input.len() / PAIR_ELEMENT_LEN) as u64 * pair_per_point_cost + pair_base_cost; if gas_used > gas_limit { - return Err(Error::OutOfGas); + return Err(PrecompileError::OutOfGas); } if input.len() % PAIR_ELEMENT_LEN != 0 { - return Err(Error::Bn128PairLength); + return Err(PrecompileError::Bn128PairLength); } - let success = if input.is_empty() { - true - } else { - let elements = input.len() / PAIR_ELEMENT_LEN; - - let mut mul = Gt::one(); - for idx in 0..elements { - let read_fq_at = |n: usize| { - debug_assert!(n < PAIR_ELEMENT_LEN / 32); - let start = idx * PAIR_ELEMENT_LEN + n * 32; - // SAFETY: We're reading `6 * 32 == PAIR_ELEMENT_LEN` bytes from `input[idx..]` - // per iteration. This is guaranteed to be in-bounds. - let slice = unsafe { input.get_unchecked(start..start + 32) }; - Fq::from_slice(slice).map_err(|_| Error::Bn128FieldPointNotAMember) - }; - let ax = read_fq_at(0)?; - let ay = read_fq_at(1)?; - let bay = read_fq_at(2)?; - let bax = read_fq_at(3)?; - let bby = read_fq_at(4)?; - let bbx = read_fq_at(5)?; - - let a = new_g1_point(ax, ay)?; - let b = { - let ba = Fq2::new(bax, bay); - let bb = Fq2::new(bbx, bby); - if ba.is_zero() && bb.is_zero() { - G2::zero() - } else { - G2::from(AffineG2::new(ba, bb).map_err(|_| Error::Bn128AffineGFailedToCreate)?) - } - }; - - mul = mul * bn::pairing(a, b); - } - - mul == Gt::one() - }; - Ok((gas_used, bool_to_bytes32(success))) + let elements = input.len() / PAIR_ELEMENT_LEN; + + let mut points = Vec::with_capacity(elements); + + for idx in 0..elements { + // Offset to the start of the pairing element at index `idx` in the byte slice + let start = idx * PAIR_ELEMENT_LEN; + let g1_start = start; + // Offset to the start of the G2 element in the pairing element + // This is where G1 ends. + let g2_start = start + G1_LEN; + + // Get G1 and G2 points from the input + let encoded_g1_element = &input[g1_start..g2_start]; + let encoded_g2_element = &input[g2_start..g2_start + G2_LEN]; + points.push((encoded_g1_element, encoded_g2_element)); + } + + let pairing_result = pairing_check(&points)?; + Ok(PrecompileOutput::new( + gas_used, + bool_to_bytes32(pairing_result), + )) } #[cfg(test)] mod tests { - use crate::bn128::add::BYZANTIUM_ADD_GAS_COST; - use crate::bn128::mul::BYZANTIUM_MUL_GAS_COST; - use crate::bn128::pair::{BYZANTIUM_PAIR_BASE, BYZANTIUM_PAIR_PER_POINT}; - use revm_primitives::hex; + use crate::{ + bn128::{ + add::BYZANTIUM_ADD_GAS_COST, + mul::BYZANTIUM_MUL_GAS_COST, + pair::{BYZANTIUM_PAIR_BASE, BYZANTIUM_PAIR_PER_POINT}, + }, + PrecompileError, + }; + use primitives::hex; use super::*; @@ -240,10 +250,10 @@ mod tests { ) .unwrap(); - let (_, res) = run_add(&input, BYZANTIUM_ADD_GAS_COST, 500).unwrap(); - assert_eq!(res, expected); + let outcome = run_add(&input, BYZANTIUM_ADD_GAS_COST, 500).unwrap(); + assert_eq!(outcome.bytes, expected); - // zero sum test + // Zero sum test let input = hex::decode( "\ 0000000000000000000000000000000000000000000000000000000000000000\ @@ -259,10 +269,10 @@ mod tests { ) .unwrap(); - let (_, res) = run_add(&input, BYZANTIUM_ADD_GAS_COST, 500).unwrap(); - assert_eq!(res, expected); + let outcome = run_add(&input, BYZANTIUM_ADD_GAS_COST, 500).unwrap(); + assert_eq!(outcome.bytes, expected); - // out of gas test + // Out of gas test let input = hex::decode( "\ 0000000000000000000000000000000000000000000000000000000000000000\ @@ -273,10 +283,10 @@ mod tests { .unwrap(); let res = run_add(&input, BYZANTIUM_ADD_GAS_COST, 499); - println!("{:?}", res); - assert!(matches!(res, Err(Error::OutOfGas))); - // no input test + assert!(matches!(res, Err(PrecompileError::OutOfGas))); + + // No input test let input = [0u8; 0]; let expected = hex::decode( "\ @@ -285,10 +295,10 @@ mod tests { ) .unwrap(); - let (_, res) = run_add(&input, BYZANTIUM_ADD_GAS_COST, 500).unwrap(); - assert_eq!(res, expected); + let outcome = run_add(&input, BYZANTIUM_ADD_GAS_COST, 500).unwrap(); + assert_eq!(outcome.bytes, expected); - // point not on curve fail + // Point not on curve fail let input = hex::decode( "\ 1111111111111111111111111111111111111111111111111111111111111111\ @@ -299,7 +309,10 @@ mod tests { .unwrap(); let res = run_add(&input, BYZANTIUM_ADD_GAS_COST, 500); - assert!(matches!(res, Err(Error::Bn128AffineGFailedToCreate))); + assert!(matches!( + res, + Err(PrecompileError::Bn128AffineGFailedToCreate) + )); } #[test] @@ -318,10 +331,10 @@ mod tests { ) .unwrap(); - let (_, res) = run_mul(&input, BYZANTIUM_MUL_GAS_COST, 40_000).unwrap(); - assert_eq!(res, expected); + let outcome = run_mul(&input, BYZANTIUM_MUL_GAS_COST, 40_000).unwrap(); + assert_eq!(outcome.bytes, expected); - // out of gas test + // Out of gas test let input = hex::decode( "\ 0000000000000000000000000000000000000000000000000000000000000000\ @@ -331,9 +344,9 @@ mod tests { .unwrap(); let res = run_mul(&input, BYZANTIUM_MUL_GAS_COST, 39_999); - assert!(matches!(res, Err(Error::OutOfGas))); + assert!(matches!(res, Err(PrecompileError::OutOfGas))); - // zero multiplication test + // Zero multiplication test let input = hex::decode( "\ 0000000000000000000000000000000000000000000000000000000000000000\ @@ -348,10 +361,10 @@ mod tests { ) .unwrap(); - let (_, res) = run_mul(&input, BYZANTIUM_MUL_GAS_COST, 40_000).unwrap(); - assert_eq!(res, expected); + let outcome = run_mul(&input, BYZANTIUM_MUL_GAS_COST, 40_000).unwrap(); + assert_eq!(outcome.bytes, expected); - // no input test + // No input test let input = [0u8; 0]; let expected = hex::decode( "\ @@ -360,10 +373,10 @@ mod tests { ) .unwrap(); - let (_, res) = run_mul(&input, BYZANTIUM_MUL_GAS_COST, 40_000).unwrap(); - assert_eq!(res, expected); + let outcome = run_mul(&input, BYZANTIUM_MUL_GAS_COST, 40_000).unwrap(); + assert_eq!(outcome.bytes, expected); - // point not on curve fail + // Point not on curve fail let input = hex::decode( "\ 1111111111111111111111111111111111111111111111111111111111111111\ @@ -373,7 +386,10 @@ mod tests { .unwrap(); let res = run_mul(&input, BYZANTIUM_MUL_GAS_COST, 40_000); - assert!(matches!(res, Err(Error::Bn128AffineGFailedToCreate))); + assert!(matches!( + res, + Err(PrecompileError::Bn128AffineGFailedToCreate) + )); } #[test] @@ -398,16 +414,16 @@ mod tests { hex::decode("0000000000000000000000000000000000000000000000000000000000000001") .unwrap(); - let (_, res) = run_pair( + let outcome = run_pair( &input, BYZANTIUM_PAIR_PER_POINT, BYZANTIUM_PAIR_BASE, 260_000, ) .unwrap(); - assert_eq!(res, expected); + assert_eq!(outcome.bytes, expected); - // out of gas test + // Out of gas test let input = hex::decode( "\ 1c76476f4def4bb94541d57ebba1193381ffa7aa76ada664dd31c16024c43f59\ @@ -431,24 +447,24 @@ mod tests { BYZANTIUM_PAIR_BASE, 259_999, ); - assert!(matches!(res, Err(Error::OutOfGas))); + assert!(matches!(res, Err(PrecompileError::OutOfGas))); - // no input test + // No input test let input = [0u8; 0]; let expected = hex::decode("0000000000000000000000000000000000000000000000000000000000000001") .unwrap(); - let (_, res) = run_pair( + let outcome = run_pair( &input, BYZANTIUM_PAIR_PER_POINT, BYZANTIUM_PAIR_BASE, 260_000, ) .unwrap(); - assert_eq!(res, expected); + assert_eq!(outcome.bytes, expected); - // point not on curve fail + // Point not on curve fail let input = hex::decode( "\ 1111111111111111111111111111111111111111111111111111111111111111\ @@ -466,9 +482,12 @@ mod tests { BYZANTIUM_PAIR_BASE, 260_000, ); - assert!(matches!(res, Err(Error::Bn128AffineGFailedToCreate))); + assert!(matches!( + res, + Err(PrecompileError::Bn128AffineGFailedToCreate) + )); - // invalid input length + // Invalid input length let input = hex::decode( "\ 1111111111111111111111111111111111111111111111111111111111111111\ @@ -484,6 +503,53 @@ mod tests { BYZANTIUM_PAIR_BASE, 260_000, ); - assert!(matches!(res, Err(Error::Bn128PairLength))); + assert!(matches!(res, Err(PrecompileError::Bn128PairLength))); + + // Test with point at infinity - should return true (identity element) + // G1 point at infinity (0,0) followed by a valid G2 point + let input = hex::decode( + "\ + 0000000000000000000000000000000000000000000000000000000000000000\ + 0000000000000000000000000000000000000000000000000000000000000000\ + 209dd15ebff5d46c4bd888e51a93cf99a7329636c63514396b4a452003a35bf7\ + 04bf11ca01483bfa8b34b43561848d28905960114c8ac04049af4b6315a41678\ + 2bb8324af6cfc93537a2ad1a445cfd0ca2a71acd7ac41fadbf933c2a51be344d\ + 120a2a4cf30c1bf9845f20c6fe39e07ea2cce61f0c9bb048165fe5e4de877550", + ) + .unwrap(); + let expected = + hex::decode("0000000000000000000000000000000000000000000000000000000000000001") + .unwrap(); + + let outcome = run_pair( + &input, + BYZANTIUM_PAIR_PER_POINT, + BYZANTIUM_PAIR_BASE, + 260_000, + ) + .unwrap(); + assert_eq!(outcome.bytes, expected); + + // Test with G2 point at infinity - should also return true + // Valid G1 point followed by G2 point at infinity (0,0,0,0) + let input = hex::decode( + "\ + 1c76476f4def4bb94541d57ebba1193381ffa7aa76ada664dd31c16024c43f59\ + 3034dd2920f673e204fee2811c678745fc819b55d3e9d294e45c9b03a76aef41\ + 0000000000000000000000000000000000000000000000000000000000000000\ + 0000000000000000000000000000000000000000000000000000000000000000\ + 0000000000000000000000000000000000000000000000000000000000000000\ + 0000000000000000000000000000000000000000000000000000000000000000", + ) + .unwrap(); + + let outcome = run_pair( + &input, + BYZANTIUM_PAIR_PER_POINT, + BYZANTIUM_PAIR_BASE, + 260_000, + ) + .unwrap(); + assert_eq!(outcome.bytes, expected); } } diff --git a/crates/precompile/src/bn128/arkworks.rs b/crates/precompile/src/bn128/arkworks.rs new file mode 100644 index 0000000000..63a14a9946 --- /dev/null +++ b/crates/precompile/src/bn128/arkworks.rs @@ -0,0 +1,239 @@ +use super::{FQ2_LEN, FQ_LEN, G1_LEN, SCALAR_LEN}; +use crate::PrecompileError; +use std::vec::Vec; + +use ark_bn254::{Bn254, Fq, Fq2, Fr, G1Affine, G1Projective, G2Affine}; +use ark_ec::{pairing::Pairing, AffineRepr, CurveGroup}; +use ark_ff::{One, PrimeField, Zero}; +use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; + +/// Reads a single `Fq` field element from the input slice. +/// +/// Takes a byte slice and attempts to interpret the first 32 bytes as an +/// elliptic curve field element. Returns an error if the bytes do not form +/// a valid field element. +/// +/// # Panics +/// +/// Panics if the input is not at least 32 bytes long. +#[inline] +fn read_fq(input_be: &[u8]) -> Result { + assert_eq!(input_be.len(), FQ_LEN, "input must be {FQ_LEN} bytes"); + + let mut input_le = [0u8; FQ_LEN]; + input_le.copy_from_slice(input_be); + + // Reverse in-place to convert from big-endian to little-endian. + input_le.reverse(); + + Fq::deserialize_uncompressed(&input_le[..]) + .map_err(|_| PrecompileError::Bn128FieldPointNotAMember) +} +/// Reads a Fq2 (quadratic extension field element) from the input slice. +/// +/// Parses two consecutive Fq field elements as the real and imaginary parts +/// of an Fq2 element. +/// The second component is parsed before the first, ie if a we represent an +/// element in Fq2 as (x,y) -- `y` is parsed before `x` +/// +/// # Panics +/// +/// Panics if the input is not at least 64 bytes long. +#[inline] +fn read_fq2(input: &[u8]) -> Result { + let y = read_fq(&input[..FQ_LEN])?; + let x = read_fq(&input[FQ_LEN..2 * FQ_LEN])?; + + Ok(Fq2::new(x, y)) +} + +/// Creates a new `G1` point from the given `x` and `y` coordinates. +/// +/// Constructs a point on the G1 curve from its affine coordinates. +/// +/// Note: The point at infinity which is represented as (0,0) is +/// handled specifically because `AffineG1` is not capable of +/// representing such a point. +/// In particular, when we convert from `AffineG1` to `G1`, the point +/// will be (0,0,1) instead of (0,1,0) +#[inline] +fn new_g1_point(px: Fq, py: Fq) -> Result { + if px.is_zero() && py.is_zero() { + Ok(G1Affine::zero()) + } else { + // We cannot use `G1Affine::new` because that triggers an assert if the point is not on the curve. + let point = G1Affine::new_unchecked(px, py); + if !point.is_on_curve() || !point.is_in_correct_subgroup_assuming_on_curve() { + return Err(PrecompileError::Bn128AffineGFailedToCreate); + } + Ok(point) + } +} + +/// Creates a new `G2` point from the given Fq2 coordinates. +/// +/// G2 points in BN128 are defined over a quadratic extension field Fq2. +/// This function takes two Fq2 elements representing the x and y coordinates +/// and creates a G2 point. +/// +/// Note: The point at infinity which is represented as (0,0) is +/// handled specifically because `AffineG2` is not capable of +/// representing such a point. +/// In particular, when we convert from `AffineG2` to `G2`, the point +/// will be (0,0,1) instead of (0,1,0) +#[inline] +fn new_g2_point(x: Fq2, y: Fq2) -> Result { + let point = if x.is_zero() && y.is_zero() { + G2Affine::zero() + } else { + // We cannot use `G1Affine::new` because that triggers an assert if the point is not on the curve. + let point = G2Affine::new_unchecked(x, y); + if !point.is_on_curve() || !point.is_in_correct_subgroup_assuming_on_curve() { + return Err(PrecompileError::Bn128AffineGFailedToCreate); + } + point + }; + + Ok(point) +} + +/// Reads a G1 point from the input slice. +/// +/// Parses a G1 point from a byte slice by reading two consecutive field elements +/// representing the x and y coordinates. +/// +/// # Panics +/// +/// Panics if the input is not at least 64 bytes long. +#[inline] +pub(super) fn read_g1_point(input: &[u8]) -> Result { + let px = read_fq(&input[0..FQ_LEN])?; + let py = read_fq(&input[FQ_LEN..2 * FQ_LEN])?; + new_g1_point(px, py) +} + +/// Encodes a G1 point into a byte array. +/// +/// Converts a G1 point in Jacobian coordinates to affine coordinates and +/// serializes the x and y coordinates as big-endian byte arrays. +/// +/// Note: If the point is the point at infinity, this function returns +/// all zeroes. +#[inline] +pub(super) fn encode_g1_point(point: G1Affine) -> [u8; G1_LEN] { + let mut output = [0u8; G1_LEN]; + let Some((x, y)) = point.xy() else { + return output; + }; + + let mut x_bytes = [0u8; FQ_LEN]; + x.serialize_uncompressed(&mut x_bytes[..]) + .expect("Failed to serialize x coordinate"); + + let mut y_bytes = [0u8; FQ_LEN]; + y.serialize_uncompressed(&mut y_bytes[..]) + .expect("Failed to serialize x coordinate"); + + // Convert to big endian by reversing the bytes. + x_bytes.reverse(); + y_bytes.reverse(); + + // Place x in the first half, y in the second half. + output[0..FQ_LEN].copy_from_slice(&x_bytes); + output[FQ_LEN..(FQ_LEN * 2)].copy_from_slice(&y_bytes); + + output +} + +/// Reads a G2 point from the input slice. +/// +/// Parses a G2 point from a byte slice by reading four consecutive Fq field elements +/// representing the two Fq2 coordinates (x and y) of the G2 point. +/// +/// # Panics +/// +/// Panics if the input is not at least 128 bytes long. +#[inline] +pub(super) fn read_g2_point(input: &[u8]) -> Result { + let ba = read_fq2(&input[0..FQ2_LEN])?; + let bb = read_fq2(&input[FQ2_LEN..2 * FQ2_LEN])?; + new_g2_point(ba, bb) +} + +/// Reads a scalar from the input slice +/// +/// Note: The scalar does not need to be canonical. +/// +/// # Panics +/// +/// If `input.len()` is not equal to [`SCALAR_LEN`]. +#[inline] +pub(super) fn read_scalar(input: &[u8]) -> Fr { + assert_eq!( + input.len(), + SCALAR_LEN, + "unexpected scalar length. got {}, expected {SCALAR_LEN}", + input.len() + ); + Fr::from_be_bytes_mod_order(input) +} + +/// Performs point addition on two G1 points. +#[inline] +pub(super) fn g1_point_add(p1_bytes: &[u8], p2_bytes: &[u8]) -> Result<[u8; 64], PrecompileError> { + let p1 = read_g1_point(p1_bytes)?; + let p2 = read_g1_point(p2_bytes)?; + + let p1_jacobian: G1Projective = p1.into(); + + let p3 = p1_jacobian + p2; + let output = encode_g1_point(p3.into_affine()); + + Ok(output) +} + +/// Performs a G1 scalar multiplication. +#[inline] +pub(super) fn g1_point_mul( + point_bytes: &[u8], + fr_bytes: &[u8], +) -> Result<[u8; 64], PrecompileError> { + let p = read_g1_point(point_bytes)?; + let fr = read_scalar(fr_bytes); + + let big_int = fr.into_bigint(); + let result = p.mul_bigint(big_int); + + let output = encode_g1_point(result.into_affine()); + + Ok(output) +} + +/// pairing_check performs a pairing check on a list of G1 and G2 point pairs and +/// returns true if the result is equal to the identity element. +/// +/// Note: If the input is empty, this function returns true. +/// This is different to EIP2537 which disallows the empty input. +#[inline] +pub(super) fn pairing_check(pairs: &[(&[u8], &[u8])]) -> Result { + let mut g1_points = Vec::with_capacity(pairs.len()); + let mut g2_points = Vec::with_capacity(pairs.len()); + + for (g1_bytes, g2_bytes) in pairs { + let g1 = read_g1_point(g1_bytes)?; + let g2 = read_g2_point(g2_bytes)?; + + // Skip pairs where either point is at infinity + if !g1.is_zero() && !g2.is_zero() { + g1_points.push(g1); + g2_points.push(g2); + } + } + + if g1_points.is_empty() { + return Ok(true); + } + + let pairing_result = Bn254::multi_pairing(&g1_points, &g2_points); + Ok(pairing_result.0.is_one()) +} diff --git a/crates/precompile/src/bn128/substrate.rs b/crates/precompile/src/bn128/substrate.rs new file mode 100644 index 0000000000..ee3b5c162b --- /dev/null +++ b/crates/precompile/src/bn128/substrate.rs @@ -0,0 +1,197 @@ +use super::{FQ2_LEN, FQ_LEN, G1_LEN, SCALAR_LEN}; +use crate::PrecompileError; +use bn::{AffineG1, AffineG2, Fq, Fq2, Group, Gt, G1, G2}; +use std::vec::Vec; + +/// Reads a single `Fq` field element from the input slice. +/// +/// Takes a byte slice and attempts to interpret the first 32 bytes as an +/// elliptic curve field element. Returns an error if the bytes do not form +/// a valid field element. +/// +/// # Panics +/// +/// Panics if the input is not at least 32 bytes long. +#[inline] +fn read_fq(input: &[u8]) -> Result { + Fq::from_slice(&input[..FQ_LEN]).map_err(|_| PrecompileError::Bn128FieldPointNotAMember) +} +/// Reads a Fq2 (quadratic extension field element) from the input slice. +/// +/// Parses two consecutive Fq field elements as the real and imaginary parts +/// of an Fq2 element. +/// The second component is parsed before the first, ie if a we represent an +/// element in Fq2 as (x,y) -- `y` is parsed before `x` +/// +/// # Panics +/// +/// Panics if the input is not at least 64 bytes long. +#[inline] +fn read_fq2(input: &[u8]) -> Result { + let y = read_fq(&input[..FQ_LEN])?; + let x = read_fq(&input[FQ_LEN..2 * FQ_LEN])?; + Ok(Fq2::new(x, y)) +} + +/// Creates a new `G1` point from the given `x` and `y` coordinates. +/// +/// Constructs a point on the G1 curve from its affine coordinates. +/// +/// Note: The point at infinity which is represented as (0,0) is +/// handled specifically because `AffineG1` is not capable of +/// representing such a point. +/// In particular, when we convert from `AffineG1` to `G1`, the point +/// will be (0,0,1) instead of (0,1,0) +#[inline] +fn new_g1_point(px: Fq, py: Fq) -> Result { + if px == Fq::zero() && py == Fq::zero() { + Ok(G1::zero()) + } else { + AffineG1::new(px, py) + .map(Into::into) + .map_err(|_| PrecompileError::Bn128AffineGFailedToCreate) + } +} + +/// Creates a new `G2` point from the given Fq2 coordinates. +/// +/// G2 points in BN128 are defined over a quadratic extension field Fq2. +/// This function takes two Fq2 elements representing the x and y coordinates +/// and creates a G2 point. +/// +/// Note: The point at infinity which is represented as (0,0) is +/// handled specifically because `AffineG2` is not capable of +/// representing such a point. +/// In particular, when we convert from `AffineG2` to `G2`, the point +/// will be (0,0,1) instead of (0,1,0) +#[inline] +fn new_g2_point(x: Fq2, y: Fq2) -> Result { + let point = if x.is_zero() && y.is_zero() { + G2::zero() + } else { + G2::from(AffineG2::new(x, y).map_err(|_| PrecompileError::Bn128AffineGFailedToCreate)?) + }; + + Ok(point) +} + +/// Reads a G1 point from the input slice. +/// +/// Parses a G1 point from a byte slice by reading two consecutive field elements +/// representing the x and y coordinates. +/// +/// # Panics +/// +/// Panics if the input is not at least 64 bytes long. +#[inline] +pub(super) fn read_g1_point(input: &[u8]) -> Result { + let px = read_fq(&input[0..FQ_LEN])?; + let py = read_fq(&input[FQ_LEN..2 * FQ_LEN])?; + new_g1_point(px, py) +} + +/// Encodes a G1 point into a byte array. +/// +/// Converts a G1 point in Jacobian coordinates to affine coordinates and +/// serializes the x and y coordinates as big-endian byte arrays. +/// +/// Note: If the point is the point at infinity, this function returns +/// all zeroes. +#[inline] +pub(super) fn encode_g1_point(point: G1) -> [u8; G1_LEN] { + let mut output = [0u8; G1_LEN]; + + if let Some(point_affine) = AffineG1::from_jacobian(point) { + point_affine + .x() + .to_big_endian(&mut output[..FQ_LEN]) + .unwrap(); + point_affine + .y() + .to_big_endian(&mut output[FQ_LEN..]) + .unwrap(); + } + + output +} + +/// Reads a G2 point from the input slice. +/// +/// Parses a G2 point from a byte slice by reading four consecutive Fq field elements +/// representing the two Fq2 coordinates (x and y) of the G2 point. +/// +/// # Panics +/// +/// Panics if the input is not at least 128 bytes long. +#[inline] +pub(super) fn read_g2_point(input: &[u8]) -> Result { + let ba = read_fq2(&input[0..FQ2_LEN])?; + let bb = read_fq2(&input[FQ2_LEN..2 * FQ2_LEN])?; + new_g2_point(ba, bb) +} + +/// Reads a scalar from the input slice +/// +/// Note: The scalar does not need to be canonical. +/// +/// # Panics +/// +/// If `input.len()` is not equal to [`SCALAR_LEN`]. +#[inline] +pub(super) fn read_scalar(input: &[u8]) -> bn::Fr { + assert_eq!( + input.len(), + SCALAR_LEN, + "unexpected scalar length. got {}, expected {SCALAR_LEN}", + input.len() + ); + // `Fr::from_slice` can only fail when the length is not `SCALAR_LEN`. + bn::Fr::from_slice(input).unwrap() +} + +/// Performs point addition on two G1 points. +#[inline] +pub(super) fn g1_point_add(p1_bytes: &[u8], p2_bytes: &[u8]) -> Result<[u8; 64], PrecompileError> { + let p1 = read_g1_point(p1_bytes)?; + let p2 = read_g1_point(p2_bytes)?; + let result = p1 + p2; + Ok(encode_g1_point(result)) +} + +/// Performs a G1 scalar multiplication. +#[inline] +pub(super) fn g1_point_mul( + point_bytes: &[u8], + fr_bytes: &[u8], +) -> Result<[u8; 64], PrecompileError> { + let p = read_g1_point(point_bytes)?; + let fr = read_scalar(fr_bytes); + let result = p * fr; + Ok(encode_g1_point(result)) +} + +/// pairing_check performs a pairing check on a list of G1 and G2 point pairs and +/// returns true if the result is equal to the identity element. +/// +/// Note: If the input is empty, this function returns true. +/// This is different to EIP2537 which disallows the empty input. +#[inline] +pub(super) fn pairing_check(pairs: &[(&[u8], &[u8])]) -> Result { + let mut parsed_pairs = Vec::with_capacity(pairs.len()); + + for (g1_bytes, g2_bytes) in pairs { + let g1 = read_g1_point(g1_bytes)?; + let g2 = read_g2_point(g2_bytes)?; + + // Skip pairs where either point is at infinity + if !g1.is_zero() && !g2.is_zero() { + parsed_pairs.push((g1, g2)); + } + } + + if parsed_pairs.is_empty() { + return Ok(true); + } + + Ok(bn::pairing_batch(&parsed_pairs) == Gt::one()) +} diff --git a/crates/precompile/src/hash.rs b/crates/precompile/src/hash.rs index 9fc6a8ae49..58286d6485 100644 --- a/crates/precompile/src/hash.rs +++ b/crates/precompile/src/hash.rs @@ -1,42 +1,49 @@ +//! Hash precompiles, it contains SHA-256 and RIPEMD-160 hash precompiles +//! More details in [`sha256_run`] and [`ripemd160_run`] use super::calc_linear_cost_u32; -use crate::{Error, Precompile, PrecompileResult, PrecompileWithAddress}; -use revm_primitives::Bytes; +use crate::{PrecompileError, PrecompileOutput, PrecompileResult, PrecompileWithAddress}; use sha2::Digest; +/// SHA-256 precompile pub const SHA256: PrecompileWithAddress = - PrecompileWithAddress(crate::u64_to_address(2), Precompile::Standard(sha256_run)); + PrecompileWithAddress(crate::u64_to_address(2), sha256_run); -pub const RIPEMD160: PrecompileWithAddress = PrecompileWithAddress( - crate::u64_to_address(3), - Precompile::Standard(ripemd160_run), -); +/// RIPEMD-160 precompile +pub const RIPEMD160: PrecompileWithAddress = + PrecompileWithAddress(crate::u64_to_address(3), ripemd160_run); -/// See: -/// See: -/// See: -pub fn sha256_run(input: &Bytes, gas_limit: u64) -> PrecompileResult { +/// Computes the SHA-256 hash of the input data +/// +/// This function follows specifications defined in the following references: +/// - [Ethereum Yellow Paper](https://ethereum.github.io/yellowpaper/paper.pdf) +/// - [Solidity Documentation on Mathematical and Cryptographic Functions](https://docs.soliditylang.org/en/develop/units-and-global-variables.html#mathematical-and-cryptographic-functions) +/// - [Address 0x02](https://etherscan.io/address/0000000000000000000000000000000000000002) +pub fn sha256_run(input: &[u8], gas_limit: u64) -> PrecompileResult { let cost = calc_linear_cost_u32(input.len(), 60, 12); if cost > gas_limit { - Err(Error::OutOfGas) + Err(PrecompileError::OutOfGas) } else { let output = sha2::Sha256::digest(input); - Ok((cost, output.to_vec().into())) + Ok(PrecompileOutput::new(cost, output.to_vec().into())) } } -/// See: -/// See: -/// See: -pub fn ripemd160_run(input: &Bytes, gas_limit: u64) -> PrecompileResult { +/// Computes the RIPEMD-160 hash of the input data +/// +/// This function follows specifications defined in the following references: +/// - [Ethereum Yellow Paper](https://ethereum.github.io/yellowpaper/paper.pdf) +/// - [Solidity Documentation on Mathematical and Cryptographic Functions](https://docs.soliditylang.org/en/develop/units-and-global-variables.html#mathematical-and-cryptographic-functions) +/// - [Address 03](https://etherscan.io/address/0000000000000000000000000000000000000003) +pub fn ripemd160_run(input: &[u8], gas_limit: u64) -> PrecompileResult { let gas_used = calc_linear_cost_u32(input.len(), 600, 120); if gas_used > gas_limit { - Err(Error::OutOfGas) + Err(PrecompileError::OutOfGas) } else { let mut hasher = ripemd::Ripemd160::new(); hasher.update(input); let mut output = [0u8; 32]; hasher.finalize_into((&mut output[12..]).into()); - Ok((gas_used, output.to_vec().into())) + Ok(PrecompileOutput::new(gas_used, output.to_vec().into())) } } diff --git a/crates/precompile/src/identity.rs b/crates/precompile/src/identity.rs index 85722ea810..9377bf440c 100644 --- a/crates/precompile/src/identity.rs +++ b/crates/precompile/src/identity.rs @@ -1,23 +1,29 @@ +//! Identity precompile returns use super::calc_linear_cost_u32; -use crate::{Error, Precompile, PrecompileResult, PrecompileWithAddress}; -use revm_primitives::Bytes; +use crate::{PrecompileError, PrecompileOutput, PrecompileResult, PrecompileWithAddress}; +use primitives::Bytes; +/// Address of the identity precompile. pub const FUN: PrecompileWithAddress = - PrecompileWithAddress(crate::u64_to_address(4), Precompile::Standard(identity_run)); + PrecompileWithAddress(crate::u64_to_address(4), identity_run); -/// The base cost of the operation. +/// The base cost of the operation pub const IDENTITY_BASE: u64 = 15; -/// The cost per word. +/// The cost per word pub const IDENTITY_PER_WORD: u64 = 3; /// Takes the input bytes, copies them, and returns it as the output. /// /// See: +/// /// See: -pub fn identity_run(input: &Bytes, gas_limit: u64) -> PrecompileResult { +pub fn identity_run(input: &[u8], gas_limit: u64) -> PrecompileResult { let gas_used = calc_linear_cost_u32(input.len(), IDENTITY_BASE, IDENTITY_PER_WORD); if gas_used > gas_limit { - return Err(Error::OutOfGas); + return Err(PrecompileError::OutOfGas); } - Ok((gas_used, input.clone())) + Ok(PrecompileOutput::new( + gas_used, + Bytes::copy_from_slice(input), + )) } diff --git a/crates/precompile/src/interface.rs b/crates/precompile/src/interface.rs new file mode 100644 index 0000000000..1c9c683458 --- /dev/null +++ b/crates/precompile/src/interface.rs @@ -0,0 +1,123 @@ +//! Interface for the precompiles. It contains the precompile result type, +//! the precompile output type, and the precompile error type. +use core::fmt; +use primitives::Bytes; +use std::string::String; + +/// A precompile operation result type +/// +/// Returns either `Ok((gas_used, return_bytes))` or `Err(error)`. +pub type PrecompileResult = Result; + +/// Precompile execution output +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct PrecompileOutput { + /// Gas used by the precompile + pub gas_used: u64, + /// Output bytes + pub bytes: Bytes, + /// Whether the precompile reverted + pub reverted: bool, +} + +impl PrecompileOutput { + /// Returns new precompile output with the given gas used and output bytes. + pub fn new(gas_used: u64, bytes: Bytes) -> Self { + Self { + gas_used, + bytes, + reverted: false, + } + } + + /// Returns new precompile revert with the given gas used and output bytes. + pub fn new_reverted(gas_used: u64, bytes: Bytes) -> Self { + Self { + gas_used, + bytes, + reverted: true, + } + } + + /// Flips [`Self::reverted`] to `true`. + pub fn reverted(mut self) -> Self { + self.reverted = true; + self + } +} + +/// Precompile function type. Takes input and gas limit and returns precompile result. +pub type PrecompileFn = fn(&[u8], u64) -> PrecompileResult; + +/// Precompile error type. +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub enum PrecompileError { + /// out of gas is the main error. Others are here just for completeness + OutOfGas, + /// Blake2 errors + Blake2WrongLength, + /// Blake2 wrong final indicator flag + Blake2WrongFinalIndicatorFlag, + /// Modexp errors + ModexpExpOverflow, + /// Modexp base overflow + ModexpBaseOverflow, + /// Modexp mod overflow + ModexpModOverflow, + /// Modexp limit all input sizes. + ModexpEip7823LimitSize, + /// Bn128 errors + Bn128FieldPointNotAMember, + /// Bn128 affine g failed to create + Bn128AffineGFailedToCreate, + /// Bn128 pair length + Bn128PairLength, + // Blob errors + /// The input length is not exactly 192 bytes + BlobInvalidInputLength, + /// The commitment does not match the versioned hash + BlobMismatchedVersion, + /// The proof verification failed + BlobVerifyKzgProofFailed, + /// Fatal error with a custom error message + Fatal(String), + /// Catch-all variant for other errors + Other(String), +} + +impl PrecompileError { + /// Returns another error with the given message. + pub fn other(err: impl Into) -> Self { + Self::Other(err.into()) + } + + /// Returns `true` if the error is out of gas. + pub fn is_oog(&self) -> bool { + matches!(self, Self::OutOfGas) + } +} + +impl core::error::Error for PrecompileError {} + +impl fmt::Display for PrecompileError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let s = match self { + Self::OutOfGas => "out of gas", + Self::Blake2WrongLength => "wrong input length for blake2", + Self::Blake2WrongFinalIndicatorFlag => "wrong final indicator flag for blake2", + Self::ModexpExpOverflow => "modexp exp overflow", + Self::ModexpBaseOverflow => "modexp base overflow", + Self::ModexpModOverflow => "modexp mod overflow", + Self::ModexpEip7823LimitSize => "Modexp limit all input sizes.", + Self::Bn128FieldPointNotAMember => "field point not a member of bn128 curve", + Self::Bn128AffineGFailedToCreate => "failed to create affine g point for bn128 curve", + Self::Bn128PairLength => "bn128 invalid pair length", + Self::BlobInvalidInputLength => "invalid blob input length", + Self::BlobMismatchedVersion => "mismatched blob version", + Self::BlobVerifyKzgProofFailed => "verifying blob kzg proof failed", + Self::Fatal(s) => s, + Self::Other(s) => s, + }; + f.write_str(s) + } +} diff --git a/crates/precompile/src/kzg_point_evaluation.rs b/crates/precompile/src/kzg_point_evaluation.rs index 5790186a99..9fb761cd7b 100644 --- a/crates/precompile/src/kzg_point_evaluation.rs +++ b/crates/precompile/src/kzg_point_evaluation.rs @@ -1,13 +1,26 @@ -use crate::{Address, Error, Precompile, PrecompileResult, PrecompileWithAddress}; -use c_kzg::{Bytes32, Bytes48, KzgProof, KzgSettings}; -use revm_primitives::{hex_literal::hex, Bytes, Env}; +//! KZG point evaluation precompile added in [`EIP-4844`](https://eips.ethereum.org/EIPS/eip-4844) +//! For more details check [`run`] function. +use crate::{Address, PrecompileError, PrecompileOutput, PrecompileResult, PrecompileWithAddress}; +cfg_if::cfg_if! { + if #[cfg(feature = "c-kzg")] { + use c_kzg::{Bytes32, Bytes48}; + } else if #[cfg(feature = "kzg-rs")] { + use kzg_rs::{Bytes32, Bytes48, KzgProof}; + } +} +use primitives::hex_literal::hex; use sha2::{Digest, Sha256}; -pub const POINT_EVALUATION: PrecompileWithAddress = - PrecompileWithAddress(ADDRESS, Precompile::Env(run)); +/// KZG point evaluation precompile, containing address and function to run. +pub const POINT_EVALUATION: PrecompileWithAddress = PrecompileWithAddress(ADDRESS, run); +/// Address of the KZG point evaluation precompile. pub const ADDRESS: Address = crate::u64_to_address(0x0A); + +/// Gas cost of the KZG point evaluation precompile. pub const GAS_COST: u64 = 50_000; + +/// Versioned hash version for KZG. pub const VERSIONED_HASH_VERSION_KZG: u8 = 0x01; /// `U256(FIELD_ELEMENTS_PER_BLOB).to_be_bytes() ++ BLS_MODULUS.to_bytes32()` @@ -24,34 +37,34 @@ pub const RETURN_VALUE: &[u8; 64] = &hex!( /// | versioned_hash | z | y | commitment | proof | /// | 32 | 32 | 32 | 48 | 48 | /// with z and y being padded 32 byte big endian values -pub fn run(input: &Bytes, gas_limit: u64, env: &Env) -> PrecompileResult { +pub fn run(input: &[u8], gas_limit: u64) -> PrecompileResult { if gas_limit < GAS_COST { - return Err(Error::OutOfGas); + return Err(PrecompileError::OutOfGas); } // Verify input length. if input.len() != 192 { - return Err(Error::BlobInvalidInputLength); + return Err(PrecompileError::BlobInvalidInputLength); } // Verify commitment matches versioned_hash let versioned_hash = &input[..32]; let commitment = &input[96..144]; if kzg_to_versioned_hash(commitment) != versioned_hash { - return Err(Error::BlobMismatchedVersion); + return Err(PrecompileError::BlobMismatchedVersion); } // Verify KZG proof with z and y in big endian format - let commitment = as_bytes48(commitment); - let z = as_bytes32(&input[32..64]); - let y = as_bytes32(&input[64..96]); - let proof = as_bytes48(&input[144..192]); - if !verify_kzg_proof(commitment, z, y, proof, env.cfg.kzg_settings.get()) { - return Err(Error::BlobVerifyKzgProofFailed); + let commitment: &[u8; 48] = commitment.try_into().unwrap(); + let z = input[32..64].try_into().unwrap(); + let y = input[64..96].try_into().unwrap(); + let proof = input[144..192].try_into().unwrap(); + if !verify_kzg_proof(commitment, z, y, proof) { + return Err(PrecompileError::BlobVerifyKzgProofFailed); } // Return FIELD_ELEMENTS_PER_BLOB and BLS_MODULUS as padded 32 byte big endian values - Ok((GAS_COST, RETURN_VALUE.into())) + Ok(PrecompileOutput::new(GAS_COST, RETURN_VALUE.into())) } /// `VERSIONED_HASH_VERSION_KZG ++ sha256(commitment)[1..]` @@ -62,33 +75,45 @@ pub fn kzg_to_versioned_hash(commitment: &[u8]) -> [u8; 32] { hash } +/// Verify KZG proof. #[inline] pub fn verify_kzg_proof( - commitment: &Bytes48, - z: &Bytes32, - y: &Bytes32, - proof: &Bytes48, - kzg_settings: &KzgSettings, + commitment: &[u8; 48], + z: &[u8; 32], + y: &[u8; 32], + proof: &[u8; 48], ) -> bool { - KzgProof::verify_kzg_proof(commitment, z, y, proof, kzg_settings).unwrap_or(false) + cfg_if::cfg_if! { + if #[cfg(feature = "c-kzg")] { + let kzg_settings = c_kzg::ethereum_kzg_settings(8); + kzg_settings.verify_kzg_proof(as_bytes48(commitment), as_bytes32(z), as_bytes32(y), as_bytes48(proof)).unwrap_or(false) + } else if #[cfg(feature = "kzg-rs")] { + let env = kzg_rs::EnvKzgSettings::default(); + let kzg_settings = env.get(); + KzgProof::verify_kzg_proof(as_bytes48(commitment), as_bytes32(z), as_bytes32(y), as_bytes48(proof), kzg_settings).unwrap_or(false) + } + } } +/// Convert a slice to an array of a specific size. #[inline] #[track_caller] -pub fn as_array(bytes: &[u8]) -> &[u8; N] { +fn as_array(bytes: &[u8]) -> &[u8; N] { bytes.try_into().expect("slice with incorrect length") } +/// Convert a slice to a 32 byte big endian array. #[inline] #[track_caller] -pub fn as_bytes32(bytes: &[u8]) -> &Bytes32 { +fn as_bytes32(bytes: &[u8]) -> &Bytes32 { // SAFETY: `#[repr(C)] Bytes32([u8; 32])` unsafe { &*as_array::<32>(bytes).as_ptr().cast() } } +/// Convert a slice to a 48 byte big endian array. #[inline] #[track_caller] -pub fn as_bytes48(bytes: &[u8]) -> &Bytes48 { +fn as_bytes48(bytes: &[u8]) -> &Bytes48 { // SAFETY: `#[repr(C)] Bytes48([u8; 48])` unsafe { &*as_array::<48>(bytes).as_ptr().cast() } } @@ -99,7 +124,7 @@ mod tests { #[test] fn basic_test() { - // test data from: https://github.com/ethereum/c-kzg-4844/blob/main/tests/verify_kzg_proof/kzg-mainnet/verify_kzg_proof_case_correct_proof_31ebd010e6098750/data.yaml + // Test data from: https://github.com/ethereum/c-kzg-4844/blob/main/tests/verify_kzg_proof/kzg-mainnet/verify_kzg_proof_case_correct_proof_4_4/data.yaml let commitment = hex!("8f59a8d2a1a625a17f3fea0fe5eb8c896db3764f3185481bc22f91b4aaffcca25f26936857bc3a7c2539ea8ec3a952b7").to_vec(); let mut versioned_hash = Sha256::digest(&commitment).to_vec(); @@ -112,9 +137,8 @@ mod tests { let expected_output = hex!("000000000000000000000000000000000000000000000000000000000000100073eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001"); let gas = 50000; - let env = Env::default(); - let (actual_gas, actual_output) = run(&input.into(), gas, &env).unwrap(); - assert_eq!(actual_gas, gas); - assert_eq!(actual_output[..], expected_output); + let output = run(&input, gas).unwrap(); + assert_eq!(output.gas_used, gas); + assert_eq!(output.bytes[..], expected_output); } } diff --git a/crates/precompile/src/lib.rs b/crates/precompile/src/lib.rs index ca797c8118..4cbb7eeee6 100644 --- a/crates/precompile/src/lib.rs +++ b/crates/precompile/src/lib.rs @@ -9,53 +9,70 @@ extern crate alloc as std; pub mod blake2; -#[cfg(feature = "blst")] pub mod bls12_381; +pub mod bls12_381_const; +pub mod bls12_381_utils; pub mod bn128; pub mod hash; pub mod identity; -#[cfg(feature = "c-kzg")] +pub mod interface; +#[cfg(any(feature = "c-kzg", feature = "kzg-rs"))] pub mod kzg_point_evaluation; pub mod modexp; pub mod secp256k1; -#[cfg(feature = "secp256r1")] pub mod secp256r1; pub mod utilities; +pub use interface::*; + +// silence arkworks lint as bn impl will be used as default if both are enabled. +cfg_if::cfg_if! { + if #[cfg(feature = "bn")]{ + use ark_bn254 as _; + use ark_ff as _; + use ark_ec as _; + use ark_serialize as _; + } +} + +use arrayref as _; + +#[cfg(all(feature = "c-kzg", feature = "kzg-rs"))] +// silence kzg-rs lint as c-kzg will be used as default if both are enabled. +use kzg_rs as _; + +// silence arkworks-bls12-381 lint as blst will be used as default if both are enabled. +cfg_if::cfg_if! { + if #[cfg(feature = "blst")]{ + use ark_bls12_381 as _; + use ark_ff as _; + use ark_ec as _; + use ark_serialize as _; + } +} + +// silence aurora-engine-modexp if gmp is enabled +#[cfg(feature = "gmp")] +use aurora_engine_modexp as _; + +use cfg_if::cfg_if; use core::hash::Hash; use once_cell::race::OnceBox; -#[doc(hidden)] -pub use revm_primitives as primitives; -pub use revm_primitives::{ - precompile::{PrecompileError as Error, *}, - Address, Bytes, HashMap, Log, B256, -}; +use primitives::{hardfork::SpecId, Address, HashMap, HashSet}; use std::{boxed::Box, vec::Vec}; +/// Calculate the linear cost of a precompile. pub fn calc_linear_cost_u32(len: usize, base: u64, word: u64) -> u64 { - (len as u64 + 32 - 1) / 32 * word + base -} - -#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] -pub struct PrecompileOutput { - pub cost: u64, - pub output: Vec, - pub logs: Vec, + (len as u64).div_ceil(32) * word + base } -impl PrecompileOutput { - pub fn without_logs(cost: u64, output: Vec) -> Self { - Self { - cost, - output, - logs: Vec::new(), - } - } -} +/// Precompiles contain map of precompile addresses to functions and HashSet of precompile addresses. #[derive(Clone, Default, Debug)] pub struct Precompiles { - /// Precompiles. - pub inner: HashMap, + /// Precompiles + inner: HashMap, + /// Addresses of precompile + addresses: HashSet

, } impl Precompiles { @@ -68,7 +85,7 @@ impl Precompiles { PrecompileSpecId::BERLIN => Self::berlin(), PrecompileSpecId::CANCUN => Self::cancun(), PrecompileSpecId::PRAGUE => Self::prague(), - PrecompileSpecId::LATEST => Self::latest(), + PrecompileSpecId::OSAKA => Self::osaka(), } } @@ -87,19 +104,24 @@ impl Precompiles { }) } + /// Returns inner HashMap of precompiles. + pub fn inner(&self) -> &HashMap { + &self.inner + } + /// Returns precompiles for Byzantium spec. pub fn byzantium() -> &'static Self { static INSTANCE: OnceBox = OnceBox::new(); INSTANCE.get_or_init(|| { let mut precompiles = Self::homestead().clone(); precompiles.extend([ + // EIP-198: Big integer modular exponentiation. + modexp::BYZANTIUM, // EIP-196: Precompiled contracts for addition and scalar multiplication on the elliptic curve alt_bn128. // EIP-197: Precompiled contracts for optimal ate pairing check on the elliptic curve alt_bn128. bn128::add::BYZANTIUM, bn128::mul::BYZANTIUM, bn128::pair::BYZANTIUM, - // EIP-198: Big integer modular exponentiation. - modexp::BYZANTIUM, ]); Box::new(precompiles) }) @@ -111,12 +133,12 @@ impl Precompiles { INSTANCE.get_or_init(|| { let mut precompiles = Self::byzantium().clone(); precompiles.extend([ - // EIP-152: Add BLAKE2 compression function `F` precompile. - blake2::FUN, // EIP-1108: Reduce alt_bn128 precompile gas costs. bn128::add::ISTANBUL, bn128::mul::ISTANBUL, bn128::pair::ISTANBUL, + // EIP-152: Add BLAKE2 compression function `F` precompile. + blake2::FUN, ]); Box::new(precompiles) }) @@ -142,18 +164,21 @@ impl Precompiles { pub fn cancun() -> &'static Self { static INSTANCE: OnceBox = OnceBox::new(); INSTANCE.get_or_init(|| { - let precompiles = Self::berlin().clone(); - - // Don't include KZG point evaluation precompile in no_std builds. - #[cfg(feature = "c-kzg")] - let precompiles = { - let mut precompiles = precompiles; - precompiles.extend([ - // EIP-4844: Shard Blob Transactions - kzg_point_evaluation::POINT_EVALUATION, - ]); - precompiles - }; + let mut precompiles = Self::berlin().clone(); + + // EIP-4844: Shard Blob Transactions + cfg_if! { + if #[cfg(any(feature = "c-kzg", feature = "kzg-rs"))] { + let precompile = kzg_point_evaluation::POINT_EVALUATION.clone(); + } else { + let precompile = PrecompileWithAddress(u64_to_address(0x0A), |_,_| Err(PrecompileError::Fatal("c-kzg feature is not enabled".into()))); + } + } + + + precompiles.extend([ + precompile, + ]); Box::new(precompiles) }) @@ -163,34 +188,36 @@ impl Precompiles { pub fn prague() -> &'static Self { static INSTANCE: OnceBox = OnceBox::new(); INSTANCE.get_or_init(|| { - let precompiles = Self::cancun().clone(); - - // Don't include BLS12-381 precompiles in no_std builds. - #[cfg(feature = "blst")] - let precompiles = { - let mut precompiles = precompiles; - precompiles.extend(bls12_381::precompiles()); - precompiles - }; + let mut precompiles = Self::cancun().clone(); + precompiles.extend(bls12_381::precompiles()); + Box::new(precompiles) + }) + } + /// Returns precompiles for Osaka spec. + pub fn osaka() -> &'static Self { + static INSTANCE: OnceBox = OnceBox::new(); + INSTANCE.get_or_init(|| { + let mut precompiles = Self::prague().clone(); + precompiles.extend([modexp::OSAKA, secp256r1::P256VERIFY_OSAKA]); Box::new(precompiles) }) } /// Returns the precompiles for the latest spec. pub fn latest() -> &'static Self { - Self::prague() + Self::osaka() } /// Returns an iterator over the precompiles addresses. #[inline] - pub fn addresses(&self) -> impl Iterator { + pub fn addresses(&self) -> impl ExactSizeIterator { self.inner.keys() } /// Consumes the type and returns all precompile addresses. #[inline] - pub fn into_addresses(self) -> impl Iterator { + pub fn into_addresses(self) -> impl ExactSizeIterator { self.inner.into_keys() } @@ -202,13 +229,13 @@ impl Precompiles { /// Returns the precompile for the given address. #[inline] - pub fn get(&self, address: &Address) -> Option<&Precompile> { + pub fn get(&self, address: &Address) -> Option<&PrecompileFn> { self.inner.get(address) } /// Returns the precompile for the given address. #[inline] - pub fn get_mut(&mut self, address: &Address) -> Option<&mut Precompile> { + pub fn get_mut(&mut self, address: &Address) -> Option<&mut PrecompileFn> { self.inner.get_mut(address) } @@ -222,44 +249,132 @@ impl Precompiles { self.inner.len() } + /// Returns the precompiles addresses as a set. + pub fn addresses_set(&self) -> &HashSet
{ + &self.addresses + } + /// Extends the precompiles with the given precompiles. /// /// Other precompiles with overwrite existing precompiles. + #[inline] pub fn extend(&mut self, other: impl IntoIterator) { - self.inner.extend(other.into_iter().map(Into::into)); + let items: Vec = other.into_iter().collect::>(); + self.addresses.extend(items.iter().map(|p| *p.address())); + self.inner.extend(items.into_iter().map(|p| (p.0, p.1))); + } + + /// Returns complement of `other` in `self`. + /// + /// Two entries are considered equal if the precompile addresses are equal. + pub fn difference(&self, other: &Self) -> Self { + let Self { inner, .. } = self; + + let inner = inner + .iter() + .filter(|(a, _)| !other.inner.contains_key(*a)) + .map(|(a, p)| (*a, *p)) + .collect::>(); + + let addresses = inner.keys().cloned().collect::>(); + + Self { inner, addresses } + } + + /// Returns intersection of `self` and `other`. + /// + /// Two entries are considered equal if the precompile addresses are equal. + pub fn intersection(&self, other: &Self) -> Self { + let Self { inner, .. } = self; + + let inner = inner + .iter() + .filter(|(a, _)| other.inner.contains_key(*a)) + .map(|(a, p)| (*a, *p)) + .collect::>(); + + let addresses = inner.keys().cloned().collect::>(); + + Self { inner, addresses } } } +/// Precompile with address and function. #[derive(Clone, Debug)] -pub struct PrecompileWithAddress(pub Address, pub Precompile); +pub struct PrecompileWithAddress(pub Address, pub PrecompileFn); -impl From<(Address, Precompile)> for PrecompileWithAddress { - fn from(value: (Address, Precompile)) -> Self { +impl From<(Address, PrecompileFn)> for PrecompileWithAddress { + fn from(value: (Address, PrecompileFn)) -> Self { PrecompileWithAddress(value.0, value.1) } } -impl From for (Address, Precompile) { +impl From for (Address, PrecompileFn) { fn from(value: PrecompileWithAddress) -> Self { (value.0, value.1) } } +impl PrecompileWithAddress { + /// Returns reference of address. + #[inline] + pub fn address(&self) -> &Address { + &self.0 + } + + /// Returns reference of precompile. + #[inline] + pub fn precompile(&self) -> &PrecompileFn { + &self.1 + } +} + +/// Ethereum hardfork spec ids. Represents the specs where precompiles had a change. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)] pub enum PrecompileSpecId { + /// Frontier spec. HOMESTEAD, + /// Byzantium spec introduced + /// * [EIP-198](https://eips.ethereum.org/EIPS/eip-198) a EIP-198: Big integer modular exponentiation (at 0x05 address). + /// * [EIP-196](https://eips.ethereum.org/EIPS/eip-196) a bn_add (at 0x06 address) and bn_mul (at 0x07 address) precompile + /// * [EIP-197](https://eips.ethereum.org/EIPS/eip-197) a bn_pair (at 0x08 address) precompile BYZANTIUM, + /// Istanbul spec introduced + /// * [`EIP-152: Add BLAKE2 compression function`](https://eips.ethereum.org/EIPS/eip-152) `F` precompile (at 0x09 address). + /// * [`EIP-1108: Reduce alt_bn128 precompile gas costs`](https://eips.ethereum.org/EIPS/eip-1108). It reduced the + /// gas cost of the bn_add, bn_mul, and bn_pair precompiles. ISTANBUL, + /// Berlin spec made a change to: + /// * [`EIP-2565: ModExp Gas Cost`](https://eips.ethereum.org/EIPS/eip-2565). It changed the gas cost of the modexp precompile. BERLIN, + /// Cancun spec added + /// * [`EIP-4844: Shard Blob Transactions`](https://eips.ethereum.org/EIPS/eip-4844). It added the KZG point evaluation precompile (at 0x0A address). CANCUN, + /// Prague spec added bls precompiles [`EIP-2537: Precompile for BLS12-381 curve operations`](https://eips.ethereum.org/EIPS/eip-2537). + /// * `BLS12_G1ADD` at address 0x0b + /// * `BLS12_G1MSM` at address 0x0c + /// * `BLS12_G2ADD` at address 0x0d + /// * `BLS12_G2MSM` at address 0x0e + /// * `BLS12_PAIRING_CHECK` at address 0x0f + /// * `BLS12_MAP_FP_TO_G1` at address 0x10 + /// * `BLS12_MAP_FP2_TO_G2` at address 0x11 PRAGUE, - LATEST, + /// Osaka spec added changes to modexp precompile: + /// * [`EIP-7823: Set upper bounds for MODEXP`](https://eips.ethereum.org/EIPS/eip-7823). + /// * [`EIP-7883: ModExp Gas Cost Increase`](https://eips.ethereum.org/EIPS/eip-7883) + OSAKA, +} + +impl From for PrecompileSpecId { + fn from(spec_id: SpecId) -> Self { + Self::from_spec_id(spec_id) + } } impl PrecompileSpecId { - /// Returns the appropriate precompile Spec for the primitive [SpecId](revm_primitives::SpecId) - pub const fn from_spec_id(spec_id: revm_primitives::SpecId) -> Self { - use revm_primitives::SpecId::*; + /// Returns the appropriate precompile Spec for the primitive [SpecId]. + pub const fn from_spec_id(spec_id: primitives::hardfork::SpecId) -> Self { + use primitives::hardfork::SpecId::*; match spec_id { FRONTIER | FRONTIER_THAWING | HOMESTEAD | DAO_FORK | TANGERINE | SPURIOUS_DRAGON => { Self::HOMESTEAD @@ -269,19 +384,16 @@ impl PrecompileSpecId { BERLIN | LONDON | ARROW_GLACIER | GRAY_GLACIER | MERGE | SHANGHAI => Self::BERLIN, CANCUN => Self::CANCUN, PRAGUE => Self::PRAGUE, - LATEST => Self::LATEST, - #[cfg(feature = "optimism")] - BEDROCK | REGOLITH | CANYON => Self::BERLIN, - #[cfg(feature = "optimism")] - ECOTONE | FJORD => Self::CANCUN, + OSAKA => Self::OSAKA, } } } /// Const function for making an address by concatenating the bytes from two given numbers. /// -/// Note that 32 + 128 = 160 = 20 bytes (the length of an address). This function is used -/// as a convenience for specifying the addresses of the various precompiles. +/// Note that 32 + 128 = 160 = 20 bytes (the length of an address). +/// +/// This function is used as a convenience for specifying the addresses of the various precompiles. #[inline] pub const fn u64_to_address(x: u64) -> Address { let x = x.to_be_bytes(); @@ -289,3 +401,21 @@ pub const fn u64_to_address(x: u64) -> Address { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7], ]) } + +#[cfg(test)] +mod test { + use crate::Precompiles; + + #[test] + fn test_difference_precompile_sets() { + let difference = Precompiles::istanbul().difference(Precompiles::berlin()); + assert!(difference.is_empty()); + } + + #[test] + fn test_intersection_precompile_sets() { + let intersection = Precompiles::homestead().intersection(Precompiles::byzantium()); + + assert_eq!(intersection.len(), 4) + } +} diff --git a/crates/precompile/src/modexp.rs b/crates/precompile/src/modexp.rs index a55b445912..08300abe3c 100644 --- a/crates/precompile/src/modexp.rs +++ b/crates/precompile/src/modexp.rs @@ -1,87 +1,135 @@ +//! Modexp precompile added in [`EIP-198`](https://eips.ethereum.org/EIPS/eip-198) +//! and reprices in berlin hardfork with [`EIP-2565`](https://eips.ethereum.org/EIPS/eip-2565). use crate::{ - primitives::U256, utilities::{left_pad, left_pad_vec, right_pad_vec, right_pad_with_offset}, - Error, Precompile, PrecompileResult, PrecompileWithAddress, + PrecompileError, PrecompileOutput, PrecompileResult, PrecompileWithAddress, }; -use aurora_engine_modexp::modexp; use core::cmp::{max, min}; -use revm_primitives::Bytes; +use primitives::{eip7823, Bytes, U256}; +use std::vec::Vec; -pub const BYZANTIUM: PrecompileWithAddress = PrecompileWithAddress( - crate::u64_to_address(5), - Precompile::Standard(byzantium_run), -); +/// `modexp` precompile with BYZANTIUM gas rules. +pub const BYZANTIUM: PrecompileWithAddress = + PrecompileWithAddress(crate::u64_to_address(5), byzantium_run); +/// `modexp` precompile with BERLIN gas rules. pub const BERLIN: PrecompileWithAddress = - PrecompileWithAddress(crate::u64_to_address(5), Precompile::Standard(berlin_run)); + PrecompileWithAddress(crate::u64_to_address(5), berlin_run); + +/// `modexp` precompile with OSAKA gas rules. +pub const OSAKA: PrecompileWithAddress = PrecompileWithAddress(crate::u64_to_address(5), osaka_run); + +#[cfg(feature = "gmp")] +/// GMP-based modular exponentiation implementation +fn modexp(base: &[u8], exponent: &[u8], modulus: &[u8]) -> Vec { + use rug::{integer::Order::Msf, Integer}; + // Convert byte slices to GMP integers + let base_int = Integer::from_digits(base, Msf); + let exp_int = Integer::from_digits(exponent, Msf); + let mod_int = Integer::from_digits(modulus, Msf); + + // Perform modular exponentiation using GMP's pow_mod + let result = base_int.pow_mod(&exp_int, &mod_int).unwrap_or_default(); + + // Convert result back to bytes + let byte_count = result.significant_bits().div_ceil(8); + let mut output = vec![0u8; byte_count as usize]; + result.write_digits(&mut output, Msf); + output +} + +#[cfg(not(feature = "gmp"))] +fn modexp(base: &[u8], exponent: &[u8], modulus: &[u8]) -> Vec { + aurora_engine_modexp::modexp(base, exponent, modulus) +} /// See: /// See: -pub fn byzantium_run(input: &Bytes, gas_limit: u64) -> PrecompileResult { - run_inner(input, gas_limit, 0, |a, b, c, d| { +pub fn byzantium_run(input: &[u8], gas_limit: u64) -> PrecompileResult { + run_inner::<_, false>(input, gas_limit, 0, |a, b, c, d| { byzantium_gas_calc(a, b, c, d) }) } -pub fn berlin_run(input: &Bytes, gas_limit: u64) -> PrecompileResult { - run_inner(input, gas_limit, 200, |a, b, c, d| { +/// See: +/// Gas cost of berlin is modified from byzantium. +pub fn berlin_run(input: &[u8], gas_limit: u64) -> PrecompileResult { + run_inner::<_, false>(input, gas_limit, 200, |a, b, c, d| { berlin_gas_calc(a, b, c, d) }) } -pub fn calculate_iteration_count(exp_length: u64, exp_highp: &U256) -> u64 { +/// See: +/// Gas cost of berlin is modified from byzantium. +pub fn osaka_run(input: &[u8], gas_limit: u64) -> PrecompileResult { + run_inner::<_, true>(input, gas_limit, 500, |a, b, c, d| { + osaka_gas_calc(a, b, c, d) + }) +} + +/// Calculate the iteration count for the modexp precompile. +pub fn calculate_iteration_count(exp_length: u64, exp_highp: &U256) -> u64 { let mut iteration_count: u64 = 0; - if exp_length <= 32 && *exp_highp == U256::ZERO { + if exp_length <= 32 && exp_highp.is_zero() { iteration_count = 0; } else if exp_length <= 32 { iteration_count = exp_highp.bit_len() as u64 - 1; } else if exp_length > 32 { - iteration_count = (8u64.saturating_mul(exp_length - 32)) + iteration_count = (MULTIPLIER.saturating_mul(exp_length - 32)) .saturating_add(max(1, exp_highp.bit_len() as u64) - 1); } max(iteration_count, 1) } -pub fn run_inner(input: &[u8], gas_limit: u64, min_gas: u64, calc_gas: F) -> PrecompileResult +/// Run the modexp precompile. +pub fn run_inner( + input: &[u8], + gas_limit: u64, + min_gas: u64, + calc_gas: F, +) -> PrecompileResult where F: FnOnce(u64, u64, u64, &U256) -> u64, { // If there is no minimum gas, return error. if min_gas > gas_limit { - return Err(Error::OutOfGas); + return Err(PrecompileError::OutOfGas); } // The format of input is: // // Where every length is a 32-byte left-padded integer representing the number of bytes - // to be taken up by the next value + // to be taken up by the next value. const HEADER_LENGTH: usize = 96; - // Extract the header. + // Extract the header let base_len = U256::from_be_bytes(right_pad_with_offset::<32>(input, 0).into_owned()); let exp_len = U256::from_be_bytes(right_pad_with_offset::<32>(input, 32).into_owned()); let mod_len = U256::from_be_bytes(right_pad_with_offset::<32>(input, 64).into_owned()); - // cast base and modulus to usize, it does not make sense to handle larger values - let Ok(base_len) = usize::try_from(base_len) else { - return Err(Error::ModexpBaseOverflow); - }; - let Ok(mod_len) = usize::try_from(mod_len) else { - return Err(Error::ModexpModOverflow); - }; + // Cast base and modulus to usize, it does not make sense to handle larger values + let base_len = + usize::try_from(base_len).map_err(|_| PrecompileError::ModexpEip7823LimitSize)?; + let mod_len = usize::try_from(mod_len).map_err(|_| PrecompileError::ModexpEip7823LimitSize)?; + // cast exp len to the max size, it will fail later in gas calculation if it is too large. + let exp_len = usize::try_from(exp_len).unwrap_or(usize::MAX); + + // for EIP-7823 we need to check size of imputs + if OSAKA + && (base_len > eip7823::INPUT_SIZE_LIMIT + || mod_len > eip7823::INPUT_SIZE_LIMIT + || exp_len > eip7823::INPUT_SIZE_LIMIT) + { + return Err(PrecompileError::ModexpEip7823LimitSize); + } - // Handle a special case when both the base and mod length are zero. + // special case for both base and mod length being 0. if base_len == 0 && mod_len == 0 { - return Ok((min_gas, Bytes::new())); + return Ok(PrecompileOutput::new(min_gas, Bytes::new())); } - // Cast exponent length to usize, since it does not make sense to handle larger values. - let Ok(exp_len) = usize::try_from(exp_len) else { - return Err(Error::ModexpModOverflow); - }; - // Used to extract ADJUSTED_EXPONENT_LENGTH. let exp_highp_len = min(exp_len, 32); @@ -89,7 +137,7 @@ where let input = input.get(HEADER_LENGTH..).unwrap_or_default(); let exp_highp = { - // get right padded bytes so if data.len is less then exp_len we will get right padded zeroes. + // Get right padded bytes so if data.len is less then exp_len we will get right padded zeroes. let right_padded_highp = right_pad_with_offset::<32>(input, base_len); // If exp_len is less then 32 bytes get only exp_len bytes and do left padding. let out = left_pad::<32>(&right_padded_highp[..exp_highp_len]); @@ -99,7 +147,7 @@ where // Check if we have enough gas. let gas_cost = calc_gas(base_len as u64, exp_len as u64, mod_len as u64, &exp_highp); if gas_cost > gas_limit { - return Err(Error::OutOfGas); + return Err(PrecompileError::OutOfGas); } // Padding is needed if the input does not contain all 3 values. @@ -112,60 +160,78 @@ where // Call the modexp. let output = modexp(base, exponent, modulus); - // left pad the result to modulus length. bytes will always by less or equal to modulus length. - Ok((gas_cost, left_pad_vec(&output, mod_len).into_owned().into())) + // Left pad the result to modulus length. bytes will always by less or equal to modulus length. + Ok(PrecompileOutput::new( + gas_cost, + left_pad_vec(&output, mod_len).into_owned().into(), + )) } +/// Calculate the gas cost for the modexp precompile with BYZANTIUM gas rules. pub fn byzantium_gas_calc(base_len: u64, exp_len: u64, mod_len: u64, exp_highp: &U256) -> u64 { - // output of this function is bounded by 2^128 - fn mul_complexity(x: u64) -> U256 { - if x <= 64 { - U256::from(x * x) - } else if x <= 1_024 { - U256::from(x * x / 4 + 96 * x - 3_072) + gas_calc::<0, 8, 20, _>(base_len, exp_len, mod_len, exp_highp, |max_len| -> U256 { + // Output of this function is bounded by 2^128 + if max_len <= 64 { + U256::from(max_len * max_len) + } else if max_len <= 1_024 { + U256::from(max_len * max_len / 4 + 96 * max_len - 3_072) } else { - // up-cast to avoid overflow - let x = U256::from(x); + // Up-cast to avoid overflow + let x = U256::from(max_len); let x_sq = x * x; // x < 2^64 => x*x < 2^128 < 2^256 (no overflow) x_sq / U256::from(16) + U256::from(480) * x - U256::from(199_680) } - } + }) +} - let mul = mul_complexity(core::cmp::max(mod_len, base_len)); - let iter_count = U256::from(calculate_iteration_count(exp_len, exp_highp)); - // mul * iter_count bounded by 2^195 < 2^256 (no overflow) - let gas = (mul * iter_count) / U256::from(20); - gas.saturating_to() +/// Calculate gas cost according to EIP 2565: +/// +pub fn berlin_gas_calc(base_len: u64, exp_len: u64, mod_len: u64, exp_highp: &U256) -> u64 { + gas_calc::<200, 8, 3, _>(base_len, exp_len, mod_len, exp_highp, |max_len| -> U256 { + let words = U256::from(max_len.div_ceil(8)); + words * words + }) } -// Calculate gas cost according to EIP 2565: -// https://eips.ethereum.org/EIPS/eip-2565 -pub fn berlin_gas_calc( - base_length: u64, - exp_length: u64, - mod_length: u64, - exp_highp: &U256, -) -> u64 { - fn calculate_multiplication_complexity(base_length: u64, mod_length: u64) -> U256 { - let max_length = max(base_length, mod_length); - let mut words = max_length / 8; - if max_length % 8 > 0 { - words += 1; +/// Calculate gas cost according to EIP-7883: +/// +/// +/// There are three changes: +/// 1. Increase minimal price from 200 to 500 +/// 2. Increase cost when exponent is larger than 32 bytes +/// 3. Increase cost when base or modulus is larger than 32 bytes +pub fn osaka_gas_calc(base_len: u64, exp_len: u64, mod_len: u64, exp_highp: &U256) -> u64 { + gas_calc::<500, 16, 1, _>(base_len, exp_len, mod_len, exp_highp, |max_len| -> U256 { + if max_len <= 32 { + return U256::from(16); // multiplication_complexity = 16 } - let words = U256::from(words); - words * words - } - let multiplication_complexity = calculate_multiplication_complexity(base_length, mod_length); - let iteration_count = calculate_iteration_count(exp_length, exp_highp); - let gas = (multiplication_complexity * U256::from(iteration_count)) / U256::from(3); - max(200, gas.saturating_to()) + let words = U256::from(max_len.div_ceil(8)); + words * words * U256::from(2) // multiplication_complexity = 2 * words**2 + }) +} + +/// Calculate gas cost. +pub fn gas_calc( + base_len: u64, + exp_len: u64, + mod_len: u64, + exp_highp: &U256, + calculate_multiplication_complexity: F, +) -> u64 +where + F: Fn(u64) -> U256, +{ + let multiplication_complexity = calculate_multiplication_complexity(max(base_len, mod_len)); + let iteration_count = calculate_iteration_count::(exp_len, exp_highp); + let gas = (multiplication_complexity * U256::from(iteration_count)) / U256::from(GAS_DIVISOR); + max(MIN_PRICE, gas.saturating_to()) } #[cfg(test)] mod tests { use super::*; - use revm_primitives::hex; + use primitives::hex; use std::vec::Vec; struct Test { @@ -343,33 +409,53 @@ mod tests { 21_845, 5_461, 5_461, 87_381, ]; + const OSAKA_GAS: [u64; 19] = [ + 453_596, 4_080, 4_080, 4_080, 500, 500, 2_048, 512, 512, 8_192, 2_048, 2_048, 32_768, + 8_192, 8_192, 131_072, 32_768, 32_768, 524_288, + ]; + #[test] fn test_byzantium_modexp_gas() { for (test, &test_gas) in TESTS.iter().zip(BYZANTIUM_GAS.iter()) { - let input = hex::decode(test.input).unwrap().into(); + let input = hex::decode(test.input).unwrap(); let res = byzantium_run(&input, 100_000_000).unwrap(); let expected = hex::decode(test.expected).unwrap(); assert_eq!( - res.0, test_gas, + res.gas_used, test_gas, "used gas not matching for test: {}", test.name ); - assert_eq!(res.1, expected, "test:{}", test.name); + assert_eq!(res.bytes, expected, "test:{}", test.name); } } #[test] fn test_berlin_modexp_gas() { for (test, &test_gas) in TESTS.iter().zip(BERLIN_GAS.iter()) { - let input = hex::decode(test.input).unwrap().into(); + let input = hex::decode(test.input).unwrap(); let res = berlin_run(&input, 100_000_000).unwrap(); let expected = hex::decode(test.expected).unwrap(); assert_eq!( - res.0, test_gas, + res.gas_used, test_gas, "used gas not matching for test: {}", test.name ); - assert_eq!(res.1, expected, "test:{}", test.name); + assert_eq!(res.bytes, expected, "test:{}", test.name); + } + } + + #[test] + fn test_osaka_modexp_gas() { + for (test, &test_gas) in TESTS.iter().zip(OSAKA_GAS.iter()) { + let input = hex::decode(test.input).unwrap(); + let res = osaka_run(&input, 100_000_000).unwrap(); + let expected = hex::decode(test.expected).unwrap(); + assert_eq!( + res.gas_used, test_gas, + "used gas not matching for test: {}", + test.name + ); + assert_eq!(res.bytes, expected, "test:{}", test.name); } } @@ -377,6 +463,346 @@ mod tests { fn test_berlin_modexp_empty_input() { let res = berlin_run(&Bytes::new(), 100_000).unwrap(); let expected: Vec = Vec::new(); - assert_eq!(res.1, expected) + assert_eq!(res.bytes, expected) + } + + #[test] + fn test_osaka_modexp_input_len() { + #[derive(Debug)] + struct TestInput { + base_len: U256, + exp_len: U256, + mod_len: U256, + expected: Option, + } + + impl TestInput { + fn input(&self) -> Bytes { + let mut input = vec![]; + input.extend(&self.base_len.to_be_bytes::<32>()); + input.extend(&self.exp_len.to_be_bytes::<32>()); + input.extend(&self.mod_len.to_be_bytes::<32>()); + Bytes::from(input) + } + } + + let test_inputs = [ + TestInput { + base_len: U256::from(1025), + exp_len: U256::from(1024), + mod_len: U256::from(1024), + expected: Some(PrecompileError::ModexpEip7823LimitSize), + }, + TestInput { + base_len: U256::from(1024), + exp_len: U256::from(1025), + mod_len: U256::from(1024), + expected: Some(PrecompileError::ModexpEip7823LimitSize), + }, + TestInput { + base_len: U256::from(1024), + exp_len: U256::from(1024), + mod_len: U256::from(1025), + expected: Some(PrecompileError::ModexpEip7823LimitSize), + }, + TestInput { + base_len: U256::from(0), + exp_len: U256::from(0), + mod_len: U256::from(1025), + expected: Some(PrecompileError::ModexpEip7823LimitSize), + }, + TestInput { + base_len: U256::from(1024), + exp_len: U256::from(1024), + mod_len: U256::from(1024), + expected: Some(PrecompileError::OutOfGas), + }, + TestInput { + base_len: U256::from(0), + exp_len: U256::from(0), + mod_len: U256::from(0), + expected: None, + }, + ]; + for test in test_inputs { + let input = test.input(); + let res = osaka_run(&input, 100_000_000).err(); + if res != test.expected { + panic!("test failed: {test:?} result: {res:?}"); + } + } + } + + #[test] + fn test_modexp_edge_cases() { + // Test case 1: Zero base with non-zero exponent and modulus + let input = hex::decode( + "0000000000000000000000000000000000000000000000000000000000000001\ + 0000000000000000000000000000000000000000000000000000000000000001\ + 0000000000000000000000000000000000000000000000000000000000000001\ + 00\ + 05\ + 07", + ) + .unwrap(); + let res = byzantium_run(&input, 100_000).unwrap(); + assert_eq!(res.bytes, vec![0x00], "0^5 mod 7 should be 0"); + + // Test case 2: Base equals modulus + let input = hex::decode( + "0000000000000000000000000000000000000000000000000000000000000001\ + 0000000000000000000000000000000000000000000000000000000000000001\ + 0000000000000000000000000000000000000000000000000000000000000001\ + 07\ + 03\ + 07", + ) + .unwrap(); + let res = byzantium_run(&input, 100_000).unwrap(); + assert_eq!(res.bytes, vec![0x00], "7^3 mod 7 should be 0"); + + // Test case 3: Exponent is zero (result should always be 1) + let input = hex::decode( + "0000000000000000000000000000000000000000000000000000000000000001\ + 0000000000000000000000000000000000000000000000000000000000000000\ + 0000000000000000000000000000000000000000000000000000000000000001\ + 05\ + 07", + ) + .unwrap(); + let res = byzantium_run(&input, 100_000).unwrap(); + assert_eq!(res.bytes, vec![0x01], "5^0 mod 7 should be 1"); + + // Test case 4: Large base with small modulus + // Actually, (2^256 - 1) mod 3 = 0, so 0^2 = 0 + let input = hex::decode( + "0000000000000000000000000000000000000000000000000000000000000020\ + 0000000000000000000000000000000000000000000000000000000000000001\ + 0000000000000000000000000000000000000000000000000000000000000001\ + ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\ + 02\ + 03", + ) + .unwrap(); + let res = byzantium_run(&input, 100_000).unwrap(); + // (2^256 - 1) = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + // This is divisible by 3, so (2^256 - 1) mod 3 = 0 + // Therefore 0^2 mod 3 = 0 + assert_eq!( + res.bytes, + vec![0x00], + "Large base mod 3 should reduce correctly" + ); + } + + #[test] + fn test_modexp_gas_edge_cases() { + // Test minimum gas consumption with empty input + // Byzantium has min_gas of 0 for empty input + let res = byzantium_run(&[], 100_000).unwrap(); + assert_eq!( + res.gas_used, 0, + "Empty input should use 0 gas for Byzantium" + ); + + // Berlin has min_gas of 200 + let res = berlin_run(&[], 100_000).unwrap(); + assert_eq!( + res.gas_used, 200, + "Empty input should use minimum gas 200 for Berlin" + ); + + // Test gas consumption with very small inputs + let input = hex::decode( + "0000000000000000000000000000000000000000000000000000000000000001\ + 0000000000000000000000000000000000000000000000000000000000000001\ + 0000000000000000000000000000000000000000000000000000000000000001\ + 01\ + 01\ + 01", + ) + .unwrap(); + // For Byzantium, check that it computes correctly + let res = byzantium_run(&input, 100_000).unwrap(); + assert_eq!(res.bytes, vec![0x00], "1^1 mod 1 = 0"); + + // For Berlin, minimum gas is 200 + let res = berlin_run(&input, 100_000).unwrap(); + assert_eq!(res.gas_used, 200, "Berlin should use minimum gas of 200"); + } + + #[test] + fn test_modexp_padding() { + // Test that results are properly padded to modulus length + let input = hex::decode( + "0000000000000000000000000000000000000000000000000000000000000001\ + 0000000000000000000000000000000000000000000000000000000000000001\ + 0000000000000000000000000000000000000000000000000000000000000020\ + 02\ + 03\ + 0000000000000000000000000000000000000000000000000000000000000101", + ) + .unwrap(); + let res = byzantium_run(&input, 100_000).unwrap(); + assert_eq!( + res.bytes.len(), + 32, + "Result should be padded to modulus length" + ); + assert_eq!(res.bytes[31], 8, "2^3 mod 257 = 8"); + } + + #[test] + fn test_modexp_berlin_vs_byzantium_gas() { + // Test that Berlin gas costs are lower than Byzantium for the same input + let input = hex::decode( + "0000000000000000000000000000000000000000000000000000000000000020\ + 0000000000000000000000000000000000000000000000000000000000000020\ + 0000000000000000000000000000000000000000000000000000000000000020\ + ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\ + ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\ + fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd", + ) + .unwrap(); + + let byzantium_res = byzantium_run(&input, 10_000_000).unwrap(); + let berlin_res = berlin_run(&input, 10_000_000).unwrap(); + + assert!( + berlin_res.gas_used < byzantium_res.gas_used, + "Berlin gas {} should be less than Byzantium gas {}", + berlin_res.gas_used, + byzantium_res.gas_used + ); + assert_eq!( + byzantium_res.bytes, berlin_res.bytes, + "Results should be identical" + ); + } + + #[test] + fn test_modexp_osaka_size_limits() { + // Test Osaka's 1024-byte limit per parameter + let input = hex::decode( + "0000000000000000000000000000000000000000000000000000000000000400\ + 0000000000000000000000000000000000000000000000000000000000000001\ + 0000000000000000000000000000000000000000000000000000000000000001\ + 00\ + 01\ + 01", + ) + .unwrap(); + + // Should succeed with exactly 1024 bytes + let res = osaka_run(&input, 100_000_000); + assert!(res.is_ok(), "1024-byte base should be allowed"); + + // Test with 1025 bytes - should fail + let input_fail = hex::decode( + "0000000000000000000000000000000000000000000000000000000000000401\ + 0000000000000000000000000000000000000000000000000000000000000001\ + 0000000000000000000000000000000000000000000000000000000000000001\ + 00\ + 01\ + 01", + ) + .unwrap(); + + let res = osaka_run(&input_fail, 100_000_000); + assert!( + matches!(res, Err(PrecompileError::ModexpEip7823LimitSize)), + "1025-byte base should be rejected" + ); + } + + #[test] + fn test_modexp_input_truncation() { + // Test behavior when input is shorter than expected + let input = hex::decode( + "0000000000000000000000000000000000000000000000000000000000000002\ + 0000000000000000000000000000000000000000000000000000000000000002\ + 0000000000000000000000000000000000000000000000000000000000000002\ + ff", // Only 1 byte provided for 2-byte base + ) + .unwrap(); + + let res = byzantium_run(&input, 100_000).unwrap(); + // Should pad with zeros and compute ff00^ff00 mod ff00 + assert!(res.bytes.len() == 2, "Result should be 2 bytes"); + } + + #[test] + fn test_modexp_maximum_values() { + // Test with maximum U256 values + let input = hex::decode( + "0000000000000000000000000000000000000000000000000000000000000020\ + 0000000000000000000000000000000000000000000000000000000000000001\ + 0000000000000000000000000000000000000000000000000000000000000020\ + ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\ + 01\ + fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe", + ) + .unwrap(); + + let res = byzantium_run(&input, 10_000_000).unwrap(); + assert_eq!(res.bytes.len(), 32, "Result should be 32 bytes"); + // (2^256 - 1)^1 mod (2^256 - 2) = 1 + assert_eq!(res.bytes[31], 1, "Max value mod (max-1) should be 1"); + } + + #[test] + fn test_modexp_consistency_across_forks() { + // Test that all three implementations give same results + let test_cases = vec![ + // Small numbers + "0000000000000000000000000000000000000000000000000000000000000001\ + 0000000000000000000000000000000000000000000000000000000000000001\ + 0000000000000000000000000000000000000000000000000000000000000001\ + 03\ + 04\ + 05", + // Larger computation + "0000000000000000000000000000000000000000000000000000000000000008\ + 0000000000000000000000000000000000000000000000000000000000000008\ + 0000000000000000000000000000000000000000000000000000000000000008\ + 0123456789abcdef\ + fedcba9876543210\ + 1000000000000001", + ]; + + for test_input in test_cases { + let input = hex::decode(test_input).unwrap(); + + let byzantium_res = byzantium_run(&input, 10_000_000).unwrap(); + let berlin_res = berlin_run(&input, 10_000_000).unwrap(); + let osaka_res = osaka_run(&input, 10_000_000).unwrap(); + + assert_eq!( + byzantium_res.bytes, berlin_res.bytes, + "Byzantium and Berlin results should match" + ); + assert_eq!( + berlin_res.bytes, osaka_res.bytes, + "Berlin and Osaka results should match" + ); + } + } + + #[test] + fn test_modexp_out_of_gas() { + // Test that large inputs properly return out of gas error + let input = hex::decode( + "0000000000000000000000000000000000000000000000000000000000000100\ + 0000000000000000000000000000000000000000000000000000000000000100\ + 0000000000000000000000000000000000000000000000000000000000000100", + ) + .unwrap(); + + // Provide insufficient gas + let res = byzantium_run(&input, 1000); + assert!( + matches!(res, Err(PrecompileError::OutOfGas)), + "Should return OutOfGas error with insufficient gas" + ); } } diff --git a/crates/precompile/src/secp256k1.rs b/crates/precompile/src/secp256k1.rs index 4ad079e1e7..2ac987af13 100644 --- a/crates/precompile/src/secp256k1.rs +++ b/crates/precompile/src/secp256k1.rs @@ -1,91 +1,75 @@ -use crate::{utilities::right_pad, Error, Precompile, PrecompileResult, PrecompileWithAddress}; -use revm_primitives::{alloy_primitives::B512, Bytes, B256}; - -pub const ECRECOVER: PrecompileWithAddress = PrecompileWithAddress( - crate::u64_to_address(1), - Precompile::Standard(ec_recover_run), -); - -pub use self::secp256k1::ecrecover; - -#[cfg(not(feature = "secp256k1"))] -#[allow(clippy::module_inception)] -mod secp256k1 { - use k256::ecdsa::{Error, RecoveryId, Signature, VerifyingKey}; - use revm_primitives::{alloy_primitives::B512, keccak256, B256}; - - pub fn ecrecover(sig: &B512, mut recid: u8, msg: &B256) -> Result { - // parse signature - let mut sig = Signature::from_slice(sig.as_slice())?; - - // normalize signature and flip recovery id if needed. - if let Some(sig_normalized) = sig.normalize_s() { - sig = sig_normalized; - recid ^= 1; - } - let recid = RecoveryId::from_byte(recid).expect("recovery ID is valid"); - - // recover key - let recovered_key = VerifyingKey::recover_from_prehash(&msg[..], &sig, recid)?; - // hash it - let mut hash = keccak256( - &recovered_key - .to_encoded_point(/* compress = */ false) - .as_bytes()[1..], - ); - - // truncate to 20 bytes - hash[..12].fill(0); - Ok(hash) - } -} - +//! `ecrecover` precompile. +//! +//! Depending on enabled features, it will use different implementations of `ecrecover`. +//! * [`k256`](https://crates.io/crates/k256) - uses maintained pure rust lib `k256`, it is perfect use for no_std environments. +//! * [`secp256k1`](https://crates.io/crates/secp256k1) - uses `bitcoin_secp256k1` lib, it is a C implementation of secp256k1 used in bitcoin core. +//! It is faster than k256 and enabled by default and in std environment. +//! * [`libsecp256k1`](https://crates.io/crates/libsecp256k1) - is made from parity in pure rust, it is alternative for k256. +//! +//! Order of preference is `secp256k1` -> `k256` -> `libsecp256k1`. Where if no features are enabled, it will use `k256`. +//! +//! Input format: +//! [32 bytes for message][64 bytes for signature][1 byte for recovery id] +//! +//! Output format: +//! [32 bytes for recovered address] #[cfg(feature = "secp256k1")] -#[allow(clippy::module_inception)] -mod secp256k1 { - use revm_primitives::{alloy_primitives::B512, keccak256, B256}; - use secp256k1::{ - ecdsa::{RecoverableSignature, RecoveryId}, - Message, Secp256k1, - }; - - // Silence the unused crate dependency warning. - use k256 as _; - - pub fn ecrecover(sig: &B512, recid: u8, msg: &B256) -> Result { - let recid = RecoveryId::from_i32(recid as i32).expect("recovery ID is valid"); - let sig = RecoverableSignature::from_compact(sig.as_slice(), recid)?; - - let secp = Secp256k1::new(); - let msg = Message::from_digest(msg.0); - let public = secp.recover_ecdsa(&msg, &sig)?; - - let mut hash = keccak256(&public.serialize_uncompressed()[1..]); - hash[..12].fill(0); - Ok(hash) - } -} - -pub fn ec_recover_run(input: &Bytes, gas_limit: u64) -> PrecompileResult { +pub mod bitcoin_secp256k1; +pub mod k256; +#[cfg(feature = "libsecp256k1")] +pub mod parity_libsecp256k1; + +use crate::{ + utilities::right_pad, PrecompileError, PrecompileOutput, PrecompileResult, + PrecompileWithAddress, +}; +use primitives::{alloy_primitives::B512, Bytes, B256}; + +/// `ecrecover` precompile, containing address and function to run. +pub const ECRECOVER: PrecompileWithAddress = + PrecompileWithAddress(crate::u64_to_address(1), ec_recover_run); + +/// `ecrecover` precompile function. Read more about input and output format in [this module docs](self). +pub fn ec_recover_run(input: &[u8], gas_limit: u64) -> PrecompileResult { const ECRECOVER_BASE: u64 = 3_000; if ECRECOVER_BASE > gas_limit { - return Err(Error::OutOfGas); + return Err(PrecompileError::OutOfGas); } let input = right_pad::<128>(input); // `v` must be a 32-byte big-endian integer equal to 27 or 28. if !(input[32..63].iter().all(|&b| b == 0) && matches!(input[63], 27 | 28)) { - return Ok((ECRECOVER_BASE, Bytes::new())); + return Ok(PrecompileOutput::new(ECRECOVER_BASE, Bytes::new())); } let msg = <&B256>::try_from(&input[0..32]).unwrap(); let recid = input[63] - 27; let sig = <&B512>::try_from(&input[64..128]).unwrap(); - let out = secp256k1::ecrecover(sig, recid, msg) - .map(|o| o.to_vec().into()) - .unwrap_or_default(); - Ok((ECRECOVER_BASE, out)) + let res = ecrecover_bytes(sig.0, recid, msg.0); + let out = res.map(|o| o.to_vec().into()).unwrap_or_default(); + Ok(PrecompileOutput::new(ECRECOVER_BASE, out)) +} + +fn ecrecover_bytes(sig: [u8; 64], recid: u8, msg: [u8; 32]) -> Option<[u8; 32]> { + let sig = B512::from_slice(&sig); + let msg = B256::from_slice(&msg); + + match ecrecover(&sig, recid, &msg) { + Ok(address) => Some(address.0), + Err(_) => None, + } +} + +// Select the correct implementation based on the enabled features. +cfg_if::cfg_if! { + if #[cfg(feature = "secp256k1")] { + pub use bitcoin_secp256k1::ecrecover; + } else if #[cfg(feature = "libsecp256k1")] { + pub use parity_libsecp256k1::ecrecover; + } else { + pub use k256::ecrecover; + } } diff --git a/crates/precompile/src/secp256k1/bitcoin_secp256k1.rs b/crates/precompile/src/secp256k1/bitcoin_secp256k1.rs new file mode 100644 index 0000000000..a1f2bb1651 --- /dev/null +++ b/crates/precompile/src/secp256k1/bitcoin_secp256k1.rs @@ -0,0 +1,24 @@ +//! bitcoin_secp256k1 implementation of `ecrecover`. More about it in [`crate::secp256k1`]. +use primitives::{alloy_primitives::B512, keccak256, B256}; +use secp256k1::{ + ecdsa::{RecoverableSignature, RecoveryId}, + Message, SECP256K1, +}; + +// Silence the unused crate dependency warning. +use k256 as _; + +/// Recover the public key from a signature and a message. +/// +/// This function is using the `secp256k1` crate, it is enabled by `libsecp256k1` feature and it is in default. +pub fn ecrecover(sig: &B512, recid: u8, msg: &B256) -> Result { + let recid = RecoveryId::try_from(recid as i32).expect("recovery ID is valid"); + let sig = RecoverableSignature::from_compact(sig.as_slice(), recid)?; + + let msg = Message::from_digest(msg.0); + let public = SECP256K1.recover_ecdsa(msg, &sig)?; + + let mut hash = keccak256(&public.serialize_uncompressed()[1..]); + hash[..12].fill(0); + Ok(hash) +} diff --git a/crates/precompile/src/secp256k1/k256.rs b/crates/precompile/src/secp256k1/k256.rs new file mode 100644 index 0000000000..49bce98ee4 --- /dev/null +++ b/crates/precompile/src/secp256k1/k256.rs @@ -0,0 +1,31 @@ +//! k256 implementation of `ecrecover`. More about it in [`crate::secp256k1`]. +use k256::ecdsa::{Error, RecoveryId, Signature, VerifyingKey}; +use primitives::{alloy_primitives::B512, keccak256, B256}; + +/// Recover the public key from a signature and a message. +/// +/// This function is using the `k256` crate. +pub fn ecrecover(sig: &B512, mut recid: u8, msg: &B256) -> Result { + // parse signature + let mut sig = Signature::from_slice(sig.as_slice())?; + + // normalize signature and flip recovery id if needed. + if let Some(sig_normalized) = sig.normalize_s() { + sig = sig_normalized; + recid ^= 1; + } + let recid = RecoveryId::from_byte(recid).expect("recovery ID is valid"); + + // recover key + let recovered_key = VerifyingKey::recover_from_prehash(&msg[..], &sig, recid)?; + // hash it + let mut hash = keccak256( + &recovered_key + .to_encoded_point(/* compress = */ false) + .as_bytes()[1..], + ); + + // truncate to 20 bytes + hash[..12].fill(0); + Ok(hash) +} diff --git a/crates/precompile/src/secp256k1/parity_libsecp256k1.rs b/crates/precompile/src/secp256k1/parity_libsecp256k1.rs new file mode 100644 index 0000000000..8a460a009b --- /dev/null +++ b/crates/precompile/src/secp256k1/parity_libsecp256k1.rs @@ -0,0 +1,19 @@ +//! `libsecp256k1` implementation of `ecrecover`. More about it in [`crate::secp256k1`]. +use libsecp256k1::{recover, Error, Message, RecoveryId, Signature}; +use primitives::{alloy_primitives::B512, keccak256, B256}; + +/// Recover the public key from a signature and a message. +/// +/// This function is using the `libsecp256k1` crate. +pub fn ecrecover(sig: &B512, recid: u8, msg: &B256) -> Result { + let recid = RecoveryId::parse(recid)?; + let sig = Signature::parse_standard(sig)?; + let msg = Message::parse(msg.as_ref()); + + // uses static context. + let public = recover(&msg, &sig, &recid)?; + + let mut hash = keccak256(&public.serialize()[1..]); + hash[..12].fill(0); + Ok(hash) +} diff --git a/crates/precompile/src/secp256r1.rs b/crates/precompile/src/secp256r1.rs index e2c9951a21..323f803f69 100644 --- a/crates/precompile/src/secp256r1.rs +++ b/crates/precompile/src/secp256r1.rs @@ -1,26 +1,41 @@ -//! # EIP-7212 secp256r1 Precompile +//! # RIP-7212 secp256r1 Precompile //! -//! This module implements the [EIP-7212](https://eips.ethereum.org/EIPS/eip-7212) precompile for +//! This module implements the [RIP-7212](https://github.com/ethereum/RIPs/blob/master/RIPS/rip-7212.md) precompile for //! secp256r1 curve support. //! //! The main purpose of this precompile is to verify ECDSA signatures that use the secp256r1, or //! P256 elliptic curve. The [`P256VERIFY`] const represents the implementation of this precompile, //! with the address that it is currently deployed at. -use crate::{u64_to_address, Precompile, PrecompileWithAddress}; -use p256::ecdsa::{signature::hazmat::PrehashVerifier, Signature, VerifyingKey}; -use revm_primitives::{Bytes, PrecompileError, PrecompileResult, B256}; +use crate::{ + u64_to_address, PrecompileError, PrecompileOutput, PrecompileResult, PrecompileWithAddress, +}; +use p256::{ + ecdsa::{signature::hazmat::PrehashVerifier, Signature, VerifyingKey}, + EncodedPoint, +}; +use primitives::{alloy_primitives::B512, Bytes, B256}; + +/// Address of secp256r1 precompile. +pub const P256VERIFY_ADDRESS: u64 = 256; /// Base gas fee for secp256r1 p256verify operation. -const P256VERIFY_BASE: u64 = 3450; +pub const P256VERIFY_BASE_GAS_FEE: u64 = 3450; + +/// Base gas fee for secp256r1 p256verify operation post Osaka. +pub const P256VERIFY_BASE_GAS_FEE_OSAKA: u64 = 6900; /// Returns the secp256r1 precompile with its address. pub fn precompiles() -> impl Iterator { [P256VERIFY].into_iter() } -/// [EIP-7212](https://eips.ethereum.org/EIPS/eip-7212#specification) secp256r1 precompile. +/// [RIP-7212](https://github.com/ethereum/RIPs/blob/master/RIPS/rip-7212.md#specification) secp256r1 precompile. pub const P256VERIFY: PrecompileWithAddress = - PrecompileWithAddress(u64_to_address(0x100), Precompile::Standard(p256_verify)); + PrecompileWithAddress(u64_to_address(P256VERIFY_ADDRESS), p256_verify); + +/// [RIP-7212](https://github.com/ethereum/RIPs/blob/master/RIPS/rip-7212.md#specification) secp256r1 precompile. +pub const P256VERIFY_OSAKA: PrecompileWithAddress = + PrecompileWithAddress(u64_to_address(P256VERIFY_ADDRESS), p256_verify_osaka); /// secp256r1 precompile logic. It takes the input bytes sent to the precompile /// and the gas limit. The output represents the result of verifying the @@ -31,8 +46,25 @@ pub const P256VERIFY: PrecompileWithAddress = /// | signed message hash | r | s | public key x | public key y | /// | :-----------------: | :-: | :-: | :----------: | :----------: | /// | 32 | 32 | 32 | 32 | 32 | -pub fn p256_verify(input: &Bytes, gas_limit: u64) -> PrecompileResult { - if P256VERIFY_BASE > gas_limit { +pub fn p256_verify(input: &[u8], gas_limit: u64) -> PrecompileResult { + p256_verify_inner(input, gas_limit, P256VERIFY_BASE_GAS_FEE) +} + +/// secp256r1 precompile logic with Osaka gas cost. It takes the input bytes sent to the precompile +/// and the gas limit. The output represents the result of verifying the +/// secp256r1 signature of the input. +/// +/// The input is encoded as follows: +/// +/// | signed message hash | r | s | public key x | public key y | +/// | :-----------------: | :-: | :-: | :----------: | :----------: | +/// | 32 | 32 | 32 | 32 | 32 | +pub fn p256_verify_osaka(input: &[u8], gas_limit: u64) -> PrecompileResult { + p256_verify_inner(input, gas_limit, P256VERIFY_BASE_GAS_FEE_OSAKA) +} + +fn p256_verify_inner(input: &[u8], gas_limit: u64, gas_cost: u64) -> PrecompileResult { + if gas_cost > gas_limit { return Err(PrecompileError::OutOfGas); } let result = if verify_impl(input).is_some() { @@ -40,7 +72,7 @@ pub fn p256_verify(input: &Bytes, gas_limit: u64) -> PrecompileResult { } else { Bytes::new() }; - Ok((P256VERIFY_BASE, result)) + Ok(PrecompileOutput::new(gas_cost, result)) } /// Returns `Some(())` if the signature included in the input byte slice is @@ -51,33 +83,35 @@ pub fn verify_impl(input: &[u8]) -> Option<()> { } // msg signed (msg is already the hash of the original message) - let msg = &input[..32]; + let msg = <&B256>::try_from(&input[..32]).unwrap(); // r, s: signature - let sig = &input[32..96]; + let sig = <&B512>::try_from(&input[32..96]).unwrap(); // x, y: public key - let pk = &input[96..160]; + let pk = <&B512>::try_from(&input[96..160]).unwrap(); - // prepend 0x04 to the public key: uncompressed form - let mut uncompressed_pk = [0u8; 65]; - uncompressed_pk[0] = 0x04; - uncompressed_pk[1..].copy_from_slice(pk); + verify_signature(msg.0, sig.0, pk.0) +} +fn verify_signature(msg: [u8; 32], sig: [u8; 64], pk: [u8; 64]) -> Option<()> { // Can fail only if the input is not exact length. - let signature = Signature::from_slice(sig).ok()?; - // Can fail if the input is not valid, so we have to propagate the error. - let public_key = VerifyingKey::from_sec1_bytes(&uncompressed_pk).ok()?; + let signature = Signature::from_slice(&sig).ok()?; + // Decode the public key bytes (x,y coordinates) using EncodedPoint + let encoded_point = EncodedPoint::from_untagged_bytes(&pk.into()); + // Create VerifyingKey from the encoded point + let public_key = VerifyingKey::from_encoded_point(&encoded_point).ok()?; - public_key.verify_prehash(msg, &signature).ok() + public_key.verify_prehash(&msg, &signature).ok() } #[cfg(test)] mod test { use super::*; - use revm_primitives::hex::FromHex; + use crate::PrecompileError; + use primitives::hex::FromHex; use rstest::rstest; #[rstest] - // test vectors from https://github.com/daimo-eth/p256-verifier/tree/master/test-vectors + // Test vectors from https://github.com/daimo-eth/p256-verifier/tree/master/test-vectors #[case::ok_1("4cee90eb86eaa050036147a12d49004b6b9c72bd725d39d4785011fe190f0b4da73bd4903f0ce3b639bbbf6e8e80d16931ff4bcf5993d58468e8fb19086e8cac36dbcd03009df8c59286b162af3bd7fcc0450c9aa81be5d10d312af6c66b1d604aebd3099c618202fcfe16ae7770b0c49ab5eadf74b754204a3bb6060e44eff37618b065f9832de4ca6ca971a7a1adc826d0f7c00181a5fb2ddf79ae00b4e10e", true)] #[case::ok_2("3fec5769b5cf4e310a7d150508e82fb8e3eda1c2c94c61492d3bd8aea99e06c9e22466e928fdccef0de49e3503d2657d00494a00e764fd437bdafa05f5922b1fbbb77c6817ccf50748419477e843d5bac67e6a70e97dde5a57e0c983b777e1ad31a80482dadf89de6302b1988c82c29544c9c07bb910596158f6062517eb089a2f54c9a0f348752950094d3228d3b940258c75fe2a413cb70baa21dc2e352fc5", true)] #[case::ok_3("e775723953ead4a90411a02908fd1a629db584bc600664c609061f221ef6bf7c440066c8626b49daaa7bf2bcc0b74be4f7a1e3dcf0e869f1542fe821498cbf2de73ad398194129f635de4424a07ca715838aefe8fe69d1a391cfa70470795a80dd056866e6e1125aff94413921880c437c9e2570a28ced7267c8beef7e9b2d8d1547d76dfcf4bee592f5fefe10ddfb6aeb0991c5b9dbbee6ec80d11b17c0eb1a", true)] @@ -96,14 +130,14 @@ mod test { fn test_sig_verify(#[case] input: &str, #[case] expect_success: bool) { let input = Bytes::from_hex(input).unwrap(); let target_gas = 3_500u64; - let (gas_used, res) = p256_verify(&input, target_gas).unwrap(); - assert_eq!(gas_used, 3_450u64); + let outcome = p256_verify(&input, target_gas).unwrap(); + assert_eq!(outcome.gas_used, 3_450u64); let expected_result = if expect_success { B256::with_last_byte(1).into() } else { Bytes::new() }; - assert_eq!(res, expected_result); + assert_eq!(outcome.bytes, expected_result); } #[rstest] diff --git a/crates/precompile/src/utilities.rs b/crates/precompile/src/utilities.rs index 6e59010a5d..8fe789e061 100644 --- a/crates/precompile/src/utilities.rs +++ b/crates/precompile/src/utilities.rs @@ -1,4 +1,5 @@ -use revm_primitives::{b256, Bytes, B256}; +//! Utility function that precompiles use, padding and converting between types. +use primitives::{b256, Bytes, B256}; use std::borrow::Cow; /// Right-pads the given slice at `offset` with zeroes until `LEN`. @@ -73,7 +74,7 @@ pub fn left_pad_vec(data: &[u8], len: usize) -> Cow<'_, [u8]> { } } -/// Converts a boolean to a left-padded 32-byte `Bytes` value. +/// Converts a boolean to a left-padded 32-byte [`Bytes`] value. /// /// This is optimized to not allocate at runtime by using 2 static arrays. #[inline] @@ -81,13 +82,15 @@ pub const fn bool_to_bytes32(value: bool) -> Bytes { Bytes::from_static(&bool_to_b256(value).0) } -/// Converts a boolean to a left-padded `B256` value. +/// Converts a boolean to a left-padded [`B256`] value. /// /// This is optimized to not allocate at runtime by using 2 static arrays. #[inline] pub const fn bool_to_b256(value: bool) -> &'static B256 { - const TRUE: &B256 = &b256!("0000000000000000000000000000000000000000000000000000000000000001"); - const FALSE: &B256 = &b256!("0000000000000000000000000000000000000000000000000000000000000000"); + const TRUE: &B256 = + &b256!("0x0000000000000000000000000000000000000000000000000000000000000001"); + const FALSE: &B256 = + &b256!("0x0000000000000000000000000000000000000000000000000000000000000000"); if value { TRUE } else { diff --git a/crates/precompile/test-vectors/add_G1_bls.json b/crates/precompile/test-vectors/add_G1_bls.json deleted file mode 100644 index a7f44dda86..0000000000 --- a/crates/precompile/test-vectors/add_G1_bls.json +++ /dev/null @@ -1,65 +0,0 @@ -[ - { - "Input": "0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e100000000000000000000000000000000112b98340eee2777cc3c14163dea3ec97977ac3dc5c70da32e6e87578f44912e902ccef9efe28d4a78b8999dfbca942600000000000000000000000000000000186b28d92356c4dfec4b5201ad099dbdede3781f8998ddf929b4cd7756192185ca7b8f4ef7088f813270ac3d48868a21", - "Name": "bls_g1add_g1+p1", - "Expected": "000000000000000000000000000000000a40300ce2dec9888b60690e9a41d3004fda4886854573974fab73b046d3147ba5b7a5bde85279ffede1b45b3918d82d0000000000000000000000000000000006d3d887e9f53b9ec4eb6cedf5607226754b07c01ace7834f57f3e7315faefb739e59018e22c492006190fba4a870025", - "Gas": 500, - "NoBenchmark": false - }, - { - "Input": "00000000000000000000000000000000112b98340eee2777cc3c14163dea3ec97977ac3dc5c70da32e6e87578f44912e902ccef9efe28d4a78b8999dfbca942600000000000000000000000000000000186b28d92356c4dfec4b5201ad099dbdede3781f8998ddf929b4cd7756192185ca7b8f4ef7088f813270ac3d48868a210000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1", - "Name": "bls_g1add_p1+g1", - "Expected": "000000000000000000000000000000000a40300ce2dec9888b60690e9a41d3004fda4886854573974fab73b046d3147ba5b7a5bde85279ffede1b45b3918d82d0000000000000000000000000000000006d3d887e9f53b9ec4eb6cedf5607226754b07c01ace7834f57f3e7315faefb739e59018e22c492006190fba4a870025", - "Gas": 500, - "NoBenchmark": false - }, - { - "Input": "000000000000000000000000000000000123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef00000000000000000000000000000000193fb7cedb32b2c3adc06ec11a96bc0d661869316f5e4a577a9f7c179593987beb4fb2ee424dbb2f5dd891e228b46c4a0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1", - "Name": "bls_g1add_g1_wrong_order+g1", - "Expected": "000000000000000000000000000000000abe7ae4ae2b092a5cc1779b1f5605d904fa6ec59b0f084907d1f5e4d2663e117a3810e027210a72186159a21271df3e0000000000000000000000000000000001e1669f00e10205f2e2f1195d65c21022f6a9a6de21f329756309815281a4434b2864d34ebcbc1d7e7cfaaee3feeea2", - "Gas": 500, - "NoBenchmark": false - }, - { - "Input": "0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "Name": "bls_g1add_(g1+0=g1)", - "Expected": "0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1", - "Gas": 500, - "NoBenchmark": false - }, - { - "Input": "00000000000000000000000000000000112b98340eee2777cc3c14163dea3ec97977ac3dc5c70da32e6e87578f44912e902ccef9efe28d4a78b8999dfbca942600000000000000000000000000000000186b28d92356c4dfec4b5201ad099dbdede3781f8998ddf929b4cd7756192185ca7b8f4ef7088f813270ac3d48868a210000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "Name": "bls_g1add_(p1+0=p1)", - "Expected": "00000000000000000000000000000000112b98340eee2777cc3c14163dea3ec97977ac3dc5c70da32e6e87578f44912e902ccef9efe28d4a78b8999dfbca942600000000000000000000000000000000186b28d92356c4dfec4b5201ad099dbdede3781f8998ddf929b4cd7756192185ca7b8f4ef7088f813270ac3d48868a21", - "Gas": 500, - "NoBenchmark": false - }, - { - "Input": "0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e10000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb00000000000000000000000000000000114d1d6855d545a8aa7d76c8cf2e21f267816aef1db507c96655b9d5caac42364e6f38ba0ecb751bad54dcd6b939c2ca", - "Name": "bls_g1add_(g1-g1=0)", - "Expected": "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "Gas": 500, - "NoBenchmark": false - }, - { - "Input": "00000000000000000000000000000000112b98340eee2777cc3c14163dea3ec97977ac3dc5c70da32e6e87578f44912e902ccef9efe28d4a78b8999dfbca942600000000000000000000000000000000186b28d92356c4dfec4b5201ad099dbdede3781f8998ddf929b4cd7756192185ca7b8f4ef7088f813270ac3d48868a2100000000000000000000000000000000112b98340eee2777cc3c14163dea3ec97977ac3dc5c70da32e6e87578f44912e902ccef9efe28d4a78b8999dfbca9426000000000000000000000000000000000195e911162921ba5ed055b496420f197693d36569ec34c63d7c0529a097d49e543070afba4b707e878e53c2b779208a", - "Name": "bls_g1add_(p1-p1=0)", - "Expected": "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "Gas": 500, - "NoBenchmark": false - }, - { - "Input": "0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e10000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1", - "Name": "bls_g1add_(g1+g1=2*g1)", - "Expected": "000000000000000000000000000000000572cbea904d67468808c8eb50a9450c9721db309128012543902d0ac358a62ae28f75bb8f1c7c42c39a8c5529bf0f4e00000000000000000000000000000000166a9d8cabc673a322fda673779d8e3822ba3ecb8670e461f73bb9021d5fd76a4c56d9d4cd16bd1bba86881979749d28", - "Gas": 500, - "NoBenchmark": false - }, - { - "Input": "00000000000000000000000000000000112b98340eee2777cc3c14163dea3ec97977ac3dc5c70da32e6e87578f44912e902ccef9efe28d4a78b8999dfbca942600000000000000000000000000000000186b28d92356c4dfec4b5201ad099dbdede3781f8998ddf929b4cd7756192185ca7b8f4ef7088f813270ac3d48868a2100000000000000000000000000000000112b98340eee2777cc3c14163dea3ec97977ac3dc5c70da32e6e87578f44912e902ccef9efe28d4a78b8999dfbca942600000000000000000000000000000000186b28d92356c4dfec4b5201ad099dbdede3781f8998ddf929b4cd7756192185ca7b8f4ef7088f813270ac3d48868a21", - "Name": "bls_g1add_(p1+p1=2*p1)", - "Expected": "0000000000000000000000000000000015222cddbabdd764c4bee0b3720322a65ff4712c86fc4b1588d0c209210a0884fa9468e855d261c483091b2bf7de6a630000000000000000000000000000000009f9edb99bc3b75d7489735c98b16ab78b9386c5f7a1f76c7e96ac6eb5bbde30dbca31a74ec6e0f0b12229eecea33c39", - "Gas": 500, - "NoBenchmark": false - } -] diff --git a/crates/precompile/test-vectors/add_G2_bls.json b/crates/precompile/test-vectors/add_G2_bls.json deleted file mode 100644 index 36a7614d3c..0000000000 --- a/crates/precompile/test-vectors/add_G2_bls.json +++ /dev/null @@ -1,65 +0,0 @@ -[ - { - "Input": "00000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be00000000000000000000000000000000103121a2ceaae586d240843a398967325f8eb5a93e8fea99b62b9f88d8556c80dd726a4b30e84a36eeabaf3592937f2700000000000000000000000000000000086b990f3da2aeac0a36143b7d7c824428215140db1bb859338764cb58458f081d92664f9053b50b3fbd2e4723121b68000000000000000000000000000000000f9e7ba9a86a8f7624aa2b42dcc8772e1af4ae115685e60abc2c9b90242167acef3d0be4050bf935eed7c3b6fc7ba77e000000000000000000000000000000000d22c3652d0dc6f0fc9316e14268477c2049ef772e852108d269d9c38dba1d4802e8dae479818184c08f9a569d878451", - "Name": "bls_g2add_g2+p2", - "Expected": "000000000000000000000000000000000b54a8a7b08bd6827ed9a797de216b8c9057b3a9ca93e2f88e7f04f19accc42da90d883632b9ca4dc38d013f71ede4db00000000000000000000000000000000077eba4eecf0bd764dce8ed5f45040dd8f3b3427cb35230509482c14651713282946306247866dfe39a8e33016fcbe520000000000000000000000000000000014e60a76a29ef85cbd69f251b9f29147b67cfe3ed2823d3f9776b3a0efd2731941d47436dc6d2b58d9e65f8438bad073000000000000000000000000000000001586c3c910d95754fef7a732df78e279c3d37431c6a2b77e67a00c7c130a8fcd4d19f159cbeb997a178108fffffcbd20", - "Gas": 800, - "NoBenchmark": false - }, - { - "Input": "00000000000000000000000000000000103121a2ceaae586d240843a398967325f8eb5a93e8fea99b62b9f88d8556c80dd726a4b30e84a36eeabaf3592937f2700000000000000000000000000000000086b990f3da2aeac0a36143b7d7c824428215140db1bb859338764cb58458f081d92664f9053b50b3fbd2e4723121b68000000000000000000000000000000000f9e7ba9a86a8f7624aa2b42dcc8772e1af4ae115685e60abc2c9b90242167acef3d0be4050bf935eed7c3b6fc7ba77e000000000000000000000000000000000d22c3652d0dc6f0fc9316e14268477c2049ef772e852108d269d9c38dba1d4802e8dae479818184c08f9a569d87845100000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be", - "Name": "bls_g2add_p2+g2", - "Expected": "000000000000000000000000000000000b54a8a7b08bd6827ed9a797de216b8c9057b3a9ca93e2f88e7f04f19accc42da90d883632b9ca4dc38d013f71ede4db00000000000000000000000000000000077eba4eecf0bd764dce8ed5f45040dd8f3b3427cb35230509482c14651713282946306247866dfe39a8e33016fcbe520000000000000000000000000000000014e60a76a29ef85cbd69f251b9f29147b67cfe3ed2823d3f9776b3a0efd2731941d47436dc6d2b58d9e65f8438bad073000000000000000000000000000000001586c3c910d95754fef7a732df78e279c3d37431c6a2b77e67a00c7c130a8fcd4d19f159cbeb997a178108fffffcbd20", - "Gas": 800, - "NoBenchmark": false - }, - { - "Input": "00000000000000000000000000000000197bfd0342bbc8bee2beced2f173e1a87be576379b343e93232d6cef98d84b1d696e5612ff283ce2cfdccb2cfb65fa0c00000000000000000000000000000000184e811f55e6f9d84d77d2f79102fd7ea7422f4759df5bf7f6331d550245e3f1bcf6a30e3b29110d85e0ca16f9f6ae7a000000000000000000000000000000000f10e1eb3c1e53d2ad9cf2d398b2dc22c5842fab0a74b174f691a7e914975da3564d835cd7d2982815b8ac57f507348f000000000000000000000000000000000767d1c453890f1b9110fda82f5815c27281aba3f026ee868e4176a0654feea41a96575e0c4d58a14dbfbcc05b5010b100000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be", - "Name": "bls_g2add_g2_wrong_order+g2", - "Expected": "0000000000000000000000000000000011f00077935238fc57086414804303b20fab5880bc29f35ebda22c13dd44e586c8a889fe2ba799082c8458d861ac10cf0000000000000000000000000000000007318be09b19be000fe5df77f6e664a8286887ad8373005d7f7a203fcc458c28004042780146d3e43fa542d921c69512000000000000000000000000000000001287eab085d6f8a29f1f1aedb5ad9e8546963f0b11865e05454d86b9720c281db567682a233631f63a2794432a5596ae0000000000000000000000000000000012ec87cea1bacb75aa97728bcd64b27c7a42dd2319a2e17fe3837a05f85d089c5ebbfb73c1d08b7007e2b59ec9c8e065", - "Gas": 800, - "NoBenchmark": false - }, - { - "Input": "00000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "Name": "bls_g2add_(g2+0=g2)", - "Expected": "00000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be", - "Gas": 800, - "NoBenchmark": false - }, - { - "Input": "00000000000000000000000000000000103121a2ceaae586d240843a398967325f8eb5a93e8fea99b62b9f88d8556c80dd726a4b30e84a36eeabaf3592937f2700000000000000000000000000000000086b990f3da2aeac0a36143b7d7c824428215140db1bb859338764cb58458f081d92664f9053b50b3fbd2e4723121b68000000000000000000000000000000000f9e7ba9a86a8f7624aa2b42dcc8772e1af4ae115685e60abc2c9b90242167acef3d0be4050bf935eed7c3b6fc7ba77e000000000000000000000000000000000d22c3652d0dc6f0fc9316e14268477c2049ef772e852108d269d9c38dba1d4802e8dae479818184c08f9a569d87845100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "Name": "bls_g2add_(p2+0=p2)", - "Expected": "00000000000000000000000000000000103121a2ceaae586d240843a398967325f8eb5a93e8fea99b62b9f88d8556c80dd726a4b30e84a36eeabaf3592937f2700000000000000000000000000000000086b990f3da2aeac0a36143b7d7c824428215140db1bb859338764cb58458f081d92664f9053b50b3fbd2e4723121b68000000000000000000000000000000000f9e7ba9a86a8f7624aa2b42dcc8772e1af4ae115685e60abc2c9b90242167acef3d0be4050bf935eed7c3b6fc7ba77e000000000000000000000000000000000d22c3652d0dc6f0fc9316e14268477c2049ef772e852108d269d9c38dba1d4802e8dae479818184c08f9a569d878451", - "Gas": 800, - "NoBenchmark": false - }, - { - "Input": "00000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be00000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000d1b3cc2c7027888be51d9ef691d77bcb679afda66c73f17f9ee3837a55024f78c71363275a75d75d86bab79f74782aa0000000000000000000000000000000013fa4d4a0ad8b1ce186ed5061789213d993923066dddaf1040bc3ff59f825c78df74f2d75467e25e0f55f8a00fa030ed", - "Name": "bls_g2add_(g2-g2=0)", - "Expected": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "Gas": 800, - "NoBenchmark": false - }, - { - "Input": "00000000000000000000000000000000103121a2ceaae586d240843a398967325f8eb5a93e8fea99b62b9f88d8556c80dd726a4b30e84a36eeabaf3592937f2700000000000000000000000000000000086b990f3da2aeac0a36143b7d7c824428215140db1bb859338764cb58458f081d92664f9053b50b3fbd2e4723121b68000000000000000000000000000000000f9e7ba9a86a8f7624aa2b42dcc8772e1af4ae115685e60abc2c9b90242167acef3d0be4050bf935eed7c3b6fc7ba77e000000000000000000000000000000000d22c3652d0dc6f0fc9316e14268477c2049ef772e852108d269d9c38dba1d4802e8dae479818184c08f9a569d87845100000000000000000000000000000000103121a2ceaae586d240843a398967325f8eb5a93e8fea99b62b9f88d8556c80dd726a4b30e84a36eeabaf3592937f2700000000000000000000000000000000086b990f3da2aeac0a36143b7d7c824428215140db1bb859338764cb58458f081d92664f9053b50b3fbd2e4723121b68000000000000000000000000000000000a6296409115572426717c73668335a949829d739cff2cb4ab043710d28f8e772f6ef41aac4806c9cb273c490384032d000000000000000000000000000000000cde4e850c721fa94e8890d500e3655b442d5c0dc4fff1b694c6f8dd68f6d8dc1bc3251a37d27e7af96f65a96278265a", - "Name": "bls_g2add_(p2-p2=0)", - "Expected": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "Gas": 800, - "NoBenchmark": false - }, - { - "Input": "00000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be00000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be", - "Name": "bls_g2add_(g2+g2=2*g2)", - "Expected": "000000000000000000000000000000001638533957d540a9d2370f17cc7ed5863bc0b995b8825e0ee1ea1e1e4d00dbae81f14b0bf3611b78c952aacab827a053000000000000000000000000000000000a4edef9c1ed7f729f520e47730a124fd70662a904ba1074728114d1031e1572c6c886f6b57ec72a6178288c47c33577000000000000000000000000000000000468fb440d82b0630aeb8dca2b5256789a66da69bf91009cbfe6bd221e47aa8ae88dece9764bf3bd999d95d71e4c9899000000000000000000000000000000000f6d4552fa65dd2638b361543f887136a43253d9c66c411697003f7a13c308f5422e1aa0a59c8967acdefd8b6e36ccf3", - "Gas": 800, - "NoBenchmark": false - }, - { - "Input": "00000000000000000000000000000000103121a2ceaae586d240843a398967325f8eb5a93e8fea99b62b9f88d8556c80dd726a4b30e84a36eeabaf3592937f2700000000000000000000000000000000086b990f3da2aeac0a36143b7d7c824428215140db1bb859338764cb58458f081d92664f9053b50b3fbd2e4723121b68000000000000000000000000000000000f9e7ba9a86a8f7624aa2b42dcc8772e1af4ae115685e60abc2c9b90242167acef3d0be4050bf935eed7c3b6fc7ba77e000000000000000000000000000000000d22c3652d0dc6f0fc9316e14268477c2049ef772e852108d269d9c38dba1d4802e8dae479818184c08f9a569d87845100000000000000000000000000000000103121a2ceaae586d240843a398967325f8eb5a93e8fea99b62b9f88d8556c80dd726a4b30e84a36eeabaf3592937f2700000000000000000000000000000000086b990f3da2aeac0a36143b7d7c824428215140db1bb859338764cb58458f081d92664f9053b50b3fbd2e4723121b68000000000000000000000000000000000f9e7ba9a86a8f7624aa2b42dcc8772e1af4ae115685e60abc2c9b90242167acef3d0be4050bf935eed7c3b6fc7ba77e000000000000000000000000000000000d22c3652d0dc6f0fc9316e14268477c2049ef772e852108d269d9c38dba1d4802e8dae479818184c08f9a569d878451", - "Name": "bls_g2add_(p2+p2=2*p2)", - "Expected": "000000000000000000000000000000000b76fcbb604082a4f2d19858a7befd6053fa181c5119a612dfec83832537f644e02454f2b70d40985ebb08042d1620d40000000000000000000000000000000019a4a02c0ae51365d964c73be7babb719db1c69e0ddbf9a8a335b5bed3b0a4b070d2d5df01d2da4a3f1e56aae2ec106d000000000000000000000000000000000d18322f821ac72d3ca92f92b000483cf5b7d9e5d06873a44071c4e7e81efd904f210208fe0b9b4824f01c65bc7e62080000000000000000000000000000000004e563d53609a2d1e216aaaee5fbc14ef460160db8d1fdc5e1bd4e8b54cd2f39abf6f925969fa405efb9e700b01c7085", - "Gas": 800, - "NoBenchmark": false - } -] diff --git a/crates/precompile/test-vectors/fail-add_G1_bls.json b/crates/precompile/test-vectors/fail-add_G1_bls.json deleted file mode 100644 index e61e269d21..0000000000 --- a/crates/precompile/test-vectors/fail-add_G1_bls.json +++ /dev/null @@ -1,32 +0,0 @@ -[ - { - "Input": "", - "ExpectedError": "invalid input length", - "Name": "bls_g1add_empty_input" - }, - { - "Input": "00000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e100000000000000000000000000000000112b98340eee2777cc3c14163dea3ec97977ac3dc5c70da32e6e87578f44912e902ccef9efe28d4a78b8999dfbca942600000000000000000000000000000000186b28d92356c4dfec4b5201ad099dbdede3781f8998ddf929b4cd7756192185ca7b8f4ef7088f813270ac3d48868a21", - "ExpectedError": "invalid input length", - "Name": "bls_g1add_short_input" - }, - { - "Input": "000000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e100000000000000000000000000000000112b98340eee2777cc3c14163dea3ec97977ac3dc5c70da32e6e87578f44912e902ccef9efe28d4a78b8999dfbca942600000000000000000000000000000000186b28d92356c4dfec4b5201ad099dbdede3781f8998ddf929b4cd7756192185ca7b8f4ef7088f813270ac3d48868a21", - "ExpectedError": "invalid input length", - "Name": "bls_g1add_large_input" - }, - { - "Input": "0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb00000000000000000000000000000000186b28d92356c4dfec4b5201ad099dbdede3781f8998ddf929b4cd7756192185ca7b8f4ef7088f813270ac3d48868a2100000000000000000000000000000000112b98340eee2777cc3c14163dea3ec97977ac3dc5c70da32e6e87578f44912e902ccef9efe28d4a78b8999dfbca942600000000000000000000000000000000186b28d92356c4dfec4b5201ad099dbdede3781f8998ddf929b4cd7756192185ca7b8f4ef7088f813270ac3d48868a21", - "ExpectedError": "invalid point: not on curve", - "Name": "bls_g1add_point_not_on_curve" - }, - { - "Input": "0000000000000000000000000000000031f2e5916b17be2e71b10b4292f558e727dfd7d48af9cbc5087f0ce00dcca27c8b01e83eaace1aefb539f00adb2271660000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e100000000000000000000000000000000112b98340eee2777cc3c14163dea3ec97977ac3dc5c70da32e6e87578f44912e902ccef9efe28d4a78b8999dfbca942600000000000000000000000000000000186b28d92356c4dfec4b5201ad099dbdede3781f8998ddf929b4cd7756192185ca7b8f4ef7088f813270ac3d48868a21", - "ExpectedError": "invalid fp.Element encoding", - "Name": "bls_g2add_invalid_field_element" - }, - { - "Input": "1000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e100000000000000000000000000000000112b98340eee2777cc3c14163dea3ec97977ac3dc5c70da32e6e87578f44912e902ccef9efe28d4a78b8999dfbca942600000000000000000000000000000000186b28d92356c4dfec4b5201ad099dbdede3781f8998ddf929b4cd7756192185ca7b8f4ef7088f813270ac3d48868a21", - "ExpectedError": "invalid field element top bytes", - "Name": "bls_g1add_violate_top_bytes" - } -] \ No newline at end of file diff --git a/crates/precompile/test-vectors/fail-add_G2_bls.json b/crates/precompile/test-vectors/fail-add_G2_bls.json deleted file mode 100644 index 9d3ab9c18a..0000000000 --- a/crates/precompile/test-vectors/fail-add_G2_bls.json +++ /dev/null @@ -1,32 +0,0 @@ -[ - { - "Input": "", - "ExpectedError": "invalid input length", - "Name": "bls_g2add_empty_input" - }, - { - "Input": "000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be00000000000000000000000000000000103121a2ceaae586d240843a398967325f8eb5a93e8fea99b62b9f88d8556c80dd726a4b30e84a36eeabaf3592937f2700000000000000000000000000000000086b990f3da2aeac0a36143b7d7c824428215140db1bb859338764cb58458f081d92664f9053b50b3fbd2e4723121b68000000000000000000000000000000000f9e7ba9a86a8f7624aa2b42dcc8772e1af4ae115685e60abc2c9b90242167acef3d0be4050bf935eed7c3b6fc7ba77e000000000000000000000000000000000d22c3652d0dc6f0fc9316e14268477c2049ef772e852108d269d9c38dba1d4802e8dae479818184c08f9a569d878451", - "ExpectedError": "invalid input length", - "Name": "bls_g2add_short_input" - }, - { - "Input": "0000000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be00000000000000000000000000000000103121a2ceaae586d240843a398967325f8eb5a93e8fea99b62b9f88d8556c80dd726a4b30e84a36eeabaf3592937f2700000000000000000000000000000000086b990f3da2aeac0a36143b7d7c824428215140db1bb859338764cb58458f081d92664f9053b50b3fbd2e4723121b68000000000000000000000000000000000f9e7ba9a86a8f7624aa2b42dcc8772e1af4ae115685e60abc2c9b90242167acef3d0be4050bf935eed7c3b6fc7ba77e000000000000000000000000000000000d22c3652d0dc6f0fc9316e14268477c2049ef772e852108d269d9c38dba1d4802e8dae479818184c08f9a569d878451", - "ExpectedError": "invalid input length", - "Name": "bls_g2add_long_input" - }, - { - "Input": "00000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb800000000000000000000000000000000086b990f3da2aeac0a36143b7d7c824428215140db1bb859338764cb58458f081d92664f9053b50b3fbd2e4723121b68000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be00000000000000000000000000000000103121a2ceaae586d240843a398967325f8eb5a93e8fea99b62b9f88d8556c80dd726a4b30e84a36eeabaf3592937f2700000000000000000000000000000000086b990f3da2aeac0a36143b7d7c824428215140db1bb859338764cb58458f081d92664f9053b50b3fbd2e4723121b68000000000000000000000000000000000f9e7ba9a86a8f7624aa2b42dcc8772e1af4ae115685e60abc2c9b90242167acef3d0be4050bf935eed7c3b6fc7ba77e000000000000000000000000000000000d22c3652d0dc6f0fc9316e14268477c2049ef772e852108d269d9c38dba1d4802e8dae479818184c08f9a569d878451", - "ExpectedError": "invalid point: not on curve", - "Name": "bls_g2add_point_not_on_curve" - }, - { - "Input": "000000000000000000000000000000001c4bb49d2a0ef12b7123acdd7110bd292b5bc659edc54dc21b81de057194c79b2a5803255959bbef8e7f56c8c12168630000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be00000000000000000000000000000000103121a2ceaae586d240843a398967325f8eb5a93e8fea99b62b9f88d8556c80dd726a4b30e84a36eeabaf3592937f2700000000000000000000000000000000086b990f3da2aeac0a36143b7d7c824428215140db1bb859338764cb58458f081d92664f9053b50b3fbd2e4723121b68000000000000000000000000000000000f9e7ba9a86a8f7624aa2b42dcc8772e1af4ae115685e60abc2c9b90242167acef3d0be4050bf935eed7c3b6fc7ba77e000000000000000000000000000000000d22c3652d0dc6f0fc9316e14268477c2049ef772e852108d269d9c38dba1d4802e8dae479818184c08f9a569d878451", - "ExpectedError": "invalid fp.Element encoding", - "Name": "bls_g2add_invalid_field_element" - }, - { - "Input": "10000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be00000000000000000000000000000000103121a2ceaae586d240843a398967325f8eb5a93e8fea99b62b9f88d8556c80dd726a4b30e84a36eeabaf3592937f2700000000000000000000000000000000086b990f3da2aeac0a36143b7d7c824428215140db1bb859338764cb58458f081d92664f9053b50b3fbd2e4723121b68000000000000000000000000000000000f9e7ba9a86a8f7624aa2b42dcc8772e1af4ae115685e60abc2c9b90242167acef3d0be4050bf935eed7c3b6fc7ba77e000000000000000000000000000000000d22c3652d0dc6f0fc9316e14268477c2049ef772e852108d269d9c38dba1d4802e8dae479818184c08f9a569d878451", - "ExpectedError": "invalid field element top bytes", - "Name": "bls_g2add_violate_top_bytes" - } -] \ No newline at end of file diff --git a/crates/precompile/test-vectors/fail-map_fp2_to_G2_bls.json b/crates/precompile/test-vectors/fail-map_fp2_to_G2_bls.json deleted file mode 100644 index 4411fdcc0f..0000000000 --- a/crates/precompile/test-vectors/fail-map_fp2_to_G2_bls.json +++ /dev/null @@ -1,27 +0,0 @@ -[ - { - "Input": "", - "ExpectedError": "invalid input length", - "Name": "bls_mapg2_empty_input" - }, - { - "Input": "0000000000000000000000000000000007355d25caf6e7f2f0cb2812ca0e513bd026ed09dda65b177500fa31714e09ea0ded3a078b526bed3307f804d4b93b040000000000000000000000000000000002829ce3c021339ccb5caf3e187f6370e1e2a311dec9b75363117063ab2015603ff52c3d3b98f19c2f65575e99e8b7", - "ExpectedError": "invalid input length", - "Name": "bls_mapg2_short_input" - }, - { - "Input": "000000000000000000000000000000000007355d25caf6e7f2f0cb2812ca0e513bd026ed09dda65b177500fa31714e09ea0ded3a078b526bed3307f804d4b93b040000000000000000000000000000000002829ce3c021339ccb5caf3e187f6370e1e2a311dec9b75363117063ab2015603ff52c3d3b98f19c2f65575e99e8b78c", - "ExpectedError": "invalid input length", - "Name": "bls_mapg2_long_input" - }, - { - "Input": "000000000000000000000000000000000007355d25caf6e7f2f0cb2812ca0e513bd026ed09dda65b177500fa31714e09ea0ded3a078b526bed3307f804d4b93b040000000000000000000000000000000002829ce3c021339ccb5caf3e187f6370e1e2a311dec9b75363117063ab2015603ff52c3d3b98f19c2f65575e99e8b7", - "ExpectedError": "invalid field element top bytes", - "Name": "bls_mapg2_top_bytes" - }, - { - "Input": "0000000000000000000000000000000021366f100476ce8d3be6cfc90d59fe13349e388ed12b6dd6dc31ccd267ff000e2c993a063ca66beced06f804d4b8e5af0000000000000000000000000000000002829ce3c021339ccb5caf3e187f6370e1e2a311dec9b75363117063ab2015603ff52c3d3b98f19c2f65575e99e8b78c", - "ExpectedError": "invalid fp.Element encoding", - "Name": "bls_mapg2_invalid_fq_element" - } -] \ No newline at end of file diff --git a/crates/precompile/test-vectors/fail-map_fp_to_G1_bls.json b/crates/precompile/test-vectors/fail-map_fp_to_G1_bls.json deleted file mode 100644 index 2f66856931..0000000000 --- a/crates/precompile/test-vectors/fail-map_fp_to_G1_bls.json +++ /dev/null @@ -1,27 +0,0 @@ -[ - { - "Input": "", - "ExpectedError": "invalid input length", - "Name": "bls_mapg1_empty_input" - }, - { - "Input": "00000000000000000000000000000000156c8a6a2c184569d69a76be144b5cdc5141d2d2ca4fe341f011e25e3969c55ad9e9b9ce2eb833c81a908e5fa4ac5f", - "ExpectedError": "invalid input length", - "Name": "bls_mapg1_short_input" - }, - { - "Input": "0000000000000000000000000000000000156c8a6a2c184569d69a76be144b5cdc5141d2d2ca4fe341f011e25e3969c55ad9e9b9ce2eb833c81a908e5fa4ac5f03", - "ExpectedError": "invalid input length", - "Name": "bls_mapg1_large_input" - }, - { - "Input": "1000000000000000000000000000000000156c8a6a2c184569d69a76be144b5cdc5141d2d2ca4fe341f011e25e3969c55ad9e9b9ce2eb833c81a908e5fa4ac5f", - "ExpectedError": "invalid field element top bytes", - "Name": "bls_mapg1_top_bytes" - }, - { - "Input": "000000000000000000000000000000002f6d9c5465982c0421b61e74579709b3b5b91e57bdd4f6015742b4ff301abb7ef895b9cce00c33c7d48f8e5fa4ac09ae", - "ExpectedError": "invalid fp.Element encoding", - "Name": "bls_invalid_fq_element" - } -] \ No newline at end of file diff --git a/crates/precompile/test-vectors/fail-mul_G1_bls.json b/crates/precompile/test-vectors/fail-mul_G1_bls.json deleted file mode 100644 index 5ae8e3b536..0000000000 --- a/crates/precompile/test-vectors/fail-mul_G1_bls.json +++ /dev/null @@ -1,37 +0,0 @@ -[ - { - "Input": "", - "ExpectedError": "invalid input length", - "Name": "bls_g1mul_empty_input" - }, - { - "Input": "00000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e10000000000000000000000000000000000000000000000000000000000000002", - "ExpectedError": "invalid input length", - "Name": "bls_g1mul_short_input" - }, - { - "Input": "000000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e10000000000000000000000000000000000000000000000000000000000000002", - "ExpectedError": "invalid input length", - "Name": "bls_g1mul_large_input" - }, - { - "Input": "0000000000000000000000000000000031f2e5916b17be2e71b10b4292f558e727dfd7d48af9cbc5087f0ce00dcca27c8b01e83eaace1aefb539f00adb2271660000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e10000000000000000000000000000000000000000000000000000000000000002", - "ExpectedError": "invalid fp.Element encoding", - "Name": "bls_g1mul_invalid_field_element" - }, - { - "Input": "0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb00000000000000000000000000000000186b28d92356c4dfec4b5201ad099dbdede3781f8998ddf929b4cd7756192185ca7b8f4ef7088f813270ac3d48868a210000000000000000000000000000000000000000000000000000000000000002", - "ExpectedError": "invalid point: not on curve", - "Name": "bls_g1mul_point_not_on_curve" - }, - { - "Input": "1000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e10000000000000000000000000000000000000000000000000000000000000002", - "ExpectedError": "invalid field element top bytes", - "Name": "bls_g1mul_violate_top_bytes" - }, - { - "Input": "000000000000000000000000000000000123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef00000000000000000000000000000000193fb7cedb32b2c3adc06ec11a96bc0d661869316f5e4a577a9f7c179593987beb4fb2ee424dbb2f5dd891e228b46c4a0000000000000000000000000000000000000000000000000000000000000002", - "ExpectedError": "g1 point is not on correct subgroup", - "Name": "bls_g1mul_g1_not_in_correct_subgroup" - } -] \ No newline at end of file diff --git a/crates/precompile/test-vectors/fail-mul_G2_bls.json b/crates/precompile/test-vectors/fail-mul_G2_bls.json deleted file mode 100644 index 5b4fa8a1f6..0000000000 --- a/crates/precompile/test-vectors/fail-mul_G2_bls.json +++ /dev/null @@ -1,37 +0,0 @@ -[ - { - "Input": "", - "ExpectedError": "invalid input length", - "Name": "bls_g2mul_empty_input" - }, - { - "Input": "000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be0000000000000000000000000000000000000000000000000000000000000002", - "ExpectedError": "invalid input length", - "Name": "bls_g2mul_short_input" - }, - { - "Input": "0000000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be0000000000000000000000000000000000000000000000000000000000000002", - "ExpectedError": "invalid input length", - "Name": "bls_g2mul_large_input" - }, - { - "Input": "000000000000000000000000000000001c4bb49d2a0ef12b7123acdd7110bd292b5bc659edc54dc21b81de057194c79b2a5803255959bbef8e7f56c8c12168630000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be0000000000000000000000000000000000000000000000000000000000000002", - "ExpectedError": "invalid fp.Element encoding", - "Name": "bls_g2mul_invalid_field_element" - }, - { - "Input": "00000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb800000000000000000000000000000000086b990f3da2aeac0a36143b7d7c824428215140db1bb859338764cb58458f081d92664f9053b50b3fbd2e4723121b68000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be0000000000000000000000000000000000000000000000000000000000000002", - "ExpectedError": "invalid point: not on curve", - "Name": "bls_g2mul_point_not_on_curve" - }, - { - "Input": "10000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be0000000000000000000000000000000000000000000000000000000000000002", - "ExpectedError": "invalid field element top bytes", - "Name": "bls_g2mul_violate_top_bytes" - }, - { - "Input": "00000000000000000000000000000000197bfd0342bbc8bee2beced2f173e1a87be576379b343e93232d6cef98d84b1d696e5612ff283ce2cfdccb2cfb65fa0c00000000000000000000000000000000184e811f55e6f9d84d77d2f79102fd7ea7422f4759df5bf7f6331d550245e3f1bcf6a30e3b29110d85e0ca16f9f6ae7a000000000000000000000000000000000f10e1eb3c1e53d2ad9cf2d398b2dc22c5842fab0a74b174f691a7e914975da3564d835cd7d2982815b8ac57f507348f000000000000000000000000000000000767d1c453890f1b9110fda82f5815c27281aba3f026ee868e4176a0654feea41a96575e0c4d58a14dbfbcc05b5010b10000000000000000000000000000000000000000000000000000000000000002", - "ExpectedError": "g2 point is not on correct subgroup", - "Name": "bls_g2mul_g2_not_in_correct_subgroup" - } -] \ No newline at end of file diff --git a/crates/precompile/test-vectors/fail-multiexp_G1_bls.json b/crates/precompile/test-vectors/fail-multiexp_G1_bls.json deleted file mode 100644 index 976f28c480..0000000000 --- a/crates/precompile/test-vectors/fail-multiexp_G1_bls.json +++ /dev/null @@ -1,37 +0,0 @@ -[ - { - "Input": "", - "ExpectedError": "invalid input length", - "Name": "bls_g1multiexp_empty_input" - }, - { - "Input": "00000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000112b98340eee2777cc3c14163dea3ec97977ac3dc5c70da32e6e87578f44912e902ccef9efe28d4a78b8999dfbca942600000000000000000000000000000000186b28d92356c4dfec4b5201ad099dbdede3781f8998ddf929b4cd7756192185ca7b8f4ef7088f813270ac3d48868a210000000000000000000000000000000000000000000000000000000000000002", - "ExpectedError": "invalid input length", - "Name": "bls_g1multiexp_short_input" - }, - { - "Input": "000000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000112b98340eee2777cc3c14163dea3ec97977ac3dc5c70da32e6e87578f44912e902ccef9efe28d4a78b8999dfbca942600000000000000000000000000000000186b28d92356c4dfec4b5201ad099dbdede3781f8998ddf929b4cd7756192185ca7b8f4ef7088f813270ac3d48868a210000000000000000000000000000000000000000000000000000000000000002", - "ExpectedError": "invalid input length", - "Name": "bls_g1multiexp_long_input" - }, - { - "Input": "0000000000000000000000000000000031f2e5916b17be2e71b10b4292f558e727dfd7d48af9cbc5087f0ce00dcca27c8b01e83eaace1aefb539f00adb2271660000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000112b98340eee2777cc3c14163dea3ec97977ac3dc5c70da32e6e87578f44912e902ccef9efe28d4a78b8999dfbca942600000000000000000000000000000000186b28d92356c4dfec4b5201ad099dbdede3781f8998ddf929b4cd7756192185ca7b8f4ef7088f813270ac3d48868a210000000000000000000000000000000000000000000000000000000000000002", - "ExpectedError": "invalid fp.Element encoding", - "Name": "bls_g1multiexp_invalid_field_element" - }, - { - "Input": "1000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000112b98340eee2777cc3c14163dea3ec97977ac3dc5c70da32e6e87578f44912e902ccef9efe28d4a78b8999dfbca942600000000000000000000000000000000186b28d92356c4dfec4b5201ad099dbdede3781f8998ddf929b4cd7756192185ca7b8f4ef7088f813270ac3d48868a210000000000000000000000000000000000000000000000000000000000000002", - "ExpectedError": "invalid field element top bytes", - "Name": "bls_g1multiexp_violate_top_bytes" - }, - { - "Input": "0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb00000000000000000000000000000000186b28d92356c4dfec4b5201ad099dbdede3781f8998ddf929b4cd7756192185ca7b8f4ef7088f813270ac3d48868a21000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000112b98340eee2777cc3c14163dea3ec97977ac3dc5c70da32e6e87578f44912e902ccef9efe28d4a78b8999dfbca942600000000000000000000000000000000186b28d92356c4dfec4b5201ad099dbdede3781f8998ddf929b4cd7756192185ca7b8f4ef7088f813270ac3d48868a210000000000000000000000000000000000000000000000000000000000000002", - "ExpectedError": "invalid point: not on curve", - "Name": "bls_g1multiexp_point_not_on_curve" - }, - { - "Input": "000000000000000000000000000000000123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef00000000000000000000000000000000193fb7cedb32b2c3adc06ec11a96bc0d661869316f5e4a577a9f7c179593987beb4fb2ee424dbb2f5dd891e228b46c4a000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000112b98340eee2777cc3c14163dea3ec97977ac3dc5c70da32e6e87578f44912e902ccef9efe28d4a78b8999dfbca942600000000000000000000000000000000186b28d92356c4dfec4b5201ad099dbdede3781f8998ddf929b4cd7756192185ca7b8f4ef7088f813270ac3d48868a210000000000000000000000000000000000000000000000000000000000000002", - "ExpectedError": "g1 point is not on correct subgroup", - "Name": "bls_g1multiexp_g1_not_in_correct_subgroup" - } -] \ No newline at end of file diff --git a/crates/precompile/test-vectors/fail-multiexp_G2_bls.json b/crates/precompile/test-vectors/fail-multiexp_G2_bls.json deleted file mode 100644 index 486138985b..0000000000 --- a/crates/precompile/test-vectors/fail-multiexp_G2_bls.json +++ /dev/null @@ -1,37 +0,0 @@ -[ - { - "Input": "", - "ExpectedError": "invalid input length", - "Name": "bls_g2multiexp_empty_input" - }, - { - "Input": "000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000103121a2ceaae586d240843a398967325f8eb5a93e8fea99b62b9f88d8556c80dd726a4b30e84a36eeabaf3592937f2700000000000000000000000000000000086b990f3da2aeac0a36143b7d7c824428215140db1bb859338764cb58458f081d92664f9053b50b3fbd2e4723121b68000000000000000000000000000000000f9e7ba9a86a8f7624aa2b42dcc8772e1af4ae115685e60abc2c9b90242167acef3d0be4050bf935eed7c3b6fc7ba77e000000000000000000000000000000000d22c3652d0dc6f0fc9316e14268477c2049ef772e852108d269d9c38dba1d4802e8dae479818184c08f9a569d8784510000000000000000000000000000000000000000000000000000000000000002", - "ExpectedError": "invalid input length", - "Name": "bls_g2multiexp_short_input" - }, - { - "Input": "0000000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000103121a2ceaae586d240843a398967325f8eb5a93e8fea99b62b9f88d8556c80dd726a4b30e84a36eeabaf3592937f2700000000000000000000000000000000086b990f3da2aeac0a36143b7d7c824428215140db1bb859338764cb58458f081d92664f9053b50b3fbd2e4723121b68000000000000000000000000000000000f9e7ba9a86a8f7624aa2b42dcc8772e1af4ae115685e60abc2c9b90242167acef3d0be4050bf935eed7c3b6fc7ba77e000000000000000000000000000000000d22c3652d0dc6f0fc9316e14268477c2049ef772e852108d269d9c38dba1d4802e8dae479818184c08f9a569d8784510000000000000000000000000000000000000000000000000000000000000002", - "ExpectedError": "invalid input length", - "Name": "bls_g2multiexp_long_input" - }, - { - "Input": "10000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000103121a2ceaae586d240843a398967325f8eb5a93e8fea99b62b9f88d8556c80dd726a4b30e84a36eeabaf3592937f2700000000000000000000000000000000086b990f3da2aeac0a36143b7d7c824428215140db1bb859338764cb58458f081d92664f9053b50b3fbd2e4723121b68000000000000000000000000000000000f9e7ba9a86a8f7624aa2b42dcc8772e1af4ae115685e60abc2c9b90242167acef3d0be4050bf935eed7c3b6fc7ba77e000000000000000000000000000000000d22c3652d0dc6f0fc9316e14268477c2049ef772e852108d269d9c38dba1d4802e8dae479818184c08f9a569d8784510000000000000000000000000000000000000000000000000000000000000002", - "ExpectedError": "invalid field element top bytes", - "Name": "bls_g2multiexp_violate_top_bytes" - }, - { - "Input": "000000000000000000000000000000001c4bb49d2a0ef12b7123acdd7110bd292b5bc659edc54dc21b81de057194c79b2a5803255959bbef8e7f56c8c12168630000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000103121a2ceaae586d240843a398967325f8eb5a93e8fea99b62b9f88d8556c80dd726a4b30e84a36eeabaf3592937f2700000000000000000000000000000000086b990f3da2aeac0a36143b7d7c824428215140db1bb859338764cb58458f081d92664f9053b50b3fbd2e4723121b68000000000000000000000000000000000f9e7ba9a86a8f7624aa2b42dcc8772e1af4ae115685e60abc2c9b90242167acef3d0be4050bf935eed7c3b6fc7ba77e000000000000000000000000000000000d22c3652d0dc6f0fc9316e14268477c2049ef772e852108d269d9c38dba1d4802e8dae479818184c08f9a569d8784510000000000000000000000000000000000000000000000000000000000000002", - "ExpectedError": "invalid fp.Element encoding", - "Name": "bls_g2multiexp_invalid_field_element" - }, - { - "Input": "00000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb800000000000000000000000000000000086b990f3da2aeac0a36143b7d7c824428215140db1bb859338764cb58458f081d92664f9053b50b3fbd2e4723121b68000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000103121a2ceaae586d240843a398967325f8eb5a93e8fea99b62b9f88d8556c80dd726a4b30e84a36eeabaf3592937f2700000000000000000000000000000000086b990f3da2aeac0a36143b7d7c824428215140db1bb859338764cb58458f081d92664f9053b50b3fbd2e4723121b68000000000000000000000000000000000f9e7ba9a86a8f7624aa2b42dcc8772e1af4ae115685e60abc2c9b90242167acef3d0be4050bf935eed7c3b6fc7ba77e000000000000000000000000000000000d22c3652d0dc6f0fc9316e14268477c2049ef772e852108d269d9c38dba1d4802e8dae479818184c08f9a569d8784510000000000000000000000000000000000000000000000000000000000000002", - "ExpectedError": "invalid point: not on curve", - "Name": "bls_g2multiexp_point_not_on_curve" - }, - { - "Input": "00000000000000000000000000000000197bfd0342bbc8bee2beced2f173e1a87be576379b343e93232d6cef98d84b1d696e5612ff283ce2cfdccb2cfb65fa0c00000000000000000000000000000000184e811f55e6f9d84d77d2f79102fd7ea7422f4759df5bf7f6331d550245e3f1bcf6a30e3b29110d85e0ca16f9f6ae7a000000000000000000000000000000000f10e1eb3c1e53d2ad9cf2d398b2dc22c5842fab0a74b174f691a7e914975da3564d835cd7d2982815b8ac57f507348f000000000000000000000000000000000767d1c453890f1b9110fda82f5815c27281aba3f026ee868e4176a0654feea41a96575e0c4d58a14dbfbcc05b5010b1000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000103121a2ceaae586d240843a398967325f8eb5a93e8fea99b62b9f88d8556c80dd726a4b30e84a36eeabaf3592937f2700000000000000000000000000000000086b990f3da2aeac0a36143b7d7c824428215140db1bb859338764cb58458f081d92664f9053b50b3fbd2e4723121b68000000000000000000000000000000000f9e7ba9a86a8f7624aa2b42dcc8772e1af4ae115685e60abc2c9b90242167acef3d0be4050bf935eed7c3b6fc7ba77e000000000000000000000000000000000d22c3652d0dc6f0fc9316e14268477c2049ef772e852108d269d9c38dba1d4802e8dae479818184c08f9a569d8784510000000000000000000000000000000000000000000000000000000000000002", - "ExpectedError": "g2 point is not on correct subgroup", - "Name": "bls_pairing_g2_not_in_correct_subgroup" - } -] \ No newline at end of file diff --git a/crates/precompile/test-vectors/fail-pairing_check_bls.json b/crates/precompile/test-vectors/fail-pairing_check_bls.json deleted file mode 100644 index e14cb8e648..0000000000 --- a/crates/precompile/test-vectors/fail-pairing_check_bls.json +++ /dev/null @@ -1,47 +0,0 @@ -[ - { - "Input": "", - "ExpectedError": "invalid input length", - "Name": "bls_pairing_empty_input" - }, - { - "Input": "00000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e100000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e100000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000d1b3cc2c7027888be51d9ef691d77bcb679afda66c73f17f9ee3837a55024f78c71363275a75d75d86bab79f74782aa0000000000000000000000000000000013fa4d4a0ad8b1ce186ed5061789213d993923066dddaf1040bc3ff59f825c78df74f2d75467e25e0f55f8a00fa030ed", - "ExpectedError": "invalid input length", - "Name": "bls_pairing_missing_data" - }, - { - "Input": "000000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e100000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e100000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000d1b3cc2c7027888be51d9ef691d77bcb679afda66c73f17f9ee3837a55024f78c71363275a75d75d86bab79f74782aa0000000000000000000000000000000013fa4d4a0ad8b1ce186ed5061789213d993923066dddaf1040bc3ff59f825c78df74f2d75467e25e0f55f8a00fa030ed", - "ExpectedError": "invalid input length", - "Name": "bls_pairing_extra_data" - }, - { - "Input": "1000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e100000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e100000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000d1b3cc2c7027888be51d9ef691d77bcb679afda66c73f17f9ee3837a55024f78c71363275a75d75d86bab79f74782aa0000000000000000000000000000000013fa4d4a0ad8b1ce186ed5061789213d993923066dddaf1040bc3ff59f825c78df74f2d75467e25e0f55f8a00fa030ed", - "ExpectedError": "invalid field element top bytes", - "Name": "bls_pairing_top_bytes" - }, - { - "Input": "0000000000000000000000000000000031f2e5916b17be2e71b10b4292f558e727dfd7d48af9cbc5087f0ce00dcca27c8b01e83eaace1aefb539f00adb2271660000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e100000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e100000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000d1b3cc2c7027888be51d9ef691d77bcb679afda66c73f17f9ee3837a55024f78c71363275a75d75d86bab79f74782aa0000000000000000000000000000000013fa4d4a0ad8b1ce186ed5061789213d993923066dddaf1040bc3ff59f825c78df74f2d75467e25e0f55f8a00fa030ed", - "ExpectedError": "invalid fp.Element encoding", - "Name": "bls_pairing_invalid_field_element" - }, - { - "Input": "0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb00000000000000000000000000000000186b28d92356c4dfec4b5201ad099dbdede3781f8998ddf929b4cd7756192185ca7b8f4ef7088f813270ac3d48868a2100000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e100000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000d1b3cc2c7027888be51d9ef691d77bcb679afda66c73f17f9ee3837a55024f78c71363275a75d75d86bab79f74782aa0000000000000000000000000000000013fa4d4a0ad8b1ce186ed5061789213d993923066dddaf1040bc3ff59f825c78df74f2d75467e25e0f55f8a00fa030ed", - "ExpectedError": "invalid point: not on curve", - "Name": "bls_pairing_g1_not_on_curve" - }, - { - "Input": "0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e100000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb800000000000000000000000000000000086b990f3da2aeac0a36143b7d7c824428215140db1bb859338764cb58458f081d92664f9053b50b3fbd2e4723121b68000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e100000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000d1b3cc2c7027888be51d9ef691d77bcb679afda66c73f17f9ee3837a55024f78c71363275a75d75d86bab79f74782aa0000000000000000000000000000000013fa4d4a0ad8b1ce186ed5061789213d993923066dddaf1040bc3ff59f825c78df74f2d75467e25e0f55f8a00fa030ed", - "ExpectedError": "invalid point: not on curve", - "Name": "bls_pairing_g2_not_on_curve" - }, - { - "Input": "000000000000000000000000000000000123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef00000000000000000000000000000000193fb7cedb32b2c3adc06ec11a96bc0d661869316f5e4a577a9f7c179593987beb4fb2ee424dbb2f5dd891e228b46c4a00000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e100000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000d1b3cc2c7027888be51d9ef691d77bcb679afda66c73f17f9ee3837a55024f78c71363275a75d75d86bab79f74782aa0000000000000000000000000000000013fa4d4a0ad8b1ce186ed5061789213d993923066dddaf1040bc3ff59f825c78df74f2d75467e25e0f55f8a00fa030ed", - "ExpectedError": "g1 point is not on correct subgroup", - "Name": "bls_pairing_g1_not_in_correct_subgroup" - }, - { - "Input": "0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e100000000000000000000000000000000197bfd0342bbc8bee2beced2f173e1a87be576379b343e93232d6cef98d84b1d696e5612ff283ce2cfdccb2cfb65fa0c00000000000000000000000000000000184e811f55e6f9d84d77d2f79102fd7ea7422f4759df5bf7f6331d550245e3f1bcf6a30e3b29110d85e0ca16f9f6ae7a000000000000000000000000000000000f10e1eb3c1e53d2ad9cf2d398b2dc22c5842fab0a74b174f691a7e914975da3564d835cd7d2982815b8ac57f507348f000000000000000000000000000000000767d1c453890f1b9110fda82f5815c27281aba3f026ee868e4176a0654feea41a96575e0c4d58a14dbfbcc05b5010b10000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e100000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000d1b3cc2c7027888be51d9ef691d77bcb679afda66c73f17f9ee3837a55024f78c71363275a75d75d86bab79f74782aa0000000000000000000000000000000013fa4d4a0ad8b1ce186ed5061789213d993923066dddaf1040bc3ff59f825c78df74f2d75467e25e0f55f8a00fa030ed", - "ExpectedError": "g2 point is not on correct subgroup", - "Name": "bls_pairing_g2_not_in_correct_subgroup" - } -] \ No newline at end of file diff --git a/crates/precompile/test-vectors/map_fp2_to_G2_bls.json b/crates/precompile/test-vectors/map_fp2_to_G2_bls.json deleted file mode 100644 index fa96b288df..0000000000 --- a/crates/precompile/test-vectors/map_fp2_to_G2_bls.json +++ /dev/null @@ -1,37 +0,0 @@ -[ - { - "Input": "0000000000000000000000000000000007355d25caf6e7f2f0cb2812ca0e513bd026ed09dda65b177500fa31714e09ea0ded3a078b526bed3307f804d4b93b040000000000000000000000000000000002829ce3c021339ccb5caf3e187f6370e1e2a311dec9b75363117063ab2015603ff52c3d3b98f19c2f65575e99e8b78c", - "Name": "bls_g2map_", - "Expected": "0000000000000000000000000000000000e7f4568a82b4b7dc1f14c6aaa055edf51502319c723c4dc2688c7fe5944c213f510328082396515734b6612c4e7bb700000000000000000000000000000000126b855e9e69b1f691f816e48ac6977664d24d99f8724868a184186469ddfd4617367e94527d4b74fc86413483afb35b000000000000000000000000000000000caead0fd7b6176c01436833c79d305c78be307da5f6af6c133c47311def6ff1e0babf57a0fb5539fce7ee12407b0a42000000000000000000000000000000001498aadcf7ae2b345243e281ae076df6de84455d766ab6fcdaad71fab60abb2e8b980a440043cd305db09d283c895e3d", - "Gas": 75000, - "NoBenchmark": false - }, - { - "Input": "00000000000000000000000000000000138879a9559e24cecee8697b8b4ad32cced053138ab913b99872772dc753a2967ed50aabc907937aefb2439ba06cc50c000000000000000000000000000000000a1ae7999ea9bab1dcc9ef8887a6cb6e8f1e22566015428d220b7eec90ffa70ad1f624018a9ad11e78d588bd3617f9f2", - "Name": "bls_g2map_616263", - "Expected": "00000000000000000000000000000000108ed59fd9fae381abfd1d6bce2fd2fa220990f0f837fa30e0f27914ed6e1454db0d1ee957b219f61da6ff8be0d6441f000000000000000000000000000000000296238ea82c6d4adb3c838ee3cb2346049c90b96d602d7bb1b469b905c9228be25c627bffee872def773d5b2a2eb57d00000000000000000000000000000000033f90f6057aadacae7963b0a0b379dd46750c1c94a6357c99b65f63b79e321ff50fe3053330911c56b6ceea08fee65600000000000000000000000000000000153606c417e59fb331b7ae6bce4fbf7c5190c33ce9402b5ebe2b70e44fca614f3f1382a3625ed5493843d0b0a652fc3f", - "Gas": 75000, - "NoBenchmark": false - }, - { - "Input": "0000000000000000000000000000000018c16fe362b7dbdfa102e42bdfd3e2f4e6191d479437a59db4eb716986bf08ee1f42634db66bde97d6c16bbfd342b3b8000000000000000000000000000000000e37812ce1b146d998d5f92bdd5ada2a31bfd63dfe18311aa91637b5f279dd045763166aa1615e46a50d8d8f475f184e", - "Name": "bls_g2map_6162636465663031", - "Expected": "00000000000000000000000000000000038af300ef34c7759a6caaa4e69363cafeed218a1f207e93b2c70d91a1263d375d6730bd6b6509dcac3ba5b567e85bf3000000000000000000000000000000000da75be60fb6aa0e9e3143e40c42796edf15685cafe0279afd2a67c3dff1c82341f17effd402e4f1af240ea90f4b659b0000000000000000000000000000000019b148cbdf163cf0894f29660d2e7bfb2b68e37d54cc83fd4e6e62c020eaa48709302ef8e746736c0e19342cc1ce3df4000000000000000000000000000000000492f4fed741b073e5a82580f7c663f9b79e036b70ab3e51162359cec4e77c78086fe879b65ca7a47d34374c8315ac5e", - "Gas": 75000, - "NoBenchmark": false - }, - { - "Input": "0000000000000000000000000000000008d4a0997b9d52fecf99427abb721f0fa779479963315fe21c6445250de7183e3f63bfdf86570da8929489e421d4ee950000000000000000000000000000000016cb4ccad91ec95aab070f22043916cd6a59c4ca94097f7f510043d48515526dc8eaaea27e586f09151ae613688d5a89", - "Name": "bls_g2map_713132385f717171", - "Expected": "000000000000000000000000000000000c5ae723be00e6c3f0efe184fdc0702b64588fe77dda152ab13099a3bacd3876767fa7bbad6d6fd90b3642e902b208f90000000000000000000000000000000012c8c05c1d5fc7bfa847f4d7d81e294e66b9a78bc9953990c358945e1f042eedafce608b67fdd3ab0cb2e6e263b9b1ad0000000000000000000000000000000004e77ddb3ede41b5ec4396b7421dd916efc68a358a0d7425bddd253547f2fb4830522358491827265dfc5bcc1928a5690000000000000000000000000000000011c624c56dbe154d759d021eec60fab3d8b852395a89de497e48504366feedd4662d023af447d66926a28076813dd646", - "Gas": 75000, - "NoBenchmark": false - }, - { - "Input": "0000000000000000000000000000000003f80ce4ff0ca2f576d797a3660e3f65b274285c054feccc3215c879e2c0589d376e83ede13f93c32f05da0f68fd6a1000000000000000000000000000000000006488a837c5413746d868d1efb7232724da10eca410b07d8b505b9363bdccf0a1fc0029bad07d65b15ccfe6dd25e20d", - "Name": "bls_g2map_613531325f616161", - "Expected": "000000000000000000000000000000000ea4e7c33d43e17cc516a72f76437c4bf81d8f4eac69ac355d3bf9b71b8138d55dc10fd458be115afa798b55dac34be1000000000000000000000000000000001565c2f625032d232f13121d3cfb476f45275c303a037faa255f9da62000c2c864ea881e2bcddd111edc4a3c0da3e88d00000000000000000000000000000000043b6f5fe4e52c839148dc66f2b3751e69a0f6ebb3d056d6465d50d4108543ecd956e10fa1640dfd9bc0030cc2558d28000000000000000000000000000000000f8991d2a1ad662e7b6f58ab787947f1fa607fce12dde171bc17903b012091b657e15333e11701edcf5b63ba2a561247", - "Gas": 75000, - "NoBenchmark": false - } -] diff --git a/crates/precompile/test-vectors/map_fp_to_G1_bls.json b/crates/precompile/test-vectors/map_fp_to_G1_bls.json deleted file mode 100644 index 80ca454d82..0000000000 --- a/crates/precompile/test-vectors/map_fp_to_G1_bls.json +++ /dev/null @@ -1,37 +0,0 @@ -[ - { - "Input": "00000000000000000000000000000000156c8a6a2c184569d69a76be144b5cdc5141d2d2ca4fe341f011e25e3969c55ad9e9b9ce2eb833c81a908e5fa4ac5f03", - "Name": "bls_g1map_", - "Expected": "00000000000000000000000000000000184bb665c37ff561a89ec2122dd343f20e0f4cbcaec84e3c3052ea81d1834e192c426074b02ed3dca4e7676ce4ce48ba0000000000000000000000000000000004407b8d35af4dacc809927071fc0405218f1401a6d15af775810e4e460064bcc9468beeba82fdc751be70476c888bf3", - "Gas": 5500, - "NoBenchmark": false - }, - { - "Input": "00000000000000000000000000000000147e1ed29f06e4c5079b9d14fc89d2820d32419b990c1c7bb7dbea2a36a045124b31ffbde7c99329c05c559af1c6cc82", - "Name": "bls_g1map_616263", - "Expected": "00000000000000000000000000000000009769f3ab59bfd551d53a5f846b9984c59b97d6842b20a2c565baa167945e3d026a3755b6345df8ec7e6acb6868ae6d000000000000000000000000000000001532c00cf61aa3d0ce3e5aa20c3b531a2abd2c770a790a2613818303c6b830ffc0ecf6c357af3317b9575c567f11cd2c", - "Gas": 5500, - "NoBenchmark": false - }, - { - "Input": "0000000000000000000000000000000004090815ad598a06897dd89bcda860f25837d54e897298ce31e6947378134d3761dc59a572154963e8c954919ecfa82d", - "Name": "bls_g1map_6162636465663031", - "Expected": "000000000000000000000000000000001974dbb8e6b5d20b84df7e625e2fbfecb2cdb5f77d5eae5fb2955e5ce7313cae8364bc2fff520a6c25619739c6bdcb6a0000000000000000000000000000000015f9897e11c6441eaa676de141c8d83c37aab8667173cbe1dfd6de74d11861b961dccebcd9d289ac633455dfcc7013a3", - "Gas": 5500, - "NoBenchmark": false - }, - { - "Input": "0000000000000000000000000000000008dccd088ca55b8bfbc96fb50bb25c592faa867a8bb78d4e94a8cc2c92306190244532e91feba2b7fed977e3c3bb5a1f", - "Name": "bls_g1map_713132385f717171", - "Expected": "000000000000000000000000000000000a7a047c4a8397b3446450642c2ac64d7239b61872c9ae7a59707a8f4f950f101e766afe58223b3bff3a19a7f754027c000000000000000000000000000000001383aebba1e4327ccff7cf9912bda0dbc77de048b71ef8c8a81111d71dc33c5e3aa6edee9cf6f5fe525d50cc50b77cc9", - "Gas": 5500, - "NoBenchmark": false - }, - { - "Input": "000000000000000000000000000000000dd824886d2123a96447f6c56e3a3fa992fbfefdba17b6673f9f630ff19e4d326529db37e1c1be43f905bf9202e0278d", - "Name": "bls_g1map_613531325f616161", - "Expected": "000000000000000000000000000000000e7a16a975904f131682edbb03d9560d3e48214c9986bd50417a77108d13dc957500edf96462a3d01e62dc6cd468ef11000000000000000000000000000000000ae89e677711d05c30a48d6d75e76ca9fb70fe06c6dd6ff988683d89ccde29ac7d46c53bb97a59b1901abf1db66052db", - "Gas": 5500, - "NoBenchmark": false - } -] \ No newline at end of file diff --git a/crates/precompile/test-vectors/mul_G1_bls.json b/crates/precompile/test-vectors/mul_G1_bls.json deleted file mode 100644 index e67f76f986..0000000000 --- a/crates/precompile/test-vectors/mul_G1_bls.json +++ /dev/null @@ -1,79 +0,0 @@ -[ - { - "Input": "0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e10000000000000000000000000000000000000000000000000000000000000002", - "Name": "bls_g1mul_(g1+g1=2*g1)", - "Expected": "000000000000000000000000000000000572cbea904d67468808c8eb50a9450c9721db309128012543902d0ac358a62ae28f75bb8f1c7c42c39a8c5529bf0f4e00000000000000000000000000000000166a9d8cabc673a322fda673779d8e3822ba3ecb8670e461f73bb9021d5fd76a4c56d9d4cd16bd1bba86881979749d28", - "Gas": 12000, - "NoBenchmark": false - }, - { - "Input": "00000000000000000000000000000000112b98340eee2777cc3c14163dea3ec97977ac3dc5c70da32e6e87578f44912e902ccef9efe28d4a78b8999dfbca942600000000000000000000000000000000186b28d92356c4dfec4b5201ad099dbdede3781f8998ddf929b4cd7756192185ca7b8f4ef7088f813270ac3d48868a210000000000000000000000000000000000000000000000000000000000000002", - "Name": "bls_g1mul_(p1+p1=2*p1)", - "Expected": "0000000000000000000000000000000015222cddbabdd764c4bee0b3720322a65ff4712c86fc4b1588d0c209210a0884fa9468e855d261c483091b2bf7de6a630000000000000000000000000000000009f9edb99bc3b75d7489735c98b16ab78b9386c5f7a1f76c7e96ac6eb5bbde30dbca31a74ec6e0f0b12229eecea33c39", - "Gas": 12000, - "NoBenchmark": false - }, - { - "Input": "0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e10000000000000000000000000000000000000000000000000000000000000001", - "Name": "bls_g1mul_(1*g1=g1)", - "Expected": "0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1", - "Gas": 12000, - "NoBenchmark": false - }, - { - "Input": "00000000000000000000000000000000112b98340eee2777cc3c14163dea3ec97977ac3dc5c70da32e6e87578f44912e902ccef9efe28d4a78b8999dfbca942600000000000000000000000000000000186b28d92356c4dfec4b5201ad099dbdede3781f8998ddf929b4cd7756192185ca7b8f4ef7088f813270ac3d48868a210000000000000000000000000000000000000000000000000000000000000001", - "Name": "bls_g1mul_(1*p1=p1)", - "Expected": "00000000000000000000000000000000112b98340eee2777cc3c14163dea3ec97977ac3dc5c70da32e6e87578f44912e902ccef9efe28d4a78b8999dfbca942600000000000000000000000000000000186b28d92356c4dfec4b5201ad099dbdede3781f8998ddf929b4cd7756192185ca7b8f4ef7088f813270ac3d48868a21", - "Gas": 12000, - "NoBenchmark": false - }, - { - "Input": "0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e10000000000000000000000000000000000000000000000000000000000000000", - "Name": "bls_g1mul_(0*g1=inf)", - "Expected": "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "Gas": 12000, - "NoBenchmark": false - }, - { - "Input": "00000000000000000000000000000000112b98340eee2777cc3c14163dea3ec97977ac3dc5c70da32e6e87578f44912e902ccef9efe28d4a78b8999dfbca942600000000000000000000000000000000186b28d92356c4dfec4b5201ad099dbdede3781f8998ddf929b4cd7756192185ca7b8f4ef7088f813270ac3d48868a210000000000000000000000000000000000000000000000000000000000000000", - "Name": "bls_g1mul_(0*p1=inf)", - "Expected": "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "Gas": 12000, - "NoBenchmark": false - }, - { - "Input": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011", - "Name": "bls_g1mul_(x*inf=inf)", - "Expected": "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "Gas": 12000, - "NoBenchmark": false - }, - { - "Input": "0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1263dbd792f5b1be47ed85f8938c0f29586af0d3ac7b977f21c278fe1462040e3", - "Name": "bls_g1mul_random*g1", - "Expected": "000000000000000000000000000000000491d1b0ecd9bb917989f0e74f0dea0422eac4a873e5e2644f368dffb9a6e20fd6e10c1b77654d067c0618f6e5a7f79a0000000000000000000000000000000017cd7061575d3e8034fcea62adaa1a3bc38dca4b50e4c5c01d04dd78037c9cee914e17944ea99e7ad84278e5d49f36c4", - "Gas": 12000, - "NoBenchmark": false - }, - { - "Input": "00000000000000000000000000000000112b98340eee2777cc3c14163dea3ec97977ac3dc5c70da32e6e87578f44912e902ccef9efe28d4a78b8999dfbca942600000000000000000000000000000000186b28d92356c4dfec4b5201ad099dbdede3781f8998ddf929b4cd7756192185ca7b8f4ef7088f813270ac3d48868a21263dbd792f5b1be47ed85f8938c0f29586af0d3ac7b977f21c278fe1462040e3", - "Name": "bls_g1mul_random*p1", - "Expected": "0000000000000000000000000000000006ee9c9331228753bcb148d0ca8623447701bb0aa6eafb0340aa7f81543923474e00f2a225de65c62dd1d8303270220c0000000000000000000000000000000018dd7be47eb4e80985d7a0d2cc96c8b004250b36a5c3ec0217705d453d3ecc6d0d3d1588722da51b40728baba1e93804", - "Gas": 12000, - "NoBenchmark": false - }, - { - "Input": "0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e19a2b64cc58f8992cb21237914262ca9ada6cb13dc7b7d3f11c278fe0462040e4", - "Name": "bls_g1mul_random*g1_unnormalized_scalar", - "Expected": "000000000000000000000000000000000491d1b0ecd9bb917989f0e74f0dea0422eac4a873e5e2644f368dffb9a6e20fd6e10c1b77654d067c0618f6e5a7f79a0000000000000000000000000000000017cd7061575d3e8034fcea62adaa1a3bc38dca4b50e4c5c01d04dd78037c9cee914e17944ea99e7ad84278e5d49f36c4", - "Gas": 12000, - "NoBenchmark": false - }, - { - "Input": "00000000000000000000000000000000112b98340eee2777cc3c14163dea3ec97977ac3dc5c70da32e6e87578f44912e902ccef9efe28d4a78b8999dfbca942600000000000000000000000000000000186b28d92356c4dfec4b5201ad099dbdede3781f8998ddf929b4cd7756192185ca7b8f4ef7088f813270ac3d48868a219a2b64cc58f8992cb21237914262ca9ada6cb13dc7b7d3f11c278fe0462040e4", - "Name": "bls_g1mul_random*p1_unnormalized_scalar", - "Expected": "0000000000000000000000000000000006ee9c9331228753bcb148d0ca8623447701bb0aa6eafb0340aa7f81543923474e00f2a225de65c62dd1d8303270220c0000000000000000000000000000000018dd7be47eb4e80985d7a0d2cc96c8b004250b36a5c3ec0217705d453d3ecc6d0d3d1588722da51b40728baba1e93804", - "Gas": 12000, - "NoBenchmark": false - } -] diff --git a/crates/precompile/test-vectors/mul_G2_bls.json b/crates/precompile/test-vectors/mul_G2_bls.json deleted file mode 100644 index 1d41f3da52..0000000000 --- a/crates/precompile/test-vectors/mul_G2_bls.json +++ /dev/null @@ -1,79 +0,0 @@ -[ - { - "Input": "00000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be0000000000000000000000000000000000000000000000000000000000000002", - "Name": "bls_g2mul_(g2+g2=2*g2)", - "Expected": "000000000000000000000000000000001638533957d540a9d2370f17cc7ed5863bc0b995b8825e0ee1ea1e1e4d00dbae81f14b0bf3611b78c952aacab827a053000000000000000000000000000000000a4edef9c1ed7f729f520e47730a124fd70662a904ba1074728114d1031e1572c6c886f6b57ec72a6178288c47c33577000000000000000000000000000000000468fb440d82b0630aeb8dca2b5256789a66da69bf91009cbfe6bd221e47aa8ae88dece9764bf3bd999d95d71e4c9899000000000000000000000000000000000f6d4552fa65dd2638b361543f887136a43253d9c66c411697003f7a13c308f5422e1aa0a59c8967acdefd8b6e36ccf3", - "Gas": 45000, - "NoBenchmark": false - }, - { - "Input": "00000000000000000000000000000000103121a2ceaae586d240843a398967325f8eb5a93e8fea99b62b9f88d8556c80dd726a4b30e84a36eeabaf3592937f2700000000000000000000000000000000086b990f3da2aeac0a36143b7d7c824428215140db1bb859338764cb58458f081d92664f9053b50b3fbd2e4723121b68000000000000000000000000000000000f9e7ba9a86a8f7624aa2b42dcc8772e1af4ae115685e60abc2c9b90242167acef3d0be4050bf935eed7c3b6fc7ba77e000000000000000000000000000000000d22c3652d0dc6f0fc9316e14268477c2049ef772e852108d269d9c38dba1d4802e8dae479818184c08f9a569d8784510000000000000000000000000000000000000000000000000000000000000002", - "Name": "bls_g2mul_(p2+p2=2*p2)", - "Expected": "000000000000000000000000000000000b76fcbb604082a4f2d19858a7befd6053fa181c5119a612dfec83832537f644e02454f2b70d40985ebb08042d1620d40000000000000000000000000000000019a4a02c0ae51365d964c73be7babb719db1c69e0ddbf9a8a335b5bed3b0a4b070d2d5df01d2da4a3f1e56aae2ec106d000000000000000000000000000000000d18322f821ac72d3ca92f92b000483cf5b7d9e5d06873a44071c4e7e81efd904f210208fe0b9b4824f01c65bc7e62080000000000000000000000000000000004e563d53609a2d1e216aaaee5fbc14ef460160db8d1fdc5e1bd4e8b54cd2f39abf6f925969fa405efb9e700b01c7085", - "Gas": 45000, - "NoBenchmark": false - }, - { - "Input": "00000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be0000000000000000000000000000000000000000000000000000000000000001", - "Name": "bls_g2mul_(1*g2=g2)", - "Expected": "00000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be", - "Gas": 45000, - "NoBenchmark": false - }, - { - "Input": "00000000000000000000000000000000103121a2ceaae586d240843a398967325f8eb5a93e8fea99b62b9f88d8556c80dd726a4b30e84a36eeabaf3592937f2700000000000000000000000000000000086b990f3da2aeac0a36143b7d7c824428215140db1bb859338764cb58458f081d92664f9053b50b3fbd2e4723121b68000000000000000000000000000000000f9e7ba9a86a8f7624aa2b42dcc8772e1af4ae115685e60abc2c9b90242167acef3d0be4050bf935eed7c3b6fc7ba77e000000000000000000000000000000000d22c3652d0dc6f0fc9316e14268477c2049ef772e852108d269d9c38dba1d4802e8dae479818184c08f9a569d8784510000000000000000000000000000000000000000000000000000000000000001", - "Name": "bls_g2mul_(1*p2=p2)", - "Expected": "00000000000000000000000000000000103121a2ceaae586d240843a398967325f8eb5a93e8fea99b62b9f88d8556c80dd726a4b30e84a36eeabaf3592937f2700000000000000000000000000000000086b990f3da2aeac0a36143b7d7c824428215140db1bb859338764cb58458f081d92664f9053b50b3fbd2e4723121b68000000000000000000000000000000000f9e7ba9a86a8f7624aa2b42dcc8772e1af4ae115685e60abc2c9b90242167acef3d0be4050bf935eed7c3b6fc7ba77e000000000000000000000000000000000d22c3652d0dc6f0fc9316e14268477c2049ef772e852108d269d9c38dba1d4802e8dae479818184c08f9a569d878451", - "Gas": 45000, - "NoBenchmark": false - }, - { - "Input": "00000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be0000000000000000000000000000000000000000000000000000000000000000", - "Name": "bls_g2mul_(0*g2=inf)", - "Expected": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "Gas": 45000, - "NoBenchmark": false - }, - { - "Input": "00000000000000000000000000000000103121a2ceaae586d240843a398967325f8eb5a93e8fea99b62b9f88d8556c80dd726a4b30e84a36eeabaf3592937f2700000000000000000000000000000000086b990f3da2aeac0a36143b7d7c824428215140db1bb859338764cb58458f081d92664f9053b50b3fbd2e4723121b68000000000000000000000000000000000f9e7ba9a86a8f7624aa2b42dcc8772e1af4ae115685e60abc2c9b90242167acef3d0be4050bf935eed7c3b6fc7ba77e000000000000000000000000000000000d22c3652d0dc6f0fc9316e14268477c2049ef772e852108d269d9c38dba1d4802e8dae479818184c08f9a569d8784510000000000000000000000000000000000000000000000000000000000000000", - "Name": "bls_g2mul_(0*p2=inf)", - "Expected": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "Gas": 45000, - "NoBenchmark": false - }, - { - "Input": "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011", - "Name": "bls_g2mul_(x*inf=inf)", - "Expected": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "Gas": 45000, - "NoBenchmark": false - }, - { - "Input": "00000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be263dbd792f5b1be47ed85f8938c0f29586af0d3ac7b977f21c278fe1462040e3", - "Name": "bls_g2mul_random*g2", - "Expected": "0000000000000000000000000000000014856c22d8cdb2967c720e963eedc999e738373b14172f06fc915769d3cc5ab7ae0a1b9c38f48b5585fb09d4bd2733bb000000000000000000000000000000000c400b70f6f8cd35648f5c126cce5417f3be4d8eefbd42ceb4286a14df7e03135313fe5845e3a575faab3e8b949d248800000000000000000000000000000000149a0aacc34beba2beb2f2a19a440166e76e373194714f108e4ab1c3fd331e80f4e73e6b9ea65fe3ec96d7136de81544000000000000000000000000000000000e4622fef26bdb9b1e8ef6591a7cc99f5b73164500c1ee224b6a761e676b8799b09a3fd4fa7e242645cc1a34708285e4", - "Gas": 45000, - "NoBenchmark": false - }, - { - "Input": "00000000000000000000000000000000103121a2ceaae586d240843a398967325f8eb5a93e8fea99b62b9f88d8556c80dd726a4b30e84a36eeabaf3592937f2700000000000000000000000000000000086b990f3da2aeac0a36143b7d7c824428215140db1bb859338764cb58458f081d92664f9053b50b3fbd2e4723121b68000000000000000000000000000000000f9e7ba9a86a8f7624aa2b42dcc8772e1af4ae115685e60abc2c9b90242167acef3d0be4050bf935eed7c3b6fc7ba77e000000000000000000000000000000000d22c3652d0dc6f0fc9316e14268477c2049ef772e852108d269d9c38dba1d4802e8dae479818184c08f9a569d878451263dbd792f5b1be47ed85f8938c0f29586af0d3ac7b977f21c278fe1462040e3", - "Name": "bls_g2mul_random*p2", - "Expected": "00000000000000000000000000000000036074dcbbd0e987531bfe0e45ddfbe09fd015665990ee0c352e8e403fe6af971d8f42141970d9ab14b4dd04874409e600000000000000000000000000000000019705637f24ba2f398f32c3a3e20d6a1cd0fd63e6f8f071cf603a8334f255744927e7bfdfdb18519e019c49ff6e914500000000000000000000000000000000008e74fcff4c4278c9accfb60809ed69bbcbe3d6213ef2304e078d15ec7d6decb4f462b24b8e7cc38cc11b6f2c9e0486000000000000000000000000000000001331d40100f38c1070afd832445881b47cf4d63894666d9907c85ac66604aab5ad329980938cc3c167ccc5b6bc1b8f30", - "Gas": 45000, - "NoBenchmark": false - }, - { - "Input": "00000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be9a2b64cc58f8992cb21237914262ca9ada6cb13dc7b7d3f11c278fe0462040e4", - "Name": "bls_g2mul_random*g2_unnormalized_scalar", - "Expected": "0000000000000000000000000000000014856c22d8cdb2967c720e963eedc999e738373b14172f06fc915769d3cc5ab7ae0a1b9c38f48b5585fb09d4bd2733bb000000000000000000000000000000000c400b70f6f8cd35648f5c126cce5417f3be4d8eefbd42ceb4286a14df7e03135313fe5845e3a575faab3e8b949d248800000000000000000000000000000000149a0aacc34beba2beb2f2a19a440166e76e373194714f108e4ab1c3fd331e80f4e73e6b9ea65fe3ec96d7136de81544000000000000000000000000000000000e4622fef26bdb9b1e8ef6591a7cc99f5b73164500c1ee224b6a761e676b8799b09a3fd4fa7e242645cc1a34708285e4", - "Gas": 45000, - "NoBenchmark": false - }, - { - "Input": "00000000000000000000000000000000103121a2ceaae586d240843a398967325f8eb5a93e8fea99b62b9f88d8556c80dd726a4b30e84a36eeabaf3592937f2700000000000000000000000000000000086b990f3da2aeac0a36143b7d7c824428215140db1bb859338764cb58458f081d92664f9053b50b3fbd2e4723121b68000000000000000000000000000000000f9e7ba9a86a8f7624aa2b42dcc8772e1af4ae115685e60abc2c9b90242167acef3d0be4050bf935eed7c3b6fc7ba77e000000000000000000000000000000000d22c3652d0dc6f0fc9316e14268477c2049ef772e852108d269d9c38dba1d4802e8dae479818184c08f9a569d8784519a2b64cc58f8992cb21237914262ca9ada6cb13dc7b7d3f11c278fe0462040e4", - "Name": "bls_g2mul_random*p2_unnormalized_scalar", - "Expected": "00000000000000000000000000000000036074dcbbd0e987531bfe0e45ddfbe09fd015665990ee0c352e8e403fe6af971d8f42141970d9ab14b4dd04874409e600000000000000000000000000000000019705637f24ba2f398f32c3a3e20d6a1cd0fd63e6f8f071cf603a8334f255744927e7bfdfdb18519e019c49ff6e914500000000000000000000000000000000008e74fcff4c4278c9accfb60809ed69bbcbe3d6213ef2304e078d15ec7d6decb4f462b24b8e7cc38cc11b6f2c9e0486000000000000000000000000000000001331d40100f38c1070afd832445881b47cf4d63894666d9907c85ac66604aab5ad329980938cc3c167ccc5b6bc1b8f30", - "Gas": 45000, - "NoBenchmark": false - } -] diff --git a/crates/precompile/test-vectors/multiexp_G1_bls.json b/crates/precompile/test-vectors/multiexp_G1_bls.json deleted file mode 100644 index 0a1373782f..0000000000 --- a/crates/precompile/test-vectors/multiexp_G1_bls.json +++ /dev/null @@ -1,79 +0,0 @@ -[ - { - "Input": "0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e10000000000000000000000000000000000000000000000000000000000000002", - "Name": "bls_g1multiexp_(g1+g1=2*g1)", - "Expected": "000000000000000000000000000000000572cbea904d67468808c8eb50a9450c9721db309128012543902d0ac358a62ae28f75bb8f1c7c42c39a8c5529bf0f4e00000000000000000000000000000000166a9d8cabc673a322fda673779d8e3822ba3ecb8670e461f73bb9021d5fd76a4c56d9d4cd16bd1bba86881979749d28", - "Gas": 14400, - "NoBenchmark": false - }, - { - "Input": "00000000000000000000000000000000112b98340eee2777cc3c14163dea3ec97977ac3dc5c70da32e6e87578f44912e902ccef9efe28d4a78b8999dfbca942600000000000000000000000000000000186b28d92356c4dfec4b5201ad099dbdede3781f8998ddf929b4cd7756192185ca7b8f4ef7088f813270ac3d48868a210000000000000000000000000000000000000000000000000000000000000002", - "Name": "bls_g1multiexp_(p1+p1=2*p1)", - "Expected": "0000000000000000000000000000000015222cddbabdd764c4bee0b3720322a65ff4712c86fc4b1588d0c209210a0884fa9468e855d261c483091b2bf7de6a630000000000000000000000000000000009f9edb99bc3b75d7489735c98b16ab78b9386c5f7a1f76c7e96ac6eb5bbde30dbca31a74ec6e0f0b12229eecea33c39", - "Gas": 14400, - "NoBenchmark": false - }, - { - "Input": "0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e10000000000000000000000000000000000000000000000000000000000000001", - "Name": "bls_g1multiexp_(1*g1=g1)", - "Expected": "0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1", - "Gas": 14400, - "NoBenchmark": false - }, - { - "Input": "00000000000000000000000000000000112b98340eee2777cc3c14163dea3ec97977ac3dc5c70da32e6e87578f44912e902ccef9efe28d4a78b8999dfbca942600000000000000000000000000000000186b28d92356c4dfec4b5201ad099dbdede3781f8998ddf929b4cd7756192185ca7b8f4ef7088f813270ac3d48868a210000000000000000000000000000000000000000000000000000000000000001", - "Name": "bls_g1multiexp_(1*p1=p1)", - "Expected": "00000000000000000000000000000000112b98340eee2777cc3c14163dea3ec97977ac3dc5c70da32e6e87578f44912e902ccef9efe28d4a78b8999dfbca942600000000000000000000000000000000186b28d92356c4dfec4b5201ad099dbdede3781f8998ddf929b4cd7756192185ca7b8f4ef7088f813270ac3d48868a21", - "Gas": 14400, - "NoBenchmark": false - }, - { - "Input": "0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e10000000000000000000000000000000000000000000000000000000000000000", - "Name": "bls_g1multiexp_(0*g1=inf)", - "Expected": "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "Gas": 14400, - "NoBenchmark": false - }, - { - "Input": "00000000000000000000000000000000112b98340eee2777cc3c14163dea3ec97977ac3dc5c70da32e6e87578f44912e902ccef9efe28d4a78b8999dfbca942600000000000000000000000000000000186b28d92356c4dfec4b5201ad099dbdede3781f8998ddf929b4cd7756192185ca7b8f4ef7088f813270ac3d48868a210000000000000000000000000000000000000000000000000000000000000000", - "Name": "bls_g1multiexp_(0*p1=inf)", - "Expected": "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "Gas": 14400, - "NoBenchmark": false - }, - { - "Input": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011", - "Name": "bls_g1multiexp_(x*inf=inf)", - "Expected": "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "Gas": 14400, - "NoBenchmark": false - }, - { - "Input": "0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e10000000000000000000000000000000000000000000000000000000000000000", - "Name": "bls_g1multiexp_(2g1+inf)", - "Expected": "000000000000000000000000000000000572cbea904d67468808c8eb50a9450c9721db309128012543902d0ac358a62ae28f75bb8f1c7c42c39a8c5529bf0f4e00000000000000000000000000000000166a9d8cabc673a322fda673779d8e3822ba3ecb8670e461f73bb9021d5fd76a4c56d9d4cd16bd1bba86881979749d28", - "Gas": 21312, - "NoBenchmark": false - }, - { - "Input": "0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e10000000000000000000000000000000000000000000000000000000000000000", - "Name": "bls_g1multiexp_(inf+inf)", - "Expected": "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "Gas": 21312, - "NoBenchmark": false - }, - { - "Input": "0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000112b98340eee2777cc3c14163dea3ec97977ac3dc5c70da32e6e87578f44912e902ccef9efe28d4a78b8999dfbca942600000000000000000000000000000000186b28d92356c4dfec4b5201ad099dbdede3781f8998ddf929b4cd7756192185ca7b8f4ef7088f813270ac3d48868a210000000000000000000000000000000000000000000000000000000000000002", - "Name": "bls_g1multiexp_(2g1+2p1)", - "Expected": "00000000000000000000000000000000148f92dced907361b4782ab542a75281d4b6f71f65c8abf94a5a9082388c64662d30fd6a01ced724feef3e284752038c0000000000000000000000000000000015c3634c3b67bc18e19150e12bfd8a1769306ed010f59be645a0823acb5b38f39e8e0d86e59b6353fdafc59ca971b769", - "Gas": 21312, - "NoBenchmark": false - }, - { - "Input": "0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1263dbd792f5b1be47ed85f8938c0f29586af0d3ac7b977f21c278fe1462040e300000000000000000000000000000000112b98340eee2777cc3c14163dea3ec97977ac3dc5c70da32e6e87578f44912e902ccef9efe28d4a78b8999dfbca942600000000000000000000000000000000186b28d92356c4dfec4b5201ad099dbdede3781f8998ddf929b4cd7756192185ca7b8f4ef7088f813270ac3d48868a2147b8192d77bf871b62e87859d653922725724a5c031afeabc60bcef5ff66513800000000000000000000000000000000184bb665c37ff561a89ec2122dd343f20e0f4cbcaec84e3c3052ea81d1834e192c426074b02ed3dca4e7676ce4ce48ba0000000000000000000000000000000004407b8d35af4dacc809927071fc0405218f1401a6d15af775810e4e460064bcc9468beeba82fdc751be70476c888bf3328388aff0d4a5b7dc9205abd374e7e98f3cd9f3418edb4eafda5fb16473d21600000000000000000000000000000000009769f3ab59bfd551d53a5f846b9984c59b97d6842b20a2c565baa167945e3d026a3755b6345df8ec7e6acb6868ae6d000000000000000000000000000000001532c00cf61aa3d0ce3e5aa20c3b531a2abd2c770a790a2613818303c6b830ffc0ecf6c357af3317b9575c567f11cd2c263dbd792f5b1be47ed85f8938c0f29586af0d3ac7b977f21c278fe1462040e2000000000000000000000000000000001974dbb8e6b5d20b84df7e625e2fbfecb2cdb5f77d5eae5fb2955e5ce7313cae8364bc2fff520a6c25619739c6bdcb6a0000000000000000000000000000000015f9897e11c6441eaa676de141c8d83c37aab8667173cbe1dfd6de74d11861b961dccebcd9d289ac633455dfcc7013a347b8192d77bf871b62e87859d653922725724a5c031afeabc60bcef5ff665131000000000000000000000000000000000a7a047c4a8397b3446450642c2ac64d7239b61872c9ae7a59707a8f4f950f101e766afe58223b3bff3a19a7f754027c000000000000000000000000000000001383aebba1e4327ccff7cf9912bda0dbc77de048b71ef8c8a81111d71dc33c5e3aa6edee9cf6f5fe525d50cc50b77cc9328388aff0d4a5b7dc9205abd374e7e98f3cd9f3418edb4eafda5fb16473d211000000000000000000000000000000000e7a16a975904f131682edbb03d9560d3e48214c9986bd50417a77108d13dc957500edf96462a3d01e62dc6cd468ef11000000000000000000000000000000000ae89e677711d05c30a48d6d75e76ca9fb70fe06c6dd6ff988683d89ccde29ac7d46c53bb97a59b1901abf1db66052db55b53c4669f19f0fc7431929bc0363d7d8fb432435fcde2635fdba334424e9f5", - "Name": "bls_g1multiexp_multiple", - "Expected": "00000000000000000000000000000000053fbdb09b6b5faa08bfe7b7069454247ad4d8bd57e90e2d2ebaa04003dcf110aa83072c07f480ab2107cca2ccff6091000000000000000000000000000000001654537b7c96fe64d13906066679c3d45808cb666452b55d1b909c230cc4b423c3f932c58754b9b762dc49fcc825522c", - "Gas": 42000, - "NoBenchmark": false - } -] \ No newline at end of file diff --git a/crates/precompile/test-vectors/multiexp_G2_bls.json b/crates/precompile/test-vectors/multiexp_G2_bls.json deleted file mode 100644 index fdf50e0fce..0000000000 --- a/crates/precompile/test-vectors/multiexp_G2_bls.json +++ /dev/null @@ -1,86 +0,0 @@ -[ - { - "Input": "00000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be0000000000000000000000000000000000000000000000000000000000000002", - "Name": "bls_g2multiexp_(g2+g2=2*g2)", - "Expected": "000000000000000000000000000000001638533957d540a9d2370f17cc7ed5863bc0b995b8825e0ee1ea1e1e4d00dbae81f14b0bf3611b78c952aacab827a053000000000000000000000000000000000a4edef9c1ed7f729f520e47730a124fd70662a904ba1074728114d1031e1572c6c886f6b57ec72a6178288c47c33577000000000000000000000000000000000468fb440d82b0630aeb8dca2b5256789a66da69bf91009cbfe6bd221e47aa8ae88dece9764bf3bd999d95d71e4c9899000000000000000000000000000000000f6d4552fa65dd2638b361543f887136a43253d9c66c411697003f7a13c308f5422e1aa0a59c8967acdefd8b6e36ccf3", - "Gas": 54000, - "NoBenchmark": false - }, - { - "Input": "00000000000000000000000000000000103121a2ceaae586d240843a398967325f8eb5a93e8fea99b62b9f88d8556c80dd726a4b30e84a36eeabaf3592937f2700000000000000000000000000000000086b990f3da2aeac0a36143b7d7c824428215140db1bb859338764cb58458f081d92664f9053b50b3fbd2e4723121b68000000000000000000000000000000000f9e7ba9a86a8f7624aa2b42dcc8772e1af4ae115685e60abc2c9b90242167acef3d0be4050bf935eed7c3b6fc7ba77e000000000000000000000000000000000d22c3652d0dc6f0fc9316e14268477c2049ef772e852108d269d9c38dba1d4802e8dae479818184c08f9a569d8784510000000000000000000000000000000000000000000000000000000000000002", - "Name": "bls_g2multiexp_(p2+p2=2*p2)", - "Expected": "000000000000000000000000000000000b76fcbb604082a4f2d19858a7befd6053fa181c5119a612dfec83832537f644e02454f2b70d40985ebb08042d1620d40000000000000000000000000000000019a4a02c0ae51365d964c73be7babb719db1c69e0ddbf9a8a335b5bed3b0a4b070d2d5df01d2da4a3f1e56aae2ec106d000000000000000000000000000000000d18322f821ac72d3ca92f92b000483cf5b7d9e5d06873a44071c4e7e81efd904f210208fe0b9b4824f01c65bc7e62080000000000000000000000000000000004e563d53609a2d1e216aaaee5fbc14ef460160db8d1fdc5e1bd4e8b54cd2f39abf6f925969fa405efb9e700b01c7085", - "Gas": 54000, - "NoBenchmark": false - }, - { - "Input": "00000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be0000000000000000000000000000000000000000000000000000000000000001", - "Name": "bls_g2multiexp_(1*g2=g2)", - "Expected": "00000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be", - "Gas": 54000, - "NoBenchmark": false - }, - { - "Input": "00000000000000000000000000000000103121a2ceaae586d240843a398967325f8eb5a93e8fea99b62b9f88d8556c80dd726a4b30e84a36eeabaf3592937f2700000000000000000000000000000000086b990f3da2aeac0a36143b7d7c824428215140db1bb859338764cb58458f081d92664f9053b50b3fbd2e4723121b68000000000000000000000000000000000f9e7ba9a86a8f7624aa2b42dcc8772e1af4ae115685e60abc2c9b90242167acef3d0be4050bf935eed7c3b6fc7ba77e000000000000000000000000000000000d22c3652d0dc6f0fc9316e14268477c2049ef772e852108d269d9c38dba1d4802e8dae479818184c08f9a569d8784510000000000000000000000000000000000000000000000000000000000000001", - "Name": "bls_g2multiexp_(1*p2=p2)", - "Expected": "00000000000000000000000000000000103121a2ceaae586d240843a398967325f8eb5a93e8fea99b62b9f88d8556c80dd726a4b30e84a36eeabaf3592937f2700000000000000000000000000000000086b990f3da2aeac0a36143b7d7c824428215140db1bb859338764cb58458f081d92664f9053b50b3fbd2e4723121b68000000000000000000000000000000000f9e7ba9a86a8f7624aa2b42dcc8772e1af4ae115685e60abc2c9b90242167acef3d0be4050bf935eed7c3b6fc7ba77e000000000000000000000000000000000d22c3652d0dc6f0fc9316e14268477c2049ef772e852108d269d9c38dba1d4802e8dae479818184c08f9a569d878451", - "Gas": 54000, - "NoBenchmark": false - }, - { - "Input": "00000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be0000000000000000000000000000000000000000000000000000000000000000", - "Name": "bls_g2multiexp_(0*g2=inf)", - "Expected": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "Gas": 54000, - "NoBenchmark": false - }, - { - "Input": "00000000000000000000000000000000103121a2ceaae586d240843a398967325f8eb5a93e8fea99b62b9f88d8556c80dd726a4b30e84a36eeabaf3592937f2700000000000000000000000000000000086b990f3da2aeac0a36143b7d7c824428215140db1bb859338764cb58458f081d92664f9053b50b3fbd2e4723121b68000000000000000000000000000000000f9e7ba9a86a8f7624aa2b42dcc8772e1af4ae115685e60abc2c9b90242167acef3d0be4050bf935eed7c3b6fc7ba77e000000000000000000000000000000000d22c3652d0dc6f0fc9316e14268477c2049ef772e852108d269d9c38dba1d4802e8dae479818184c08f9a569d8784510000000000000000000000000000000000000000000000000000000000000000", - "Name": "bls_g2multiexp_(0*p2=inf)", - "Expected": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "Gas": 54000, - "NoBenchmark": false - }, - { - "Input": "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011", - "Name": "bls_g2multiexp_(x*inf=inf)", - "Expected": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "Gas": 54000, - "NoBenchmark": false - }, - { - "Input": "00000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002", - "Name": "bls_g2multiexp_(2g2+inf)", - "Expected": "000000000000000000000000000000001638533957d540a9d2370f17cc7ed5863bc0b995b8825e0ee1ea1e1e4d00dbae81f14b0bf3611b78c952aacab827a053000000000000000000000000000000000a4edef9c1ed7f729f520e47730a124fd70662a904ba1074728114d1031e1572c6c886f6b57ec72a6178288c47c33577000000000000000000000000000000000468fb440d82b0630aeb8dca2b5256789a66da69bf91009cbfe6bd221e47aa8ae88dece9764bf3bd999d95d71e4c9899000000000000000000000000000000000f6d4552fa65dd2638b361543f887136a43253d9c66c411697003f7a13c308f5422e1aa0a59c8967acdefd8b6e36ccf3", - "Gas": 79920, - "NoBenchmark": false - }, - { - "Input": "00000000000000000000000000000000103121a2ceaae586d240843a398967325f8eb5a93e8fea99b62b9f88d8556c80dd726a4b30e84a36eeabaf3592937f2700000000000000000000000000000000086b990f3da2aeac0a36143b7d7c824428215140db1bb859338764cb58458f081d92664f9053b50b3fbd2e4723121b68000000000000000000000000000000000f9e7ba9a86a8f7624aa2b42dcc8772e1af4ae115685e60abc2c9b90242167acef3d0be4050bf935eed7c3b6fc7ba77e000000000000000000000000000000000d22c3652d0dc6f0fc9316e14268477c2049ef772e852108d269d9c38dba1d4802e8dae479818184c08f9a569d8784510000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002", - "Name": "bls_g2multiexp_(2p2+inf)", - "Expected": "000000000000000000000000000000000b76fcbb604082a4f2d19858a7befd6053fa181c5119a612dfec83832537f644e02454f2b70d40985ebb08042d1620d40000000000000000000000000000000019a4a02c0ae51365d964c73be7babb719db1c69e0ddbf9a8a335b5bed3b0a4b070d2d5df01d2da4a3f1e56aae2ec106d000000000000000000000000000000000d18322f821ac72d3ca92f92b000483cf5b7d9e5d06873a44071c4e7e81efd904f210208fe0b9b4824f01c65bc7e62080000000000000000000000000000000004e563d53609a2d1e216aaaee5fbc14ef460160db8d1fdc5e1bd4e8b54cd2f39abf6f925969fa405efb9e700b01c7085", - "Gas": 79920, - "NoBenchmark": false - }, - { - "Input": "00000000000000000000000000000000103121a2ceaae586d240843a398967325f8eb5a93e8fea99b62b9f88d8556c80dd726a4b30e84a36eeabaf3592937f2700000000000000000000000000000000086b990f3da2aeac0a36143b7d7c824428215140db1bb859338764cb58458f081d92664f9053b50b3fbd2e4723121b68000000000000000000000000000000000f9e7ba9a86a8f7624aa2b42dcc8772e1af4ae115685e60abc2c9b90242167acef3d0be4050bf935eed7c3b6fc7ba77e000000000000000000000000000000000d22c3652d0dc6f0fc9316e14268477c2049ef772e852108d269d9c38dba1d4802e8dae479818184c08f9a569d878451000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000103121a2ceaae586d240843a398967325f8eb5a93e8fea99b62b9f88d8556c80dd726a4b30e84a36eeabaf3592937f2700000000000000000000000000000000086b990f3da2aeac0a36143b7d7c824428215140db1bb859338764cb58458f081d92664f9053b50b3fbd2e4723121b68000000000000000000000000000000000f9e7ba9a86a8f7624aa2b42dcc8772e1af4ae115685e60abc2c9b90242167acef3d0be4050bf935eed7c3b6fc7ba77e000000000000000000000000000000000d22c3652d0dc6f0fc9316e14268477c2049ef772e852108d269d9c38dba1d4802e8dae479818184c08f9a569d8784510000000000000000000000000000000000000000000000000000000000000000", - "Name": "bls_g1multiexp_(inf+inf)", - "Expected": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "Gas": 79920, - "NoBenchmark": false - }, - { - "Input": "00000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000103121a2ceaae586d240843a398967325f8eb5a93e8fea99b62b9f88d8556c80dd726a4b30e84a36eeabaf3592937f2700000000000000000000000000000000086b990f3da2aeac0a36143b7d7c824428215140db1bb859338764cb58458f081d92664f9053b50b3fbd2e4723121b68000000000000000000000000000000000f9e7ba9a86a8f7624aa2b42dcc8772e1af4ae115685e60abc2c9b90242167acef3d0be4050bf935eed7c3b6fc7ba77e000000000000000000000000000000000d22c3652d0dc6f0fc9316e14268477c2049ef772e852108d269d9c38dba1d4802e8dae479818184c08f9a569d8784510000000000000000000000000000000000000000000000000000000000000002", - "Name": "bls_g2multiexp_(2g2+2p2)", - "Expected": "00000000000000000000000000000000009cc9ed6635623ba19b340cbc1b0eb05c3a58770623986bb7e041645175b0a38d663d929afb9a949f7524656043bccc000000000000000000000000000000000c0fb19d3f083fd5641d22a861a11979da258003f888c59c33005cb4a2df4df9e5a2868832063ac289dfa3e997f21f8a00000000000000000000000000000000168bf7d87cef37cf1707849e0a6708cb856846f5392d205ae7418dd94d94ef6c8aa5b424af2e99d957567654b9dae1d90000000000000000000000000000000017e0fa3c3b2665d52c26c7d4cea9f35443f4f9007840384163d3aa3c7d4d18b21b65ff4380cf3f3b48e94b5eecb221dd", - "Gas": 79920, - "NoBenchmark": false - }, - { - "Input": "00000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be263dbd792f5b1be47ed85f8938c0f29586af0d3ac7b977f21c278fe1462040e300000000000000000000000000000000103121a2ceaae586d240843a398967325f8eb5a93e8fea99b62b9f88d8556c80dd726a4b30e84a36eeabaf3592937f2700000000000000000000000000000000086b990f3da2aeac0a36143b7d7c824428215140db1bb859338764cb58458f081d92664f9053b50b3fbd2e4723121b68000000000000000000000000000000000f9e7ba9a86a8f7624aa2b42dcc8772e1af4ae115685e60abc2c9b90242167acef3d0be4050bf935eed7c3b6fc7ba77e000000000000000000000000000000000d22c3652d0dc6f0fc9316e14268477c2049ef772e852108d269d9c38dba1d4802e8dae479818184c08f9a569d87845147b8192d77bf871b62e87859d653922725724a5c031afeabc60bcef5ff66513800000000000000000000000000000000108ed59fd9fae381abfd1d6bce2fd2fa220990f0f837fa30e0f27914ed6e1454db0d1ee957b219f61da6ff8be0d6441f000000000000000000000000000000000296238ea82c6d4adb3c838ee3cb2346049c90b96d602d7bb1b469b905c9228be25c627bffee872def773d5b2a2eb57d00000000000000000000000000000000033f90f6057aadacae7963b0a0b379dd46750c1c94a6357c99b65f63b79e321ff50fe3053330911c56b6ceea08fee65600000000000000000000000000000000153606c417e59fb331b7ae6bce4fbf7c5190c33ce9402b5ebe2b70e44fca614f3f1382a3625ed5493843d0b0a652fc3f328388aff0d4a5b7dc9205abd374e7e98f3cd9f3418edb4eafda5fb16473d21600000000000000000000000000000000038af300ef34c7759a6caaa4e69363cafeed218a1f207e93b2c70d91a1263d375d6730bd6b6509dcac3ba5b567e85bf3000000000000000000000000000000000da75be60fb6aa0e9e3143e40c42796edf15685cafe0279afd2a67c3dff1c82341f17effd402e4f1af240ea90f4b659b0000000000000000000000000000000019b148cbdf163cf0894f29660d2e7bfb2b68e37d54cc83fd4e6e62c020eaa48709302ef8e746736c0e19342cc1ce3df4000000000000000000000000000000000492f4fed741b073e5a82580f7c663f9b79e036b70ab3e51162359cec4e77c78086fe879b65ca7a47d34374c8315ac5e263dbd792f5b1be47ed85f8938c0f29586af0d3ac7b977f21c278fe1462040e2000000000000000000000000000000000c5ae723be00e6c3f0efe184fdc0702b64588fe77dda152ab13099a3bacd3876767fa7bbad6d6fd90b3642e902b208f90000000000000000000000000000000012c8c05c1d5fc7bfa847f4d7d81e294e66b9a78bc9953990c358945e1f042eedafce608b67fdd3ab0cb2e6e263b9b1ad0000000000000000000000000000000004e77ddb3ede41b5ec4396b7421dd916efc68a358a0d7425bddd253547f2fb4830522358491827265dfc5bcc1928a5690000000000000000000000000000000011c624c56dbe154d759d021eec60fab3d8b852395a89de497e48504366feedd4662d023af447d66926a28076813dd64647b8192d77bf871b62e87859d653922725724a5c031afeabc60bcef5ff665131000000000000000000000000000000000ea4e7c33d43e17cc516a72f76437c4bf81d8f4eac69ac355d3bf9b71b8138d55dc10fd458be115afa798b55dac34be1000000000000000000000000000000001565c2f625032d232f13121d3cfb476f45275c303a037faa255f9da62000c2c864ea881e2bcddd111edc4a3c0da3e88d00000000000000000000000000000000043b6f5fe4e52c839148dc66f2b3751e69a0f6ebb3d056d6465d50d4108543ecd956e10fa1640dfd9bc0030cc2558d28000000000000000000000000000000000f8991d2a1ad662e7b6f58ab787947f1fa607fce12dde171bc17903b012091b657e15333e11701edcf5b63ba2a561247328388aff0d4a5b7dc9205abd374e7e98f3cd9f3418edb4eafda5fb16473d211", - "Name": "bls_g2multiexp_multiple", - "Expected": "0000000000000000000000000000000016cf5fd2c2f1b2e01cc48a6d03e8e6d7f3ad754d6c7d4000f806c18c28d8d559cf529dd159c74946a7713d1906894718000000000000000000000000000000000628d42142df8d620d1f3709ac01f382ba950eaf14c12863885af5838067deec4bb363ffda427fcbdd2b8ec6cc5784ae0000000000000000000000000000000018168dec2441ef462e9a769c782f81acdc7fa49dffebb996764ba9fa96b9200ceb5edd9e96b33c383bd042b4e6af191a000000000000000000000000000000001065aaea2c4aa1d2bee7f1e82a2138ae7016dbbade8383ad912d81eca5fb260086238f95f8cef8f2f491969d4cefa2c3", - "Gas": 147690, - "NoBenchmark": false - } -] diff --git a/crates/precompile/test-vectors/pairing_check_bls.json b/crates/precompile/test-vectors/pairing_check_bls.json deleted file mode 100644 index a74d848920..0000000000 --- a/crates/precompile/test-vectors/pairing_check_bls.json +++ /dev/null @@ -1,44 +0,0 @@ -[ - { - "Input": "0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be", - "Name": "bls_pairing_e(G1,0)=e(0,G2)", - "Expected": "0000000000000000000000000000000000000000000000000000000000000001", - "Gas": 151000, - "NoBenchmark": false - }, - { - "Input": "0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e100000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be", - "Name": "bls_pairing_non-degeneracy", - "Expected": "0000000000000000000000000000000000000000000000000000000000000000", - "Gas": 108000, - "NoBenchmark": false - }, - { - "Input": "0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e100000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be00000000000000000000000000000000112b98340eee2777cc3c14163dea3ec97977ac3dc5c70da32e6e87578f44912e902ccef9efe28d4a78b8999dfbca942600000000000000000000000000000000186b28d92356c4dfec4b5201ad099dbdede3781f8998ddf929b4cd7756192185ca7b8f4ef7088f813270ac3d48868a2100000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be000000000000000000000000000000000a40300ce2dec9888b60690e9a41d3004fda4886854573974fab73b046d3147ba5b7a5bde85279ffede1b45b3918d82d0000000000000000000000000000000006d3d887e9f53b9ec4eb6cedf5607226754b07c01ace7834f57f3e7315faefb739e59018e22c492006190fba4a87002500000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000d1b3cc2c7027888be51d9ef691d77bcb679afda66c73f17f9ee3837a55024f78c71363275a75d75d86bab79f74782aa0000000000000000000000000000000013fa4d4a0ad8b1ce186ed5061789213d993923066dddaf1040bc3ff59f825c78df74f2d75467e25e0f55f8a00fa030ed", - "Name": "bls_pairing_bilinearity", - "Expected": "0000000000000000000000000000000000000000000000000000000000000001", - "Gas": 194000, - "NoBenchmark": false - }, - { - "Input": "0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e100000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e100000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000d1b3cc2c7027888be51d9ef691d77bcb679afda66c73f17f9ee3837a55024f78c71363275a75d75d86bab79f74782aa0000000000000000000000000000000013fa4d4a0ad8b1ce186ed5061789213d993923066dddaf1040bc3ff59f825c78df74f2d75467e25e0f55f8a00fa030ed", - "Name": "bls_pairing_e(G1,-G2)=e(-G1,G2)", - "Expected": "0000000000000000000000000000000000000000000000000000000000000001", - "Gas": 151000, - "NoBenchmark": false - }, - { - "Input": "000000000000000000000000000000000491d1b0ecd9bb917989f0e74f0dea0422eac4a873e5e2644f368dffb9a6e20fd6e10c1b77654d067c0618f6e5a7f79a0000000000000000000000000000000017cd7061575d3e8034fcea62adaa1a3bc38dca4b50e4c5c01d04dd78037c9cee914e17944ea99e7ad84278e5d49f36c4000000000000000000000000000000000bc2357c6782bbb6a078d9e171fc7a81f7bd8ca73eb485e76317359908bb09bd372fd362a637512a9d48019b383e54890000000000000000000000000000000004b8f49c3bac0247a09487049492b0ed99cf90c56263141daa35f011330d3ced3f3ad78d252c51a3bb42fc7d8f182594000000000000000000000000000000000982d17b17404ac198a0ff5f2dffa56a328d95ec4732d9cca9da420ec7cf716dc63d56d0f5179a8b1ec71fe0328fe88200000000000000000000000000000000147c92cb19e43943bb20c5360a6c4347411eb8ffb3d6f19cc428a8dc0cb3fd1eb3ad02b1c21e21c78f65a7691ee63de90000000000000000000000000000000016cae74dc6523e5273dbd2d9d25c53f1e2c453e6d9ba3f605021cfb514fa0bdf721b05f2200f32591d733e739fabf438000000000000000000000000000000001405df65fb71b738510b3a2fc31c33ef3d884ccc84efb1017341a368bf40727b7ad8cdc8e3fd6b0eb94102488c5cb77000000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000d1b3cc2c7027888be51d9ef691d77bcb679afda66c73f17f9ee3837a55024f78c71363275a75d75d86bab79f74782aa0000000000000000000000000000000013fa4d4a0ad8b1ce186ed5061789213d993923066dddaf1040bc3ff59f825c78df74f2d75467e25e0f55f8a00fa030ed", - "Name": "bls_pairing_e(aG1,bG2)=e(abG1,G2)", - "Expected": "0000000000000000000000000000000000000000000000000000000000000001", - "Gas": 151000, - "NoBenchmark": false - }, - { - "Input": "000000000000000000000000000000000491d1b0ecd9bb917989f0e74f0dea0422eac4a873e5e2644f368dffb9a6e20fd6e10c1b77654d067c0618f6e5a7f79a0000000000000000000000000000000017cd7061575d3e8034fcea62adaa1a3bc38dca4b50e4c5c01d04dd78037c9cee914e17944ea99e7ad84278e5d49f36c4000000000000000000000000000000000bc2357c6782bbb6a078d9e171fc7a81f7bd8ca73eb485e76317359908bb09bd372fd362a637512a9d48019b383e54890000000000000000000000000000000004b8f49c3bac0247a09487049492b0ed99cf90c56263141daa35f011330d3ced3f3ad78d252c51a3bb42fc7d8f182594000000000000000000000000000000000982d17b17404ac198a0ff5f2dffa56a328d95ec4732d9cca9da420ec7cf716dc63d56d0f5179a8b1ec71fe0328fe88200000000000000000000000000000000147c92cb19e43943bb20c5360a6c4347411eb8ffb3d6f19cc428a8dc0cb3fd1eb3ad02b1c21e21c78f65a7691ee63de90000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb00000000000000000000000000000000114d1d6855d545a8aa7d76c8cf2e21f267816aef1db507c96655b9d5caac42364e6f38ba0ecb751bad54dcd6b939c2ca00000000000000000000000000000000166335679f3b3e2617b70c22c48e820e2c6a35149c4f96293035c1494a1ce4591f7a44bce94e9d76def50a71c9e7fa41000000000000000000000000000000000ef11c636091748476331159c8259c064da712ffec033c89299384b4c11b801893026726d992aacdc8e0a28db1a3ab82000000000000000000000000000000000fd8d4944030f480f44ce0d2d4fb67ff6264d30a0f3193cc218b062e5114cf9e4ce847489f7be94b0d4a9fc0c550fdc60000000000000000000000000000000000edba2c166be3d673ea77016163ae5cdf7b3c9bd480e733eb5c08a5f1c798793d339cb503005f5a9e586ea5aabf9695", - "Name": "bls_pairing_e(aG1,bG2)=e(G1,abG2)", - "Expected": "0000000000000000000000000000000000000000000000000000000000000001", - "Gas": 151000, - "NoBenchmark": false - } -] diff --git a/crates/primitives/CHANGELOG.md b/crates/primitives/CHANGELOG.md index ad68b29b62..9b8105eae8 100644 --- a/crates/primitives/CHANGELOG.md +++ b/crates/primitives/CHANGELOG.md @@ -1,4 +1,5 @@ # Changelog + All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), @@ -6,6 +7,319 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [20.2.1](https://github.com/bluealloy/revm/compare/revm-primitives-v20.2.0...revm-primitives-v20.2.1) - 2025-08-12 + +### Other + +- small performance and safety improvements ([#2868](https://github.com/bluealloy/revm/pull/2868)) + +## [20.2.0](https://github.com/bluealloy/revm/compare/revm-primitives-v20.1.0...revm-primitives-v20.2.0) - 2025-08-06 + +### Added + +- short address for journal cold/warm check ([#2849](https://github.com/bluealloy/revm/pull/2849)) + +### Other + +- update README.md ([#2842](https://github.com/bluealloy/revm/pull/2842)) +- improve primitives crate documentation and consistency ([#2829](https://github.com/bluealloy/revm/pull/2829)) +- reuse global crypto provide idea ([#2786](https://github.com/bluealloy/revm/pull/2786)) +- add rust-version and note about MSRV ([#2789](https://github.com/bluealloy/revm/pull/2789)) +- add OnceLock re-export with no_std support ([#2787](https://github.com/bluealloy/revm/pull/2787)) +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [20.1.0](https://github.com/bluealloy/revm/compare/revm-primitives-v20.0.0...revm-primitives-v20.1.0) - 2025-07-23 + +### Added + +- *(osaka)* update EIP-7825 constant ([#2753](https://github.com/bluealloy/revm/pull/2753)) +- expose sha3-keccak in revm and revm-primitives ([#2713](https://github.com/bluealloy/revm/pull/2713)) + +### Fixed + +- features and check in ci ([#2766](https://github.com/bluealloy/revm/pull/2766)) + +## [20.0.0](https://github.com/bluealloy/revm/compare/revm-primitives-v19.2.0...revm-primitives-v20.0.0) - 2025-06-19 + +### Added + +- remove EOF ([#2644](https://github.com/bluealloy/revm/pull/2644)) +- configurable contract size limit ([#2611](https://github.com/bluealloy/revm/pull/2611)) ([#2642](https://github.com/bluealloy/revm/pull/2642)) +- *(precompile)* rug/gmp-based modexp ([#2596](https://github.com/bluealloy/revm/pull/2596)) + +## [19.2.0](https://github.com/bluealloy/revm/compare/revm-primitives-v19.1.0...revm-primitives-v19.2.0) - 2025-06-06 + +### Added + +- *(Osaka)* EIP-7825 tx limit cap ([#2575](https://github.com/bluealloy/revm/pull/2575)) +- transact multi tx ([#2517](https://github.com/bluealloy/revm/pull/2517)) + +### Other + +- support functions for eip7918 ([#2579](https://github.com/bluealloy/revm/pull/2579)) + +## [19.1.0](https://github.com/bluealloy/revm/compare/revm-primitives-v19.0.0...revm-primitives-v19.1.0) - 2025-05-22 + +### Added + +- *(Osaka)* modexp input limit and gas change, EIP-7823 and EIP-7883 ([#2531](https://github.com/bluealloy/revm/pull/2531)) + +### Other + +- nit, activation timestamp was 84, first 7702 bundle landed in 86 ([#2528](https://github.com/bluealloy/revm/pull/2528)) +- make crates.io version badge clickable ([#2526](https://github.com/bluealloy/revm/pull/2526)) +- add Prague activation timestamp ([#2514](https://github.com/bluealloy/revm/pull/2514)) +- Storage Types Alias ([#2461](https://github.com/bluealloy/revm/pull/2461)) + +## [19.0.0](https://github.com/bluealloy/revm/compare/revm-primitives-v18.0.0...revm-primitives-v19.0.0) - 2025-05-07 + +### Added + +- *(Osaka)* disable EOF ([#2480](https://github.com/bluealloy/revm/pull/2480)) +- *(EOF)* Changes needed for devnet-1 ([#2377](https://github.com/bluealloy/revm/pull/2377)) + +### Other + +- copy edit The Book ([#2463](https://github.com/bluealloy/revm/pull/2463)) +- bump dependency version ([#2431](https://github.com/bluealloy/revm/pull/2431)) +- fixed broken link ([#2421](https://github.com/bluealloy/revm/pull/2421)) +- replaced SpecId enumn with num_enum ([#2420](https://github.com/bluealloy/revm/pull/2420)) +- bump stable tests, introduce lints ([#2403](https://github.com/bluealloy/revm/pull/2403)) + +## [18.0.0](https://github.com/bluealloy/revm/compare/revm-primitives-v17.0.0...revm-primitives-v18.0.0) - 2025-04-09 + +### Other + +- add 0x prefix to b256! and address! calls ([#2345](https://github.com/bluealloy/revm/pull/2345)) + +## [17.0.0](https://github.com/bluealloy/revm/compare/revm-primitives-v16.0.0...revm-primitives-v17.0.0) - 2025-03-28 + +### Other + +- Remove LATEST variant from SpecId enum ([#2299](https://github.com/bluealloy/revm/pull/2299)) +- make number more readable ([#2300](https://github.com/bluealloy/revm/pull/2300)) + +## [16.0.0](https://github.com/bluealloy/revm/compare/revm-primitives-v16.0.0-alpha.5...revm-primitives-v16.0.0) - 2025-03-24 + +Stable version + +## [16.0.0-alpha.5](https://github.com/bluealloy/revm/compare/revm-primitives-v16.0.0-alpha.4...revm-primitives-v16.0.0-alpha.5) - 2025-03-21 + +### Other + +- make str to SpecId conversion fallible ([#2236](https://github.com/bluealloy/revm/pull/2236)) +- remove blockhash windows const ([#2228](https://github.com/bluealloy/revm/pull/2228)) + +## [16.0.0-alpha.4](https://github.com/bluealloy/revm/compare/revm-primitives-v16.0.0-alpha.3...revm-primitives-v16.0.0-alpha.4) - 2025-03-16 + +### Added + +- *(docs)* MyEvm example and book cleanup ([#2218](https://github.com/bluealloy/revm/pull/2218)) + +## [16.0.0-alpha.3](https://github.com/bluealloy/revm/compare/revm-primitives-v16.0.0-alpha.2...revm-primitives-v16.0.0-alpha.3) - 2025-03-11 + +### Fixed + +- correct propagate features ([#2177](https://github.com/bluealloy/revm/pull/2177)) + +## [16.0.0-alpha.2](https://github.com/bluealloy/revm/compare/revm-primitives-v16.0.0-alpha.1...revm-primitives-v16.0.0-alpha.2) - 2025-03-10 + +### Added + +- remove specification crate ([#2165](https://github.com/bluealloy/revm/pull/2165)) + +### Other + +- move all dependencies to workspace ([#2092](https://github.com/bluealloy/revm/pull/2092)) + +## [16.0.0-alpha.1](https://github.com/bluealloy/revm/compare/revm-primitives-v15.1.0...revm-primitives-v16.0.0-alpha.1) - 2025-02-16 + +### Added + +- *(eip7702)* apply latest EIP-7702 changes, backport from v52 (#1969) +- simplify Transaction trait (#1959) +- restructuring Part6 transaction crate (#1814) +- restructure Part2 database crate (#1784) +- project restructuring Part1 (#1776) +- to_plain_state (#1778) +- introducing EvmWiring, a chain-specific configuration (#1672) + +### Other + +- backport op l1 fetch perf (#2076) +- Bump licence year to 2025 (#2058) +- align crates versions (#1983) +- Update HISTORY_STORAGE_ADDRESS (#1946) +- fix comments and docs into more sensible (#1920) +- *(primitives)* replace HashMap re-exports with alloy_primitives::map (#1805) + +## [15.1.0](https://github.com/bluealloy/revm/compare/revm-primitives-v14.0.0...revm-primitives-v15.1.0) - 2024-12-26 + +### Added + +- blst reprice, remove g1/g2 mul, eest test bump ([#1951](https://github.com/bluealloy/revm/pull/1951)) +- add Isthmus spec ([#1948](https://github.com/bluealloy/revm/pull/1948)) +- eip7691 fraction update ([#1900](https://github.com/bluealloy/revm/pull/1900)) +- apply latest EIP-7702 changes ([#1850](https://github.com/bluealloy/revm/pull/1850)) +- *(Prague)* EIP-7623 Increase Calldata Cost ([#1744](https://github.com/bluealloy/revm/pull/1744)) + +### Other + +- eip7702 chainid u256 change ([#1950](https://github.com/bluealloy/revm/pull/1950)) +- Uncouple blob count between CL and EL ([#1899](https://github.com/bluealloy/revm/pull/1899)) + +## [14.0.0](https://github.com/bluealloy/revm/compare/revm-primitives-v13.0.0...revm-primitives-v14.0.0) - 2024-11-06 + +### Added + +- to_plain_state ([#1778](https://github.com/bluealloy/revm/pull/1778)) ([#1841](https://github.com/bluealloy/revm/pull/1841)) + +### Other + +- bump alloy-eip7702 and remove `Parity` re-export ([#1842](https://github.com/bluealloy/revm/pull/1842)) + +## [13.0.0](https://github.com/bluealloy/revm/compare/revm-primitives-v12.0.0...revm-primitives-v13.0.0) - 2024-10-23 + +### Other + +- bump alloy-eip7702 ([#1829](https://github.com/bluealloy/revm/pull/1829)) + +## [12.0.0](https://github.com/bluealloy/revm/compare/revm-primitives-v11.0.0...revm-primitives-v12.0.0) - 2024-10-17 + +### Other + +- update Cargo.toml dependencies + +## [11.0.0](https://github.com/bluealloy/revm/compare/revm-primitives-v10.0.0...revm-primitives-v11.0.0) - 2024-10-17 + +### Added + +- EIP-7702 Add u8 validity ([#1824](https://github.com/bluealloy/revm/pull/1824)) +- Rename PRAGUE_EOF to OSAKA ([#1822](https://github.com/bluealloy/revm/pull/1822)) +- *(EIP-7702)* devnet-4 changes ([#1821](https://github.com/bluealloy/revm/pull/1821)) + +### Other + +- bump newest primitives ([#1823](https://github.com/bluealloy/revm/pull/1823)) + +## [10.0.1](https://github.com/bluealloy/revm/compare/revm-primitives-v10.0.0...revm-primitives-v10.0.1) - 2024-09-26 + +### Other + +- update Cargo.toml dependencies + +## [9.0.2](https://github.com/bluealloy/revm/compare/revm-primitives-v9.0.1...revm-primitives-v9.0.2) - 2024-09-18 + +### Other + +- *(deps)* bump alloy-primitives from 0.8.0 to 0.8.2 ([#1761](https://github.com/bluealloy/revm/pull/1761)) + +## [9.0.1](https://github.com/bluealloy/revm/compare/revm-primitives-v9.0.0...revm-primitives-v9.0.1) - 2024-08-30 + +### Other +- Bump new logo ([#1735](https://github.com/bluealloy/revm/pull/1735)) +- bump kzg-rs version ([#1734](https://github.com/bluealloy/revm/pull/1734)) + +## [9.0.1](https://github.com/bluealloy/revm/compare/revm-primitives-v9.0.0...revm-primitives-v9.0.1) - 2024-08-30 + +### Other +- Bump new logo ([#1735](https://github.com/bluealloy/revm/pull/1735)) +- bump kzg-rs version ([#1734](https://github.com/bluealloy/revm/pull/1734)) + +## [9.0.0](https://github.com/bluealloy/revm/compare/revm-primitives-v8.0.0...revm-primitives-v9.0.0) - 2024-08-29 + +### Added +- *(eip7702)* Impl newest version of EIP ([#1695](https://github.com/bluealloy/revm/pull/1695)) +- c-kzg bump, cleanup on kzgsetting ([#1719](https://github.com/bluealloy/revm/pull/1719)) + +### Other +- *(deps)* bump alloy and primitives ([#1725](https://github.com/bluealloy/revm/pull/1725)) +- cast block number to u64 and not usize ([#1727](https://github.com/bluealloy/revm/pull/1727)) +- bump `kzg-rs` version ([#1726](https://github.com/bluealloy/revm/pull/1726)) + +## [8.0.0](https://github.com/bluealloy/revm/compare/revm-primitives-v7.1.0...revm-primitives-v8.0.0) - 2024-08-08 + +### Added +- *(EOF)* add evmone test suite ([#1689](https://github.com/bluealloy/revm/pull/1689)) +- check for typos in CI ([#1686](https://github.com/bluealloy/revm/pull/1686)) +- *(EOF)* Add non-returning CALLF/JUMPF checks ([#1663](https://github.com/bluealloy/revm/pull/1663)) +- *(EOF)* EOF Validation add code type and sub container tracker ([#1648](https://github.com/bluealloy/revm/pull/1648)) + +### Fixed +- *(EOF)* Overflow on num_sections ([#1656](https://github.com/bluealloy/revm/pull/1656)) + +### Other +- Add OP-Granite hardfork, limiting bn256Pairing input size ([#1685](https://github.com/bluealloy/revm/pull/1685)) +- Renamed some city name ([#1645](https://github.com/bluealloy/revm/pull/1645)) +- use `is_zero` for `U256` and `B256` ([#1638](https://github.com/bluealloy/revm/pull/1638)) +- fix some typos & remove useless Arc::clone ([#1621](https://github.com/bluealloy/revm/pull/1621)) +- *(eof)* avoid some allocations ([#1632](https://github.com/bluealloy/revm/pull/1632)) +- *(eof)* simplify magic checks ([#1633](https://github.com/bluealloy/revm/pull/1633)) + +## [7.0.0](https://github.com/bluealloy/revm/compare/revm-primitives-v6.0.0...revm-primitives-v7.0.0) - 2024-07-16 + +### Added +- *(EOF)* Bytecode::new_raw supports EOF, new_raw_checked added ([#1607](https://github.com/bluealloy/revm/pull/1607)) +- use `kzg-rs` for kzg point evaluation ([#1558](https://github.com/bluealloy/revm/pull/1558)) + +### Fixed +- *(eip7702)* Add tests and fix some bugs ([#1605](https://github.com/bluealloy/revm/pull/1605)) +- *(EOF)* Use cfg code size limit for eofcreate ([#1606](https://github.com/bluealloy/revm/pull/1606)) +- missing kzg_settings if kzg-rs feature enabled ([#1601](https://github.com/bluealloy/revm/pull/1601)) + +### Other +- bump alloy deps ([#1623](https://github.com/bluealloy/revm/pull/1623)) +- *(deps)* bump alloy-primitives from 0.7.6 to 0.7.7 ([#1612](https://github.com/bluealloy/revm/pull/1612)) +- group optimism invalid txn errors ([#1604](https://github.com/bluealloy/revm/pull/1604)) +- *(deps)* bump bitflags from 2.5.0 to 2.6.0 ([#1583](https://github.com/bluealloy/revm/pull/1583)) +- Rename gas_price to gas_limit for precompile args ([#1593](https://github.com/bluealloy/revm/pull/1593)) + +## [6.0.0](https://github.com/bluealloy/revm/compare/revm-primitives-v5.0.0...revm-primitives-v6.0.0) - 2024-07-08 + +### Added +- *(Precompiles)* Throw fatal error if c-kzg is disabled ([#1589](https://github.com/bluealloy/revm/pull/1589)) +- *(Prague)* Add EIP-7702 ([#1565](https://github.com/bluealloy/revm/pull/1565)) +- add helper function to mape EVMError's Database error variant ([#1567](https://github.com/bluealloy/revm/pull/1567)) + +### Other +- *(README)* add rbuilder to used-by ([#1585](https://github.com/bluealloy/revm/pull/1585)) +- add utility function AccountInfo::from_bytecode ([#1577](https://github.com/bluealloy/revm/pull/1577)) +- replace AccessList with alloy version ([#1552](https://github.com/bluealloy/revm/pull/1552)) +- replace U256 with u64 in BLOCKHASH ([#1505](https://github.com/bluealloy/revm/pull/1505)) + +## [5.0.0](https://github.com/bluealloy/revm/compare/revm-primitives-v4.0.0...revm-primitives-v5.0.0) - 2024-06-20 + +### Added +- *(EOF)* Put EOF bytecode behind an Arc ([#1517](https://github.com/bluealloy/revm/pull/1517)) +- *(EOF)* EXTCODECOPY,EXTCODESIZE,EXTCODEHASH eof support ([#1504](https://github.com/bluealloy/revm/pull/1504)) +- *(precompiles)* fatal error for precompiles ([#1499](https://github.com/bluealloy/revm/pull/1499)) +- Persist reverted account and storage slot lookups in `JournaledState` ([#1437](https://github.com/bluealloy/revm/pull/1437)) +- *(EOF)* EIP-7698 eof creation transaction ([#1467](https://github.com/bluealloy/revm/pull/1467)) +- *(optimism)* Add secp256r1 precompile for Fjord ([#1436](https://github.com/bluealloy/revm/pull/1436)) +- *(EOF)* Add CALLF/JUMPF stack checks ([#1417](https://github.com/bluealloy/revm/pull/1417)) +- *(EOF)* remove TXCREATE ([#1415](https://github.com/bluealloy/revm/pull/1415)) + +### Fixed +- *(eof)* fixture 2 tests ([#1550](https://github.com/bluealloy/revm/pull/1550)) +- *(primitives)* specify the optimism cfg on spec_to_generic ([#1412](https://github.com/bluealloy/revm/pull/1412)) + +### Other +- replace TransactTo with TxKind ([#1542](https://github.com/bluealloy/revm/pull/1542)) +- remove DatabaseWithDebugError ([#1545](https://github.com/bluealloy/revm/pull/1545)) +- avoid cloning precompiles ([#1486](https://github.com/bluealloy/revm/pull/1486)) +- added simular to used-by ([#1521](https://github.com/bluealloy/revm/pull/1521)) +- derive PartialEq and Hash on EnvKzgSettings ([#1494](https://github.com/bluealloy/revm/pull/1494)) +- remove old deprecated items ([#1489](https://github.com/bluealloy/revm/pull/1489)) +- *(primitives)* rename State/Storage to EvmState/EvmStorage ([#1459](https://github.com/bluealloy/revm/pull/1459)) +- Revert "Revert "feat: implement EIP-2935 ([#1354](https://github.com/bluealloy/revm/pull/1354))" ([#1424](https://github.com/bluealloy/revm/pull/1424))" ([#1426](https://github.com/bluealloy/revm/pull/1426)) +- Revert "feat: implement EIP-2935 ([#1354](https://github.com/bluealloy/revm/pull/1354))" ([#1424](https://github.com/bluealloy/revm/pull/1424)) + ## [4.0.0](https://github.com/bluealloy/revm/compare/revm-primitives-v3.1.1...revm-primitives-v4.0.0) - 2024-05-12 ### Added diff --git a/crates/primitives/Cargo.toml b/crates/primitives/Cargo.toml index a9d009d2e4..140960ee12 100644 --- a/crates/primitives/Cargo.toml +++ b/crates/primitives/Cargo.toml @@ -1,99 +1,43 @@ [package] -authors = ["Dragan Rakita "] -description = "revm primitives" -edition = "2021" -keywords = ["no_std", "ethereum", "evm", "revm", "types"] -license = "MIT" name = "revm-primitives" -repository = "https://github.com/bluealloy/revm" -version = "4.0.0" -readme = "../../README.md" +description = "Revm primitives types" +version = "20.2.1" +authors.workspace = true +edition.workspace = true +keywords.workspace = true +license.workspace = true +repository.workspace = true +readme.workspace = true [package.metadata.docs.rs] all-features = true rustdoc-args = ["--cfg", "docsrs"] -[lints.rust] -unreachable_pub = "warn" -unused_must_use = "deny" -rust_2018_idioms = "deny" - -[lints.rustdoc] -all = "warn" +[lints] +workspace = true [dependencies] -alloy-primitives = { version = "0.7.2", default-features = false, features = [ - "rlp", +# alloy +alloy-primitives = { workspace = true, features = ["rlp", "map"] } + +# mics +num_enum = { version = "0.7.3", default-features = false } +once_cell = { version = "1.21", default-features = false, features = [ + "alloc", + "race", ] } -hashbrown = "0.14" -auto_impl = "1.2" -bitvec = { version = "1", default-features = false, features = ["alloc"] } -bitflags = { version = "2.5.0", default-features = false } - -# For setting the CfgEnv KZGSettings. Enabled by c-kzg flag. -c-kzg = { version = "1.0.2", default-features = false, optional = true } -once_cell = { version = "1.19", default-features = false, optional = true } - -# utility -enumn = "0.1" -derive_more = { version = "0.99", optional = true } -cfg-if = "1" -dyn-clone = "1.0" - -# optional -serde = { version = "1.0", default-features = false, features = [ - "derive", - "rc", -], optional = true } -[build-dependencies] -hex = { version = "0.4", default-features = false } +# Optional +serde = { workspace = true, features = ["derive", "rc"], optional = true } [features] -default = ["std", "c-kzg", "portable"] -std = [ - "serde?/std", - "alloy-primitives/std", - "hex/std", - "bitvec/std", - "bitflags/std", -] -hashbrown = [] -serde = [ - "dep:serde", - "alloy-primitives/serde", - "hex/serde", - "hashbrown/serde", - "bitvec/serde", - "bitflags/serde", - "c-kzg?/serde", -] -arbitrary = ["std", "alloy-primitives/arbitrary", "bitflags/arbitrary"] -asm-keccak = ["alloy-primitives/asm-keccak"] -portable = ["c-kzg?/portable"] - -optimism = [] -# Optimism default handler enabled Optimism handler register by default in EvmBuilder. -optimism-default-handler = ["optimism"] -negate-optimism-default-handler = [] +default = ["std"] +std = ["alloy-primitives/std", "serde?/std", "num_enum/std", "once_cell/std"] +serde = ["dep:serde", "alloy-primitives/serde"] +map-foldhash = ["alloy-primitives/map-foldhash"] -dev = [ - "memory_limit", - "optional_balance_check", - "optional_block_gas_limit", - "optional_eip3607", - "optional_gas_refund", - "optional_no_base_fee", - "optional_beneficiary_reward", -] -memory_limit = [] -optional_balance_check = [] -optional_block_gas_limit = [] -optional_eip3607 = [] -optional_gas_refund = [] -optional_no_base_fee = [] -optional_beneficiary_reward = [] +hashbrown = ["alloy-primitives/map-hashbrown"] +arbitrary = ["std", "alloy-primitives/arbitrary"] +asm-keccak = ["alloy-primitives/asm-keccak"] +sha3-keccak = ["alloy-primitives/sha3-keccak"] rand = ["alloy-primitives/rand"] - -# See comments in `revm-precompile` -c-kzg = ["dep:c-kzg", "dep:once_cell", "dep:derive_more"] diff --git a/crates/primitives/LICENSE b/crates/primitives/LICENSE index ad98ff22cc..be6d350ebe 100644 --- a/crates/primitives/LICENSE +++ b/crates/primitives/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2021-2024 draganrakita +Copyright (c) 2021-2025 draganrakita Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/crates/primitives/src/bytecode.rs b/crates/primitives/src/bytecode.rs deleted file mode 100644 index 232d61f66d..0000000000 --- a/crates/primitives/src/bytecode.rs +++ /dev/null @@ -1,168 +0,0 @@ -pub mod eof; -pub mod legacy; - -pub use eof::Eof; -pub use legacy::{JumpTable, LegacyAnalyzedBytecode}; - -use crate::{keccak256, Bytes, B256, KECCAK_EMPTY}; - -/// State of the [`Bytecode`] analysis. -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum Bytecode { - /// No analysis has been performed. - LegacyRaw(Bytes), - /// The bytecode has been analyzed for valid jump destinations. - LegacyAnalyzed(LegacyAnalyzedBytecode), - /// Ethereum Object Format - Eof(Eof), -} - -impl Default for Bytecode { - #[inline] - fn default() -> Self { - // Creates a new legacy analyzed [`Bytecode`] with exactly one STOP opcode. - Self::new() - } -} - -impl Bytecode { - // Creates a new legacy analyzed [`Bytecode`] with exactly one STOP opcode. - #[inline] - pub fn new() -> Self { - Self::LegacyAnalyzed(LegacyAnalyzedBytecode::default()) - } - - /// Return jump table if bytecode is analyzed - #[inline] - pub fn legacy_jump_table(&self) -> Option<&JumpTable> { - match &self { - Self::LegacyAnalyzed(analyzed) => Some(analyzed.jump_table()), - _ => None, - } - } - - /// Calculate hash of the bytecode. - pub fn hash_slow(&self) -> B256 { - if self.is_empty() { - KECCAK_EMPTY - } else { - keccak256(self.original_byte_slice()) - } - } - - /// Return reference to the EOF if bytecode is EOF. - #[inline] - pub const fn eof(&self) -> Option<&Eof> { - match self { - Self::Eof(eof) => Some(eof), - _ => None, - } - } - - /// Return true if bytecode is EOF. - #[inline] - pub const fn is_eof(&self) -> bool { - matches!(self, Self::Eof(_)) - } - - /// Creates a new raw [`Bytecode`]. - #[inline] - pub fn new_raw(bytecode: Bytes) -> Self { - Self::LegacyRaw(bytecode) - } - - /// Create new checked bytecode. - /// - /// # Safety - /// - /// Bytecode needs to end with STOP (0x00) opcode as checked bytecode assumes - /// that it is safe to iterate over bytecode without checking lengths. - pub unsafe fn new_analyzed( - bytecode: Bytes, - original_len: usize, - jump_table: JumpTable, - ) -> Self { - Self::LegacyAnalyzed(LegacyAnalyzedBytecode::new( - bytecode, - original_len, - jump_table, - )) - } - - /// Returns a reference to the bytecode. - /// - /// In case of EOF this will be the first code section. - #[inline] - pub fn bytecode(&self) -> &Bytes { - match self { - Self::LegacyRaw(bytes) => bytes, - Self::LegacyAnalyzed(analyzed) => analyzed.bytecode(), - Self::Eof(eof) => eof - .body - .code(0) - .expect("Valid EOF has at least one code section"), - } - } - - /// Returns false if bytecode can't be executed in Interpreter. - pub fn is_execution_ready(&self) -> bool { - !matches!(self, Self::LegacyRaw(_)) - } - - /// Returns bytes - #[inline] - pub fn bytes(&self) -> Bytes { - match self { - Self::LegacyRaw(bytes) => bytes.clone(), - Self::LegacyAnalyzed(analyzed) => analyzed.bytecode().clone(), - Self::Eof(eof) => eof.raw().clone(), - } - } - - /// Returns bytes slice - #[inline] - pub fn bytes_slice(&self) -> &[u8] { - match self { - Self::LegacyRaw(bytes) => bytes, - Self::LegacyAnalyzed(analyzed) => analyzed.bytecode(), - Self::Eof(eof) => eof.raw(), - } - } - - /// Returns a reference to the original bytecode. - #[inline] - pub fn original_bytes(&self) -> Bytes { - match self { - Self::LegacyRaw(bytes) => bytes.clone(), - Self::LegacyAnalyzed(analyzed) => analyzed.original_bytes(), - Self::Eof(eof) => eof.raw().clone(), - } - } - - /// Returns the original bytecode as a byte slice. - #[inline] - pub fn original_byte_slice(&self) -> &[u8] { - match self { - Self::LegacyRaw(bytes) => bytes, - Self::LegacyAnalyzed(analyzed) => analyzed.original_byte_slice(), - Self::Eof(eof) => eof.raw(), - } - } - - /// Returns the length of the raw bytes. - #[inline] - pub fn len(&self) -> usize { - match self { - Self::LegacyRaw(bytes) => bytes.len(), - Self::LegacyAnalyzed(analyzed) => analyzed.original_len(), - Self::Eof(eof) => eof.size(), - } - } - - /// Returns whether the bytecode is empty. - #[inline] - pub fn is_empty(&self) -> bool { - self.len() == 0 - } -} diff --git a/crates/primitives/src/bytecode/eof.rs b/crates/primitives/src/bytecode/eof.rs deleted file mode 100644 index 67580c1577..0000000000 --- a/crates/primitives/src/bytecode/eof.rs +++ /dev/null @@ -1,156 +0,0 @@ -mod body; -mod decode_helpers; -mod header; -mod types_section; - -pub use body::EofBody; -pub use header::EofHeader; -pub use types_section::TypesSection; - -use crate::Bytes; -use core::cmp::min; -use std::{vec, vec::Vec}; - -/// EOF - Ethereum Object Format. -/// -/// It consist of a header, body and raw original bytes Specified in EIP. -/// Most of body contain Bytes so it references to the raw bytes. -/// -/// If there is a need to create new EOF from scratch, it is recommended to use `EofBody` and -/// use `encode` function to create full [`Eof`] object. -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Eof { - pub header: EofHeader, - pub body: EofBody, - pub raw: Bytes, -} - -impl Default for Eof { - fn default() -> Self { - let body = EofBody { - // types section with zero inputs, zero outputs and zero max stack size. - types_section: vec![TypesSection::default()], - // One code section with a STOP byte. - code_section: vec![[0x00].into()], - container_section: vec![], - data_section: Bytes::new(), - is_data_filled: true, - }; - body.into_eof() - } -} - -impl Eof { - /// Returns len of the header and body in bytes. - pub fn size(&self) -> usize { - self.header.size() + self.header.body_size() - } - - /// Return raw EOF bytes. - pub fn raw(&self) -> &Bytes { - &self.raw - } - - /// Returns a slice of the raw bytes. - /// If offset is greater than the length of the raw bytes, an empty slice is returned. - /// If len is greater than the length of the raw bytes, the slice is truncated to the length of the raw bytes. - pub fn data_slice(&self, offset: usize, len: usize) -> &[u8] { - self.body - .data_section - .get(offset..) - .and_then(|bytes| bytes.get(..min(len, bytes.len()))) - .unwrap_or(&[]) - } - - /// Returns a slice of the data section. - pub fn data(&self) -> &[u8] { - &self.body.data_section - } - - /// Slow encode EOF bytes. - pub fn encode_slow(&self) -> Bytes { - let mut buffer: Vec = Vec::with_capacity(self.size()); - self.header.encode(&mut buffer); - self.body.encode(&mut buffer); - buffer.into() - } - - /// Decode EOF from raw bytes. - pub fn decode(raw: Bytes) -> Result { - let (header, _) = EofHeader::decode(&raw)?; - let body = EofBody::decode(&raw, &header)?; - Ok(Self { header, body, raw }) - } -} - -/// EOF decode errors. -#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)] -pub enum EofDecodeError { - /// Short input while processing EOF. - MissingInput, - /// Short body while processing EOF. - MissingBodyWithoutData, - /// Body size is more than specified in the header. - DanglingData, - /// Invalid types section data. - InvalidTypesSection, - /// Invalid types section size. - InvalidTypesSectionSize, - /// Invalid EOF magic number. - InvalidEOFMagicNumber, - /// Invalid EOF version. - InvalidEOFVersion, - /// Invalid number for types kind - InvalidTypesKind, - /// Invalid number for code kind - InvalidCodeKind, - /// Invalid terminal code - InvalidTerminalByte, - /// Invalid data kind - InvalidDataKind, - /// Invalid kind after code - InvalidKindAfterCode, - /// Mismatch of code and types sizes. - MismatchCodeAndTypesSize, - /// There should be at least one size. - NonSizes, - /// Missing size. - ShortInputForSizes, - /// Size cant be zero - ZeroSize, - /// Invalid code number. - TooManyCodeSections, - /// Invalid number of code sections. - ZeroCodeSections, - /// Invalid container number. - TooManyContainerSections, -} - -#[cfg(test)] -mod test { - - use super::*; - use crate::bytes; - - #[test] - fn decode_eof() { - let bytes = bytes!("ef000101000402000100010400000000800000fe"); - let eof = Eof::decode(bytes.clone()).unwrap(); - assert_eq!(bytes, eof.encode_slow()); - } - - #[test] - fn data_slice() { - let bytes = bytes!("ef000101000402000100010400000000800000fe"); - let mut eof = Eof::decode(bytes.clone()).unwrap(); - eof.body.data_section = bytes!("01020304"); - assert_eq!(eof.data_slice(0, 1), &[0x01]); - assert_eq!(eof.data_slice(0, 4), &[0x01, 0x02, 0x03, 0x04]); - assert_eq!(eof.data_slice(0, 5), &[0x01, 0x02, 0x03, 0x04]); - assert_eq!(eof.data_slice(1, 2), &[0x02, 0x03]); - assert_eq!(eof.data_slice(10, 2), &[]); - assert_eq!(eof.data_slice(1, 0), &[]); - assert_eq!(eof.data_slice(10, 0), &[]); - } -} diff --git a/crates/primitives/src/bytecode/eof/body.rs b/crates/primitives/src/bytecode/eof/body.rs deleted file mode 100644 index 3759372b8a..0000000000 --- a/crates/primitives/src/bytecode/eof/body.rs +++ /dev/null @@ -1,109 +0,0 @@ -use super::{Eof, EofDecodeError, EofHeader, TypesSection}; -use crate::Bytes; -use std::vec::Vec; - -/// EOF Body, contains types, code, container and data sections. -/// -/// Can be used to create new EOF object. -#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct EofBody { - pub types_section: Vec, - pub code_section: Vec, - pub container_section: Vec, - pub data_section: Bytes, - pub is_data_filled: bool, -} - -impl EofBody { - // Get code section - pub fn code(&self, index: usize) -> Option<&Bytes> { - self.code_section.get(index) - } - - /// Create EOF from body. - pub fn into_eof(self) -> Eof { - // TODO add bounds checks. - let header = EofHeader { - types_size: self.types_section.len() as u16 * 4, - code_sizes: self.code_section.iter().map(|x| x.len() as u16).collect(), - container_sizes: self - .container_section - .iter() - .map(|x| x.len() as u16) - .collect(), - data_size: self.data_section.len() as u16, - sum_code_sizes: self.code_section.iter().map(|x| x.len()).sum(), - sum_container_sizes: self.container_section.iter().map(|x| x.len()).sum(), - }; - let mut buffer = Vec::new(); - header.encode(&mut buffer); - self.encode(&mut buffer); - Eof { - header, - body: self, - raw: buffer.into(), - } - } - - /// Encode Body into buffer. - pub fn encode(&self, buffer: &mut Vec) { - for types_section in &self.types_section { - types_section.encode(buffer); - } - - for code_section in &self.code_section { - buffer.extend_from_slice(code_section); - } - - for container_section in &self.container_section { - buffer.extend_from_slice(container_section); - } - - buffer.extend_from_slice(&self.data_section); - } - - /// Decode EOF body from buffer and Header. - pub fn decode(input: &Bytes, header: &EofHeader) -> Result { - let header_len = header.size(); - let partial_body_len = - header.sum_code_sizes + header.sum_container_sizes + header.types_size as usize; - let full_body_len = partial_body_len + header.data_size as usize; - - if input.len() < header_len + partial_body_len { - return Err(EofDecodeError::MissingBodyWithoutData); - } - - if input.len() > header_len + full_body_len { - return Err(EofDecodeError::DanglingData); - } - - let mut body = EofBody::default(); - - let mut types_input = &input[header_len..]; - for _ in 0..header.types_count() { - let (types_section, local_input) = TypesSection::decode(types_input)?; - types_input = local_input; - body.types_section.push(types_section); - } - - // extract code section - let mut start = header_len + header.types_size as usize; - for size in header.code_sizes.iter().map(|x| *x as usize) { - body.code_section.push(input.slice(start..start + size)); - start += size; - } - - // extract container section - for size in header.container_sizes.iter().map(|x| *x as usize) { - body.container_section - .push(input.slice(start..start + size)); - start += size; - } - - body.data_section = input.slice(start..); - body.is_data_filled = body.data_section.len() == header.data_size as usize; - - Ok(body) - } -} diff --git a/crates/primitives/src/bytecode/eof/decode_helpers.rs b/crates/primitives/src/bytecode/eof/decode_helpers.rs deleted file mode 100644 index d2d2eb555d..0000000000 --- a/crates/primitives/src/bytecode/eof/decode_helpers.rs +++ /dev/null @@ -1,20 +0,0 @@ -use super::EofDecodeError; - -/// Consumes a u8 from the input. -#[inline] -pub(crate) fn consume_u8(input: &[u8]) -> Result<(&[u8], u8), EofDecodeError> { - if input.is_empty() { - return Err(EofDecodeError::MissingInput); - } - Ok((&input[1..], input[0])) -} - -/// Consumes a u16 from the input. -#[inline] -pub(crate) fn consume_u16(input: &[u8]) -> Result<(&[u8], u16), EofDecodeError> { - if input.len() < 2 { - return Err(EofDecodeError::MissingInput); - } - let (int_bytes, rest) = input.split_at(2); - Ok((rest, u16::from_be_bytes([int_bytes[0], int_bytes[1]]))) -} diff --git a/crates/primitives/src/bytecode/eof/header.rs b/crates/primitives/src/bytecode/eof/header.rs deleted file mode 100644 index bd7a33d7b7..0000000000 --- a/crates/primitives/src/bytecode/eof/header.rs +++ /dev/null @@ -1,257 +0,0 @@ -use super::{ - decode_helpers::{consume_u16, consume_u8}, - EofDecodeError, -}; -use std::vec::Vec; - -/// EOF Header containing -#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct EofHeader { - /// Size of EOF types section. - /// types section includes num of input and outputs and max stack size. - pub types_size: u16, - /// Sizes of EOF code section. - /// Code size can't be zero. - pub code_sizes: Vec, - /// EOF Container size. - /// Container size can be zero. - pub container_sizes: Vec, - /// EOF data size. - pub data_size: u16, - /// sum code sizes - pub sum_code_sizes: usize, - /// sum container sizes - pub sum_container_sizes: usize, -} - -const KIND_TERMINAL: u8 = 0; -const KIND_TYPES: u8 = 1; -const KIND_CODE: u8 = 2; -const KIND_CONTAINER: u8 = 3; -const KIND_DATA: u8 = 4; - -#[inline] -fn consume_header_section_size(input: &[u8]) -> Result<(&[u8], Vec, usize), EofDecodeError> { - // num_sections 2 bytes 0x0001-0xFFFF - // 16-bit unsigned big-endian integer denoting the number of the sections - let (input, num_sections) = consume_u16(input)?; - if num_sections == 0 { - return Err(EofDecodeError::NonSizes); - } - let byte_size = (num_sections * 2) as usize; - if input.len() < byte_size { - return Err(EofDecodeError::ShortInputForSizes); - } - let mut sizes = Vec::with_capacity(num_sections as usize); - let mut sum = 0; - for i in 0..num_sections as usize { - // size 2 bytes 0x0001-0xFFFF - // 16-bit unsigned big-endian integer denoting the length of the section content - let code_size = u16::from_be_bytes([input[i * 2], input[i * 2 + 1]]); - if code_size == 0 { - return Err(EofDecodeError::ZeroSize); - } - sum += code_size as usize; - sizes.push(code_size); - } - - Ok((&input[byte_size..], sizes, sum)) -} - -impl EofHeader { - /// Length of the header in bytes. - /// - /// Length is calculated as: - /// magic 2 byte + - /// version 1 byte + - /// types section 3 bytes + - /// code section 3 bytes + - /// num_code_sections * 2 + - /// if num_container_sections != 0 { container section 3 bytes} + - /// num_container_sections * 2 + - /// data section 3 bytes + - /// terminator 1 byte - /// - /// It is minimum 15 bytes (there is at least one code section). - pub fn size(&self) -> usize { - let optional_container_sizes = if self.container_sizes.is_empty() { - 0 - } else { - 3 + self.container_sizes.len() * 2 - }; - 13 + self.code_sizes.len() * 2 + optional_container_sizes - } - - /// Returns number of types. - pub fn types_count(&self) -> usize { - self.types_size as usize / 4 - } - - /// Returns body size. It is sum of code sizes, container sizes and data size. - pub fn body_size(&self) -> usize { - self.sum_code_sizes + self.sum_container_sizes + self.data_size as usize - } - - /// Returns raw size of the EOF. - pub fn eof_size(&self) -> usize { - self.size() + self.body_size() - } - - /// Encodes EOF header into binary form. - pub fn encode(&self, buffer: &mut Vec) { - // magic 2 bytes 0xEF00 EOF prefix - buffer.extend_from_slice(&0xEF00u16.to_be_bytes()); - // version 1 byte 0x01 EOF version - buffer.push(0x01); - // kind_types 1 byte 0x01 kind marker for types size section - buffer.push(KIND_TYPES); - // types_size 2 bytes 0x0004-0xFFFF - buffer.extend_from_slice(&self.types_size.to_be_bytes()); - // kind_code 1 byte 0x02 kind marker for code size section - buffer.push(KIND_CODE); - // code_sections_sizes - buffer.extend_from_slice(&(self.code_sizes.len() as u16).to_be_bytes()); - for size in &self.code_sizes { - buffer.extend_from_slice(&size.to_be_bytes()); - } - // kind_container_or_data 1 byte 0x03 or 0x04 kind marker for container size section or data size section - if self.container_sizes.is_empty() { - buffer.push(KIND_DATA); - } else { - buffer.push(KIND_CONTAINER); - // container_sections_sizes - buffer.extend_from_slice(&(self.container_sizes.len() as u16).to_be_bytes()); - for size in &self.container_sizes { - buffer.extend_from_slice(&size.to_be_bytes()); - } - // kind_data 1 byte 0x04 kind marker for data size section - buffer.push(KIND_DATA); - } - // data_size 2 bytes 0x0000-0xFFFF 16-bit unsigned big-endian integer denoting the length of the data section content - buffer.extend_from_slice(&self.data_size.to_be_bytes()); - // terminator 1 byte 0x00 marks the end of the EofHeader - buffer.push(KIND_TERMINAL); - } - - /// Decodes EOF header from binary form. - pub fn decode(input: &[u8]) -> Result<(Self, &[u8]), EofDecodeError> { - let mut header = EofHeader::default(); - - // magic 2 bytes 0xEF00 EOF prefix - let (input, kind) = consume_u16(input)?; - if kind != 0xEF00 { - return Err(EofDecodeError::InvalidEOFMagicNumber); - } - - // version 1 byte 0x01 EOF version - let (input, version) = consume_u8(input)?; - if version != 0x01 { - return Err(EofDecodeError::InvalidEOFVersion); - } - - // kind_types 1 byte 0x01 kind marker for types size section - let (input, kind_types) = consume_u8(input)?; - if kind_types != KIND_TYPES { - return Err(EofDecodeError::InvalidTypesKind); - } - - // types_size 2 bytes 0x0004-0xFFFF - // 16-bit unsigned big-endian integer denoting the length of the type section content - let (input, types_size) = consume_u16(input)?; - header.types_size = types_size; - - if header.types_size % 4 != 0 { - return Err(EofDecodeError::InvalidTypesSection); - } - - // kind_code 1 byte 0x02 kind marker for code size section - let (input, kind_types) = consume_u8(input)?; - if kind_types != KIND_CODE { - return Err(EofDecodeError::InvalidCodeKind); - } - - // code_sections_sizes - let (input, sizes, sum) = consume_header_section_size(input)?; - - if sizes.len() > 1024 { - return Err(EofDecodeError::TooManyCodeSections); - } - - if sizes.is_empty() { - return Err(EofDecodeError::ZeroCodeSections); - } - - if sizes.len() != (types_size / 4) as usize { - return Err(EofDecodeError::MismatchCodeAndTypesSize); - } - - header.code_sizes = sizes; - header.sum_code_sizes = sum; - - let (input, kind_container_or_data) = consume_u8(input)?; - - let input = match kind_container_or_data { - KIND_CONTAINER => { - // container_sections_sizes - let (input, sizes, sum) = consume_header_section_size(input)?; - // the number of container sections must not exceed 256 - if sizes.len() > 256 { - return Err(EofDecodeError::TooManyContainerSections); - } - header.container_sizes = sizes; - header.sum_container_sizes = sum; - let (input, kind_data) = consume_u8(input)?; - if kind_data != KIND_DATA { - return Err(EofDecodeError::InvalidDataKind); - } - input - } - KIND_DATA => input, - _ => return Err(EofDecodeError::InvalidKindAfterCode), - }; - - // data_size 2 bytes 0x0000-0xFFFF 16-bit - // unsigned big-endian integer denoting the length - // of the data section content (for not yet deployed - // containers this can be more than the actual content, see Data Section Lifecycle) - let (input, data_size) = consume_u16(input)?; - header.data_size = data_size; - - // terminator 1 byte 0x00 marks the end of the EofHeader - let (input, terminator) = consume_u8(input)?; - if terminator != KIND_TERMINAL { - return Err(EofDecodeError::InvalidTerminalByte); - } - - Ok((header, input)) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::hex; - - #[test] - fn sanity_header_decode() { - let input = hex!("ef000101000402000100010400000000800000fe"); - let (header, _) = EofHeader::decode(&input).unwrap(); - assert_eq!(header.types_size, 4); - assert_eq!(header.code_sizes, vec![1]); - assert_eq!(header.container_sizes, vec![]); - assert_eq!(header.data_size, 0); - } - - #[test] - fn decode_header_not_terminated() { - let input = hex!("ef0001010004"); - assert_eq!(EofHeader::decode(&input), Err(EofDecodeError::MissingInput)); - } - - #[test] - fn failing_test() { - let input = hex!("ef00010100040200010006030001001404000200008000016000e0000000ef000101000402000100010400000000800000fe"); - let _ = EofHeader::decode(&input).unwrap(); - } -} diff --git a/crates/primitives/src/bytecode/eof/types_section.rs b/crates/primitives/src/bytecode/eof/types_section.rs deleted file mode 100644 index 5acc3b7138..0000000000 --- a/crates/primitives/src/bytecode/eof/types_section.rs +++ /dev/null @@ -1,70 +0,0 @@ -use super::{ - decode_helpers::{consume_u16, consume_u8}, - EofDecodeError, -}; -use std::vec::Vec; - -/// Types section that contains stack information for matching code section. -#[derive(Debug, Clone, Default, Hash, PartialEq, Eq, Copy)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct TypesSection { - /// inputs - 1 byte - `0x00-0x7F` - /// number of stack elements the code section consumes - pub inputs: u8, - /// outputs - 1 byte - `0x00-0x80` - /// number of stack elements the code section returns or 0x80 for non-returning functions - pub outputs: u8, - /// max_stack_height - 2 bytes - `0x0000-0x03FF` - /// maximum number of elements ever placed onto the stack by the code section - pub max_stack_size: u16, -} - -impl TypesSection { - /// Returns new `TypesSection` with the given inputs, outputs, and max_stack_size. - pub fn new(inputs: u8, outputs: u8, max_stack_size: u16) -> Self { - Self { - inputs, - outputs, - max_stack_size, - } - } - /// Calculates the difference between the number of input and output stack elements. - #[inline] - pub const fn io_diff(&self) -> i32 { - self.outputs as i32 - self.inputs as i32 - } - - /// Encode the section into the buffer. - #[inline] - pub fn encode(&self, buffer: &mut Vec) { - buffer.push(self.inputs); - buffer.push(self.outputs); - buffer.extend_from_slice(&self.max_stack_size.to_be_bytes()); - } - - /// Decode the section from the input. - #[inline] - pub fn decode(input: &[u8]) -> Result<(Self, &[u8]), EofDecodeError> { - let (input, inputs) = consume_u8(input)?; - let (input, outputs) = consume_u8(input)?; - let (input, max_stack_size) = consume_u16(input)?; - let section = Self { - inputs, - outputs, - max_stack_size, - }; - section.validate()?; - Ok((section, input)) - } - - /// Validate the section. - pub fn validate(&self) -> Result<(), EofDecodeError> { - if self.inputs > 0x7f || self.outputs > 0x80 || self.max_stack_size > 0x03FF { - return Err(EofDecodeError::InvalidTypesSection); - } - if self.inputs as u16 > self.max_stack_size { - return Err(EofDecodeError::InvalidTypesSection); - } - Ok(()) - } -} diff --git a/crates/primitives/src/bytecode/legacy.rs b/crates/primitives/src/bytecode/legacy.rs deleted file mode 100644 index 2a44fefd43..0000000000 --- a/crates/primitives/src/bytecode/legacy.rs +++ /dev/null @@ -1,68 +0,0 @@ -mod jump_map; - -pub use jump_map::JumpTable; - -use crate::Bytes; -use bitvec::{bitvec, order::Lsb0}; -use std::sync::Arc; - -/// Legacy analyzed -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct LegacyAnalyzedBytecode { - /// Bytecode with 32 zero bytes padding. - bytecode: Bytes, - /// Original bytes length. - original_len: usize, - /// Jump table. - jump_table: JumpTable, -} - -impl Default for LegacyAnalyzedBytecode { - #[inline] - fn default() -> Self { - Self { - bytecode: Bytes::from_static(&[0]), - original_len: 0, - jump_table: JumpTable(Arc::new(bitvec![u8, Lsb0; 0])), - } - } -} - -impl LegacyAnalyzedBytecode { - /// Create new analyzed bytecode. - pub fn new(bytecode: Bytes, original_len: usize, jump_table: JumpTable) -> Self { - Self { - bytecode, - original_len, - jump_table, - } - } - - /// Returns a reference to the bytecode. - /// - /// The bytecode is padded with 32 zero bytes. - pub fn bytecode(&self) -> &Bytes { - &self.bytecode - } - - /// Original bytes length. - pub fn original_len(&self) -> usize { - self.original_len - } - - /// Original bytes without padding. - pub fn original_bytes(&self) -> Bytes { - self.bytecode.slice(..self.original_len) - } - - /// Original bytes without padding. - pub fn original_byte_slice(&self) -> &[u8] { - &self.bytecode[..self.original_len] - } - - /// Jumptable of analyzed bytes. - pub fn jump_table(&self) -> &JumpTable { - &self.jump_table - } -} diff --git a/crates/primitives/src/bytecode/legacy/jump_map.rs b/crates/primitives/src/bytecode/legacy/jump_map.rs deleted file mode 100644 index af86178775..0000000000 --- a/crates/primitives/src/bytecode/legacy/jump_map.rs +++ /dev/null @@ -1,36 +0,0 @@ -use crate::hex; -use bitvec::vec::BitVec; -use std::{fmt::Debug, sync::Arc}; - -/// A map of valid `jump` destinations. -#[derive(Clone, Default, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct JumpTable(pub Arc>); - -impl Debug for JumpTable { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.debug_struct("JumpTable") - .field("map", &hex::encode(self.0.as_raw_slice())) - .finish() - } -} - -impl JumpTable { - /// Get the raw bytes of the jump map - #[inline] - pub fn as_slice(&self) -> &[u8] { - self.0.as_raw_slice() - } - - /// Construct a jump map from raw bytes - #[inline] - pub fn from_slice(slice: &[u8]) -> Self { - Self(Arc::new(BitVec::from_slice(slice))) - } - - /// Check if `pc` is a valid jump destination. - #[inline] - pub fn is_valid(&self, pc: usize) -> bool { - pc < self.0.len() && self.0[pc] - } -} diff --git a/crates/primitives/src/constants.rs b/crates/primitives/src/constants.rs index c8223300bf..0ce8e1b065 100644 --- a/crates/primitives/src/constants.rs +++ b/crates/primitives/src/constants.rs @@ -1,62 +1,22 @@ -use alloy_primitives::{address, Address}; +//! Global constants for the EVM +//! +//! Here you can find constants that dont belong to any EIP and are there for the genesis. -/// EIP-170: Contract code size limit -/// -/// By default the limit is `0x6000` (~25kb) -pub const MAX_CODE_SIZE: usize = 0x6000; +use alloy_primitives::{b256, Address, B256}; -/// Number of block hashes that EVM can access in the past (pre-Prague). -pub const BLOCK_HASH_HISTORY: usize = 256; +/// Number of block hashes that EVM can access in the past (pre-Prague) +pub const BLOCK_HASH_HISTORY: u64 = 256; -/// EIP-2935: Serve historical block hashes from state -/// -/// Number of block hashes the EVM can access in the past (Prague). -/// -/// # Note -/// -/// This is named `HISTORY_SERVE_WINDOW` in the EIP. -pub const BLOCKHASH_SERVE_WINDOW: usize = 8192; - -/// EIP-2935: Serve historical block hashes from state -/// -/// The address where historical blockhashes are available. -/// -/// # Note -/// -/// This is named `HISTORY_STORAGE_ADDRESS` in the EIP. -pub const BLOCKHASH_STORAGE_ADDRESS: Address = address!("25a219378dad9b3503c8268c9ca836a52427a4fb"); - -/// EIP-3860: Limit and meter initcode -/// -/// Limit of maximum initcode size is `2 * MAX_CODE_SIZE`. -pub const MAX_INITCODE_SIZE: usize = 2 * MAX_CODE_SIZE; - -/// The address of precompile 3, which is handled specially in a few places. +/// The address of precompile 3, which is handled specially in a few places pub const PRECOMPILE3: Address = Address::new([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3]); -// === EIP-4844 constants === - -/// Gas consumption of a single data blob (== blob byte size). -pub const GAS_PER_BLOB: u64 = 1 << 17; - -/// Target number of the blob per block. -pub const TARGET_BLOB_NUMBER_PER_BLOCK: u64 = 3; - -/// Max number of blobs per block -pub const MAX_BLOB_NUMBER_PER_BLOCK: u64 = 2 * TARGET_BLOB_NUMBER_PER_BLOCK; - -/// Maximum consumable blob gas for data blobs per block. -pub const MAX_BLOB_GAS_PER_BLOCK: u64 = MAX_BLOB_NUMBER_PER_BLOCK * GAS_PER_BLOB; - -/// Target consumable blob gas for data blobs per block (for 1559-like pricing). -pub const TARGET_BLOB_GAS_PER_BLOCK: u64 = TARGET_BLOB_NUMBER_PER_BLOCK * GAS_PER_BLOB; - -/// Minimum gas price for data blobs. -pub const MIN_BLOB_GASPRICE: u64 = 1; +/// EVM interpreter stack limit +pub const STACK_LIMIT: usize = 1024; -/// Controls the maximum rate of change for blob gas price. -pub const BLOB_GASPRICE_UPDATE_FRACTION: u64 = 3338477; +/// EVM call stack limit +pub const CALL_STACK_LIMIT: u64 = 1024; -/// First version of the blob. -pub const VERSIONED_HASH_VERSION_KZG: u8 = 0x01; +/// The Keccak-256 hash of the empty string `""`. +pub const KECCAK_EMPTY: B256 = + b256!("0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"); diff --git a/crates/primitives/src/db.rs b/crates/primitives/src/db.rs deleted file mode 100644 index 3b1c6dc803..0000000000 --- a/crates/primitives/src/db.rs +++ /dev/null @@ -1,145 +0,0 @@ -use crate::{Account, AccountInfo, Address, Bytecode, HashMap, B256, U256}; -use auto_impl::auto_impl; - -pub mod components; -pub use components::{ - BlockHash, BlockHashRef, DatabaseComponentError, DatabaseComponents, State, StateRef, -}; - -/// EVM database interface. -#[auto_impl(&mut, Box)] -pub trait Database { - /// The database error type. - type Error; - - /// Get basic account information. - fn basic(&mut self, address: Address) -> Result, Self::Error>; - - /// Get account code by its hash. - fn code_by_hash(&mut self, code_hash: B256) -> Result; - - /// Get storage value of address at index. - fn storage(&mut self, address: Address, index: U256) -> Result; - - /// Get block hash by block number. - fn block_hash(&mut self, number: U256) -> Result; -} - -/// EVM database commit interface. -#[auto_impl(&mut, Box)] -pub trait DatabaseCommit { - /// Commit changes to the database. - fn commit(&mut self, changes: HashMap); -} - -/// EVM database interface. -/// -/// Contains the same methods as [`Database`], but with `&self` receivers instead of `&mut self`. -/// -/// Use [`WrapDatabaseRef`] to provide [`Database`] implementation for a type -/// that only implements this trait. -#[auto_impl(&, &mut, Box, Rc, Arc)] -pub trait DatabaseRef { - /// The database error type. - type Error; - - /// Get basic account information. - fn basic_ref(&self, address: Address) -> Result, Self::Error>; - - /// Get account code by its hash. - fn code_by_hash_ref(&self, code_hash: B256) -> Result; - - /// Get storage value of address at index. - fn storage_ref(&self, address: Address, index: U256) -> Result; - - /// Get block hash by block number. - fn block_hash_ref(&self, number: U256) -> Result; -} - -/// Wraps a [`DatabaseRef`] to provide a [`Database`] implementation. -#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct WrapDatabaseRef(pub T); - -impl From for WrapDatabaseRef { - #[inline] - fn from(f: F) -> Self { - WrapDatabaseRef(f) - } -} - -pub trait DatabaseWithDebugError: Database -where - ::Error: std::fmt::Debug + std::fmt::Display, -{ -} - -impl Database for WrapDatabaseRef { - type Error = T::Error; - - #[inline] - fn basic(&mut self, address: Address) -> Result, Self::Error> { - self.0.basic_ref(address) - } - - #[inline] - fn code_by_hash(&mut self, code_hash: B256) -> Result { - self.0.code_by_hash_ref(code_hash) - } - - #[inline] - fn storage(&mut self, address: Address, index: U256) -> Result { - self.0.storage_ref(address, index) - } - - #[inline] - fn block_hash(&mut self, number: U256) -> Result { - self.0.block_hash_ref(number) - } -} - -impl DatabaseCommit for WrapDatabaseRef { - #[inline] - fn commit(&mut self, changes: HashMap) { - self.0.commit(changes) - } -} - -/// Wraps a `dyn DatabaseRef` to provide a [`Database`] implementation. -#[doc(hidden)] -#[deprecated = "use `WrapDatabaseRef` instead"] -pub struct RefDBWrapper<'a, E> { - pub db: &'a dyn DatabaseRef, -} - -#[allow(deprecated)] -impl<'a, E> RefDBWrapper<'a, E> { - #[inline] - pub fn new(db: &'a dyn DatabaseRef) -> Self { - Self { db } - } -} - -#[allow(deprecated)] -impl<'a, E> Database for RefDBWrapper<'a, E> { - type Error = E; - - #[inline] - fn basic(&mut self, address: Address) -> Result, Self::Error> { - self.db.basic_ref(address) - } - - #[inline] - fn code_by_hash(&mut self, code_hash: B256) -> Result { - self.db.code_by_hash_ref(code_hash) - } - - #[inline] - fn storage(&mut self, address: Address, index: U256) -> Result { - self.db.storage_ref(address, index) - } - - #[inline] - fn block_hash(&mut self, number: U256) -> Result { - self.db.block_hash_ref(number) - } -} diff --git a/crates/primitives/src/db/components/block_hash.rs b/crates/primitives/src/db/components/block_hash.rs deleted file mode 100644 index a0a0fe21e6..0000000000 --- a/crates/primitives/src/db/components/block_hash.rs +++ /dev/null @@ -1,45 +0,0 @@ -//! BlockHash database component from [`crate::db::Database`] -//! it is used inside [`crate::db::DatabaseComponents`] - -use crate::{B256, U256}; -use auto_impl::auto_impl; -use core::ops::Deref; -use std::sync::Arc; - -#[auto_impl(&mut, Box)] -pub trait BlockHash { - type Error; - - /// Get block hash by block number - fn block_hash(&mut self, number: U256) -> Result; -} - -#[auto_impl(&, &mut, Box, Rc, Arc)] -pub trait BlockHashRef { - type Error; - - /// Get block hash by block number - fn block_hash(&self, number: U256) -> Result; -} - -impl BlockHash for &T -where - T: BlockHashRef, -{ - type Error = ::Error; - - fn block_hash(&mut self, number: U256) -> Result { - BlockHashRef::block_hash(*self, number) - } -} - -impl BlockHash for Arc -where - T: BlockHashRef, -{ - type Error = ::Error; - - fn block_hash(&mut self, number: U256) -> Result { - self.deref().block_hash(number) - } -} diff --git a/crates/primitives/src/db/components/state.rs b/crates/primitives/src/db/components/state.rs deleted file mode 100644 index d3b948ddaa..0000000000 --- a/crates/primitives/src/db/components/state.rs +++ /dev/null @@ -1,73 +0,0 @@ -//! State database component from [`crate::db::Database`] -//! it is used inside [`crate::db::DatabaseComponents`] - -use crate::{AccountInfo, Address, Bytecode, B256, U256}; -use auto_impl::auto_impl; -use core::ops::Deref; -use std::sync::Arc; - -#[auto_impl(&mut, Box)] -pub trait State { - type Error; - - /// Get basic account information. - fn basic(&mut self, address: Address) -> Result, Self::Error>; - - /// Get account code by its hash - fn code_by_hash(&mut self, code_hash: B256) -> Result; - - /// Get storage value of address at index. - fn storage(&mut self, address: Address, index: U256) -> Result; -} - -#[auto_impl(&, &mut, Box, Rc, Arc)] -pub trait StateRef { - type Error; - - /// Get basic account information. - fn basic(&self, address: Address) -> Result, Self::Error>; - - /// Get account code by its hash - fn code_by_hash(&self, code_hash: B256) -> Result; - - /// Get storage value of address at index. - fn storage(&self, address: Address, index: U256) -> Result; -} - -impl State for &T -where - T: StateRef, -{ - type Error = ::Error; - - fn basic(&mut self, address: Address) -> Result, Self::Error> { - StateRef::basic(*self, address) - } - - fn code_by_hash(&mut self, code_hash: B256) -> Result { - StateRef::code_by_hash(*self, code_hash) - } - - fn storage(&mut self, address: Address, index: U256) -> Result { - StateRef::storage(*self, address, index) - } -} - -impl State for Arc -where - T: StateRef, -{ - type Error = ::Error; - - fn basic(&mut self, address: Address) -> Result, Self::Error> { - self.deref().basic(address) - } - - fn code_by_hash(&mut self, code_hash: B256) -> Result { - self.deref().code_by_hash(code_hash) - } - - fn storage(&mut self, address: Address, index: U256) -> Result { - self.deref().storage(address, index) - } -} diff --git a/crates/primitives/src/eip170.rs b/crates/primitives/src/eip170.rs new file mode 100644 index 0000000000..7022626e11 --- /dev/null +++ b/crates/primitives/src/eip170.rs @@ -0,0 +1,8 @@ +//! EIP-170: Contract Code Size Limit +//! +//! Introduces a maximum limit on smart contract code size. + +/// EIP-170: Contract code size limit +/// +/// By default the limit is `0x6000` (~25kb). +pub const MAX_CODE_SIZE: usize = 0x6000; diff --git a/crates/primitives/src/eip3860.rs b/crates/primitives/src/eip3860.rs new file mode 100644 index 0000000000..160c4bd09d --- /dev/null +++ b/crates/primitives/src/eip3860.rs @@ -0,0 +1,10 @@ +//! EIP-3860: Limit and Meter Initcode +//! +//! Introduces limits and gas metering for contract creation code. + +use crate::eip170; + +/// EIP-3860: Limit and meter initcode +/// +/// Limit of maximum initcode size is `2 * eip170::MAX_CODE_SIZE`. +pub const MAX_INITCODE_SIZE: usize = 2 * eip170::MAX_CODE_SIZE; diff --git a/crates/primitives/src/eip4844.rs b/crates/primitives/src/eip4844.rs new file mode 100644 index 0000000000..8a67e8224a --- /dev/null +++ b/crates/primitives/src/eip4844.rs @@ -0,0 +1,44 @@ +//! EIP-4844: Shard Blob Transactions +//! +//! Constants for blob transaction support in Cancun and Prague hard forks. + +/// First version of the blob +pub const VERSIONED_HASH_VERSION_KZG: u8 = 0x01; + +/// Gas consumption of a single data blob (== blob byte size) +pub const GAS_PER_BLOB: u64 = 1 << 17; + +/// Min blob gas price +pub const MIN_BLOB_GASPRICE: u64 = 1; + +/// Target number of the blob per block +pub const TARGET_BLOB_NUMBER_PER_BLOCK_CANCUN: u64 = 3; + +/// Max number of blobs per block +pub const MAX_BLOB_NUMBER_PER_BLOCK_CANCUN: u64 = 2 * TARGET_BLOB_NUMBER_PER_BLOCK_CANCUN; + +/// Maximum consumable blob gas for data blobs per block +pub const MAX_BLOB_GAS_PER_BLOCK_CANCUN: u64 = MAX_BLOB_NUMBER_PER_BLOCK_CANCUN * GAS_PER_BLOB; + +/// Target consumable blob gas for data blobs per block (for 1559-like pricing) +pub const TARGET_BLOB_GAS_PER_BLOCK_CANCUN: u64 = + TARGET_BLOB_NUMBER_PER_BLOCK_CANCUN * GAS_PER_BLOB; + +/// Controls the maximum rate of change for blob gas price +pub const BLOB_BASE_FEE_UPDATE_FRACTION_CANCUN: u64 = 3_338_477; + +/// Target number of the blob per block +pub const TARGET_BLOB_NUMBER_PER_BLOCK_PRAGUE: u64 = 6; + +/// Max number of blobs per block +pub const MAX_BLOB_NUMBER_PER_BLOCK_PRAGUE: u64 = 9; + +/// Maximum consumable blob gas for data blobs per block +pub const MAX_BLOB_GAS_PER_BLOCK_PRAGUE: u64 = MAX_BLOB_NUMBER_PER_BLOCK_PRAGUE * GAS_PER_BLOB; + +/// Target consumable blob gas for data blobs per block (for 1559-like pricing) +pub const TARGET_BLOB_GAS_PER_BLOCK_PRAGUE: u64 = + TARGET_BLOB_NUMBER_PER_BLOCK_PRAGUE * GAS_PER_BLOB; + +/// Controls the maximum rate of change for blob gas price +pub const BLOB_BASE_FEE_UPDATE_FRACTION_PRAGUE: u64 = 5_007_716; diff --git a/crates/primitives/src/eip7702.rs b/crates/primitives/src/eip7702.rs new file mode 100644 index 0000000000..0a958fb905 --- /dev/null +++ b/crates/primitives/src/eip7702.rs @@ -0,0 +1,9 @@ +//! EIP-7702: Set EOA Account Code +//! +//! Constants for account authorization and delegation functionality. + +/// Base cost of updating authorized account. +pub const PER_AUTH_BASE_COST: u64 = 12500; + +/// Cost of creating authorized account that was previously empty. +pub const PER_EMPTY_ACCOUNT_COST: u64 = 25000; diff --git a/crates/primitives/src/eip7823.rs b/crates/primitives/src/eip7823.rs new file mode 100644 index 0000000000..5fa40e6f59 --- /dev/null +++ b/crates/primitives/src/eip7823.rs @@ -0,0 +1,8 @@ +//! EIP-7823: Set Upper Bounds for MODEXP +//! +//! Introduces an upper bound on the inputs of the MODEXP precompile. +//! This reduces the number of potential bugs and makes it easier to replace using EVMMAX. + +/// Each of the modexp length inputs (length_of_BASE, length_of_EXPONENT and length_of_MODULUS) +/// MUST be less than or equal to 8192 bits (1024 bytes). +pub const INPUT_SIZE_LIMIT: usize = 1024; diff --git a/crates/primitives/src/eip7825.rs b/crates/primitives/src/eip7825.rs new file mode 100644 index 0000000000..bfde4cfb10 --- /dev/null +++ b/crates/primitives/src/eip7825.rs @@ -0,0 +1,12 @@ +//! EIP-7825: Transaction Gas Limit Cap +//! +//! Introduces a protocol-level cap on the maximum gas used by a transaction. + +/// Transaction gas limit cap. +/// +/// # Rationale from EIP +/// +/// The proposed cap of 16,777,216 gas (2^24) provides a clean power-of-two boundary that simplifies implementation while still +/// being large enough to accommodate most complex transactions, including contract deployments and advanced DeFi interactions. +/// This value represents approximately half of typical block sizes (30-40 million gas), ensuring multiple transactions can fit within each block. +pub const TX_GAS_LIMIT_CAP: u64 = 16_777_216; diff --git a/crates/primitives/src/eip7907.rs b/crates/primitives/src/eip7907.rs new file mode 100644 index 0000000000..fd9e03f479 --- /dev/null +++ b/crates/primitives/src/eip7907.rs @@ -0,0 +1,8 @@ +//! EIP-7907: Meter Contract Code Size And Increase Limit (Prague) +//! +//! This EIP introduces updated code size limits that apply starting from the Prague hard fork. + +/// By default the limit is `0xC000` (49_152 bytes). +pub const MAX_CODE_SIZE: usize = 0xC000; +/// By default the limit is `0x12000` (73_728 bytes). +pub const MAX_INITCODE_SIZE: usize = 0x12000; diff --git a/crates/primitives/src/eip7918.rs b/crates/primitives/src/eip7918.rs new file mode 100644 index 0000000000..a84d99c902 --- /dev/null +++ b/crates/primitives/src/eip7918.rs @@ -0,0 +1,6 @@ +//! EIP-7918: Blob Base Fee Bounded by Execution Cost +//! +//! Constants for blob base fee calculation with execution cost bounds. + +/// Minimum base fee for blobs, if price of the blob is less than this value, this value will be used. +pub const BLOB_BASE_COST: u64 = 2_u64.pow(14); diff --git a/crates/primitives/src/env.rs b/crates/primitives/src/env.rs deleted file mode 100644 index 44b0736977..0000000000 --- a/crates/primitives/src/env.rs +++ /dev/null @@ -1,744 +0,0 @@ -pub mod handler_cfg; - -pub use handler_cfg::{CfgEnvWithHandlerCfg, EnvWithHandlerCfg, HandlerCfg}; - -use crate::{ - calc_blob_gasprice, Account, Address, Bytes, InvalidHeader, InvalidTransaction, Spec, SpecId, - B256, GAS_PER_BLOB, KECCAK_EMPTY, MAX_BLOB_NUMBER_PER_BLOCK, MAX_INITCODE_SIZE, U256, - VERSIONED_HASH_VERSION_KZG, -}; -use core::cmp::{min, Ordering}; -use core::hash::Hash; -use std::boxed::Box; -use std::vec::Vec; - -/// EVM environment configuration. -#[derive(Clone, Debug, Default, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Env { - /// Configuration of the EVM itself. - pub cfg: CfgEnv, - /// Configuration of the block the transaction is in. - pub block: BlockEnv, - /// Configuration of the transaction that is being executed. - pub tx: TxEnv, -} - -impl Env { - /// Resets environment to default values. - #[inline] - pub fn clear(&mut self) { - *self = Self::default(); - } - - /// Create boxed [Env]. - #[inline] - pub fn boxed(cfg: CfgEnv, block: BlockEnv, tx: TxEnv) -> Box { - Box::new(Self { cfg, block, tx }) - } - - /// Calculates the effective gas price of the transaction. - #[inline] - pub fn effective_gas_price(&self) -> U256 { - if let Some(priority_fee) = self.tx.gas_priority_fee { - min(self.tx.gas_price, self.block.basefee + priority_fee) - } else { - self.tx.gas_price - } - } - - /// Calculates the [EIP-4844] `data_fee` of the transaction. - /// - /// Returns `None` if `Cancun` is not enabled. This is enforced in [`Env::validate_block_env`]. - /// - /// [EIP-4844]: https://eips.ethereum.org/EIPS/eip-4844 - #[inline] - pub fn calc_data_fee(&self) -> Option { - self.block.get_blob_gasprice().map(|blob_gas_price| { - U256::from(blob_gas_price).saturating_mul(U256::from(self.tx.get_total_blob_gas())) - }) - } - - /// Calculates the maximum [EIP-4844] `data_fee` of the transaction. - /// - /// This is used for ensuring that the user has at least enough funds to pay the - /// `max_fee_per_blob_gas * total_blob_gas`, on top of regular gas costs. - /// - /// See EIP-4844: - /// - pub fn calc_max_data_fee(&self) -> Option { - self.tx.max_fee_per_blob_gas.map(|max_fee_per_blob_gas| { - max_fee_per_blob_gas.saturating_mul(U256::from(self.tx.get_total_blob_gas())) - }) - } - - /// Validate the block environment. - #[inline] - pub fn validate_block_env(&self) -> Result<(), InvalidHeader> { - // `prevrandao` is required for the merge - if SPEC::enabled(SpecId::MERGE) && self.block.prevrandao.is_none() { - return Err(InvalidHeader::PrevrandaoNotSet); - } - // `excess_blob_gas` is required for Cancun - if SPEC::enabled(SpecId::CANCUN) && self.block.blob_excess_gas_and_price.is_none() { - return Err(InvalidHeader::ExcessBlobGasNotSet); - } - Ok(()) - } - - /// Validate transaction data that is set inside ENV and return error if something is wrong. - /// - /// Return initial spend gas (Gas needed to execute transaction). - #[inline] - pub fn validate_tx(&self) -> Result<(), InvalidTransaction> { - // BASEFEE tx check - if SPEC::enabled(SpecId::LONDON) { - if let Some(priority_fee) = self.tx.gas_priority_fee { - if priority_fee > self.tx.gas_price { - // or gas_max_fee for eip1559 - return Err(InvalidTransaction::PriorityFeeGreaterThanMaxFee); - } - } - - // check minimal cost against basefee - if !self.cfg.is_base_fee_check_disabled() - && self.effective_gas_price() < self.block.basefee - { - return Err(InvalidTransaction::GasPriceLessThanBasefee); - } - } - - // Check if gas_limit is more than block_gas_limit - if !self.cfg.is_block_gas_limit_disabled() - && U256::from(self.tx.gas_limit) > self.block.gas_limit - { - return Err(InvalidTransaction::CallerGasLimitMoreThanBlock); - } - - // EIP-3860: Limit and meter initcode - if SPEC::enabled(SpecId::SHANGHAI) && self.tx.transact_to.is_create() { - let max_initcode_size = self - .cfg - .limit_contract_code_size - .map(|limit| limit.saturating_mul(2)) - .unwrap_or(MAX_INITCODE_SIZE); - if self.tx.data.len() > max_initcode_size { - return Err(InvalidTransaction::CreateInitCodeSizeLimit); - } - } - - // Check if the transaction's chain id is correct - if let Some(tx_chain_id) = self.tx.chain_id { - if tx_chain_id != self.cfg.chain_id { - return Err(InvalidTransaction::InvalidChainId); - } - } - - // Check that access list is empty for transactions before BERLIN - if !SPEC::enabled(SpecId::BERLIN) && !self.tx.access_list.is_empty() { - return Err(InvalidTransaction::AccessListNotSupported); - } - - // - For CANCUN and later, check that the gas price is not more than the tx max - // - For before CANCUN, check that `blob_hashes` and `max_fee_per_blob_gas` are empty / not set - if SPEC::enabled(SpecId::CANCUN) { - // Presence of max_fee_per_blob_gas means that this is blob transaction. - if let Some(max) = self.tx.max_fee_per_blob_gas { - // ensure that the user was willing to at least pay the current blob gasprice - let price = self.block.get_blob_gasprice().expect("already checked"); - if U256::from(price) > max { - return Err(InvalidTransaction::BlobGasPriceGreaterThanMax); - } - - // there must be at least one blob - if self.tx.blob_hashes.is_empty() { - return Err(InvalidTransaction::EmptyBlobs); - } - - // The field `to` deviates slightly from the semantics with the exception - // that it MUST NOT be nil and therefore must always represent - // a 20-byte address. This means that blob transactions cannot - // have the form of a create transaction. - if self.tx.transact_to.is_create() { - return Err(InvalidTransaction::BlobCreateTransaction); - } - - // all versioned blob hashes must start with VERSIONED_HASH_VERSION_KZG - for blob in self.tx.blob_hashes.iter() { - if blob[0] != VERSIONED_HASH_VERSION_KZG { - return Err(InvalidTransaction::BlobVersionNotSupported); - } - } - - // ensure the total blob gas spent is at most equal to the limit - // assert blob_gas_used <= MAX_BLOB_GAS_PER_BLOCK - let num_blobs = self.tx.blob_hashes.len(); - if num_blobs > MAX_BLOB_NUMBER_PER_BLOCK as usize { - return Err(InvalidTransaction::TooManyBlobs { - have: num_blobs, - max: MAX_BLOB_NUMBER_PER_BLOCK as usize, - }); - } - } - } else { - if !self.tx.blob_hashes.is_empty() { - return Err(InvalidTransaction::BlobVersionedHashesNotSupported); - } - if self.tx.max_fee_per_blob_gas.is_some() { - return Err(InvalidTransaction::MaxFeePerBlobGasNotSupported); - } - } - - Ok(()) - } - - /// Validate transaction against state. - #[inline] - pub fn validate_tx_against_state( - &self, - account: &mut Account, - ) -> Result<(), InvalidTransaction> { - // EIP-3607: Reject transactions from senders with deployed code - // This EIP is introduced after london but there was no collision in past - // so we can leave it enabled always - if !self.cfg.is_eip3607_disabled() && account.info.code_hash != KECCAK_EMPTY { - return Err(InvalidTransaction::RejectCallerWithCode); - } - - // Check that the transaction's nonce is correct - if let Some(tx) = self.tx.nonce { - let state = account.info.nonce; - match tx.cmp(&state) { - Ordering::Greater => { - return Err(InvalidTransaction::NonceTooHigh { tx, state }); - } - Ordering::Less => { - return Err(InvalidTransaction::NonceTooLow { tx, state }); - } - _ => {} - } - } - - let mut balance_check = U256::from(self.tx.gas_limit) - .checked_mul(self.tx.gas_price) - .and_then(|gas_cost| gas_cost.checked_add(self.tx.value)) - .ok_or(InvalidTransaction::OverflowPaymentInTransaction)?; - - if SPEC::enabled(SpecId::CANCUN) { - // if the tx is not a blob tx, this will be None, so we add zero - let data_fee = self.calc_max_data_fee().unwrap_or_default(); - balance_check = balance_check - .checked_add(U256::from(data_fee)) - .ok_or(InvalidTransaction::OverflowPaymentInTransaction)?; - } - - // Check if account has enough balance for gas_limit*gas_price and value transfer. - // Transfer will be done inside `*_inner` functions. - if balance_check > account.info.balance { - if self.cfg.is_balance_check_disabled() { - // Add transaction cost to balance to ensure execution doesn't fail. - account.info.balance = balance_check; - } else { - return Err(InvalidTransaction::LackOfFundForMaxFee { - fee: Box::new(balance_check), - balance: Box::new(account.info.balance), - }); - } - } - - Ok(()) - } -} - -/// EVM configuration. -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[derive(Clone, Debug, Eq, PartialEq)] -#[non_exhaustive] -pub struct CfgEnv { - /// Chain ID of the EVM, it will be compared to the transaction's Chain ID. - /// Chain ID is introduced EIP-155 - pub chain_id: u64, - /// KZG Settings for point evaluation precompile. By default, this is loaded from the ethereum mainnet trusted setup. - #[cfg(feature = "c-kzg")] - #[cfg_attr(feature = "serde", serde(skip))] - pub kzg_settings: crate::kzg::EnvKzgSettings, - /// Bytecode that is created with CREATE/CREATE2 is by default analysed and jumptable is created. - /// This is very beneficial for testing and speeds up execution of that bytecode if called multiple times. - /// - /// Default: Analyse - pub perf_analyse_created_bytecodes: AnalysisKind, - /// If some it will effects EIP-170: Contract code size limit. Useful to increase this because of tests. - /// By default it is 0x6000 (~25kb). - pub limit_contract_code_size: Option, - /// A hard memory limit in bytes beyond which [crate::result::OutOfGasError::Memory] cannot be resized. - /// - /// In cases where the gas limit may be extraordinarily high, it is recommended to set this to - /// a sane value to prevent memory allocation panics. Defaults to `2^32 - 1` bytes per - /// EIP-1985. - #[cfg(feature = "memory_limit")] - pub memory_limit: u64, - /// Skip balance checks if true. Adds transaction cost to balance to ensure execution doesn't fail. - #[cfg(feature = "optional_balance_check")] - pub disable_balance_check: bool, - /// There are use cases where it's allowed to provide a gas limit that's higher than a block's gas limit. To that - /// end, you can disable the block gas limit validation. - /// By default, it is set to `false`. - #[cfg(feature = "optional_block_gas_limit")] - pub disable_block_gas_limit: bool, - /// EIP-3607 rejects transactions from senders with deployed code. In development, it can be desirable to simulate - /// calls from contracts, which this setting allows. - /// By default, it is set to `false`. - #[cfg(feature = "optional_eip3607")] - pub disable_eip3607: bool, - /// Disables all gas refunds. This is useful when using chains that have gas refunds disabled e.g. Avalanche. - /// Reasoning behind removing gas refunds can be found in EIP-3298. - /// By default, it is set to `false`. - #[cfg(feature = "optional_gas_refund")] - pub disable_gas_refund: bool, - /// Disables base fee checks for EIP-1559 transactions. - /// This is useful for testing method calls with zero gas price. - /// By default, it is set to `false`. - #[cfg(feature = "optional_no_base_fee")] - pub disable_base_fee: bool, - /// Disables the payout of the reward to the beneficiary. - /// By default, it is set to `false`. - #[cfg(feature = "optional_beneficiary_reward")] - pub disable_beneficiary_reward: bool, -} - -impl CfgEnv { - pub fn with_chain_id(mut self, chain_id: u64) -> Self { - self.chain_id = chain_id; - self - } - - #[cfg(feature = "optional_eip3607")] - pub fn is_eip3607_disabled(&self) -> bool { - self.disable_eip3607 - } - - #[cfg(not(feature = "optional_eip3607"))] - pub fn is_eip3607_disabled(&self) -> bool { - false - } - - #[cfg(feature = "optional_balance_check")] - pub fn is_balance_check_disabled(&self) -> bool { - self.disable_balance_check - } - - #[cfg(not(feature = "optional_balance_check"))] - pub fn is_balance_check_disabled(&self) -> bool { - false - } - - #[cfg(feature = "optional_gas_refund")] - pub fn is_gas_refund_disabled(&self) -> bool { - self.disable_gas_refund - } - - #[cfg(not(feature = "optional_gas_refund"))] - pub fn is_gas_refund_disabled(&self) -> bool { - false - } - - #[cfg(feature = "optional_no_base_fee")] - pub fn is_base_fee_check_disabled(&self) -> bool { - self.disable_base_fee - } - - #[cfg(not(feature = "optional_no_base_fee"))] - pub fn is_base_fee_check_disabled(&self) -> bool { - false - } - - #[cfg(feature = "optional_block_gas_limit")] - pub fn is_block_gas_limit_disabled(&self) -> bool { - self.disable_block_gas_limit - } - - #[cfg(not(feature = "optional_block_gas_limit"))] - pub fn is_block_gas_limit_disabled(&self) -> bool { - false - } - - #[cfg(feature = "optional_beneficiary_reward")] - pub fn is_beneficiary_reward_disabled(&self) -> bool { - self.disable_beneficiary_reward - } - - #[cfg(not(feature = "optional_beneficiary_reward"))] - pub fn is_beneficiary_reward_disabled(&self) -> bool { - false - } -} - -impl Default for CfgEnv { - fn default() -> Self { - Self { - chain_id: 1, - perf_analyse_created_bytecodes: AnalysisKind::default(), - limit_contract_code_size: None, - #[cfg(feature = "c-kzg")] - kzg_settings: crate::kzg::EnvKzgSettings::Default, - #[cfg(feature = "memory_limit")] - memory_limit: (1 << 32) - 1, - #[cfg(feature = "optional_balance_check")] - disable_balance_check: false, - #[cfg(feature = "optional_block_gas_limit")] - disable_block_gas_limit: false, - #[cfg(feature = "optional_eip3607")] - disable_eip3607: false, - #[cfg(feature = "optional_gas_refund")] - disable_gas_refund: false, - #[cfg(feature = "optional_no_base_fee")] - disable_base_fee: false, - #[cfg(feature = "optional_beneficiary_reward")] - disable_beneficiary_reward: false, - } - } -} - -/// The block environment. -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct BlockEnv { - /// The number of ancestor blocks of this block (block height). - pub number: U256, - /// Coinbase or miner or address that created and signed the block. - /// - /// This is the receiver address of all the gas spent in the block. - pub coinbase: Address, - - /// The timestamp of the block in seconds since the UNIX epoch. - pub timestamp: U256, - /// The gas limit of the block. - pub gas_limit: U256, - /// The base fee per gas, added in the London upgrade with [EIP-1559]. - /// - /// [EIP-1559]: https://eips.ethereum.org/EIPS/eip-1559 - pub basefee: U256, - /// The difficulty of the block. - /// - /// Unused after the Paris (AKA the merge) upgrade, and replaced by `prevrandao`. - pub difficulty: U256, - /// The output of the randomness beacon provided by the beacon chain. - /// - /// Replaces `difficulty` after the Paris (AKA the merge) upgrade with [EIP-4399]. - /// - /// NOTE: `prevrandao` can be found in a block in place of `mix_hash`. - /// - /// [EIP-4399]: https://eips.ethereum.org/EIPS/eip-4399 - pub prevrandao: Option, - /// Excess blob gas and blob gasprice. - /// See also [`crate::calc_excess_blob_gas`] - /// and [`calc_blob_gasprice`]. - /// - /// Incorporated as part of the Cancun upgrade via [EIP-4844]. - /// - /// [EIP-4844]: https://eips.ethereum.org/EIPS/eip-4844 - pub blob_excess_gas_and_price: Option, -} - -impl BlockEnv { - /// Takes `blob_excess_gas` saves it inside env - /// and calculates `blob_fee` with [`BlobExcessGasAndPrice`]. - pub fn set_blob_excess_gas_and_price(&mut self, excess_blob_gas: u64) { - self.blob_excess_gas_and_price = Some(BlobExcessGasAndPrice::new(excess_blob_gas)); - } - /// See [EIP-4844] and [`crate::calc_blob_gasprice`]. - /// - /// Returns `None` if `Cancun` is not enabled. This is enforced in [`Env::validate_block_env`]. - /// - /// [EIP-4844]: https://eips.ethereum.org/EIPS/eip-4844 - #[inline] - pub fn get_blob_gasprice(&self) -> Option { - self.blob_excess_gas_and_price - .as_ref() - .map(|a| a.blob_gasprice) - } - - /// Return `blob_excess_gas` header field. See [EIP-4844]. - /// - /// Returns `None` if `Cancun` is not enabled. This is enforced in [`Env::validate_block_env`]. - /// - /// [EIP-4844]: https://eips.ethereum.org/EIPS/eip-4844 - #[inline] - pub fn get_blob_excess_gas(&self) -> Option { - self.blob_excess_gas_and_price - .as_ref() - .map(|a| a.excess_blob_gas) - } - - /// Clears environment and resets fields to default values. - #[inline] - pub fn clear(&mut self) { - *self = Self::default(); - } -} - -impl Default for BlockEnv { - fn default() -> Self { - Self { - number: U256::ZERO, - coinbase: Address::ZERO, - timestamp: U256::from(1), - gas_limit: U256::MAX, - basefee: U256::ZERO, - difficulty: U256::ZERO, - prevrandao: Some(B256::ZERO), - blob_excess_gas_and_price: Some(BlobExcessGasAndPrice::new(0)), - } - } -} - -/// The transaction environment. -#[derive(Clone, Debug, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct TxEnv { - /// Caller aka Author aka transaction signer. - pub caller: Address, - /// The gas limit of the transaction. - pub gas_limit: u64, - /// The gas price of the transaction. - pub gas_price: U256, - /// The destination of the transaction. - pub transact_to: TransactTo, - /// The value sent to `transact_to`. - pub value: U256, - /// The data of the transaction. - pub data: Bytes, - /// The nonce of the transaction. - /// - /// Caution: If set to `None`, then nonce validation against the account's nonce is skipped: [InvalidTransaction::NonceTooHigh] and [InvalidTransaction::NonceTooLow] - pub nonce: Option, - - /// The chain ID of the transaction. If set to `None`, no checks are performed. - /// - /// Incorporated as part of the Spurious Dragon upgrade via [EIP-155]. - /// - /// [EIP-155]: https://eips.ethereum.org/EIPS/eip-155 - pub chain_id: Option, - - /// A list of addresses and storage keys that the transaction plans to access. - /// - /// Added in [EIP-2930]. - /// - /// [EIP-2930]: https://eips.ethereum.org/EIPS/eip-2930 - pub access_list: Vec<(Address, Vec)>, - - /// The priority fee per gas. - /// - /// Incorporated as part of the London upgrade via [EIP-1559]. - /// - /// [EIP-1559]: https://eips.ethereum.org/EIPS/eip-1559 - pub gas_priority_fee: Option, - - /// The list of blob versioned hashes. Per EIP there should be at least - /// one blob present if [`Self::max_fee_per_blob_gas`] is `Some`. - /// - /// Incorporated as part of the Cancun upgrade via [EIP-4844]. - /// - /// [EIP-4844]: https://eips.ethereum.org/EIPS/eip-4844 - pub blob_hashes: Vec, - - /// The max fee per blob gas. - /// - /// Incorporated as part of the Cancun upgrade via [EIP-4844]. - /// - /// [EIP-4844]: https://eips.ethereum.org/EIPS/eip-4844 - pub max_fee_per_blob_gas: Option, - - #[cfg_attr(feature = "serde", serde(flatten))] - #[cfg(feature = "optimism")] - /// Optimism fields. - pub optimism: OptimismFields, -} - -pub enum TxType { - Legacy, - Eip1559, - BlobTx, - EofCreate, -} - -impl TxEnv { - /// See [EIP-4844], [`Env::calc_data_fee`], and [`Env::calc_max_data_fee`]. - /// - /// [EIP-4844]: https://eips.ethereum.org/EIPS/eip-4844 - #[inline] - pub fn get_total_blob_gas(&self) -> u64 { - GAS_PER_BLOB * self.blob_hashes.len() as u64 - } - - /// Clears environment and resets fields to default values. - #[inline] - pub fn clear(&mut self) { - *self = Self::default(); - } -} - -impl Default for TxEnv { - fn default() -> Self { - Self { - caller: Address::ZERO, - gas_limit: u64::MAX, - gas_price: U256::ZERO, - gas_priority_fee: None, - transact_to: TransactTo::Call(Address::ZERO), // will do nothing - value: U256::ZERO, - data: Bytes::new(), - chain_id: None, - nonce: None, - access_list: Vec::new(), - blob_hashes: Vec::new(), - max_fee_per_blob_gas: None, - #[cfg(feature = "optimism")] - optimism: OptimismFields::default(), - } - } -} - -/// Structure holding block blob excess gas and it calculates blob fee. -/// -/// Incorporated as part of the Cancun upgrade via [EIP-4844]. -/// -/// [EIP-4844]: https://eips.ethereum.org/EIPS/eip-4844 -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct BlobExcessGasAndPrice { - /// The excess blob gas of the block. - pub excess_blob_gas: u64, - /// The calculated blob gas price based on the `excess_blob_gas`, See [calc_blob_gasprice] - pub blob_gasprice: u128, -} - -impl BlobExcessGasAndPrice { - /// Creates a new instance by calculating the blob gas price with [`calc_blob_gasprice`]. - pub fn new(excess_blob_gas: u64) -> Self { - let blob_gasprice = calc_blob_gasprice(excess_blob_gas); - Self { - excess_blob_gas, - blob_gasprice, - } - } -} - -/// Additional [TxEnv] fields for optimism. -#[cfg(feature = "optimism")] -#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct OptimismFields { - /// The source hash is used to make sure that deposit transactions do - /// not have identical hashes. - /// - /// L1 originated deposit transaction source hashes are computed using - /// the hash of the l1 block hash and the l1 log index. - /// L1 attributes deposit source hashes are computed with the l1 block - /// hash and the sequence number = l2 block number - l2 epoch start - /// block number. - /// - /// These two deposit transaction sources specify a domain in the outer - /// hash so there are no collisions. - pub source_hash: Option, - /// The amount to increase the balance of the `from` account as part of - /// a deposit transaction. This is unconditional and is applied to the - /// `from` account even if the deposit transaction fails since - /// the deposit is pre-paid on L1. - pub mint: Option, - /// Whether or not the transaction is a system transaction. - pub is_system_transaction: Option, - /// An enveloped EIP-2718 typed transaction. This is used - /// to compute the L1 tx cost using the L1 block info, as - /// opposed to requiring downstream apps to compute the cost - /// externally. - /// This field is optional to allow the [TxEnv] to be constructed - /// for non-optimism chains when the `optimism` feature is enabled, - /// but the [CfgEnv] `optimism` field is set to false. - pub enveloped_tx: Option, -} - -/// Transaction destination. -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum TransactTo { - /// Simple call to an address. - Call(Address), - /// Contract creation. - Create, -} - -impl TransactTo { - /// Calls the given address. - #[inline] - pub fn call(address: Address) -> Self { - Self::Call(address) - } - - /// Creates a contract. - #[inline] - pub fn create() -> Self { - Self::Create - } - /// Returns `true` if the transaction is `Call`. - #[inline] - pub fn is_call(&self) -> bool { - matches!(self, Self::Call(_)) - } - - /// Returns `true` if the transaction is `Create` or `Create2`. - #[inline] - pub fn is_create(&self) -> bool { - matches!(self, Self::Create) - } -} - -/// Create scheme. -#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum CreateScheme { - /// Legacy create scheme of `CREATE`. - Create, - /// Create scheme of `CREATE2`. - Create2 { - /// Salt. - salt: U256, - }, -} - -/// What bytecode analysis to perform. -#[derive(Clone, Default, Debug, Eq, PartialEq, Hash)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum AnalysisKind { - /// Do not perform bytecode analysis. - Raw, - /// Perform bytecode analysis. - #[default] - Analyse, -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_validate_tx_chain_id() { - let mut env = Env::default(); - env.tx.chain_id = Some(1); - env.cfg.chain_id = 2; - assert_eq!( - env.validate_tx::(), - Err(InvalidTransaction::InvalidChainId) - ); - } - - #[test] - fn test_validate_tx_access_list() { - let mut env = Env::default(); - env.tx.access_list = vec![(Address::ZERO, vec![])]; - assert_eq!( - env.validate_tx::(), - Err(InvalidTransaction::AccessListNotSupported) - ); - } -} diff --git a/crates/primitives/src/env/handler_cfg.rs b/crates/primitives/src/env/handler_cfg.rs deleted file mode 100644 index f57a3e8c99..0000000000 --- a/crates/primitives/src/env/handler_cfg.rs +++ /dev/null @@ -1,159 +0,0 @@ -use super::{BlockEnv, CfgEnv, Env, SpecId, TxEnv}; -use core::ops::{Deref, DerefMut}; -use std::boxed::Box; - -/// Handler configuration fields. It is used to configure the handler. -/// It contains specification id and the Optimism related field if -/// optimism feature is enabled. -#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] -pub struct HandlerCfg { - /// Specification identification. - pub spec_id: SpecId, - /// Optimism related field, it will append the Optimism handle register to the EVM. - #[cfg(feature = "optimism")] - pub is_optimism: bool, -} - -impl Default for HandlerCfg { - fn default() -> Self { - Self::new(SpecId::default()) - } -} - -impl HandlerCfg { - /// Creates new `HandlerCfg` instance. - pub fn new(spec_id: SpecId) -> Self { - cfg_if::cfg_if! { - if #[cfg(all(feature = "optimism-default-handler", - not(feature = "negate-optimism-default-handler")))] { - let is_optimism = true; - } else if #[cfg(feature = "optimism")] { - let is_optimism = false; - } - } - Self { - spec_id, - #[cfg(feature = "optimism")] - is_optimism, - } - } - - /// Creates new `HandlerCfg` instance with the optimism feature. - #[cfg(feature = "optimism")] - pub fn new_with_optimism(spec_id: SpecId, is_optimism: bool) -> Self { - Self { - spec_id, - is_optimism, - } - } - - /// Returns `true` if the optimism feature is enabled and flag is set to `true`. - pub fn is_optimism(&self) -> bool { - cfg_if::cfg_if! { - if #[cfg(feature = "optimism")] { - self.is_optimism - } else { - false - } - } - } -} - -/// Configuration environment with the chain spec id. -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct CfgEnvWithHandlerCfg { - /// Configuration environment. - pub cfg_env: CfgEnv, - /// Handler configuration fields. - pub handler_cfg: HandlerCfg, -} - -impl CfgEnvWithHandlerCfg { - /// Returns new instance of `CfgEnvWithHandlerCfg` with the handler configuration. - pub fn new(cfg_env: CfgEnv, handler_cfg: HandlerCfg) -> Self { - Self { - cfg_env, - handler_cfg, - } - } - - /// Returns new `CfgEnvWithHandlerCfg` instance with the chain spec id. - /// - /// is_optimism will be set to default value depending on `optimism-default-handler` feature. - pub fn new_with_spec_id(cfg_env: CfgEnv, spec_id: SpecId) -> Self { - Self::new(cfg_env, HandlerCfg::new(spec_id)) - } - - /// Enables the optimism feature. - #[cfg(feature = "optimism")] - pub fn enable_optimism(&mut self) { - self.handler_cfg.is_optimism = true; - } -} - -impl DerefMut for CfgEnvWithHandlerCfg { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.cfg_env - } -} - -impl Deref for CfgEnvWithHandlerCfg { - type Target = CfgEnv; - - fn deref(&self) -> &Self::Target { - &self.cfg_env - } -} - -/// Evm environment with the chain spec id. -#[derive(Clone, Debug, Default, Eq, PartialEq)] -pub struct EnvWithHandlerCfg { - /// Evm enironment. - pub env: Box, - /// Handler configuration fields. - pub handler_cfg: HandlerCfg, -} - -impl EnvWithHandlerCfg { - /// Returns new `EnvWithHandlerCfg` instance. - pub fn new(env: Box, handler_cfg: HandlerCfg) -> Self { - Self { env, handler_cfg } - } - - /// Returns new `EnvWithHandlerCfg` instance with the chain spec id. - /// - /// is_optimism will be set to default value depending on `optimism-default-handler` feature. - pub fn new_with_spec_id(env: Box, spec_id: SpecId) -> Self { - Self::new(env, HandlerCfg::new(spec_id)) - } - - /// Takes `CfgEnvWithHandlerCfg` and returns new `EnvWithHandlerCfg` instance. - pub fn new_with_cfg_env(cfg: CfgEnvWithHandlerCfg, block: BlockEnv, tx: TxEnv) -> Self { - Self::new(Env::boxed(cfg.cfg_env, block, tx), cfg.handler_cfg) - } - - /// Returns the specification id. - pub const fn spec_id(&self) -> SpecId { - self.handler_cfg.spec_id - } - - /// Enables the optimism handle register. - #[cfg(feature = "optimism")] - pub fn enable_optimism(&mut self) { - self.handler_cfg.is_optimism = true; - } -} - -impl DerefMut for EnvWithHandlerCfg { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.env - } -} - -impl Deref for EnvWithHandlerCfg { - type Target = Env; - - fn deref(&self) -> &Self::Target { - &self.env - } -} diff --git a/crates/primitives/src/hardfork.rs b/crates/primitives/src/hardfork.rs new file mode 100644 index 0000000000..0e2862602c --- /dev/null +++ b/crates/primitives/src/hardfork.rs @@ -0,0 +1,205 @@ +#![allow(non_camel_case_types)] +// enumn has missing docs. Should be replaced in the future https://github.com/bluealloy/revm/issues/2402 +#![allow(missing_docs)] + +use core::str::FromStr; +pub use num_enum::TryFromPrimitive; +pub use std::string::{String, ToString}; +pub use SpecId::*; + +/// Specification IDs and their activation block +/// +/// Information was obtained from the [Ethereum Execution Specifications](https://github.com/ethereum/execution-specs). +#[repr(u8)] +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, TryFromPrimitive)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub enum SpecId { + /// Frontier hard fork + /// Activated at block 0 + FRONTIER = 0, + /// Frontier Thawing hard fork + /// Activated at block 200000 + FRONTIER_THAWING, + /// Homestead hard fork + /// Activated at block 1150000 + HOMESTEAD, + /// DAO Fork hard fork + /// Activated at block 1920000 + DAO_FORK, + /// Tangerine Whistle hard fork + /// Activated at block 2463000 + TANGERINE, + /// Spurious Dragon hard fork + /// Activated at block 2675000 + SPURIOUS_DRAGON, + /// Byzantium hard fork + /// Activated at block 4370000 + BYZANTIUM, + /// Constantinople hard fork + /// Activated at block 7280000 is overwritten with PETERSBURG + CONSTANTINOPLE, + /// Petersburg hard fork + /// Activated at block 7280000 + PETERSBURG, + /// Istanbul hard fork + /// Activated at block 9069000 + ISTANBUL, + /// Muir Glacier hard fork + /// Activated at block 9200000 + MUIR_GLACIER, + /// Berlin hard fork + /// Activated at block 12244000 + BERLIN, + /// London hard fork + /// Activated at block 12965000 + LONDON, + /// Arrow Glacier hard fork + /// Activated at block 13773000 + ARROW_GLACIER, + /// Gray Glacier hard fork + /// Activated at block 15050000 + GRAY_GLACIER, + /// Paris/Merge hard fork + /// Activated at block 15537394 (TTD: 58750000000000000000000) + MERGE, + /// Shanghai hard fork + /// Activated at block 17034870 (Timestamp: 1681338455) + SHANGHAI, + /// Cancun hard fork + /// Activated at block 19426587 (Timestamp: 1710338135) + CANCUN, + /// Prague hard fork + /// Activated at block 22431084 (Timestamp: 1746612311) + #[default] + PRAGUE, + /// Osaka hard fork + /// Activated at block TBD + OSAKA, +} + +impl SpecId { + /// Returns the [`SpecId`] for the given [`u8`]. + #[inline] + pub fn try_from_u8(spec_id: u8) -> Option { + Self::try_from(spec_id).ok() + } + + /// Returns `true` if the given specification ID is enabled in this spec. + #[inline] + pub const fn is_enabled_in(self, other: Self) -> bool { + self as u8 >= other as u8 + } +} + +/// String identifiers for hardforks. +pub mod name { + /// String identifier for the Frontier hardfork + pub const FRONTIER: &str = "Frontier"; + /// String identifier for the Frontier Thawing hardfork + pub const FRONTIER_THAWING: &str = "Frontier Thawing"; + /// String identifier for the Homestead hardfork + pub const HOMESTEAD: &str = "Homestead"; + /// String identifier for the DAO Fork hardfork + pub const DAO_FORK: &str = "DAO Fork"; + /// String identifier for the Tangerine Whistle hardfork + pub const TANGERINE: &str = "Tangerine"; + /// String identifier for the Spurious Dragon hardfork + pub const SPURIOUS_DRAGON: &str = "Spurious"; + /// String identifier for the Byzantium hardfork + pub const BYZANTIUM: &str = "Byzantium"; + /// String identifier for the Constantinople hardfork + pub const CONSTANTINOPLE: &str = "Constantinople"; + /// String identifier for the Petersburg hardfork + pub const PETERSBURG: &str = "Petersburg"; + /// String identifier for the Istanbul hardfork + pub const ISTANBUL: &str = "Istanbul"; + /// String identifier for the Muir Glacier hardfork + pub const MUIR_GLACIER: &str = "MuirGlacier"; + /// String identifier for the Berlin hardfork + pub const BERLIN: &str = "Berlin"; + /// String identifier for the London hardfork + pub const LONDON: &str = "London"; + /// String identifier for the Arrow Glacier hardfork + pub const ARROW_GLACIER: &str = "Arrow Glacier"; + /// String identifier for the Gray Glacier hardfork + pub const GRAY_GLACIER: &str = "Gray Glacier"; + /// String identifier for the Paris/Merge hardfork + pub const MERGE: &str = "Merge"; + /// String identifier for the Shanghai hardfork + pub const SHANGHAI: &str = "Shanghai"; + /// String identifier for the Cancun hardfork + pub const CANCUN: &str = "Cancun"; + /// String identifier for the Prague hardfork + pub const PRAGUE: &str = "Prague"; + /// String identifier for the Osaka hardfork + pub const OSAKA: &str = "Osaka"; + /// String identifier for the latest hardfork + pub const LATEST: &str = "Latest"; +} + +/// Error type for unknown hardfork names. Returned by [`SpecId::from_str`]. +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct UnknownHardfork; + +impl FromStr for SpecId { + type Err = UnknownHardfork; + + fn from_str(s: &str) -> Result { + match s { + name::FRONTIER => Ok(Self::FRONTIER), + name::FRONTIER_THAWING => Ok(Self::FRONTIER_THAWING), + name::HOMESTEAD => Ok(Self::HOMESTEAD), + name::DAO_FORK => Ok(Self::DAO_FORK), + name::TANGERINE => Ok(Self::TANGERINE), + name::SPURIOUS_DRAGON => Ok(Self::SPURIOUS_DRAGON), + name::BYZANTIUM => Ok(Self::BYZANTIUM), + name::CONSTANTINOPLE => Ok(Self::CONSTANTINOPLE), + name::PETERSBURG => Ok(Self::PETERSBURG), + name::ISTANBUL => Ok(Self::ISTANBUL), + name::MUIR_GLACIER => Ok(Self::MUIR_GLACIER), + name::BERLIN => Ok(Self::BERLIN), + name::LONDON => Ok(Self::LONDON), + name::ARROW_GLACIER => Ok(Self::ARROW_GLACIER), + name::GRAY_GLACIER => Ok(Self::GRAY_GLACIER), + name::MERGE => Ok(Self::MERGE), + name::SHANGHAI => Ok(Self::SHANGHAI), + name::CANCUN => Ok(Self::CANCUN), + name::PRAGUE => Ok(Self::PRAGUE), + name::OSAKA => Ok(Self::OSAKA), + _ => Err(UnknownHardfork), + } + } +} + +impl From for &'static str { + fn from(spec_id: SpecId) -> Self { + match spec_id { + SpecId::FRONTIER => name::FRONTIER, + SpecId::FRONTIER_THAWING => name::FRONTIER_THAWING, + SpecId::HOMESTEAD => name::HOMESTEAD, + SpecId::DAO_FORK => name::DAO_FORK, + SpecId::TANGERINE => name::TANGERINE, + SpecId::SPURIOUS_DRAGON => name::SPURIOUS_DRAGON, + SpecId::BYZANTIUM => name::BYZANTIUM, + SpecId::CONSTANTINOPLE => name::CONSTANTINOPLE, + SpecId::PETERSBURG => name::PETERSBURG, + SpecId::ISTANBUL => name::ISTANBUL, + SpecId::MUIR_GLACIER => name::MUIR_GLACIER, + SpecId::BERLIN => name::BERLIN, + SpecId::LONDON => name::LONDON, + SpecId::ARROW_GLACIER => name::ARROW_GLACIER, + SpecId::GRAY_GLACIER => name::GRAY_GLACIER, + SpecId::MERGE => name::MERGE, + SpecId::SHANGHAI => name::SHANGHAI, + SpecId::CANCUN => name::CANCUN, + SpecId::PRAGUE => name::PRAGUE, + SpecId::OSAKA => name::OSAKA, + } + } +} + +impl core::fmt::Display for SpecId { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{}", <&'static str>::from(*self)) + } +} diff --git a/crates/primitives/src/kzg.rs b/crates/primitives/src/kzg.rs deleted file mode 100644 index 8d37463f0c..0000000000 --- a/crates/primitives/src/kzg.rs +++ /dev/null @@ -1,9 +0,0 @@ -mod env_settings; -mod trusted_setup_points; - -pub use c_kzg::KzgSettings; -pub use env_settings::EnvKzgSettings; -pub use trusted_setup_points::{ - parse_kzg_trusted_setup, G1Points, G2Points, KzgErrors, BYTES_PER_G1_POINT, BYTES_PER_G2_POINT, - G1_POINTS, G2_POINTS, NUM_G1_POINTS, NUM_G2_POINTS, -}; diff --git a/crates/primitives/src/kzg/env_settings.rs b/crates/primitives/src/kzg/env_settings.rs deleted file mode 100644 index 849ec3c463..0000000000 --- a/crates/primitives/src/kzg/env_settings.rs +++ /dev/null @@ -1,59 +0,0 @@ -use super::{ - trusted_setup_points::{G1_POINTS, G2_POINTS}, - KzgSettings, -}; -use core::hash::{Hash, Hasher}; -use once_cell::race::OnceBox; -use std::{boxed::Box, sync::Arc}; - -/// KZG Settings that allow us to specify a custom trusted setup. -/// or use hardcoded default settings. -#[derive(Debug, Clone, Default, Eq)] -pub enum EnvKzgSettings { - /// Default mainnet trusted setup - #[default] - Default, - /// Custom trusted setup. - Custom(Arc), -} - -// Implement PartialEq and Hash manually because `c_kzg::KzgSettings` does not implement them -impl PartialEq for EnvKzgSettings { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (Self::Default, Self::Default) => true, - (Self::Custom(a), Self::Custom(b)) => Arc::ptr_eq(a, b), - _ => false, - } - } -} - -impl Hash for EnvKzgSettings { - fn hash(&self, state: &mut H) { - core::mem::discriminant(self).hash(state); - match self { - Self::Default => {} - Self::Custom(settings) => Arc::as_ptr(settings).hash(state), - } - } -} - -impl EnvKzgSettings { - /// Return set KZG settings. - /// - /// In will initialize the default settings if it is not already loaded. - pub fn get(&self) -> &KzgSettings { - match self { - Self::Default => { - static DEFAULT: OnceBox = OnceBox::new(); - DEFAULT.get_or_init(|| { - let settings = - KzgSettings::load_trusted_setup(G1_POINTS.as_ref(), G2_POINTS.as_ref()) - .expect("failed to load default trusted setup"); - Box::new(settings) - }) - } - Self::Custom(settings) => settings, - } - } -} diff --git a/crates/primitives/src/kzg/g1_points.bin b/crates/primitives/src/kzg/g1_points.bin deleted file mode 100644 index 2ac35953ab..0000000000 Binary files a/crates/primitives/src/kzg/g1_points.bin and /dev/null differ diff --git a/crates/primitives/src/kzg/g2_points.bin b/crates/primitives/src/kzg/g2_points.bin deleted file mode 100644 index ca5625282b..0000000000 Binary files a/crates/primitives/src/kzg/g2_points.bin and /dev/null differ diff --git a/crates/primitives/src/kzg/trusted_setup.txt b/crates/primitives/src/kzg/trusted_setup.txt deleted file mode 100644 index d2519656fb..0000000000 --- a/crates/primitives/src/kzg/trusted_setup.txt +++ /dev/null @@ -1,4163 +0,0 @@ -4096 -65 -a0413c0dcafec6dbc9f47d66785cf1e8c981044f7d13cfe3e4fcbb71b5408dfde6312493cb3c1d30516cb3ca88c03654 -8b997fb25730d661918371bb41f2a6e899cac23f04fc5365800b75433c0a953250e15e7a98fb5ca5cc56a8cd34c20c57 -83302852db89424d5699f3f157e79e91dc1380f8d5895c5a772bb4ea3a5928e7c26c07db6775203ce33e62a114adaa99 -a759c48b7e4a685e735c01e5aa6ef9c248705001f470f9ad856cd87806983e917a8742a3bd5ee27db8d76080269b7c83 -967f8dc45ebc3be14c8705f43249a30ff48e96205fb02ae28daeab47b72eb3f45df0625928582aa1eb4368381c33e127 -a418eb1e9fb84cb32b370610f56f3cb470706a40ac5a47c411c464299c45c91f25b63ae3fcd623172aa0f273c0526c13 -8f44e3f0387293bc7931e978165abbaed08f53acd72a0a23ac85f6da0091196b886233bcee5b4a194db02f3d5a9b3f78 -97173434b336be73c89412a6d70d416e170ea355bf1956c32d464090b107c090ef2d4e1a467a5632fbc332eeb679bf2d -a24052ad8d55ad04bc5d951f78e14213435681594110fd18173482609d5019105b8045182d53ffce4fc29fc8810516c1 -b950768136b260277590b5bec3f56bbc2f7a8bc383d44ce8600e85bf8cf19f479898bcc999d96dfbd2001ede01d94949 -92ab8077871037bd3b57b95cbb9fb10eb11efde9191690dcac655356986fd02841d8fdb25396faa0feadfe3f50baf56d -a79b096dff98038ac30f91112dd14b78f8ad428268af36d20c292e2b3b6d9ed4fb28480bb04e465071cc67d05786b6d1 -b9ff71461328f370ce68bf591aa7fb13027044f42a575517f3319e2be4aa4843fa281e756d0aa5645428d6dfa857cef2 -8d765808c00b3543ff182e2d159c38ae174b12d1314da88ea08e13bd9d1c37184cb515e6bf6420531b5d41767987d7ce -b8c9a837d20c3b53e6f578e4a257bb7ef8fc43178614ec2a154915b267ad2be135981d01ed2ee1b5fbd9d9bb27f0800a -a9773d92cf23f65f98ef68f6cf95c72b53d0683af2f9bf886bb9036e4a38184b1131b26fd24397910b494fbef856f3aa -b41ebe38962d112da4a01bf101cb248d808fbd50aaf749fc7c151cf332032eb3e3bdbd716db899724b734d392f26c412 -90fbb030167fb47dcc13d604a726c0339418567c1d287d1d87423fa0cb92eec3455fbb46bcbe2e697144a2d3972142e4 -b11d298bd167464b35fb923520d14832bd9ed50ed841bf6d7618424fd6f3699190af21759e351b89142d355952149da1 -8bc36066f69dc89f7c4d1e58d67497675050c6aa002244cebd9fc957ec5e364c46bab4735ea3db02b73b3ca43c96e019 -ab7ab92c5d4d773068e485aa5831941ebd63db7118674ca38089635f3b4186833af2455a6fb9ed2b745df53b3ce96727 -af191ca3089892cb943cd97cf11a51f38e38bd9be50844a4e8da99f27e305e876f9ed4ab0628e8ae3939066b7d34a15f -a3204c1747feabc2c11339a542195e7cb6628fd3964f846e71e2e3f2d6bb379a5e51700682ea1844eba12756adb13216 -903a29883846b7c50c15968b20e30c471aeac07b872c40a4d19eb1a42da18b649d5bbfde4b4cf6225d215a461b0deb6d -8e6e9c15ffbf1e16e5865a5fef7ed751dc81957a9757b535cb38b649e1098cda25d42381dc4f776778573cdf90c3e6e0 -a8f6dd26100b512a8c96c52e00715c4b2cb9ac457f17aed8ffe1cf1ea524068fe5a1ddf218149845fc1417b789ecfc98 -a5b0ffc819451ea639cfd1c18cbc9365cc79368d3b2e736c0ae54eba2f0801e6eb0ee14a5f373f4a70ca463bdb696c09 -879f91ccd56a1b9736fbfd20d8747354da743fb121f0e308a0d298ff0d9344431890e41da66b5009af3f442c636b4f43 -81bf3a2d9755e206b515a508ac4d1109bf933c282a46a4ae4a1b4cb4a94e1d23642fad6bd452428845afa155742ade7e -8de778d4742f945df40004964e165592f9c6b1946263adcdd5a88b00244bda46c7bb49098c8eb6b3d97a0dd46148a8ca -b7a57b21d13121907ee28c5c1f80ee2e3e83a3135a8101e933cf57171209a96173ff5037f5af606e9fd6d066de6ed693 -b0877d1963fd9200414a38753dffd9f23a10eb3198912790d7eddbc9f6b477019d52ddd4ebdcb9f60818db076938a5a9 -88da2d7a6611bc16adc55fc1c377480c828aba4496c645e3efe0e1a67f333c05a0307f7f1d2df8ac013602c655c6e209 -95719eb02e8a9dede1a888c656a778b1c69b7716fbe3d1538fe8afd4a1bc972183c7d32aa7d6073376f7701df80116d8 -8e8a1ca971f2444b35af3376e85dccda3abb8e8e11d095d0a4c37628dfe5d3e043a377c3de68289ef142e4308e9941a0 -b720caaff02f6d798ac84c4f527203e823ff685869e3943c979e388e1c34c3f77f5c242c6daa7e3b30e511aab917b866 -86040d55809afeec10e315d1ad950d269d37cfee8c144cd8dd4126459e3b15a53b3e68df5981df3c2346d23c7b4baaf4 -82d8cabf13ab853db0377504f0aec00dba3a5cd3119787e8ad378ddf2c40b022ecfc67c642b7acc8c1e3dd03ab50993e -b8d873927936719d2484cd03a6687d65697e17dcf4f0d5aed6f5e4750f52ef2133d4645894e7ebfc4ef6ce6788d404c8 -b1235594dbb15b674a419ff2b2deb644ad2a93791ca05af402823f87114483d6aa1689b7a9bea0f547ad12fe270e4344 -a53fda86571b0651f5affb74312551a082fffc0385cfd24c1d779985b72a5b1cf7c78b42b4f7e51e77055f8e5e915b00 -b579adcfd9c6ef916a5a999e77a0cb21d378c4ea67e13b7c58709d5da23a56c2e54218691fc4ac39a4a3d74f88cc31f7 -ab79e584011713e8a2f583e483a91a0c2a40771b77d91475825b5acbea82db4262132901cb3e4a108c46d7c9ee217a4e -a0fe58ea9eb982d7654c8aaf9366230578fc1362f6faae0594f8b9e659bcb405dff4aac0c7888bbe07f614ecf0d800a6 -867e50e74281f28ecd4925560e2e7a6f8911b135557b688254623acce0dbc41e23ac3e706a184a45d54c586edc416eb0 -89f81b61adda20ea9d0b387a36d0ab073dc7c7cbff518501962038be19867042f11fcc7ff78096e5d3b68c6d8dc04d9b -a58ee91bb556d43cf01f1398c5811f76dc0f11efdd569eed9ef178b3b0715e122060ec8f945b4dbf6eebfa2b90af6fa6 -ac460be540f4c840def2eef19fc754a9af34608d107cbadb53334cf194cc91138d53b9538fcd0ec970b5d4aa455b224a -b09b91f929de52c09d48ca0893be6eb44e2f5210a6c394689dc1f7729d4be4e11d0474b178e80cea8c2ac0d081f0e811 -8d37a442a76b06a02a4e64c2504aea72c8b9b020ab7bcc94580fe2b9603c7c50d7b1e9d70d2a7daea19c68667e8f8c31 -a9838d4c4e3f3a0075a952cf7dd623307ec633fcc81a7cf9e52e66c31780de33dbb3d74c320dc7f0a4b72f7a49949515 -a44766b6251af458fe4f5f9ed1e02950f35703520b8656f09fc42d9a2d38a700c11a7c8a0436ac2e5e9f053d0bb8ff91 -ad78d9481c840f5202546bea0d13c776826feb8b1b7c72e83d99a947622f0bf38a4208551c4c41beb1270d7792075457 -b619ffa8733b470039451e224b777845021e8dc1125f247a4ff2476cc774657d0ff9c5279da841fc1236047de9d81c60 -af760b0a30a1d6af3bc5cd6686f396bd41779aeeb6e0d70a09349bd5da17ca2e7965afc5c8ec22744198fbe3f02fb331 -a0cc209abdb768b589fcb7b376b6e1cac07743288c95a1cf1a0354b47f0cf91fca78a75c1fcafa6f5926d6c379116608 -864add673c89c41c754eeb3cd8dcff5cdde1d739fce65c30e474a082bb5d813cba6412e61154ce88fdb6c12c5d9be35b -b091443b0ce279327dc37cb484e9a5b69b257a714ce21895d67539172f95ffa326903747b64a3649e99aea7bb10d03f7 -a8c452b8c4ca8e0a61942a8e08e28f17fb0ef4c5b018b4e6d1a64038280afa2bf1169202f05f14af24a06ca72f448ccd -a23c24721d18bc48d5dcf70effcbef89a7ae24e67158d70ae1d8169ee75d9a051d34b14e9cf06488bac324fe58549f26 -92a730e30eb5f3231feb85f6720489dbb1afd42c43f05a1610c6b3c67bb949ec8fde507e924498f4ffc646f7b07d9123 -8dbe5abf4031ec9ba6bb06d1a47dd1121fb9e03b652804069250967fd5e9577d0039e233441b7f837a7c9d67ba18c28e -aa456bcfef6a21bb88181482b279df260297b3778e84594ebddbdf337e85d9e3d46ca1d0b516622fb0b103df8ec519b7 -a3b31ae621bd210a2b767e0e6f22eb28fe3c4943498a7e91753225426168b9a26da0e02f1dc5264da53a5ad240d9f51b -aa8d66857127e6e71874ce2202923385a7d2818b84cb73a6c42d71afe70972a70c6bdd2aad1a6e8c5e4ca728382a8ea8 -ac7e8e7a82f439127a5e40558d90d17990f8229852d21c13d753c2e97facf077cf59582b603984c3dd3faebd80aff4f5 -93a8bcf4159f455d1baa73d2ef2450dcd4100420de84169bbe28b8b7a5d1746273f870091a87a057e834f754f34204b1 -89d0ebb287c3613cdcae7f5acc43f17f09c0213fc40c074660120b755d664109ffb9902ed981ede79e018ddb0c845698 -a87ccbfad431406aadbee878d9cf7d91b13649d5f7e19938b7dfd32645a43b114eef64ff3a13201398bd9b0337832e5a -833c51d0d0048f70c3eefb4e70e4ff66d0809c41838e8d2c21c288dd3ae9d9dfaf26d1742bf4976dab83a2b381677011 -8bcd6b1c3b02fffead432e8b1680bad0a1ac5a712d4225e220690ee18df3e7406e2769e1f309e2e803b850bc96f0e768 -b61e3dbd88aaf4ff1401521781e2eea9ef8b66d1fac5387c83b1da9e65c2aa2a56c262dea9eceeb4ad86c90211672db0 -866d3090db944ecf190dd0651abf67659caafd31ae861bab9992c1e3915cb0952da7c561cc7e203560a610f48fae633b -a5e8971543c14274a8dc892b0be188c1b4fbc75c692ed29f166e0ea80874bc5520c2791342b7c1d2fb5dd454b03b8a5b -8f2f9fc50471bae9ea87487ebd1bc8576ef844cc42d606af5c4c0969670fdf2189afd643e4de3145864e7773d215f37f -b1bb0f2527db6d51f42b9224383c0f96048bbc03d469bf01fe1383173ef8b1cc9455d9dd8ba04d46057f46949bfc92b5 -aa7c99d906b4d7922296cfe2520473fc50137c03d68b7865c5bfb8adbc316b1034310ec4b5670c47295f4a80fb8d61e9 -a5d1da4d6aba555919df44cbaa8ff79378a1c9e2cfdfbf9d39c63a4a00f284c5a5724e28ecbc2d9dba27fe4ee5018bd5 -a8db53224f70af4d991b9aae4ffe92d2aa5b618ad9137784b55843e9f16cefbfd25ada355d308e9bbf55f6d2f7976fb3 -b6536c4232bb20e22af1a8bb12de76d5fec2ad9a3b48af1f38fa67e0f8504ef60f305a73d19385095bb6a9603fe29889 -87f7e371a1817a63d6838a8cf4ab3a8473d19ce0d4f40fd013c03d5ddd5f4985df2956531cc9f187928ef54c68f4f9a9 -ae13530b1dbc5e4dced9d909ea61286ec09e25c12f37a1ed2f309b0eb99863d236c3b25ed3484acc8c076ad2fa8cd430 -98928d850247c6f7606190e687d5c94a627550198dbdbea0161ef9515eacdb1a0f195cae3bb293112179082daccf8b35 -918528bb8e6a055ad4db6230d3a405e9e55866da15c4721f5ddd1f1f37962d4904aad7a419218fe6d906fe191a991806 -b71e31a06afe065773dd3f4a6e9ef81c3292e27a3b7fdfdd452d03e05af3b6dd654c355f7516b2a93553360c6681a73a -8870b83ab78a98820866f91ac643af9f3ff792a2b7fda34185a9456a63abdce42bfe8ad4dc67f08a6392f250d4062df4 -91eea1b668e52f7a7a5087fabf1cab803b0316f78d9fff469fbfde2162f660c250e4336a9eea4cb0450bd30ac067bc8b -8b74990946de7b72a92147ceac1bd9d55999a8b576e8df68639e40ed5dc2062cfcd727903133de482b6dca19d0aaed82 -8ebad537fece090ebbab662bdf2618e21ca30cf6329c50935e8346d1217dcbe3c1fe1ea28efca369c6003ce0a94703c1 -a8640479556fb59ebd1c40c5f368fbd960932fdbb782665e4a0e24e2bdb598fc0164ce8c0726d7759cfc59e60a62e182 -a9a52a6bf98ee4d749f6d38be2c60a6d54b64d5cbe4e67266633dc096cf28c97fe998596707d31968cbe2064b72256bf -847953c48a4ce6032780e9b39d0ed4384e0be202c2bbe2dfda3910f5d87aa5cd3c2ffbfcfae4dddce16d6ab657599b95 -b6f6e1485d3ec2a06abaecd23028b200b2e4a0096c16144d07403e1720ff8f9ba9d919016b5eb8dc5103880a7a77a1d3 -98dfc2065b1622f596dbe27131ea60bef7a193b12922cecb27f8c571404f483014f8014572e86ae2e341ab738e4887ef -acb0d205566bacc87bbe2e25d10793f63f7a1f27fd9e58f4f653ceae3ffeba511eaf658e068fad289eeb28f9edbeb35b -ae4411ed5b263673cee894c11fe4abc72a4bf642d94022a5c0f3369380fcdfc1c21e277f2902972252503f91ada3029a -ac4a7a27ba390a75d0a247d93d4a8ef1f0485f8d373a4af4e1139369ec274b91b3464d9738eeaceb19cd6f509e2f8262 -87379c3bf231fdafcf6472a79e9e55a938d851d4dd662ab6e0d95fd47a478ed99e2ad1e6e39be3c0fc4f6d996a7dd833 -81316904b035a8bcc2041199a789a2e6879486ba9fddcba0a82c745cc8dd8374a39e523b91792170cd30be7aa3005b85 -b8206809c6cd027ed019f472581b45f7e12288f89047928ba32b4856b6560ad30395830d71e5e30c556f6f182b1fe690 -88d76c028f534a62e019b4a52967bb8642ede6becfa3807be68fdd36d366fc84a4ac8dc176e80a68bc59eb62caf5dff9 -8c3b8be685b0f8aad131ee7544d0e12f223f08a6f8edaf464b385ac644e0ddc9eff7cc7cb5c1b50ab5d71ea0f41d2213 -8d91410e004f76c50fdc05784157b4d839cb5090022c629c7c97a5e0c3536eeafee17a527b54b1165c3cd81774bb54ce -b25c2863bc28ec5281ce800ddf91a7e1a53f4c6d5da1e6c86ef4616e93bcf55ed49e297216d01379f5c6e7b3c1e46728 -865f7b09ac3ca03f20be90c48f6975dd2588838c2536c7a3532a6aa5187ed0b709cd03d91ff4048061c10d0aa72b69ce -b3f7477c90c11596eb4f8bbf34adbcb832638c4ff3cdd090d4d477ee50472ac9ddaf5be9ad7eca3f148960d362bbd098 -8db35fd53fca04faecd1c76a8227160b3ab46ac1af070f2492445a19d8ff7c25bbaef6c9fa0c8c088444561e9f7e4eb2 -a478b6e9d058a2e01d2fc053b739092e113c23a6a2770a16afbef044a3709a9e32f425ace9ba7981325f02667c3f9609 -98caa6bd38916c08cf221722a675a4f7577f33452623de801d2b3429595f988090907a7e99960fff7c076d6d8e877b31 -b79aaaacefc49c3038a14d2ac468cfec8c2161e88bdae91798d63552cdbe39e0e02f9225717436b9b8a40a022c633c6e -845a31006c680ee6a0cc41d3dc6c0c95d833fcf426f2e7c573fa15b2c4c641fbd6fe5ebb0e23720cc3467d6ee1d80dc4 -a1bc287e272cf8b74dbf6405b3a5190883195806aa351f1dc8e525aa342283f0a35ff687e3b434324dedee74946dd185 -a4fd2dc8db75d3783a020856e2b3aa266dc6926e84f5c491ef739a3bddd46dc8e9e0fc1177937839ef1b18d062ffbb9e -acbf0d3c697f57c202bb8c5dc4f3fc341b8fc509a455d44bd86acc67cad2a04495d5537bcd3e98680185e8aa286f2587 -a5caf423a917352e1b8e844f5968a6da4fdeae467d10c6f4bbd82b5eea46a660b82d2f5440d3641c717b2c3c9ed0be52 -8a39d763c08b926599ab1233219c49c825368fad14d9afc7c0c039224d37c00d8743293fd21645bf0b91eaf579a99867 -b2b53a496def0ba06e80b28f36530fbe0fb5d70a601a2f10722e59abee529369c1ae8fd0f2db9184dd4a2519bb832d94 -a73980fcef053f1b60ebbb5d78ba6332a475e0b96a0c724741a3abf3b59dd344772527f07203cf4c9cb5155ebed81fa0 -a070d20acce42518ece322c9db096f16aed620303a39d8d5735a0df6e70fbeceb940e8d9f5cc38f3314b2240394ec47b -a50cf591f522f19ca337b73089557f75929d9f645f3e57d4f241e14cdd1ea3fb48d84bcf05e4f0377afbb789fbdb5d20 -82a5ffce451096aca8eeb0cd2ae9d83db3ed76da3f531a80d9a70a346359bf05d74863ce6a7c848522b526156a5e20cd -88e0e84d358cbb93755a906f329db1537c3894845f32b9b0b691c29cbb455373d9452fadd1e77e20a623f6eaf624de6f -aa07ac7b84a6d6838826e0b9e350d8ec75e398a52e9824e6b0da6ae4010e5943fec4f00239e96433f291fef9d1d1e609 -ac8887bf39366034bc63f6cc5db0c26fd27307cbc3d6cce47894a8a019c22dd51322fb5096edc018227edfafc053a8f6 -b7d26c26c5b33f77422191dca94977588ab1d4b9ce7d0e19c4a3b4cd1c25211b78c328dbf81e755e78cd7d1d622ad23e -99a676d5af49f0ba44047009298d8474cabf2d5bca1a76ba21eff7ee3c4691a102fdefea27bc948ccad8894a658abd02 -b0d09a91909ab3620c183bdf1d53d43d39eb750dc7a722c661c3de3a1a5d383ad221f71bae374f8a71867505958a3f76 -84681a883de8e4b93d68ac10e91899c2bbb815ce2de74bb48a11a6113b2a3f4df8aceabda1f5f67bc5aacac8c9da7221 -9470259957780fa9b43521fab3644f555f5343281c72582b56d2efd11991d897b3b481cafa48681c5aeb80c9663b68f7 -ab1b29f7ece686e6fa968a4815da1d64f3579fed3bc92e1f3e51cd13a3c076b6cf695ed269d373300a62463dc98a4234 -8ab415bfcd5f1061f7687597024c96dd9c7cb4942b5989379a7a3b5742f7d394337886317659cbeacaf030234a24f972 -b9b524aad924f9acc63d002d617488f31b0016e0f0548f050cada285ce7491b74a125621638f19e9c96eabb091d945be -8c4c373e79415061837dd0def4f28a2d5d74d21cb13a76c9049ad678ca40228405ab0c3941df49249847ecdefc1a5b78 -a8edf4710b5ab2929d3db6c1c0e3e242261bbaa8bcec56908ddadd7d2dad2dca9d6eb9de630b960b122ebeea41040421 -8d66bb3b50b9df8f373163629f9221b3d4b6980a05ea81dc3741bfe9519cf3ebba7ab98e98390bae475e8ede5821bd5c -8d3c21bae7f0cfb97c56952bb22084b58e7bb718890935b73103f33adf5e4d99cd262f929c6eeab96209814f0dbae50a -a5c66cfab3d9ebf733c4af24bebc97070e7989fe3c73e79ac85fb0e4d40ae44fb571e0fad4ad72560e13ed453900d14f -9362e6b50b43dbefbc3254471372297b5dcce809cd3b60bf74a1268ab68bdb50e46e462cbd78f0d6c056330e982846af -854630d08e3f0243d570cc2e856234cb4c1a158d9c1883bf028a76525aaa34be897fe918d5f6da9764a3735fa9ebd24a -8c7d246985469ff252c3f4df6c7c9196fc79f05c1c66a609d84725c78001d0837c7a7049394ba5cf7e863e2d58af8417 -ae050271e01b528925302e71903f785b782f7bf4e4e7a7f537140219bc352dc7540c657ed03d3a297ad36798ecdb98cd -8d2ae9179fcf2b0c69850554580b52c1f4a5bd865af5f3028f222f4acad9c1ad69a8ef6c7dc7b03715ee5c506b74325e -b8ef8de6ce6369a8851cd36db0ccf00a85077e816c14c4e601f533330af9e3acf0743a95d28962ed8bfcfc2520ef3cfe -a6ecad6fdfb851b40356a8b1060f38235407a0f2706e7b8bb4a13465ca3f81d4f5b99466ac2565c60af15f022d26732e -819ff14cdea3ab89d98e133cd2d0379361e2e2c67ad94eeddcdb9232efd509f51d12f4f03ebd4dd953bd262a886281f7 -8561cd0f7a6dbcddd83fcd7f472d7dbcba95b2d4fb98276f48fccf69f76d284e626d7e41314b633352df8e6333fd52a1 -b42557ccce32d9a894d538c48712cb3e212d06ac05cd5e0527ccd2db1078ee6ae399bf6a601ffdab1f5913d35fc0b20c -89b4008d767aad3c6f93c349d3b956e28307311a5b1cec237e8d74bb0dee7e972c24f347fd56afd915a2342bd7bc32f0 -877487384b207e53f5492f4e36c832c2227f92d1bb60542cfeb35e025a4a7afc2b885fae2528b33b40ab09510398f83e -8c411050b63c9053dd0cd81dacb48753c3d7f162028098e024d17cd6348482703a69df31ad6256e3d25a8bbf7783de39 -a8506b54a88d17ac10fb1b0d1fe4aa40eae7553a064863d7f6b52ccc4236dd4b82d01dca6ba87da9a239e3069ba879fb -b1a24caef9df64750c1350789bb8d8a0db0f39474a1c74ea9ba064b1516db6923f00af8d57c632d58844fb8786c3d47a -959d6e255f212b0708c58a2f75cb1fe932248c9d93424612c1b8d1e640149656059737e4db2139afd5556bcdacf3eda2 -84525af21a8d78748680b6535bbc9dc2f0cf9a1d1740d12f382f6ecb2e73811d6c1da2ad9956070b1a617c61fcff9fe5 -b74417d84597a485d0a8e1be07bf78f17ebb2e7b3521b748f73935b9afbbd82f34b710fb7749e7d4ab55b0c7f9de127d -a4a9aecb19a6bab167af96d8b9d9aa5308eab19e6bfb78f5a580f9bf89bdf250a7b52a09b75f715d651cb73febd08e84 -9777b30be2c5ffe7d29cc2803a562a32fb43b59d8c3f05a707ab60ec05b28293716230a7d264d7cd9dd358fc031cc13e -95dce7a3d4f23ac0050c510999f5fbf8042f771e8f8f94192e17bcbfa213470802ebdbe33a876cb621cf42e275cbfc8b -b0b963ebcbbee847ab8ae740478544350b3ac7e86887e4dfb2299ee5096247cd2b03c1de74c774d9bde94ae2ee2dcd59 -a4ab20bafa316030264e13f7ef5891a2c3b29ab62e1668fcb5881f50a9acac6adbe3d706c07e62f2539715db768f6c43 -901478a297669d608e406fe4989be75264b6c8be12169aa9e0ad5234f459ca377f78484ffd2099a2fe2db5e457826427 -88c76e5c250810c057004a03408b85cd918e0c8903dc55a0dd8bb9b4fc2b25c87f9b8cf5943eb19fbbe99d36490050c5 -91607322bbad4a4f03fc0012d0821eff5f8c516fda45d1ec1133bface6f858bf04b25547be24159cab931a7aa08344d4 -843203e07fce3c6c81f84bc6dc5fb5e9d1c50c8811ace522dc66e8658433a0ef9784c947e6a62c11bf705307ef05212e -91dd8813a5d6dddcda7b0f87f672b83198cd0959d8311b2b26fb1fae745185c01f796fbd03aad9db9b58482483fdadd8 -8d15911aacf76c8bcd7136e958febd6963104addcd751ce5c06b6c37213f9c4fb0ffd4e0d12c8e40c36d658999724bfd -8a36c5732d3f1b497ebe9250610605ee62a78eaa9e1a45f329d09aaa1061131cf1d9df00f3a7d0fe8ad614a1ff9caaae -a407d06affae03660881ce20dab5e2d2d6cddc23cd09b95502a9181c465e57597841144cb34d22889902aff23a76d049 -b5fd856d0578620a7e25674d9503be7d97a2222900e1b4738c1d81ff6483b144e19e46802e91161e246271f90270e6cf -91b7708869cdb5a7317f88c0312d103f8ce90be14fb4f219c2e074045a2a83636fdc3e69e862049fc7c1ef000e832541 -b64719cc5480709d1dae958f1d3082b32a43376da446c8f9f64cb02a301effc9c34d9102051733315a8179aed94d53cc -94347a9542ff9d18f7d9eaa2f4d9b832d0e535fe49d52aa2de08aa8192400eddabdb6444a2a78883e27c779eed7fdf5a -840ef44a733ff1376466698cd26f82cf56bb44811e196340467f932efa3ae1ef9958a0701b3b032f50fd9c1d2aed9ab5 -90ab3f6f67688888a31ffc2a882bb37adab32d1a4b278951a21646f90d03385fc976715fc639a785d015751171016f10 -b56f35d164c24b557dbcbc8a4bfa681ec916f8741ffcb27fb389c164f4e3ed2be325210ef5bdaeae7a172ca9599ab442 -a7921a5a80d7cf6ae81ba9ee05e0579b18c20cd2852762c89d6496aa4c8ca9d1ca2434a67b2c16d333ea8e382cdab1e3 -a506bcfbd7e7e5a92f68a1bd87d07ad5fe3b97aeee40af2bf2cae4efcd77fff03f872732c5b7883aa6584bee65d6f8cb -a8c46cff58931a1ce9cbe1501e1da90b174cddd6d50f3dfdfb759d1d4ad4673c0a8feed6c1f24c7af32865a7d6c984e5 -b45686265a83bff69e312c5149db7bb70ac3ec790dc92e392b54d9c85a656e2bf58596ce269f014a906eafc97461aa5f -8d4009a75ccb2f29f54a5f16684b93202c570d7a56ec1a8b20173269c5f7115894f210c26b41e8d54d4072de2d1c75d0 -aef8810af4fc676bf84a0d57b189760ddc3375c64e982539107422e3de2580b89bd27aa6da44e827b56db1b5555e4ee8 -888f0e1e4a34f48eb9a18ef4de334c27564d72f2cf8073e3d46d881853ac1424d79e88d8ddb251914890588937c8f711 -b64b0aa7b3a8f6e0d4b3499fe54e751b8c3e946377c0d5a6dbb677be23736b86a7e8a6be022411601dd75012012c3555 -8d57776f519f0dd912ea14f79fbab53a30624e102f9575c0bad08d2dc754e6be54f39b11278c290977d9b9c7c0e1e0ad -a018fc00d532ceb2e4de908a15606db9b6e0665dd77190e2338da7c87a1713e6b9b61554e7c1462f0f6d4934b960b15c -8c932be83ace46f65c78e145b384f58e41546dc0395270c1397874d88626fdeda395c8a289d602b4c312fe98c1311856 -89174838e21639d6bdd91a0621f04dc056907b88e305dd66e46a08f6d65f731dea72ae87ca5e3042d609e8de8de9aa26 -b7b7f508bb74f7a827ac8189daa855598ff1d96fa3a02394891fd105d8f0816224cd50ac4bf2ed1cf469ace516c48184 -b31877ad682583283baadd68dc1bebd83f5748b165aadd7fe9ef61a343773b88bcd3a022f36d6c92f339b7bfd72820a9 -b79d77260b25daf9126dab7a193df2d7d30542786fa1733ffaf6261734770275d3ca8bae1d9915d1181a78510b3439db -91894fb94cd4c1dd2ceaf9c53a7020c5799ba1217cf2d251ea5bc91ed26e1159dd758e98282ebe35a0395ef9f1ed15a0 -ab59895cdafd33934ceedfc3f0d5d89880482cba6c99a6db93245f9e41987efd76e0640e80aef31782c9a8c7a83fccec -aa22ea63654315e033e09d4d4432331904a6fc5fb1732557987846e3c564668ca67c60a324b4af01663a23af11a9ce4b -b53ba3ef342601467e1f71aa280e100fbabbd38518fa0193e0099505036ee517c1ac78e96e9baeb549bb6879bb698fb0 -943fd69fd656f37487cca3605dc7e5a215fddd811caf228595ec428751fc1de484a0cb84c667fe4d7c35599bfa0e5e34 -9353128b5ebe0dddc555093cf3e5942754f938173541033e8788d7331fafc56f68d9f97b4131e37963ab7f1c8946f5f1 -a76cd3c566691f65cfb86453b5b31dbaf3cab8f84fe1f795dd1e570784b9b01bdd5f0b3c1e233942b1b5838290e00598 -983d84b2e53ffa4ae7f3ba29ef2345247ea2377686b74a10479a0ef105ecf90427bf53b74c96dfa346d0f842b6ffb25b -92e0fe9063306894a2c6970c001781cff416c87e87cb5fbac927a3192655c3da4063e6fa93539f6ff58efac6adcc5514 -b00a81f03c2b8703acd4e2e4c21e06973aba696415d0ea1a648ace2b0ea19b242fede10e4f9d7dcd61c546ab878bc8f9 -b0d08d880f3b456a10bf65cff983f754f545c840c413aea90ce7101a66eb0a0b9b1549d6c4d57725315828607963f15a -90cb64d03534f913b411375cce88a9e8b1329ce67a9f89ca5df8a22b8c1c97707fec727dbcbb9737f20c4cf751359277 -8327c2d42590dfcdb78477fc18dcf71608686ad66c49bce64d7ee874668be7e1c17cc1042a754bbc77c9daf50b2dae07 -8532171ea13aa7e37178e51a6c775da469d2e26ec854eb16e60f3307db4acec110d2155832c202e9ba525fc99174e3b0 -83ca44b15393d021de2a511fa5511c5bd4e0ac7d67259dce5a5328f38a3cce9c3a269405959a2486016bc27bb140f9ff -b1d36e8ca812be545505c8214943b36cabee48112cf0de369957afa796d37f86bf7249d9f36e8e990f26f1076f292b13 -9803abf45be5271e2f3164c328d449efc4b8fc92dfc1225d38e09630909fe92e90a5c77618daa5f592d23fc3ad667094 -b268ad68c7bf432a01039cd889afae815c3e120f57930d463aece10af4fd330b5bd7d8869ef1bcf6b2e78e4229922edc -a4c91a0d6f16b1553264592b4cbbbf3ca5da32ab053ffbdd3dbb1aed1afb650fb6e0dc5274f71a51d7160856477228db -ad89d043c2f0f17806277ffdf3ecf007448e93968663f8a0b674254f36170447b7527d5906035e5e56f4146b89b5af56 -8b6964f757a72a22a642e4d69102951897e20c21449184e44717bd0681d75f7c5bfa5ee5397f6e53febf85a1810d6ed1 -b08f5cdaabec910856920cd6e836c830b863eb578423edf0b32529488f71fe8257d90aed4a127448204df498b6815d79 -af26bb3358be9d280d39b21d831bb53145c4527a642446073fee5a86215c4c89ff49a3877a7a549486262f6f57a0f476 -b4010b37ec4d7c2af20800e272539200a6b623ae4636ecbd0e619484f4ab9240d02bc5541ace3a3fb955dc0a3d774212 -82752ab52bdcc3cc2fc405cb05a2e694d3df4a3a68f2179ec0652536d067b43660b96f85f573f26fbd664a9ef899f650 -96d392dde067473a81faf2d1fea55b6429126b88b160e39b4210d31d0a82833ffd3a80e07d24d495aea2d96be7251547 -a76d8236d6671204d440c33ac5b8deb71fa389f6563d80e73be8b043ec77d4c9b06f9a586117c7f957f4af0331cbc871 -b6c90961f68b5e385d85c9830ec765d22a425f506904c4d506b87d8944c2b2c09615e740ed351df0f9321a7b93979cae -a6ec5ea80c7558403485b3b1869cdc63bde239bafdf936d9b62a37031628402a36a2cfa5cfbb8e26ac922cb0a209b3ba -8c3195bbdbf9bc0fc95fa7e3d7f739353c947f7767d1e3cb24d8c8602d8ea0a1790ac30b815be2a2ba26caa5227891e2 -a7f8a63d809f1155722c57f375ea00412b00147776ae4444f342550279ef4415450d6f400000a326bf11fea6c77bf941 -97fa404df48433a00c85793440e89bb1af44c7267588ae937a1f5d53e01e1c4d4fc8e4a6d517f3978bfdd6c2dfde012f -a984a0a3836de3d8d909c4629a2636aacb85393f6f214a2ef68860081e9db05ad608024762db0dc35e895dc00e2d4cdd -9526cf088ab90335add1db4d3a4ac631b58cbfbe88fa0845a877d33247d1cfeb85994522e1eb8f8874651bfb1df03e2a -ac83443fd0afe99ad49de9bf8230158c118e2814c9c89db5ac951c240d6c2ce45e7677221279d9e97848ec466b99aafe -aeeefdbaba612e971697798ceaf63b247949dc823a0ad771ae5b988a5e882b338a98d3d0796230f49d533ec5ba411b39 -ae3f248b5a7b0f92b7820a6c5ae21e5bd8f4265d4f6e21a22512079b8ee9be06393fd3133ce8ebac0faf23f4f8517e36 -a64a831b908eee784b8388b45447d2885ec0551b26b0c2b15e5f417d0a12c79e867fb7bd3d008d0af98b44336f8ec1ad -b242238cd8362b6e440ba21806905714dd55172db25ec7195f3fc4937b2aba146d5cbf3cf691a1384b4752dc3b54d627 -819f97f337eea1ffb2a678cc25f556f1aab751c6b048993a1d430fe1a3ddd8bb411c152e12ca60ec6e057c190cd1db9a -b9d7d187407380df54ee9fef224c54eec1bfabf17dc8abf60765b7951f538f59aa26fffd5846cfe05546c35f59b573f4 -aa6e3c14efa6a5962812e3f94f8ce673a433f4a82d07a67577285ea0eaa07f8be7115853122d12d6d4e1fdf64c504be1 -82268bee9c1662d3ddb5fb785abfae6fb8b774190f30267f1d47091d2cd4b3874db4372625aa36c32f27b0eee986269b -b236459565b7b966166c4a35b2fa71030b40321821b8e96879d95f0e83a0baf33fa25721f30af4a631df209e25b96061 -8708d752632d2435d2d5b1db4ad1fa2558d776a013655f88e9a3556d86b71976e7dfe5b8834fdec97682cd94560d0d0d -ae1424a68ae2dbfb0f01211f11773732a50510b5585c1fb005cb892b2c6a58f4a55490b5c5b4483c6fce40e9d3236a52 -b3f5f722af9dddb07293c871ce97abbccba0093ca98c8d74b1318fa21396fc1b45b69c15084f63d728f9908442024506 -9606f3ce5e63886853ca476dc0949e7f1051889d529365c0cb0296fdc02abd088f0f0318ecd2cf36740a3634132d36f6 -b11a833a49fa138db46b25ff8cdda665295226595bc212c0931b4931d0a55c99da972c12b4ef753f7e37c6332356e350 -afede34e7dab0a9e074bc19a7daddb27df65735581ca24ad70c891c98b1349fcebbcf3ba6b32c2617fe06a5818dabc2d -97993d456e459e66322d01f8eb13918979761c3e8590910453944bdff90b24091bb018ac6499792515c9923be289f99f -977e3e967eff19290a192cd11df3667d511b398fb3ac9a5114a0f3707e25a0edcb56105648b1b85a8b7519fc529fc6f6 -b873a7c88bf58731fe1bf61ff6828bf114cf5228f254083304a4570e854e83748fc98683ddba62d978fff7909f2c5c47 -ad4b2691f6f19da1d123aaa23cca3e876247ed9a4ab23c599afdbc0d3aa49776442a7ceaa996ac550d0313d9b9a36cee -b9210713c78e19685608c6475bfa974b57ac276808a443f8b280945c5d5f9c39da43effa294bfb1a6c6f7b6b9f85bf6c -a65152f376113e61a0e468759de38d742caa260291b4753391ee408dea55927af08a4d4a9918600a3bdf1df462dffe76 -8bf8c27ad5140dde7f3d2280fd4cc6b29ab76537e8d7aa7011a9d2796ee3e56e9a60c27b5c2da6c5e14fc866301dc195 -92fde8effc9f61393a2771155812b863cff2a0c5423d7d40aa04d621d396b44af94ddd376c28e7d2f53c930aea947484 -97a01d1dd9ee30553ce676011aea97fa93d55038ada95f0057d2362ae9437f3ed13de8290e2ff21e3167dd7ba10b9c3f -89affffaa63cb2df3490f76f0d1e1d6ca35c221dd34057176ba739fa18d492355e6d2a5a5ad93a136d3b1fed0bb8aa19 -928b8e255a77e1f0495c86d3c63b83677b4561a5fcbbe5d3210f1e0fc947496e426d6bf3b49394a5df796c9f25673fc4 -842a0af91799c9b533e79ee081efe2a634cac6c584c2f054fb7d1db67dde90ae36de36cbf712ec9cd1a0c7ee79e151ea -a65b946cf637e090baf2107c9a42f354b390e7316beb8913638130dbc67c918926eb87bec3b1fe92ef72bc77a170fa3b -aafc0f19bfd71ab5ae4a8510c7861458b70ad062a44107b1b1dbacbfa44ba3217028c2824bd7058e2fa32455f624040b -95269dc787653814e0be899c95dba8cfa384f575a25e671c0806fd80816ad6797dc819d30ae06e1d0ed9cb01c3950d47 -a1e760f7fa5775a1b2964b719ff961a92083c5c617f637fc46e0c9c20ab233f8686f7f38c3cb27d825c54dd95e93a59b -ac3b8a7c2317ea967f229eddc3e23e279427f665c4705c7532ed33443f1243d33453c1088f57088d2ab1e3df690a9cc9 -b787beeddfbfe36dd51ec4efd9cf83e59e84d354c3353cc9c447be53ae53d366ed1c59b686e52a92f002142c8652bfe0 -b7a64198300cb6716aa7ac6b25621f8bdec46ad5c07a27e165b3f774cdf65bcfdbf31e9bae0c16b44de4b00ada7a4244 -b8ae9f1452909e0c412c7a7fe075027691ea8df1347f65a5507bc8848f1d2c833d69748076db1129e5b4fb912f65c86c -9682e41872456b9fa67def89e71f06d362d6c8ca85c9c48536615bc401442711e1c9803f10ab7f8ab5feaec0f9df20a6 -88889ff4e271dc1c7e21989cc39f73cde2f0475acd98078281591ff6c944fadeb9954e72334319050205d745d4df73df -8f79b5b8159e7fd0d93b0645f3c416464f39aec353b57d99ecf24f96272df8a068ad67a6c90c78d82c63b40bb73989bb -838c01a009a3d8558a3f0bdd5e22de21af71ca1aefc8423c91dc577d50920e9516880e87dce3e6d086e11cd45c9052d9 -b97f1c6eee8a78f137c840667cc288256e39294268a3009419298a04a1d0087c9c9077b33c917c65caf76637702dda8a -972284ce72f96a61c899260203dfa06fc3268981732bef74060641c1a5068ead723e3399431c247ca034b0dae861e8df -945a8d52d6d3db6663dbd3110c6587f9e9c44132045eeffba15621576d178315cb52870fa5861669f84f0bee646183fe -a0a547b5f0967b1c3e5ec6c6a9a99f0578521489180dfdfbb5561f4d166baac43a2f06f950f645ce991664e167537eed -a0592cda5cdddf1340033a745fd13a6eff2021f2e26587116c61c60edead067e0f217bc2bef4172a3c9839b0b978ab35 -b9c223b65a3281587fa44ec829e609154b32f801fd1de6950e01eafb07a8324243b960d5735288d0f89f0078b2c42b5b -99ebfc3b8f9f98249f4d37a0023149ed85edd7a5abe062c8fb30c8c84555258b998bdcdd1d400bc0fa2a4aaa8b224466 -955b68526e6cb3937b26843270f4e60f9c6c8ece2fa9308fe3e23afa433309c068c66a4bc16ee2cf04220f095e9afce4 -b766caeafcc00378135ae53397f8a67ed586f5e30795462c4a35853de6681b1f17401a1c40958de32b197c083b7279c1 -921bf87cad947c2c33fa596d819423c10337a76fe5a63813c0a9dc78a728207ae7b339407a402fc4d0f7cba3af6da6fc -a74ba1f3bc3e6c025db411308f49b347ec91da1c916bda9da61e510ec8d71d25e0ac0f124811b7860e5204f93099af27 -a29b4d144e0bf17a7e8353f2824cef0ce85621396babe8a0b873ca1e8a5f8d508b87866cf86da348470649fceefd735c -a8040e12ffc3480dd83a349d06741d1572ef91932c46f5cf03aee8454254156ee95786fd013d5654725e674c920cec32 -8c4cf34ca60afd33923f219ffed054f90cd3f253ffeb2204a3b61b0183417e366c16c07fae860e362b0f2bfe3e1a1d35 -8195eede4ddb1c950459df6c396b2e99d83059f282b420acc34220cadeed16ab65c856f2c52568d86d3c682818ed7b37 -91fff19e54c15932260aa990c7fcb3c3c3da94845cc5aa8740ef56cf9f58d19b4c3c55596f8d6c877f9f4d22921d93aa -a3e0bf7e5d02a80b75cf75f2db7e66cb625250c45436e3c136d86297d652590ec97c2311bafe407ad357c79ab29d107b -81917ff87e5ed2ae4656b481a63ced9e6e5ff653b8aa6b7986911b8bc1ee5b8ef4f4d7882c3f250f2238e141b227e510 -915fdbe5e7de09c66c0416ae14a8750db9412e11dc576cf6158755fdcaf67abdbf0fa79b554cac4fe91c4ec245be073f -8df27eafb5c3996ba4dc5773c1a45ca77e626b52e454dc1c4058aa94c2067c18332280630cc3d364821ee53bf2b8c130 -934f8a17c5cbb827d7868f5c8ca00cb027728a841000a16a3428ab16aa28733f16b52f58c9c4fbf75ccc45df72d9c4df -b83f4da811f9183c25de8958bc73b504cf790e0f357cbe74ef696efa7aca97ad3b7ead1faf76e9f982c65b6a4d888fc2 -87188213c8b5c268dc2b6da413f0501c95749e953791b727450af3e43714149c115b596b33b63a2f006a1a271b87efd0 -83e9e888ab9c3e30761de635d9aabd31248cdd92f7675fc43e4b21fd96a03ec1dc4ad2ec94fec857ffb52683ac98e360 -b4b9a1823fe2d983dc4ec4e3aaea297e581c3fc5ab4b4af5fa1370caa37af2d1cc7fc6bfc5e7da60ad8fdce27dfe4b24 -856388bc78aef465dbcdd1f559252e028c9e9a2225c37d645c138e78f008f764124522705822a61326a6d1c79781e189 -a6431b36db93c3b47353ba22e7c9592c9cdfb9cbdd052ecf2cc3793f5b60c1e89bc96e6bae117bfd047f2308da00dd2f -b619972d48e7e4291542dcde08f7a9cdc883c892986ded2f23ccb216e245cd8d9ad1d285347b0f9d7611d63bf4cee2bc -8845cca6ff8595955f37440232f8e61d5351500bd016dfadd182b9d39544db77a62f4e0102ff74dd4173ae2c181d24ef -b2f5f7fa26dcd3b6550879520172db2d64ee6aaa213cbef1a12befbce03f0973a22eb4e5d7b977f466ac2bf8323dcedd -858b7f7e2d44bdf5235841164aa8b4f3d33934e8cb122794d90e0c1cac726417b220529e4f896d7b77902ab0ccd35b3a -80b0408a092dae2b287a5e32ea1ad52b78b10e9c12f49282976cd738f5d834e03d1ad59b09c5ccaccc39818b87d06092 -b996b0a9c6a2d14d984edcd6ab56bc941674102980d65b3ad9733455f49473d3f587c8cbf661228a7e125ddbe07e3198 -90224fcebb36865293bd63af786e0c5ade6b67c4938d77eb0cbae730d514fdd0fe2d6632788e858afd29d46310cf86df -b71351fdfff7168b0a5ec48397ecc27ac36657a8033d9981e97002dcca0303e3715ce6dd3f39423bc8ef286fa2e9e669 -ae2a3f078b89fb753ce4ed87e0c1a58bb19b4f0cfb6586dedb9fcab99d097d659a489fb40e14651741e1375cfc4b6c5f -8ef476b118e0b868caed297c161f4231bbeb863cdfa5e2eaa0fc6b6669425ce7af50dc374abceac154c287de50c22307 -92e46ab472c56cfc6458955270d3c72b7bde563bb32f7d4ab4d959db6f885764a3d864e1aa19802fefaa5e16b0cb0b54 -96a3f68323d1c94e73d5938a18a377af31b782f56212de3f489d22bc289cf24793a95b37f1d6776edf88114b5c1fa695 -962cc068cfce6faaa27213c4e43e44eeff0dfbb6d25b814e82c7da981fb81d7d91868fa2344f05fb552362f98cfd4a72 -895d4e4c4ad670abf66d43d59675b1add7afad7438ada8f42a0360c704cee2060f9ac15b4d27e9b9d0996bb801276fe3 -b3ad18d7ece71f89f2ef749b853c45dc56bf1c796250024b39a1e91ed11ca32713864049c9aaaea60cde309b47486bbf -8f05404e0c0258fdbae50e97ccb9b72ee17e0bd2400d9102c0dad981dac8c4c71585f03e9b5d50086d0a2d3334cb55d1 -8bd877e9d4591d02c63c6f9fc9976c109de2d0d2df2bfa5f6a3232bab5b0b8b46e255679520480c2d7a318545efa1245 -8d4c16b5d98957c9da13d3f36c46f176e64e5be879f22be3179a2c0e624fe4758a82bf8c8027410002f973a3b84cd55a -86e2a8dea86427b424fa8eada881bdff896907084a495546e66556cbdf070b78ba312bf441eb1be6a80006d25d5097a3 -8608b0c117fd8652fdab0495b08fadbeba95d9c37068e570de6fddfef1ba4a1773b42ac2be212836141d1bdcdef11a17 -a13d6febf5fb993ae76cae08423ca28da8b818d6ef0fde32976a4db57839cd45b085026b28ee5795f10a9a8e3098c683 -8e261967fa6de96f00bc94a199d7f72896a6ad8a7bbb1d6187cca8fad824e522880e20f766620f4f7e191c53321d70f9 -8b8e8972ac0218d7e3d922c734302803878ad508ca19f5f012bc047babd8a5c5a53deb5fe7c15a4c00fd6d1cb9b1dbd0 -b5616b233fb3574a2717d125a434a2682ff68546dccf116dd8a3b750a096982f185614b9fb6c7678107ff40a451f56fa -aa6adf9b0c3334b0d0663f583a4914523b2ac2e7adffdb026ab9109295ff6af003ef8357026dbcf789896d2afded8d73 -acb72df56a0b65496cd534448ed4f62950bb1e11e50873b6ed349c088ee364441821294ce0f7c61bd7d38105bea3b442 -abae12df83e01ec947249fedd0115dc501d2b03ff7232092979eda531dbbca29ace1d46923427c7dde4c17bdf3fd7708 -820b4fc2b63a9fda7964acf5caf19a2fc4965007cb6d6b511fcafcb1f71c3f673a1c0791d3f86e3a9a1eb6955b191cc0 -af277259d78c6b0f4f030a10c53577555df5e83319ddbad91afbd7c30bc58e7671c56d00d66ec3ab5ef56470cd910cee -ad4a861c59f1f5ca1beedd488fb3d131dea924fffd8e038741a1a7371fad7370ca5cf80dc01f177fbb9576713bb9a5b3 -b67a5162982ce6a55ccfb2f177b1ec26b110043cf18abd6a6c451cf140b5af2d634591eb4f28ad92177d8c7e5cd0a5e8 -96176d0a83816330187798072d449cbfccff682561e668faf6b1220c9a6535b32a6e4f852e8abb00f79abb87493df16b -b0afe6e7cb672e18f0206e4423f51f8bd0017bf464c4b186d46332c5a5847647f89ff7fa4801a41c1b0b42f6135bcc92 -8fc5e7a95ef20c1278c645892811f6fe3f15c431ebc998a32ec0da44e7213ea934ed2be65239f3f49b8ec471e9914160 -b7793e41adda6c82ba1f2a31f656f6205f65bf8a3d50d836ee631bc7ce77c153345a2d0fc5c60edf8b37457c3729c4ec -a504dd7e4d6b2f4379f22cc867c65535079c75ccc575955f961677fa63ecb9f74026fa2f60c9fb6323c1699259e5e9c8 -ab899d00ae693649cc1afdf30fb80d728973d2177c006e428bf61c7be01e183866614e05410041bc82cb14a33330e69c -8a3bd8b0b1be570b65c4432a0f6dc42f48a2000e30ab089cf781d38f4090467b54f79c0d472fcbf18ef6a00df69cc6f3 -b4d7028f7f76a96a3d7803fca7f507ae11a77c5346e9cdfccb120a833a59bda1f4264e425aa588e7a16f8e7638061d84 -b9c7511a76ea5fb105de905d44b02edb17008335766ee357ed386b7b3cf19640a98b38785cb14603c1192bee5886c9b6 -8563afb12e53aed71ac7103ab8602bfa8371ae095207cb0d59e8fd389b6ad1aff0641147e53cb6a7ca16c7f37c9c5e6b -8e108be614604e09974a9ed90960c28c4ea330a3d9a0cb4af6dd6f193f84ab282b243ecdf549b3131036bebc8905690c -b794d127fbedb9c5b58e31822361706ffac55ce023fbfe55716c3c48c2fd2f2c7660a67346864dfe588812d369cb50b6 -b797a3442fc3b44f41baefd30346f9ac7f96e770d010d53c146ce74ce424c10fb62758b7e108b8abfdc5fafd89d745cb -993bb71e031e8096442e6205625e1bfddfe6dd6a83a81f3e2f84fafa9e5082ab4cad80a099f21eff2e81c83457c725c3 -8711ab833fc03e37acf2e1e74cfd9133b101ff4144fe30260654398ae48912ab46549d552eb9d15d2ea57760d35ac62e -b21321fd2a12083863a1576c5930e1aecb330391ef83326d9d92e1f6f0d066d1394519284ddab55b2cb77417d4b0292f -877d98f731ffe3ee94b0b5b72d127630fa8a96f6ca4f913d2aa581f67732df6709493693053b3e22b0181632ac6c1e3b -ae391c12e0eb8c145103c62ea64f41345973311c3bf7281fa6bf9b7faafac87bcf0998e5649b9ef81e288c369c827e07 -b83a2842f36998890492ab1cd5a088d9423d192681b9a3a90ec518d4c541bce63e6c5f4df0f734f31fbfdd87785a2463 -a21b6a790011396e1569ec5b2a423857b9bec16f543e63af28024e116c1ea24a3b96e8e4c75c6537c3e4611fd265e896 -b4251a9c4aab3a495da7a42e684ba4860dbcf940ad1da4b6d5ec46050cbe8dab0ab9ae6b63b5879de97b905723a41576 -8222f70aebfe6ac037f8543a08498f4cadb3edaac00336fc00437eb09f2cba758f6c38e887cc634b4d5b7112b6334836 -86f05038e060594c46b5d94621a1d9620aa8ba59a6995baf448734e21f58e23c1ea2993d3002ad5250d6edd5ba59b34f -a7c0c749baef811ab31b973c39ceb1d94750e2bc559c90dc5eeb20d8bb6b78586a2b363c599ba2107d6be65cd435f24e -861d46a5d70b38d6c1cd72817a2813803d9f34c00320c8b62f8b9deb67f5b5687bc0b37c16d28fd017367b92e05da9ca -b3365d3dab639bffbe38e35383686a435c8c88b397b717cd4aeced2772ea1053ceb670f811f883f4e02975e5f1c4ac58 -a5750285f61ab8f64cd771f6466e2c0395e01b692fd878f2ef2d5c78bdd8212a73a3b1dfa5e4c8d9e1afda7c84857d3b -835a10809ccf939bc46cf950a33b36d71be418774f51861f1cd98a016ade30f289114a88225a2c11e771b8b346cbe6ef -a4f59473a037077181a0a62f1856ec271028546ca9452b45cedfcb229d0f4d1aabfc13062b07e536cc8a0d4b113156a2 -95cd14802180b224d44a73cc1ed599d6c4ca62ddcaa503513ccdc80aaa8be050cc98bd4b4f3b639549beb4587ac6caf9 -973b731992a3e69996253d7f36dd7a0af1982b5ed21624b77a7965d69e9a377b010d6dabf88a8a97eec2a476259859cc -af8a1655d6f9c78c8eb9a95051aa3baaf9c811adf0ae8c944a8d3fcba87b15f61021f3baf6996fa0aa51c81b3cb69de1 -835aad5c56872d2a2d6c252507b85dd742bf9b8c211ccb6b25b52d15c07245b6d89b2a40f722aeb5083a47cca159c947 -abf4e970b02bef8a102df983e22e97e2541dd3650b46e26be9ee394a3ea8b577019331857241d3d12b41d4eacd29a3ac -a13c32449dbedf158721c13db9539ae076a6ce5aeaf68491e90e6ad4e20e20d1cdcc4a89ed9fd49cb8c0dd50c17633c1 -8c8f78f88b7e22dd7e9150ab1c000f10c28e696e21d85d6469a6fe315254740f32e73d81ab1f3c1cf8f544c86df506e8 -b4b77f2acfe945abf81f2605f906c10b88fb4d28628487fb4feb3a09f17f28e9780445dfcee4878349d4c6387a9d17d4 -8d255c235f3812c6ecc646f855fa3832be5cb4dbb9c9e544989fafdf3f69f05bfd370732eaf954012f0044aa013fc9c6 -b982efd3f34b47df37c910148ac56a84e8116647bea24145a49e34e0a6c0176e3284d838dae6230cb40d0be91c078b85 -983f365aa09bd85df2a6a2ad8e4318996b1e27d02090755391d4486144e40d80b1fbfe1c798d626db92f52e33aa634da -95fd1981271f3ea3a41d654cf497e6696730d9ff7369f26bc4d7d15c7adb4823dd0c42e4a005a810af12d234065e5390 -a9f5219bd4b913c186ef30c02f995a08f0f6f1462614ea5f236964e02bdaa33db9d9b816c4aee5829947840a9a07ba60 -9210e6ceb05c09b46fd09d036287ca33c45124ab86315e5d6911ff89054f1101faaa3e83d123b7805056d388bcec6664 -8ed9cbf69c6ff3a5c62dd9fe0d7264578c0f826a29e614bc2fb4d621d90c8c9992438accdd7a614b1dca5d1bb73dc315 -85cf2a8cca93e00da459e3cecd22c342d697eee13c74d5851634844fc215f60053cf84b0e03c327cb395f48d1c71a8a4 -8818a18e9a2ec90a271b784400c1903089ffb0e0b40bc5abbbe12fbebe0f731f91959d98c5519ef1694543e31e2016d4 -8dabc130f296fa7a82870bf9a8405aaf542b222ed9276bba9bd3c3555a0f473acb97d655ee7280baff766a827a8993f0 -ac7952b84b0dc60c4d858f034093b4d322c35959605a3dad2b806af9813a4680cb038c6d7f4485b4d6b2ff502aaeca25 -ad65cb6d57b48a2602568d2ec8010baed0eb440eec7638c5ec8f02687d764e9de5b5d42ad5582934e592b48471c22d26 -a02ab8bd4c3d114ea23aebdd880952f9495912817da8c0c08eabc4e6755439899d635034413d51134c72a6320f807f1c -8319567764b8295402ec1ebef4c2930a138480b37e6d7d01c8b4c9cd1f2fc3f6e9a44ae6e380a0c469b25b06db23305f -afec53b2301dc0caa8034cd9daef78c48905e6068d692ca23d589b84a6fa9ddc2ed24a39480597e19cb3e83eec213b3f -ac0b4ffdb5ae08e586a9cdb98f9fe56f4712af3a97065e89e274feacfb52b53c839565aee93c4cfaaccfe51432c4fab0 -8972cbf07a738549205b1094c5987818124144bf187bc0a85287c94fdb22ce038c0f11df1aa16ec5992e91b44d1af793 -b7267aa6f9e3de864179b7da30319f1d4cb2a3560f2ea980254775963f1523b44c680f917095879bebfa3dc2b603efcf -80f68f4bfc337952e29504ee5149f15093824ea7ab02507efd1317a670f6cbc3611201848560312e3e52e9d9af72eccf -8897fee93ce8fc1e1122e46b6d640bba309384dbd92e46e185e6364aa8210ebf5f9ee7e5e604b6ffba99aa80a10dd7d0 -b58ea6c02f2360be60595223d692e82ee64874fda41a9f75930f7d28586f89be34b1083e03bbc1575bbfdda2d30db1ea -85a523a33d903280d70ac5938770453a58293480170c84926457ac2df45c10d5ff34322ab130ef4a38c916e70d81af53 -a2cbf045e1bed38937492c1f2f93a5ba41875f1f262291914bc1fc40c60bd0740fb3fea428faf6da38b7c180fe8ac109 -8c09328770ed8eb17afc6ac7ddd87bb476de18ed63cab80027234a605806895959990c47bd10d259d7f3e2ecb50074c9 -b4b9e19edb4a33bde8b7289956568a5b6b6557404e0a34584b5721fe6f564821091013fbb158e2858c6d398293bb4b59 -8a47377df61733a2aa5a0e945fce00267f8e950f37e109d4487d92d878fb8b573317bb382d902de515b544e9e233458d -b5804c9d97efeff5ca94f3689b8088c62422d92a1506fd1d8d3b1b30e8a866ad0d6dad4abfa051dfc4471250cac4c5d9 -9084a6ee8ec22d4881e9dcc8a9eb3c2513523d8bc141942370fd191ad2601bf9537a0b1e84316f3209b3d8a54368051e -85447eea2fa26656a649f8519fa67279183044791d61cf8563d0783d46d747d96af31d0a93507bbb2242666aa87d3720 -97566a84481027b60116c751aec552adfff2d9038e68d48c4db9811fb0cbfdb3f1d91fc176a0b0d988a765f8a020bce1 -ae87e5c1b9e86c49a23dceda4ecfd1dcf08567f1db8e5b6ec752ebd45433c11e7da4988573cdaebbb6f4135814fc059e -abee05cf9abdbc52897ac1ce9ed157f5466ed6c383d6497de28616238d60409e5e92619e528af8b62cc552bf09970dc2 -ae6d31cd7bf9599e5ee0828bab00ceb4856d829bba967278a73706b5f388465367aa8a6c7da24b5e5f1fdd3256ef8e63 -ac33e7b1ee47e1ee4af472e37ab9e9175260e506a4e5ce449788075da1b53c44cb035f3792d1eea2aa24b1f688cc6ed3 -80f65b205666b0e089bb62152251c48c380a831e5f277f11f3ef4f0d52533f0851c1b612267042802f019ec900dc0e8f -858520ad7aa1c9fed738e3b583c84168f2927837ad0e1d326afe9935c26e9b473d7f8c382e82ef1fe37d2b39bb40a1ee -b842dd4af8befe00a97c2d0f0c33c93974761e2cb9e5ab8331b25170318ddd5e4bdbc02d8f90cbfdd5f348f4f371c1f7 -8bf2cb79bc783cb57088aae7363320cbeaabd078ffdec9d41bc74ff49e0043d0dad0086a30e5112b689fd2f5a606365d -982eb03bbe563e8850847cd37e6a3306d298ab08c4d63ab6334e6b8c1fa13fce80cf2693b09714c7621d74261a0ff306 -b143edb113dec9f1e5105d4a93fbe502b859e587640d3db2f628c09a17060e6aec9e900e2c8c411cda99bc301ff96625 -af472d9befa750dcebc5428fe1a024f18ec1c07bca0f95643ce6b5f4189892a910285afb03fd7ed7068fbe614e80d33c -a97e3bc57ede73ecd1bbf02de8f51b4e7c1a067da68a3cd719f4ba26a0156cbf1cef2169fd35a18c5a4cced50d475998 -a862253c937cf3d75d7183e5f5be6a4385d526aeda5171c1c60a8381fea79f88f5f52a4fab244ecc70765d5765e6dfd5 -90cb776f8e5a108f1719df4a355bebb04bf023349356382cae55991b31720f0fd03206b895fa10c56c98f52453be8778 -a7614e8d0769dccd520ea4b46f7646e12489951efaef5176bc889e9eb65f6e31758df136b5bf1e9107e68472fa9b46ec -ac3a9b80a3254c42e5ed3a090a0dd7aee2352f480de96ad187027a3bb6c791eddfc3074b6ffd74eea825188f107cda4d -82a01d0168238ef04180d4b6e0a0e39024c02c2d75b065017c2928039e154d093e1af4503f4d1f3d8a948917abb5d09f -8fab000a2b0eef851a483aec8d2dd85fe60504794411a2f73ed82e116960547ac58766cb73df71aea71079302630258d -872451a35c6db61c63e9b8bb9f16b217f985c20be4451c14282c814adb29d7fb13f201367c664435c7f1d4d9375d7a58 -887d9ff54cc96b35d562df4a537ff972d7c4b3fd91ab06354969a4cfede0b9fc68bbffb61d0dbf1a58948dc701e54f5a -8cb5c2a6bd956875d88f41ae24574434f1308514d44057b55c9c70f13a3366ed054150eed0955a38fda3f757be73d55f -89ad0163cad93e24129d63f8e38422b7674632a8d0a9016ee8636184cab177659a676c4ee7efba3abe1a68807c656d60 -b9ec01c7cab6d00359b5a0b4a1573467d09476e05ca51a9227cd16b589a9943d161eef62dcc73f0de2ec504d81f4d252 -8031d17635d39dfe9705c485d2c94830b6fc9bc67b91300d9d2591b51e36a782e77ab5904662effa9382d9cca201f525 -8be5a5f6bc8d680e5092d6f9a6585acbaaaa2ddc671da560dcf5cfa4472f4f184b9597b5b539438accd40dda885687cc -b1fc0f052fae038a2e3de3b3a96b0a1024b009de8457b8b3adb2d315ae68a89af905720108a30038e5ab8d0d97087785 -8b8bdc77bd3a6bc7ca5492b6f8c614852c39a70d6c8a74916eaca0aeb4533b11898b8820a4c2620a97bf35e275480029 -af35f4dc538d4ad5cdf710caa38fd1eb496c3fa890a047b6a659619c5ad3054158371d1e88e0894428282eed9f47f76b -8166454a7089cc07758ad78724654f4e7a1a13e305bbf88ddb86f1a4b2904c4fc8ab872d7da364cdd6a6c0365239e2ad -ab287c7d3addce74ce40491871c768abe01daaa0833481276ff2e56926b38a7c6d2681ffe837d2cc323045ad1a4414f9 -b90317f4505793094d89365beb35537f55a6b5618904236258dd04ca61f21476837624a2f45fef8168acf732cab65579 -98ae5ea27448e236b6657ab5ef7b1cccb5372f92ab25f5fa651fbac97d08353a1dae1b280b1cd42b17d2c6a70a63ab9d -adcf54e752d32cbaa6cb98fbca48d8cd087b1db1d131d465705a0d8042c8393c8f4d26b59006eb50129b21e6240f0c06 -b591a3e4db18a7345fa935a8dd7994bbac5cc270b8ebd84c8304c44484c7a74afb45471fdbe4ab22156a30fae1149b40 -806b53ac049a42f1dcc1d6335505371da0bf27c614f441b03bbf2e356be7b2fb4eed7117eabcce9e427a542eaa2bf7d8 -800482e7a772d49210b81c4a907f5ce97f270b959e745621ee293cf8c71e8989363d61f66a98f2d16914439544ca84c7 -99de9eafdad3617445312341644f2bb888680ff01ce95ca9276b1d2e5ef83fa02dab5e948ebf66c17df0752f1bd37b70 -961ee30810aa4c93ae157fbe9009b8e443c082192bd36a73a6764ff9b2ad8b0948fe9a73344556e01399dd77badb4257 -ae0a361067c52efbe56c8adf982c00432cd478929459fc7f74052c8ee9531cd031fe1335418fde53f7c2ef34254eb7ac -a3503d16b6b27eb20c1b177bcf90d13706169220523a6271b85b2ce35a9a2b9c5bed088540031c0a4ebfdae3a4c6ab04 -909420122c3e723289ca4e7b81c2df5aff312972a2203f4c45821b176e7c862bf9cac7f7df3adf1d59278f02694d06e7 -989f42380ae904b982f85d0c6186c1aef5d6bcba29bcfbb658e811b587eb2749c65c6e4a8cc6409c229a107499a4f5d7 -8037a6337195c8e26a27ea4ef218c6e7d79a9720aaab43932d343192abc2320fe72955f5e431c109093bda074103330a -b312e168663842099b88445e940249cc508f080ab0c94331f672e7760258dbd86be5267e4cf25ea25facb80bff82a7e9 -aaa3ff8639496864fcdbfdda1ac97edc4f08e3c9288b768f6c8073038c9fbbf7e1c4bea169b4d45c31935cdf0680d45e -97dbd3df37f0b481a311dfc5f40e59227720f367912200d71908ef6650f32cc985cb05b981e3eea38958f7e48d10a15d -a89d49d1e267bb452d6cb621b9a90826fe55e9b489c0427b94442d02a16f390eed758e209991687f73f6b5a032321f42 -9530dea4e0e19d6496f536f2e75cf7d814d65fde567055eb20db48fd8d20d501cd2a22fb506db566b94c9ee10f413d43 -81a7009b9e67f1965fa7da6a57591c307de91bf0cd35ab4348dc4a98a4961e096d004d7e7ad318000011dc4342c1b809 -83440a9402b766045d7aca61a58bba2aa29cac1cf718199e472ba086f5d48093d9dda4d135292ba51d049a23964eceae -a06c9ce5e802df14f6b064a3d1a0735d429b452f0e2e276042800b0a4f16df988fd94cf3945921d5dd3802ab2636f867 -b1359e358b89936dee9e678a187aad3e9ab14ac40e96a0a68f70ee2583cdcf467ae03bef4215e92893f4e12f902adec8 -835304f8619188b4d14674d803103d5a3fa594d48e96d9699e653115dd05fdc2dda6ba3641cf7ad53994d448da155f02 -8327cba5a9ff0d3f5cd0ae55e77167448926d5fcf76550c0ad978092a14122723090c51c415e88e42a2b62eb07cc3981 -b373dcdaea85f85ce9978b1426a7ef4945f65f2d3467a9f1cc551a99766aac95df4a09e2251d3f89ca8c9d1a7cfd7b0e -ab1422dc41af2a227b973a6fd124dfcb2367e2a11a21faa1d381d404f51b7257e5bc82e9cf20cd7fe37d7ae761a2ab37 -a93774a03519d2f20fdf2ef46547b0a5b77c137d6a3434b48d56a2cbef9e77120d1b85d0092cf8842909213826699477 -8eb967a495a38130ea28711580b7e61bcd1d051cd9e4f2dbf62f1380bd86e0d60e978d72f6f31e909eb97b3b9a2b867c -ae8213378da1287ba1fe4242e1acaec19b877b6fe872400013c6eac1084b8d03156792fa3020201725b08228a1e80f49 -b143daf6893d674d607772b3b02d8ac48f294237e2f2c87963c0d4e26d9227d94a2a13512457c3d5883544bbc259f0ef -b343bd2aca8973888e42542218924e2dda2e938fd1150d06878af76f777546213912b7c7a34a0f94186817d80ffa185c -b188ebc6a8c3007001aa347ae72cc0b15d09bc6c19a80e386ee4b334734ec0cc2fe8b493c2422f38d1e6d133cc3db6fe -b795f6a8b9b826aaeee18ccd6baf6c5adeeec85f95eb5b6d19450085ec7217e95a2d9e221d77f583b297d0872073ba0e -b1c7dbd998ad32ae57bfa95deafa147024afd57389e98992c36b6e52df915d3d5a39db585141ec2423173e85d212fed8 -812bcdeb9fe5f12d0e1df9964798056e1f1c3de3b17b6bd2919b6356c4b86d8e763c01933efbe0224c86a96d5198a4be -b19ebeda61c23d255cbf472ef0b8a441f4c55b70f0d8ed47078c248b1d3c7c62e076b43b95c00a958ec8b16d5a7cb0d7 -b02adc9aaa20e0368a989c2af14ff48b67233d28ebee44ff3418bb0473592e6b681af1cc45450bd4b175df9051df63d9 -8d87f0714acee522eb58cec00360e762adc411901dba46adc9227124fa70ee679f9a47e91a6306d6030dd4eb8de2f3c1 -8be54cec21e74bcc71de29dc621444263737db15f16d0bb13670f64e42f818154e04b484593d19ef95f2ee17e4b3fe21 -ab8e20546c1db38d31493b5d5f535758afb17e459645c1b70813b1cf7d242fd5d1f4354a7c929e8f7259f6a25302e351 -89f035a1ed8a1e302ac893349ba8ddf967580fcb6e73d44af09e3929cde445e97ff60c87dafe489e2c0ab9c9986cfa00 -8b2b0851a795c19191a692af55f7e72ad2474efdc5401bc3733cfdd910e34c918aaebe69d5ea951bdddf3c01cabbfc67 -a4edb52c2b51495ccd1ee6450fc14b7b3ede8b3d106808929d02fb31475bacb403e112ba9c818d2857651e508b3a7dd1 -9569341fded45d19f00bcf3cbf3f20eb2b4d82ef92aba3c8abd95866398438a2387437e580d8b646f17cf6fde8c5af23 -aa4b671c6d20f72f2f18a939a6ff21cc37e0084b44b4a717f1be859a80b39fb1be026b3205adec2a66a608ec2bcd578f -94902e980de23c4de394ad8aec91b46f888d18f045753541492bfbb92c59d3daa8de37ae755a6853744af8472ba7b72b -af651ef1b2a0d30a7884557edfad95b6b5d445a7561caebdc46a485aedd25932c62c0798465c340a76f6feaa196dd712 -b7b669b8e5a763452128846dd46b530dca4893ace5cc5881c7ddcd3d45969d7e73fbebdb0e78aa81686e5f7b22ec5759 -82507fd4ebe9fa656a7f2e084d64a1fa6777a2b0bc106d686e2d9d2edafc58997e58cb6bfd0453b2bf415704aa82ae62 -b40bce2b42b88678400ecd52955bbdadd15f8b9e1b3751a1a3375dc0efb5ca3ee258cf201e1140b3c09ad41217d1d49e -b0210d0cbb3fbf3b8cdb39e862f036b0ff941cd838e7aaf3a8354e24246e64778d22f3de34572e6b2a580614fb6425be -876693cba4301b251523c7d034108831df3ce133d8be5a514e7a2ca494c268ca0556fa2ad8310a1d92a16b55bcd99ea9 -8660281406d22a4950f5ef050bf71dd3090edb16eff27fa29ef600cdea628315e2054211ed2cc6eaf8f2a1771ef689fd -a610e7e41e41ab66955b809ba4ade0330b8e9057d8efc9144753caed81995edeb1a42a53f93ce93540feca1fae708dac -a49e2c176a350251daef1218efaccc07a1e06203386ede59c136699d25ca5cb2ac1b800c25b28dd05678f14e78e51891 -83e0915aa2b09359604566080d411874af8c993beba97d4547782fdbe1a68e59324b800ff1f07b8db30c71adcbd102a8 -a19e84e3541fb6498e9bb8a099c495cbfcad113330e0262a7e4c6544495bb8a754b2208d0c2d895c93463558013a5a32 -87f2bd49859a364912023aca7b19a592c60214b8d6239e2be887ae80b69ebdeb59742bdebcfa73a586ab23b2c945586c -b8e8fdddae934a14b57bc274b8dcd0d45ebb95ddbaabef4454e0f6ce7d3a5a61c86181929546b3d60c447a15134d08e1 -87e0c31dcb736ea4604727e92dc1d9a3cf00adcff79df3546e02108355260f3dd171531c3c0f57be78d8b28058fcc8c0 -9617d74e8f808a4165a8ac2e30878c349e1c3d40972006f0787b31ea62d248c2d9f3fc3da83181c6e57e95feedfd0e8c -8949e2cee582a2f8db86e89785a6e46bc1565c2d8627d5b6bf43ba71ffadfab7e3c5710f88dcb5fb2fc6edf6f4fae216 -ad3fa7b0edceb83118972a2935a09f409d09a8db3869f30be3a76f67aa9fb379cabb3a3aff805ba023a331cad7d7eb64 -8c95718a4112512c4efbd496be38bf3ca6cdcaad8a0d128f32a3f9aae57f3a57bdf295a3b372a8c549fda8f4707cffed -88f3261d1e28a58b2dee3fcc799777ad1c0eb68b3560f9b4410d134672d9533532a91ea7be28a041784872632d3c9d80 -b47472a41d72dd2e8b72f5c4f8ad626737dde3717f63d6bc776639ab299e564cbad0a2ad5452a07f02ff49a359c437e5 -9896d21dc2e8aad87b76d6df1654f10cd7bceed4884159d50a818bea391f8e473e01e14684814c7780235f28e69dca6e -82d47c332bbd31bbe83b5eb44a23da76d4a7a06c45d7f80f395035822bc27f62f59281d5174e6f8e77cc9b5c3193d6f0 -95c74cd46206e7f70c9766117c34c0ec45c2b0f927a15ea167901a160e1530d8522943c29b61e03568aa0f9c55926c53 -a89d7757825ae73a6e81829ff788ea7b3d7409857b378ebccd7df73fdbe62c8d9073741cf038314971b39af6c29c9030 -8c1cd212d0b010905d560688cfc036ae6535bc334fa8b812519d810b7e7dcf1bb7c5f43deaa40f097158358987324a7f -b86993c383c015ed8d847c6b795164114dd3e9efd25143f509da318bfba89389ea72a420699e339423afd68b6512fafb -8d06bd379c6d87c6ed841d8c6e9d2d0de21653a073725ff74be1934301cc3a79b81ef6dd0aad4e7a9dc6eac9b73019bc -81af4d2d87219985b9b1202d724fe39ef988f14fef07dfe3c3b11714e90ffba2a97250838e8535eb63f107abfe645e96 -8c5e0af6330a8becb787e4b502f34f528ef5756e298a77dc0c7467433454347f3a2e0bd2641fbc2a45b95e231c6e1c02 -8e2a8f0f04562820dc8e7da681d5cad9fe2e85dd11c785fb6fba6786c57a857e0b3bd838fb849b0376c34ce1665e4837 -a39be8269449bfdfc61b1f62077033649f18dae9bef7c6163b9314ca8923691fb832f42776f0160b9e8abd4d143aa4e1 -8c154e665706355e1cc98e0a4cabf294ab019545ba9c4c399d666e6ec5c869ca9e1faf8fb06cd9c0a5c2f51a7d51b70a -a046a7d4de879d3ebd4284f08f24398e9e3bf006cd4e25b5c67273ade248689c69affff92ae810c07941e4904296a563 -afd94c1cb48758e5917804df03fb38a6da0e48cd9b6262413ea13b26973f9e266690a1b7d9d24bbaf7e82718e0e594b0 -859e21080310c8d6a38e12e2ac9f90a156578cdeb4bb2e324700e97d9a5511cd6045dc39d1d0de3f94aeed043a24119d -a219fb0303c379d0ab50893264919f598e753aac9065e1f23ef2949abc992577ab43c636a1d2c089203ec9ddb941e27d -b0fdb639d449588a2ca730afcba59334e7c387342d56defdfb7ef79c493f7fd0e5277eff18e7203e756c7bdda5803047 -87f9c3b7ed01f54368aca6dbcf2f6e06bff96e183c4b2c65f8baa23b377988863a0a125d5cdd41a072da8462ced4c070 -99ef7a5d5ac2f1c567160e1f8c95f2f38d41881850f30c461a205f7b1b9fb181277311333839b13fb3ae203447e17727 -aeaca9b1c2afd24e443326cc68de67b4d9cedb22ad7b501a799d30d39c85bb2ea910d4672673e39e154d699e12d9b3dc -a11675a1721a4ba24dd3d0e4c3c33a6edf4cd1b9f6b471070b4386c61f77452266eae6e3f566a40cfc885eada9a29f23 -b228334445e37b9b49cb4f2cc56b454575e92173ddb01370a553bba665adadd52df353ad74470d512561c2c3473c7bb9 -a18177087c996572d76f81178d18ed1ceebc8362a396348ce289f1d8bd708b9e99539be6fccd4acb1112381cfc5749b4 -8e7b8bf460f0d3c99abb19803b9e43422e91507a1c0c22b29ee8b2c52d1a384da4b87c292e28eff040db5be7b1f8641f -b03d038d813e29688b6e6f444eb56fec3abba64c3d6f890a6bcf2e916507091cdb2b9d2c7484617be6b26552ed1c56cb -a1c88ccd30e934adfc5494b72655f8afe1865a84196abfb376968f22ddc07761210b6a9fb7638f1413d1b4073d430290 -961b714faebf172ad2dbc11902461e286e4f24a99a939152a53406117767682a571057044decbeb3d3feef81f4488497 -a03dc4059b46effdd786a0a03cc17cfee8585683faa35bb07936ded3fa3f3a097f518c0b8e2db92fd700149db1937789 -adf60180c99ca574191cbcc23e8d025b2f931f98ca7dfcebfc380226239b6329347100fcb8b0fcb12db108c6ad101c07 -805d4f5ef24d46911cbf942f62cb84b0346e5e712284f82b0db223db26d51aabf43204755eb19519b00e665c7719fcaa -8dea7243e9c139662a7fe3526c6c601eee72fd8847c54c8e1f2ad93ef7f9e1826b170afe58817dac212427164a88e87f -a2ba42356606d651b077983de1ad643650997bb2babb188c9a3b27245bb65d2036e46667c37d4ce02cb1be5ae8547abe -af2ae50b392bdc013db2d12ce2544883472d72424fc767d3f5cb0ca2d973fc7d1f425880101e61970e1a988d0670c81b -98e6bec0568d3939b31d00eb1040e9b8b2a35db46ddf4369bdaee41bbb63cc84423d29ee510a170fb5b0e2df434ba589 -822ff3cd12fbef4f508f3ca813c04a2e0b9b799c99848e5ad3563265979e753ee61a48f6adc2984a850f1b46c1a43d35 -891e8b8b92a394f36653d55725ef514bd2e2a46840a0a2975c76c2a935577f85289026aaa74384da0afe26775cbddfb9 -b2a3131a5d2fe7c8967047aa66e4524babae941d90552171cc109527f345f42aa0df06dcbb2fa01b33d0043917bbed69 -80c869469900431f3eeefafdbe07b8afd8cee7739e659e6d0109b397cacff85a88247698f87dc4e2fe39a592f250ac64 -9091594f488b38f9d2bb5df49fd8b4f8829d9c2f11a197dd1431ed5abbc5c954bbde3387088f9ee3a5a834beb7619bce -b472e241e6956146cca57b97a8a204668d050423b4e76f857bad5b47f43b203a04c8391ba9d9c3e95093c071f9d376a1 -b7dd2de0284844392f7dfb56fe7ca3ede41e27519753ffc579a0a8d2d65ceb8108d06b6b0d4c3c1a2588951297bd1a1e -902116ce70d0a079ac190321c1f48701318c05f8e69ee09694754885d33a835a849cafe56f499a2f49f6cda413ddf9a7 -b18105cc736787fafaf7c3c11c448bce9466e683159dff52723b7951dff429565e466e4841d982e3aaa9ee2066838666 -97ab9911f3f659691762d568ae0b7faa1047b0aed1009c319fa79d15d0db8db9f808fc385dc9a68fa388c10224985379 -b2a2cba65f5b927e64d2904ba412e2bac1cf18c9c3eda9c72fb70262497ecf505b640827e2afebecf10eebbcf48ccd3e -b36a3fd677baa0d3ef0dac4f1548ff50a1730286b8c99d276a0a45d576e17b39b3cbadd2fe55e003796d370d4be43ce3 -a5dfec96ca3c272566e89dc453a458909247e3895d3e44831528130bc47cc9d0a0dac78dd3cad680a4351d399d241967 -8029382113909af6340959c3e61db27392531d62d90f92370a432aec3eb1e4c36ae1d4ef2ba8ec6edb4d7320c7a453f6 -971d85121ea108e6769d54f9c51299b0381ece8b51d46d49c89f65bedc123bab4d5a8bc14d6f67f4f680077529cbae4c -98ff6afc01d0bec80a278f25912e1b1ebff80117adae72e31d5b9fa4d9624db4ba2065b444df49b489b0607c45e26c4c -8fa29be10fb3ab30ce25920fec0187e6e91e458947009dabb869aade7136c8ba23602682b71e390c251f3743164cbdaa -b3345c89eb1653418fe3940cf3e56a9a9c66526389b98f45ca02dd62bfb37baa69a4baaa7132d7320695f8ea6ad1fd94 -b72c7f5541c9ac6b60a7ec9f5415e7fb14da03f7164ea529952a29399f3a071576608dbbcc0d45994f21f92ddbeb1e19 -aa3450bb155a5f9043d0ef95f546a2e6ade167280bfb75c9f09c6f9cdb1fffb7ce8181436161a538433afa3681c7a141 -92a18fecaded7854b349f441e7102b638ababa75b1b0281dd0bded6541abe7aa37d96693595be0b01fe0a2e2133d50f9 -980756ddf9d2253cfe6c94960b516c94889d09e612810935150892627d2ecee9a2517e04968eea295d0106850c04ca44 -ae68c6ccc454318cdd92f32b11d89116a3b8350207a36d22a0f626718cad671d960090e054c0c77ac3162ae180ecfd4b -99f31f66eaaa551749ad91d48a0d4e3ff4d82ef0e8b28f3184c54e852422ba1bdafd53b1e753f3a070f3b55f3c23b6a2 -a44eaeaa6589206069e9c0a45ff9fc51c68da38d4edff1d15529b7932e6f403d12b9387019c44a1488a5d5f27782a51f -b80b5d54d4b344840e45b79e621bd77a3f83fb4ce6d8796b7d6915107b3f3c34d2e7d95bdafd120f285669e5acf2437a -b36c069ec085a612b5908314d6b84c00a83031780261d1c77a0384c406867c9847d5b0845deddfa512cc04a8df2046fb -b09dbe501583220f640d201acea7ee3e39bf9eda8b91aa07b5c50b7641d86d71acb619b38d27835ce97c3759787f08e9 -87403d46a2bf63170fff0b857acacf42ee801afe9ccba8e5b4aea967b68eac73a499a65ca46906c2eb4c8f27bc739faa -82b93669f42a0a2aa5e250ffe6097269da06a9c02fcd1801abbad415a7729a64f830754bafc702e64600ba47671c2208 -8e3a3029be7edb8dd3ab1f8216664c8dc50d395f603736061d802cef77627db7b859ef287ed850382c13b4d22d6a2d80 -968e9ec7194ff424409d182ce0259acd950c384c163c04463bc8700a40b79beba6146d22b7fa7016875a249b7b31c602 -8b42c984bbe4996e0c20862059167c6bdc5164b1ffcd928f29512664459212d263e89f0f0e30eed4e672ffa5ed0b01b5 -96bac54062110dada905363211133f1f15dc7e4fd80a4c6e4a83bc9a0bcbbaba11cd2c7a13debcf0985e1a954c1da66b -a16dc8a653d67a7cd7ae90b2fffac0bf1ca587005430fe5ba9403edd70ca33e38ba5661d2ed6e9d2864400d997626a62 -a68ab11a570a27853c8d67e491591dcba746bfbee08a2e75ae0790399130d027ed387f41ef1d7de8df38b472df309161 -92532b74886874447c0300d07eda9bbe4b41ed25349a3da2e072a93fe32c89d280f740d8ff70d5816793d7f2b97373cc -88e35711b471e89218fd5f4d0eadea8a29405af1cd81974427bc4a5fb26ed60798daaf94f726c96e779b403a2cd82820 -b5c72aa4147c19f8c4f3a0a62d32315b0f4606e0a7025edc5445571eaf4daff64f4b7a585464821574dd50dbe1b49d08 -9305d9b4095258e79744338683fd93f9e657367b3ab32d78080e51d54eec331edbc224fad5093ebf8ee4bd4286757eb8 -b2a17abb3f6a05bcb14dc7b98321fa8b46d299626c73d7c6eb12140bf4c3f8e1795250870947af817834f033c88a59d6 -b3477004837dbd8ba594e4296f960fc91ab3f13551458445e6c232eb04b326da803c4d93e2e8dcd268b4413305ff84da -924b4b2ebaafdcfdfedb2829a8bf46cd32e1407d8d725a5bd28bdc821f1bafb3614f030ea4352c671076a63494275a3f -8b81b9ef6125c82a9bece6fdcb9888a767ac16e70527753428cc87c56a1236e437da8be4f7ecfe57b9296dc3ae7ba807 -906e19ec8b8edd58bdf9ae05610a86e4ea2282b1bbc1e8b00b7021d093194e0837d74cf27ac9916bdb8ec308b00da3da -b41c5185869071760ac786078a57a2ab4e2af60a890037ac0c0c28d6826f15c2cf028fddd42a9b6de632c3d550bfbc14 -a646e5dec1b713ae9dfdf7bdc6cd474d5731a320403c7dfcfd666ffc9ae0cff4b5a79530e8df3f4aa9cb80568cb138e9 -b0efad22827e562bd3c3e925acbd0d9425d19057868608d78c2209a531cccd0f2c43dc5673acf9822247428ffa2bb821 -a94c19468d14b6f99002fc52ac06bbe59e5c472e4a0cdb225144a62f8870b3f10593749df7a2de0bd3c9476ce682e148 -803864a91162f0273d49271dafaab632d93d494d1af935aefa522768af058fce52165018512e8d6774976d52bd797e22 -a08711c2f7d45c68fb340ac23597332e1bcaec9198f72967b9921204b9d48a7843561ff318f87908c05a44fc35e3cc9d -91c3cad94a11a3197ae4f9461faab91a669e0dddb0371d3cab3ed9aeb1267badc797d8375181130e461eadd05099b2a2 -81bdaaf48aae4f7b480fc13f1e7f4dd3023a41439ba231760409ce9292c11128ab2b0bdbbf28b98af4f97b3551f363af -8d60f9df9fd303f625af90e8272c4ecb95bb94e6efc5da17b8ab663ee3b3f673e9f6420d890ccc94acf4d2cae7a860d8 -a7b75901520c06e9495ab983f70b61483504c7ff2a0980c51115d11e0744683ce022d76e3e09f4e99e698cbd21432a0d -82956072df0586562fda7e7738226f694e1c73518dd86e0799d2e820d7f79233667192c9236dcb27637e4c65ef19d493 -a586beb9b6ffd06ad200957490803a7cd8c9bf76e782734e0f55e04a3dc38949de75dc607822ec405736c576cf83bca3 -a179a30d00def9b34a7e85607a447eea0401e32ab5abeee1a281f2acd1cf6ec81a178020666f641d9492b1bdf66f05a3 -83e129705c538787ed8e0fdc1275e6466a3f4ee21a1e6abedd239393b1df72244723b92f9d9d9339a0cab6ebf28f5a16 -811bd8d1e3722b64cd2f5b431167e7f91456e8bba2cc669d3fbbce7d553e29c3c19f629fcedd2498bc26d33a24891d17 -a243c030c858f1f60cccd26b45b024698cc6d9d9e6198c1ed4964a235d9f8d0baf9cde10c8e63dfaa47f8e74e51a6e85 -ab839eb82e23ca52663281f863b55b0a3d6d4425c33ffb4eeb1d7979488ab068bf99e2a60e82cea4dc42c56c26cbfebe -8b896f9bb21d49343e67aec6ad175b58c0c81a3ca73d44d113ae4354a0065d98eb1a5cafedaf232a2bb9cdc62152f309 -af6230340cc0b66f5bf845540ed4fc3e7d6077f361d60762e488d57834c3e7eb7eacc1b0ed73a7d134f174a01410e50c -88975e1b1af678d1b5179f72300a30900736af580dd748fd9461ef7afccc91ccd9bed33f9da55c8711a7635b800e831f -a97486bb9047391661718a54b8dd5a5e363964e495eae6c692730264478c927cf3e66dd3602413189a3699fbeae26e15 -a5973c161ab38732885d1d2785fd74bf156ba34881980cba27fe239caef06b24a533ffe6dbbbeca5e6566682cc00300a -a24776e9a840afda0003fa73b415d5bd6ecd9b5c2cc842b643ee51b8c6087f4eead4d0bfbd987eb174c489a7b952ff2a -a8a6ee06e3af053b705a12b59777267c546f33ba8a0f49493af8e6df4e15cf8dd2d4fb4daf7e84c6b5d3a7363118ff03 -a28e59ce6ad02c2ce725067c0123117e12ac5a52c8f5af13eec75f4a9efc4f696777db18a374fa33bcae82e0734ebd16 -86dfc3b78e841c708aff677baa8ee654c808e5d257158715097c1025d46ece94993efe12c9d188252ad98a1e0e331fec -a88d0275510f242eab11fdb0410ff6e1b9d7a3cbd3658333539815f1b450a84816e6613d15aa8a8eb15d87cdad4b27a2 -8440acea2931118a5b481268ff9f180ee4ede85d14a52c026adc882410825b8275caa44aff0b50c2b88d39f21b1a0696 -a7c3182eab25bd6785bacf12079d0afb0a9b165d6ed327814e2177148539f249eb9b5b2554538f54f3c882d37c0a8abe -85291fbe10538d7da38efdd55a7acebf03b1848428a2f664c3ce55367aece60039f4f320b1771c9c89a35941797f717c -a2c6414eeb1234728ab0de94aa98fc06433a58efa646ca3fcbd97dbfb8d98ae59f7ce6d528f669c8149e1e13266f69c9 -840c8462785591ee93aee2538d9f1ec44ba2ca61a569ab51d335ac873f5d48099ae8d7a7efa0725d9ff8f9475bfa4f56 -a7065a9d02fb3673acf7702a488fbc01aa69580964932f6f40b6c2d1c386b19e50b0e104fcac24ea26c4e723611d0238 -b72db6d141267438279e032c95e6106c2ccb3164b842ba857a2018f3a35f4b040da92680881eb17cd61d0920d5b8f006 -a8005d6c5960e090374747307ef0be2871a7a43fa4e76a16c35d2baab808e9777b496e9f57a4218b23390887c33a0b55 -8e152cea1e00a451ca47c20a1e8875873419700af15a5f38ee2268d3fbc974d4bd5f4be38008fa6f404dbdedd6e6e710 -a3391aed1fcd68761f06a7d1008ec62a09b1cb3d0203cd04e300a0c91adfed1812d8bc1e4a3fd7976dc0aae0e99f52f1 -967eb57bf2aa503ee0c6e67438098149eac305089c155f1762cf5e84e31f0fbf27c34a9af05621e34645c1ec96afaec8 -88af97ddc4937a95ec0dcd25e4173127260f91c8db2f6eac84afb789b363705fb3196235af631c70cafd09411d233589 -a32df75b3f2c921b8767638fd289bcfc61e08597170186637a7128ffedd52c798c434485ac2c7de07014f9e895c2c3d8 -b0a783832153650aa0d766a3a73ec208b6ce5caeb40b87177ffc035ab03c7705ecdd1090b6456a29f5fb7e90e2fa8930 -b59c8e803b4c3486777d15fc2311b97f9ded1602fa570c7b0200bada36a49ee9ef4d4c1474265af8e1c38a93eb66b18b -982f2c85f83e852022998ff91bafbb6ff093ef22cf9d5063e083a48b29175ccbd51b9c6557151409e439096300981a6c -939e3b5989fefebb9d272a954659a4eb125b98c9da6953f5e628d26266bd0525ec38304b8d56f08d65abc4d6da4a8dbb -8898212fe05bc8de7d18503cb84a1c1337cc2c09d1eeef2b475aa79185b7322bf1f8e065f1bf871c0c927dd19faf1f6d -94b0393a41cd00f724aee2d4bc72103d626a5aecb4b5486dd1ef8ac27528398edf56df9db5c3d238d8579af368afeb09 -96ac564450d998e7445dd2ea8e3fc7974d575508fa19e1c60c308d83b645864c029f2f6b7396d4ff4c1b24e92e3bac37 -8adf6638e18aff3eb3b47617da696eb6c4bdfbecbbc3c45d3d0ab0b12cbad00e462fdfbe0c35780d21aa973fc150285e -b53f94612f818571b5565bbb295e74bada9b5f9794b3b91125915e44d6ddcc4da25510eab718e251a09c99534d6042d9 -8b96462508d77ee083c376cd90807aebad8de96bca43983c84a4a6f196d5faf6619a2351f43bfeec101864c3bf255519 -aeadf34657083fc71df33bd44af73bf5281c9ca6d906b9c745536e1819ea90b56107c55e2178ebad08f3ba75b3f81c86 -9784ba29b2f0057b5af1d3ab2796d439b8753f1f749c73e791037461bdfc3f7097394283105b8ab01788ea5255a96710 -8756241bda159d4a33bf74faba0d4594d963c370fb6a18431f279b4a865b070b0547a6d1613cf45b8cfb5f9236bbf831 -b03ebfd6b71421dfd49a30460f9f57063eebfe31b9ceaa2a05c37c61522b35bdc09d7db3ad75c76c253c00ba282d3cd2 -b34e7e6341fa9d854b2d3153bdda0c4ae2b2f442ab7af6f99a0975d45725aa48e36ae5f7011edd249862e91f499687d4 -b462ee09dc3963a14354244313e3444de5cc37ea5ccfbf14cd9aca8027b59c4cb2a949bc30474497cab8123e768460e6 -aea753290e51e2f6a21a9a0ee67d3a2713f95c2a5c17fe41116c87d3aa77b1683761264d704df1ac34f8b873bc88ef7b -98430592afd414394f98ddfff9f280fcb1c322dbe3510f45e1e9c4bb8ee306b3e0cf0282c0ee73ebb8ba087d4d9e0858 -b95d3b5aaf54ffca11f4be8d57f76e14afdb20afc859dc7c7471e0b42031e8f3d461b726ecb979bdb2f353498dfe95ea -984d17f9b11a683132e0b5a9ee5945e3ff7054c2d5c716be73b29078db1d36f54c6e652fd2f52a19da313112e97ade07 -ab232f756b3fff3262be418a1af61a7e0c95ceebbc775389622a8e10610508cd6784ab7960441917a83cc191c58829ea -a28f41678d6e60de76b0e36ab10e4516e53e02e9c77d2b5af3cfeee3ce94cfa30c5797bd1daab20c98e1cad83ad0f633 -b55395fca84dd3ccc05dd480cb9b430bf8631ff06e24cb51d54519703d667268c2f8afcde4ba4ed16bece8cc7bc8c6e0 -8a8a5392a0e2ea3c7a8c51328fab11156004e84a9c63483b64e8f8ebf18a58b6ffa8fe8b9d95af0a2f655f601d096396 -ab480000fe194d23f08a7a9ec1c392334e9c687e06851f083845121ce502c06b54dda8c43092bcc1035df45cc752fe9b -b265644c29f628d1c7e8e25a5e845cabb21799371814730a41a363e1bda8a7be50fee7c3996a365b7fcba4642add10db -b8a915a3c685c2d4728f6931c4d29487cad764c5ce23c25e64b1a3259ac27235e41b23bfe7ae982921b4cb84463097df -8efa7338442a4b6318145a5440fc213b97869647eeae41b9aa3c0a27ee51285b73e3ae3b4a9423df255e6add58864aa9 -9106d65444f74d217f4187dfc8fcf3810b916d1e4275f94f6a86d1c4f3565b131fd6cde1fa708bc05fe183c49f14941a -948252dac8026bbbdb0a06b3c9d66ec4cf9532163bab68076fda1bd2357b69e4b514729c15aaa83b5618b1977bbc60c4 -ae6596ccfdf5cbbc5782efe3bb0b101bb132dbe1d568854ca24cacc0b2e0e9fabcb2ca7ab42aecec412efd15cf8cb7a2 -84a0b6c198ff64fd7958dfd1b40eac9638e8e0b2c4cd8cf5d8cdf80419baee76a05184bce6c5b635f6bf2d30055476a7 -8893118be4a055c2b3da593dbca51b1ae2ea2469911acfb27ee42faf3e6c3ad0693d3914c508c0b05b36a88c8b312b76 -b097479e967504deb6734785db7e60d1d8034d6ca5ba9552887e937f5e17bb413fccac2c1d1082154ed76609127860ad -a0294e6b9958f244d29943debf24b00b538b3da1116269b6e452bb12dc742226712fd1a15b9c88195afeb5d2415f505c -b3cc15f635080bc038f61b615f62b5b5c6f2870586191f59476e8368a73641d6ac2f7d0c1f54621982defdb318020230 -99856f49b9fe1604d917c94d09cc0ed753d13d015d30587a94e6631ffd964b214e607deb8a69a8b5e349a7edf4309206 -a8571e113ea22b4b4fce41a094da8c70de37830ae32e62c65c2fa5ad06a9bc29e884b945e73d448c72b176d6ecebfb58 -a9e9c6e52beb0013273c29844956b3ce291023678107cdc785f7b44eff5003462841ad8780761b86aefc6b734adde7cf -80a784b0b27edb51ef2bad3aee80e51778dcaa0f3f5d3dcb5dc5d4f4b2cf7ae35b08de6680ea9dac53f8438b92eb09ef -827b543e609ea328e97e373f70ad72d4915a2d1daae0c60d44ac637231070e164c43a2a58db80a64df1c624a042b38f9 -b449c65e8195202efdcb9bdb4e869a437313b118fef8b510cbbf8b79a4e99376adb749b37e9c20b51b31ed3310169e27 -8ea3028f4548a79a94c717e1ed28ad4d8725b8d6ab18b021063ce46f665c79da3c49440c6577319dab2d036b7e08f387 -897798431cfb17fe39f08f5f854005dc37b1c1ec1edba6c24bc8acb3b88838d0534a75475325a5ea98b326ad47dbad75 -89cf232e6303b0751561960fd4dea5754a28c594daf930326b4541274ffb03c7dd75938e411eb9a375006a70ce38097f -9727c6ae7f0840f0b6c8bfb3a1a5582ceee705e0b5c59b97def7a7a2283edd4d3f47b7971e902a3a2079e40b53ff69b8 -b76ed72b122c48679d221072efc0eeea063cb205cbf5f9ef0101fd10cb1075b8628166c83577cced654e1c001c7882f7 -ae908c42d208759da5ee9b405df85a6532ea35c6f0f6a1288d22870f59d98edc896841b8ac890a538e6c8d1e8b02d359 -809d12fe4039a0ec80dc9be6a89acaab7797e5f7f9b163378f52f9a75a1d73b2e9ae6e3dd49e32ced439783c1cabbef5 -a4149530b7f85d1098ba534d69548c6c612c416e8d35992fc1f64f4deeb41e09e49c6cf7aadbed7e846b91299358fe2d -a49342eacd1ec1148b8df1e253b1c015f603c39de11fa0a364ccb86ea32d69c34fd7aa6980a1fadcd8e785a57fa46f60 -87d43eff5a006dc4dddcf76cc96c656a1f3a68f19f124181feab86c6cc9a52cb9189cdbb423414defdd9bb0ca8ff1ddc -861367e87a9aa2f0f68296ba50aa5dbc5713008d260cc2c7e62d407c2063064749324c4e8156dc21b749656cfebce26b -b5303c2f72e84e170e66ae1b0fbd51b8c7a6f27476eaf5694b64e8737d5c84b51fe90100b256465a4c4156dd873cddb0 -b62849a4f891415d74f434cdc1d23c4a69074487659ca96e1762466b2b7a5d8525b056b891d0feea6fe6845cba8bc7fb -923dd9e0d6590a9307e8c4c23f13bae3306b580e297a937711a8b13e8de85e41a61462f25b7d352b682e8437bf2b4ab3 -9147379860cd713cd46c94b8cdf75125d36c37517fbecf81ace9680b98ce6291cd1c3e472f84249cc3b2b445e314b1b6 -a808a4f17ac21e3fb5cfef404e61fae3693ca3e688d375f99b6116779696059a146c27b06de3ac36da349b0649befd56 -87787e9322e1b75e66c1f0d9ea0915722a232770930c2d2a95e9478c4b950d15ab767e30cea128f9ed65893bfc2d0743 -9036a6ee2577223be105defe1081c48ea7319e112fff9110eb9f61110c319da25a6cea0464ce65e858635b079691ef1f -af5548c7c24e1088c23b57ee14d26c12a83484c9fd9296edf1012d8dcf88243f20039b43c8c548c265ef9a1ffe9c1c88 -a0fff520045e14065965fb8accd17e878d3fcaf9e0af2962c8954e50be6683d31fa0bf4816ab68f08630dbac6bfce52a -b4c1b249e079f6ae1781af1d97a60b15855f49864c50496c09c91fe1946266915b799f0406084d7783f5b1039116dd8b -8b0ffa5e7c498cb3879dddca34743b41eee8e2dea3d4317a6e961b58adb699ef0c92400c068d5228881a2b08121226bf -852ae8b19a1d80aa8ae5382e7ee5c8e7670ceb16640871c56b20b96b66b3b60e00015a3dde039446972e57b49a999ddd -a49942f04234a7d8492169da232cfff8051df86e8e1ba3db46aede02422c689c87dc1d99699c25f96cb763f5ca0983e5 -b04b597b7760cf5dcf411ef896d1661e6d5b0db3257ac2cf64b20b60c6cc18fa10523bb958a48d010b55bac7b02ab3b1 -a494591b51ea8285daecc194b5e5bd45ae35767d0246ac94fae204d674ee180c8e97ff15f71f28b7aeb175b8aea59710 -97d2624919e78406e7460730680dea8e71c8571cf988e11441aeea54512b95bd820e78562c99372d535d96f7e200d20d -ac693ddb00e48f76e667243b9b6a7008424043fb779e4f2252330285232c3fccac4da25cbd6d95fe9ad959ff305a91f6 -8d20ca0a71a64a3f702a0825bb46bd810d03bebfb227683680d474a52f965716ff99e19a165ebaf6567987f4f9ee3c94 -a5c516a438f916d1d68ca76996404792e0a66e97b7f18fc54c917bf10cf3211b62387932756e39e67e47b0bd6e88385a -b089614d830abc0afa435034cec7f851f2f095d479cacf1a3fb57272da826c499a52e7dcbc0eb85f4166fb94778e18e9 -a8dacc943765d930848288192f4c69e2461c4b9bc6e79e30eeef9a543318cf9ae9569d6986c65c5668a89d49993f8e07 -ab5a9361fa339eec8c621bdad0a58078983abd8942d4282b22835d7a3a47e132d42414b7c359694986f7db39386c2e19 -94230517fb57bd8eb26c6f64129b8b2abd0282323bf7b94b8bac7fab27b4ecc2c4290c294275e1a759de19f2216134f3 -b8f158ea5006bc3b90b285246625faaa6ac9b5f5030dc69701b12f3b79a53ec7e92eeb5a63bbd1f9509a0a3469ff3ffc -8b6944fd8cb8540957a91a142fdcda827762aa777a31e8810ca6d026e50370ee1636fc351724767e817ca38804ebe005 -82d1ee40fe1569c29644f79fa6c4033b7ed45cd2c3b343881f6eb0de2e79548fded4787fae19bed6ee76ed76ff9f2f11 -a8924c7035e99eaed244ca165607e7e568b6c8085510dcdbaf6ebdbed405af2e6c14ee27d94ffef10d30aa52a60bf66d -956f82a6c2ae044635e85812581e4866c5fa2f427b01942047d81f6d79a14192f66fbbe77c9ffeaef4e6147097fdd2b5 -b1100255a1bcf5e05b6aff1dfeb6e1d55b5d68d43a7457ba10cc76b61885f67f4d0d5179abda786e037ae95deb8eea45 -99510799025e3e5e8fbf06dedb14c060c6548ba2bda824f687d3999dc395e794b1fb6514b9013f3892b6cf65cb0d65aa -8f9091cebf5e9c809aab415942172258f894e66e625d7388a05289183f01b8d994d52e05a8e69f784fba41db9ea357f0 -a13d2eeb0776bdee9820ecb6693536720232848c51936bb4ef4fe65588d3f920d08a21907e1fdb881c1ad70b3725e726 -a68b8f18922d550284c5e5dc2dda771f24c21965a6a4d5e7a71678178f46df4d8a421497aad8fcb4c7e241aba26378a0 -8b7601f0a3c6ad27f03f2d23e785c81c1460d60100f91ea9d1cab978aa03b523150206c6d52ce7c7769c71d2c8228e9e -a8e02926430813caa851bb2b46de7f0420f0a64eb5f6b805401c11c9091d3b6d67d841b5674fa2b1dce0867714124cd8 -b7968ecba568b8193b3058400af02c183f0a6df995a744450b3f7e0af7a772454677c3857f99c140bbdb2a09e832e8e0 -8f20b1e9ba87d0a3f35309b985f3c18d2e8800f1ca7f0c52cadef773f1496b6070c936eea48c4a1cae83fd2524e9d233 -88aef260042db0d641a51f40639dbeeefa9e9811df30bee695f3791f88a2f84d318f04e8926b7f47bf25956cb9e3754f -9725345893b647e9ba4e6a29e12f96751f1ae25fcaec2173e9a259921a1a7edb7a47159b3c8767e44d9e2689f5aa0f72 -8c281e6f72752cb11e239e4df9341c45106eb7993c160e54423c2bffe10bc39d42624b45a1f673936ef2e1a02fc92f1a -90aba2f68bddb2fcce6c51430dacdfeec43ea8dc379660c99095df11017691ccf5faa27665cf4b9f0eea7728ae53c327 -b7022695c16521c5704f49b7ddbdbec9b5f57ce0ceebe537bc0ebb0906d8196cc855a9afeb8950a1710f6a654464d93f -8fe1b9dd3c6a258116415d36e08374e094b22f0afb104385a5da48be17123e86fb8327baacc4f0d9ebae923d55d99bb5 -817e85d8e3d19a4cbc1dec31597142c2daa4871bda89c2177fa719c00eda3344eb08b82eb92d4aa91a9eaacb3fc09783 -b59053e1081d2603f1ca0ba553804d6fa696e1fd996631db8f62087b26a40dfef02098b0326bb75f99ec83b9267ca738 -990a173d857d3ba81ff3789b931bfc9f5609cde0169b7f055fa3cb56451748d593d62d46ba33f80f9cafffe02b68dd14 -b0c538dbba4954b809ab26f9f94a3cf1dcb77ce289eaec1d19f556c0ae4be1fa03af4a9b7057837541c3cc0a80538736 -ac3ba42f5f44f9e1fc453ce49c4ab79d0e1d5c42d3b30b1e098f3ab3f414c4c262fa12fb2be249f52d4aaf3c5224beb9 -af47467eb152e59870e21f0d4da2f43e093daf40180ab01438030684b114d025326928eaab12c41b81a066d94fce8436 -98d1b58ba22e7289b1c45c79a24624f19b1d89e00f778eef327ec4856a9a897278e6f1a9a7e673844b31dde949153000 -97ccb15dfadc7c59dca08cfe0d22df2e52c684cf97de1d94bc00d7ba24e020025130b0a39c0f4d46e4fc872771ee7875 -b699e4ed9a000ff96ca296b2f09dce278832bc8ac96851ff3cff99ed3f6f752cfc0fea8571be28cd9b5a7ec36f1a08ee -b9f49f0edb7941cc296435ff0a912e3ad16848ee8765ab5f60a050b280d6ea585e5b34051b15f6b8934ef01ceb85f648 -ac3893df7b4ceab23c6b9054e48e8ba40d6e5beda8fbe90b814f992f52494186969b35d8c4cdc3c99890a222c9c09008 -a41293ad22fae81dea94467bc1488c3707f3d4765059173980be93995fa4fcc3c9340796e3eed0beeb0ba0d9bb4fa3aa -a0543e77acd2aeecde13d18d258aeb2c7397b77f17c35a1992e8666ea7abcd8a38ec6c2741bd929abba2f766138618cc -92e79b22bc40e69f6527c969500ca543899105837b6b1075fa1796755c723462059b3d1b028e0b3df2559fa440e09175 -a1fa1eac8f41a5197a6fb4aa1eae1a031c89f9c13ff9448338b222780cf9022e0b0925d930c37501a0ef7b2b00fdaf83 -b3cb29ff73229f0637335f28a08ad8c5f166066f27c6c175164d0f26766a927f843b987ee9b309ed71cbf0a65d483831 -84d4ab787f0ac00f104f4a734dc693d62d48c2aeb03913153da62c2ae2c27d11b1110dcef8980368dd84682ea2c1a308 -ab6a8e4bbc78d4a7b291ad3e9a8fe2d65f640524ba3181123b09d2d18a9e300e2509ccf7000fe47e75b65f3e992a2e7e -b7805ebe4f1a4df414003dc10bca805f2ab86ca75820012653e8f9b79c405196b0e2cab099f2ab953d67f0d60d31a0f9 -b12c582454148338ea605d22bd00a754109063e22617f1f8ac8ddf5502c22a181c50c216c3617b9852aa5f26af56b323 -86333ad9f898947e31ce747728dc8c887479e18d36ff3013f69ebef807d82c6981543b5c3788af93c4d912ba084d3cba -b514efa310dc4ad1258add138891e540d8c87142a881b5f46563cc58ecd1488e6d3a2fca54c0b72a929f3364ca8c333e -aa0a30f92843cf2f484066a783a1d75a7aa6f41f00b421d4baf20a6ac7886c468d0eea7ca8b17dd22f4f74631b62b640 -b3b7dc63baec9a752e8433c0cdee4d0f9bc41f66f2b8d132faf925eef9cf89aae756fc132c45910f057122462605dc10 -b9b8190dac5bfdeb59fd44f4da41a57e7f1e7d2c21faba9da91fa45cbeca06dcf299c9ae22f0c89ece11ac46352d619f -89f8cf36501ad8bdfeab863752a9090e3bfda57cf8fdeca2944864dc05925f501e252c048221bcc57136ab09a64b64b2 -b0cbfaf317f05f97be47fc9d69eda2dd82500e00d42612f271a1fe24626408c28881f171e855bd5bd67409f9847502b4 -a7c21a8fcede581bfd9847b6835eda62ba250bea81f1bb17372c800a19c732abe03064e64a2f865d974fb636cab4b859 -95f9df524ba7a4667351696c4176b505d8ea3659f5ff2701173064acc624af69a0fad4970963736383b979830cb32260 -856a74fe8b37a2e3afeac858c8632200485d438422a16ae3b29f359e470e8244995c63ad79c7e007ed063f178d0306fd -b37faa4d78fdc0bb9d403674dbea0176c2014a171c7be8527b54f7d1a32a76883d3422a3e7a5f5fcc5e9b31b57822eeb -8d37234d8594ec3fe75670b5c9cc1ec3537564d4739b2682a75b18b08401869a4264c0f264354219d8d896cded715db4 -b5289ee5737f0e0bde485d32096d23387d68dab8f01f47821ab4f06cc79a967afe7355e72dc0c751d96b2747b26f6255 -9085e1fdf9f813e9c3b8232d3c8863cd84ab30d45e8e0d3d6a0abd9ebc6fd70cdf749ff4d04390000e14c7d8c6655fc7 -93a388c83630331eca4da37ea4a97b3b453238af474817cc0a0727fd3138dcb4a22de38c04783ec829c22cb459cb4e8e -a5377116027c5d061dbe24c240b891c08cdd8cd3f0899e848d682c873aff5b8132c1e7cfe76d2e5ed97ee0eb1d42cb68 -a274c84b04338ed28d74683e2a7519c2591a3ce37c294d6f6e678f7d628be2db8eff253ede21823e2df7183e6552f622 -8bc201147a842453a50bec3ac97671397bc086d6dfc9377fa38c2124cdc286abda69b7324f47d64da094ae011d98d9d9 -9842d0c066c524592b76fbec5132bc628e5e1d21c424bec4555efca8619cc1fd8ea3161febcb8b9e8ab54702f4e815e2 -a19191b713a07efe85c266f839d14e25660ee74452e6c691cd9997d85ae4f732052d802d3deb018bdd847caa298a894b -a24f71fc0db504da4e287dd118a4a74301cbcd16033937ba2abc8417956fcb4ae19b8e63b931795544a978137eff51cb -a90eec4a6a3a4b8f9a5b93d978b5026fcf812fe65585b008d7e08c4aaf21195a1d0699f12fc16f79b6a18a369af45771 -8b551cf89737d7d06d9b3b9c4c1c73b41f2ea0af4540999c70b82dabff8580797cf0a3caf34c86c59a7069eb2e38f087 -b8d312e6c635e7a216a1cda075ae77ba3e1d2fd501dc31e83496e6e81ed5d9c7799f8e578869c2e0e256fb29f5de10a7 -8d144bdb8cae0b2cdb5b33d44bbc96984a5925202506a8cc65eb67ac904b466f5a7fe3e1cbf04aa785bbb7348c4bb73c -a101b3d58b7a98659244b88de0b478b3fb87dc5fc6031f6e689b99edf498abd43e151fd32bd4bbd240e0b3e59c440359 -907453abca7d8e7151a05cc3d506c988007692fe7401395dc93177d0d07d114ab6cca0cc658eb94c0223fe8658295cad -825329ffbe2147ddb68f63a0a67f32d7f309657b8e5d9ab5bb34b3730bfa2c77a23eaaadb05def7d9f94a9e08fdc1e96 -88ee923c95c1dac99ae7ed6067906d734d793c5dc5d26339c1bb3314abe201c5dccb33b9007351885eb2754e9a8ea06c -98bc9798543f5f1adc9f2cfcfa72331989420e9c3f6598c45269f0dc9b7c8607bbeaf03faa0aea2ddde2b8f17fdceff5 -8ee87877702a79aef923ab970db6fa81561b3c07d5bf1a072af0a7bad765b4cbaec910afe1a91703feacc7822fa38a94 -8060b9584aa294fe8adc2b22f67e988bc6da768eae91e429dcc43ddc53cfcc5d6753fdc1b420b268c7eb2fb50736a970 -b344a5524d80a2f051870c7001f74fcf348a70fcf78dbd20c6ff9ca85d81567d2318c8b8089f2c4f195d6aec9fc15fa6 -8f5a5d893e1936ed062149d20eb73d98b62b7f50ab5d93a6429c03656b36688d1c80cb5010e4977491e51fa0d7dd35d5 -86fa32ebbf97328c5f5f15564e1238297e289ec3219b9a741724e9f3ae8d5c15277008f555863a478b247ba5dc601d44 -9557e55377e279f4b6b5e0ffe01eca037cc13aac242d67dfcd0374a1e775c5ed5cb30c25fe21143fee54e3302d34a3ea -8cb6bcbc39372d23464a416ea7039f57ba8413cf3f00d9a7a5b356ab20dcb8ed11b3561f7bce372b8534d2870c7ee270 -b5d59075cb5abde5391f64b6c3b8b50adc6e1f654e2a580b6d6d6eff3f4fbdd8fffc92e06809c393f5c8eab37f774c4b -afcfb6903ef13e493a1f7308675582f15af0403b6553e8c37afb8b2808ad21b88b347dc139464367dc260df075fea1ad -810fbbe808375735dd22d5bc7fc3828dc49fdd22cc2d7661604e7ac9c4535c1df578780affb3b895a0831640a945bcad -8056b0c678803b416f924e09a6299a33cf9ad7da6fe1ad7accefe95c179e0077da36815fde3716711c394e2c5ea7127f -8b67403702d06979be19f1d6dc3ec73cc2e81254d6b7d0cc49cd4fdda8cd51ab0835c1d2d26fc0ecab5df90585c2f351 -87f97f9e6d4be07e8db250e5dd2bffdf1390665bc5709f2b631a6fa69a7fca958f19bd7cc617183da1f50ee63e9352b5 -ae151310985940471e6803fcf37600d7fa98830613e381e00dab943aec32c14162d51c4598e8847148148000d6e5af5c -81eb537b35b7602c45441cfc61b27fa9a30d3998fad35a064e05bc9479e9f10b62eba2b234b348219eea3cadcaac64bb -8a441434934180ab6f5bc541f86ebd06eadbee01f438836d797e930fa803a51510e005c9248cecc231a775b74d12b5e9 -81f3c250a27ba14d8496a5092b145629eb2c2e6a5298438670375363f57e2798207832c8027c3e9238ad94ecdadfc4df -a6217c311f2f3db02ceaa5b6096849fe92b6f4b6f1491535ef8525f6ccee6130bed2809e625073ecbaddd4a3eb3df186 -82d1c396f0388b942cf22b119d7ef1ad03d3dad49a74d9d01649ee284f377c8daddd095d596871669e16160299a210db -a40ddf7043c5d72a7246bd727b07f7fff1549f0e443d611de6f9976c37448b21664c5089c57f20105102d935ab82f27b -b6c03c1c97adf0c4bf4447ec71366c6c1bff401ba46236cd4a33d39291e7a1f0bb34bd078ba3a18d15c98993b153a279 -8a94f5f632068399c359c4b3a3653cb6df2b207379b3d0cdace51afdf70d6d5cce6b89a2b0fee66744eba86c98fb21c2 -b2f19e78ee85073f680c3bba1f07fd31b057c00b97040357d97855b54a0b5accb0d3b05b2a294568fcd6a4be6f266950 -a74632d13bbe2d64b51d7a9c3ae0a5a971c19f51cf7596a807cea053e6a0f3719700976d4e394b356c0329a2dced9aa2 -afef616d341a9bc94393b8dfba68ff0581436aa3a3adb7c26a1bbf2cf19fa877066191681f71f17f3cd6f9cf6bf70b5a -8ce96d93ae217408acf7eb0f9cbb9563363e5c7002e19bbe1e80760bc9d449daee2118f3878b955163ed664516b97294 -8414f79b496176bc8b8e25f8e4cfee28f4f1c2ddab099d63d2aca1b6403d26a571152fc3edb97794767a7c4686ad557c -b6c61d01fd8ce087ef9f079bf25bf10090db483dd4f88c4a786d31c1bdf52065651c1f5523f20c21e75cea17df69ab73 -a5790fd629be70545093631efadddc136661f63b65ec682609c38ef7d3d7fa4e56bdf94f06e263bc055b90cb1c6bcefe -b515a767e95704fb7597bca9e46f1753abacdc0e56e867ee3c6f4cd382643c2a28e65312c05ad040eaa3a8cbe7217a65 -8135806a02ead6aa92e9adb6fefb91349837ab73105aaa7be488ef966aa8dfaafdfa64bbae30fcbfa55dd135a036a863 -8f22435702716d76b1369750694540742d909d5e72b54d0878245fab7c269953b1c6f2b29c66f08d5e0263ca3a731771 -8e0f8a8e8753e077dac95848212aeffd51c23d9b6d611df8b102f654089401954413ecbedc6367561ca599512ae5dda7 -815a9084e3e2345f24c5fa559deec21ee1352fb60f4025c0779be65057f2d528a3d91593bd30d3a185f5ec53a9950676 -967e6555ccba395b2cc1605f8484c5112c7b263f41ce8439a99fd1c71c5ed14ad02684d6f636364199ca48afbbde13be -8cd0ccf17682950b34c796a41e2ea7dd5367aba5e80a907e01f4cdc611e4a411918215e5aebf4292f8b24765d73314a6 -a58bf1bbb377e4b3915df6f058a0f53b8fb8130fdec8c391f6bc82065694d0be59bb67ffb540e6c42cc8b380c6e36359 -92af3151d9e6bfb3383d85433e953c0160859f759b0988431ec5893542ba40288f65db43c78a904325ef8d324988f09d -8011bbb05705167afb47d4425065630f54cb86cd462095e83b81dfebf348f846e4d8fbcf1c13208f5de1931f81da40b9 -81c743c104fc3cb047885c9fa0fb9705c3a83ee24f690f539f4985509c3dafd507af3f6a2128276f45d5939ef70c167f -a2c9679b151c041aaf5efeac5a737a8f70d1631d931609fca16be1905682f35e291292874cb3b03f14994f98573c6f44 -a4949b86c4e5b1d5c82a337e5ce6b2718b1f7c215148c8bfb7e7c44ec86c5c9476048fc5c01f57cb0920876478c41ad6 -86c2495088bd1772152e527a1da0ef473f924ea9ab0e5b8077df859c28078f73c4e22e3a906b507fdf217c3c80808b5c -892e0a910dcf162bcea379763c3e2349349e4cda9402949255ac4a78dd5a47e0bf42f5bd0913951576b1d206dc1e536a -a7009b2c6b396138afe4754b7cc10dee557c51c7f1a357a11486b3253818531f781ea8107360c8d4c3b1cd96282353c0 -911763ef439c086065cc7b4e57484ed6d693ea44acee4b18c9fd998116da55fbe7dcb8d2a0f0f9b32132fca82d73dff6 -a722000b95a4a2d40bed81870793f15ba2af633f9892df507f2842e52452e02b5ea8dea6a043c2b2611d82376e33742a -9387ac49477bd719c2f92240d0bdfcf9767aad247ca93dc51e56106463206bc343a8ec855eb803471629a66fffb565d6 -92819a1fa48ab4902939bb72a0a4e6143c058ea42b42f9bc6cea5df45f49724e2530daf3fc4f097cceefa2a8b9db0076 -98eac7b04537653bc0f4941aae732e4b1f84bd276c992c64a219b8715eb1fb829b5cbd997d57feb15c7694c468f95f70 -b275e7ba848ce21bf7996e12dbeb8dadb5d0e4f1cb5a0248a4f8f9c9fe6c74e3c93f4b61edbcb0a51af5a141e1c14bc7 -97243189285aba4d49c53770c242f2faf5fd3914451da4931472e3290164f7663c726cf86020f8f181e568c72fd172d1 -839b0b3c25dd412bee3dc24653b873cc65454f8f16186bb707bcd58259c0b6765fa4c195403209179192a4455c95f3b8 -8689d1a870514568a074a38232e2ceb4d7df30fabeb76cff0aed5b42bf7f02baea12c5fadf69f4713464dbd52aafa55f -8958ae7b290f0b00d17c3e9fdb4dbf168432b457c7676829299dd428984aba892de1966fc106cfc58a772862ecce3976 -a422bc6bd68b8870cfa5bc4ce71781fd7f4368b564d7f1e0917f6013c8bbb5b240a257f89ecfdbecb40fe0f3aa31d310 -aa61f78130cebe09bc9a2c0a37f0dd57ed2d702962e37d38b1df7f17dc554b1d4b7a39a44182a452ce4c5eb31fa4cfcc -b7918bd114f37869bf1a459023386825821bfadce545201929d13ac3256d92a431e34f690a55d944f77d0b652cefeffc -819bba35fb6ace1510920d4dcff30aa682a3c9af9022e287751a6a6649b00c5402f14b6309f0aeef8fce312a0402915e -8b7c9ad446c6f63c11e1c24e24014bd570862b65d53684e107ba9ad381e81a2eaa96731b4b33536efd55e0f055071274 -8fe79b53f06d33386c0ec7d6d521183c13199498594a46d44a8a716932c3ec480c60be398650bbfa044fa791c4e99b65 -9558e10fb81250b9844c99648cf38fa05ec1e65d0ccbb18aa17f2d1f503144baf59d802c25be8cc0879fff82ed5034ad -b538a7b97fbd702ba84645ca0a63725be1e2891c784b1d599e54e3480e4670d0025526674ef5cf2f87dddf2290ba09f0 -92eafe2e869a3dd8519bbbceb630585c6eb21712b2f31e1b63067c0acb5f9bdbbcbdb612db4ea7f9cc4e7be83d31973f -b40d21390bb813ab7b70a010dff64c57178418c62685761784e37d327ba3cb9ef62df87ecb84277c325a637fe3709732 -b349e6fbf778c4af35fbed33130bd8a7216ed3ba0a79163ebb556e8eb8e1a7dad3456ddd700dad9d08d202491c51b939 -a8fdaedecb251f892b66c669e34137f2650509ade5d38fbe8a05d9b9184bb3b2d416186a3640429bd1f3e4b903c159dd -ac6167ebfee1dbab338eff7642f5e785fc21ef0b4ddd6660333fe398068cbd6c42585f62e81e4edbb72161ce852a1a4f -874b1fbf2ebe140c683bd7e4e0ab017afa5d4ad38055aaa83ee6bbef77dbc88a6ce8eb0dcc48f0155244af6f86f34c2d -903c58e57ddd9c446afab8256a6bb6c911121e6ccfb4f9b4ed3e2ed922a0e500a5cb7fa379d5285bc16e11dac90d1fda -8dae7a0cffa2fd166859cd1bf10ff82dd1932e488af377366b7efc0d5dec85f85fe5e8150ff86a79a39cefc29631733a -aa047857a47cc4dfc08585f28640420fcf105b881fd59a6cf7890a36516af0644d143b73f3515ab48faaa621168f8c31 -864508f7077c266cc0cb3f7f001cb6e27125ebfe79ab57a123a8195f2e27d3799ff98413e8483c533b46a816a3557f1f -8bcd45ab1f9cbab36937a27e724af819838f66dfeb15923f8113654ff877bd8667c54f6307aaf0c35027ca11b6229bfd -b21aa34da9ab0a48fcfdd291df224697ce0c1ebc0e9b022fdee8750a1a4b5ba421c419541ed5c98b461eecf363047471 -a9a18a2ab2fae14542dc336269fe612e9c1af6cf0c9ac933679a2f2cb77d3c304114f4d219ca66fe288adde30716775b -b5205989b92c58bdda71817f9a897e84100b5c4e708de1fced5c286f7a6f01ae96b1c8d845f3a320d77c8e2703c0e8b1 -a364059412bbcc17b8907d43ac8e5df90bc87fd1724b5f99832d0d24559fae6fa76a74cff1d1eac8cbac6ec80b44af20 -ae709f2c339886b31450834cf29a38b26eb3b0779bd77c9ac269a8a925d1d78ea3837876c654b61a8fe834b3b6940808 -8802581bba66e1952ac4dab36af371f66778958f4612901d95e5cac17f59165e6064371d02de8fb6fccf89c6dc8bd118 -a313252df653e29c672cbcfd2d4f775089cb77be1077381cf4dc9533790e88af6cedc8a119158e7da5bf6806ad9b91a1 -992a065b4152c7ef11515cd54ba9d191fda44032a01aed954acff3443377ee16680c7248d530b746b8c6dee2d634e68c -b627b683ee2b32c1ab4ccd27b9f6cce2fe097d96386fa0e5c182ad997c4c422ab8dfc03870cd830b8c774feb66537282 -b823cf8a9aee03dadd013eb9efe40a201b4b57ef67efaae9f99683005f5d1bf55e950bf4af0774f50859d743642d3fea -b8a7449ffac0a3f206677097baf7ce00ca07a4d2bd9b5356fbcb83f3649b0fda07cfebad220c1066afba89e5a52abf4b -b2dd1a2f986395bb4e3e960fbbe823dbb154f823284ebc9068502c19a7609790ec0073d08bfa63f71e30c7161b6ef966 -98e5236de4281245234f5d40a25b503505af140b503a035fc25a26159a9074ec81512b28f324c56ea2c9a5aa7ce90805 -89070847dc8bbf5bc4ed073aa2e2a1f699cf0c2ca226f185a0671cecc54e7d3e14cd475c7752314a7a8e7476829da4bc -a9402dc9117fdb39c4734c0688254f23aed3dce94f5f53f5b7ef2b4bf1b71a67f85ab1a38ec224a59691f3bee050aeb3 -957288f9866a4bf56a4204218ccc583f717d7ce45c01ea27142a7e245ad04a07f289cc044f8cf1f21d35e67e39299e9c -b2fb31ccb4e69113763d7247d0fc8edaae69b550c5c56aecacfd780c7217dc672f9fb7496edf4aba65dacf3361268e5b -b44a4526b2f1d6eb2aa8dba23bfa385ff7634572ab2afddd0546c3beb630fbfe85a32f42dd287a7fec069041411537f7 -8db5a6660c3ac7fd7a093573940f068ee79a82bc17312af900b51c8c439336bc86ca646c6b7ab13aaaa008a24ca508ab -8f9899a6d7e8eb4367beb5c060a1f8e94d8a21099033ae582118477265155ba9e72176a67f7f25d7bad75a152b56e21a -a67de0e91ade8d69a0e00c9ff33ee2909b8a609357095fa12319e6158570c232e5b6f4647522efb7345ce0052aa9d489 -82eb2414898e9c3023d57907a2b17de8e7eea5269029d05a94bfd7bf5685ac4a799110fbb375eb5e0e2bd16acf6458ae -94451fc7fea3c5a89ba701004a9693bab555cb622caf0896b678faba040409fdfd14a978979038b2a81e8f0abc4994d2 -ac879a5bb433998e289809a4a966bd02b4bf6a9c1cc276454e39c886efcf4fc68baebed575826bde577ab5aa71d735a9 -880c0f8f49c875dfd62b4ddedde0f5c8b19f5687e693717f7e5c031bc580e58e13ab497d48b4874130a18743c59fdce3 -b582af8d8ff0bf76f0a3934775e0b54c0e8fed893245d7d89cae65b03c8125b7237edc29dc45b4fe1a3fe6db45d280ee -89f337882ed3ae060aaee98efa20d79b6822bde9708c1c5fcee365d0ec9297f694cae37d38fd8e3d49717c1e86f078e7 -826d2c1faea54061848b484e288a5f4de0d221258178cf87f72e14baaa4acc21322f8c9eab5dde612ef497f2d2e1d60b -a5333d4f227543e9cd741ccf3b81db79f2f03ca9e649e40d6a6e8ff9073e06da83683566d3b3c8d7b258c62970fb24d1 -a28f08c473db06aaf4c043a2fae82b3c8cfaa160bce793a4c208e4e168fb1c65115ff8139dea06453c5963d95e922b94 -8162546135cc5e124e9683bdfaa45833c18553ff06a0861c887dc84a5b12ae8cd4697f6794c7ef6230492c32faba7014 -b23f0d05b74c08d6a7df1760792be83a761b36e3f8ae360f3c363fb196e2a9dd2de2e492e49d36561366e14daa77155c -b6f70d6c546722d3907c708d630dbe289771d2c8bf059c2e32b77f224696d750b4dda9b3a014debda38e7d02c9a77585 -83bf4c4a9f3ca022c631017e7a30ea205ba97f7f5927cba8fc8489a4646eac6712cb821c5668c9ffe94d69d524374a27 -b0371475425a8076d0dd5f733f55aabbe42d20a7c8ea7da352e736d4d35a327b2beb370dfcb05284e22cfd69c5f6c4cc -a0031ba7522c79211416c2cca3aa5450f96f8fee711552a30889910970ba13608646538781a2c08b834b140aadd7166f -99d273c80c7f2dc6045d4ed355d9fc6f74e93549d961f4a3b73cd38683f905934d359058cd1fc4da8083c7d75070487f -b0e4b0efa3237793e9dcce86d75aafe9879c5fa23f0d628649aef2130454dcf72578f9bf227b9d2b9e05617468e82588 -a5ab076fa2e1c5c51f3ae101afdd596ad9d106bba7882b359c43d8548b64f528af19afa76cd6f40da1e6c5fca4def3fa -8ce2299e570331d60f6a6eff1b271097cd5f1c0e1113fc69b89c6a0f685dabea3e5bc2ac6bd789aa492ab189f89be494 -91b829068874d911a310a5f9dee001021f97471307b5a3de9ec336870ec597413e1d92010ce320b619f38bed7c4f7910 -b14fe91f4b07bf33b046e9285b66cb07927f3a8da0af548ac2569b4c4fb1309d3ced76d733051a20814e90dd5b75ffd1 -abaab92ea6152d40f82940277c725aa768a631ee0b37f5961667f82fb990fc11e6d3a6a2752b0c6f94563ed9bb28265c -b7fe28543eca2a716859a76ab9092f135337e28109544f6bd2727728d0a7650428af5713171ea60bfc273d1c821d992c -8a4917b2ab749fc7343fc64bdf51b6c0698ff15d740cc7baf248c030475c097097d5a473bcc00d8c25817563fe0447b4 -aa96156d1379553256350a0a3250166add75948fb9cde62aa555a0a9dc0a9cb7f2f7b8428aff66097bf6bfedaf14bbe2 -ae4ffeb9bdc76830d3eca2b705f30c1bdede6412fa064260a21562c8850c7fb611ec62bc68479fe48f692833e6f66d8d -b96543caaba9d051600a14997765d49e4ab10b07c7a92cccf0c90b309e6da334fdd6d18c96806cbb67a7801024fbd3c7 -97b2b9ad76f19f500fcc94ca8e434176249f542ac66e5881a3dccd07354bdab6a2157018b19f8459437a68d8b86ba8e0 -a8d206f6c5a14c80005849474fde44b1e7bcf0b2d52068f5f97504c3c035b09e65e56d1cf4b5322791ae2c2fdbd61859 -936bad397ad577a70cf99bf9056584a61bd7f02d2d5a6cf219c05d770ae30a5cd902ba38366ce636067fc1dd10108d31 -a77e30195ee402b84f3882e2286bf5380c0ed374a112dbd11e16cef6b6b61ab209d4635e6f35cdaaa72c1a1981d5dabe -a46ba4d3947188590a43c180757886a453a0503f79cc435322d92490446f37419c7b999fdf868a023601078070e03346 -80d8d4c5542f223d48240b445d4d8cf6a75d120b060bc08c45e99a13028b809d910b534d2ac47fb7068930c54efd8da9 -803be9c68c91b42b68e1f55e58917a477a9a6265e679ca44ee30d3eb92453f8c89c64eafc04c970d6831edd33d066902 -b14b2b3d0dfe2bb57cee4cd72765b60ac33c1056580950be005790176543826c1d4fbd737f6cfeada6c735543244ab57 -a9e480188bba1b8fb7105ff12215706665fd35bf1117bacfb6ab6985f4dbc181229873b82e5e18323c2b8f5de03258e0 -a66a0f0779436a9a3999996d1e6d3000f22c2cac8e0b29cddef9636393c7f1457fb188a293b6c875b05d68d138a7cc4a -848397366300ab40c52d0dbbdafbafef6cd3dadf1503bb14b430f52bb9724188928ac26f6292a2412bc7d7aa620763c8 -95466cc1a78c9f33a9aaa3829a4c8a690af074916b56f43ae46a67a12bb537a5ac6dbe61590344a25b44e8512355a4a7 -8b5f7a959f818e3baf0887f140f4575cac093d0aece27e23b823cf421f34d6e4ff4bb8384426e33e8ec7b5eed51f6b5c -8d5e1368ec7e3c65640d216bcc5d076f3d9845924c734a34f3558ac0f16e40597c1a775a25bf38b187213fbdba17c93b -b4647c1b823516880f60d20c5cc38c7f80b363c19d191e8992226799718ee26b522a12ecb66556ed3d483aa4824f3326 -ac3abaea9cd283eb347efda4ed9086ea3acf495043e08d0d19945876329e8675224b685612a6badf8fd72fb6274902b1 -8eae1ce292d317aaa71bcf6e77e654914edd5090e2e1ebab78b18bb41b9b1bc2e697439f54a44c0c8aa0d436ebe6e1a9 -94dc7d1aec2c28eb43d93b111fa59aaa0d77d5a09501220bd411768c3e52208806abf973c6a452fd8292ff6490e0c9e2 -8fd8967f8e506fef27d17b435d6b86b232ec71c1036351f12e6fb8a2e12daf01d0ee04451fb944d0f1bf7fd20e714d02 -824e6865be55d43032f0fec65b3480ea89b0a2bf860872237a19a54bc186a85d2f8f9989cc837fbb325b7c72d9babe2c -8bd361f5adb27fd6f4e3f5de866e2befda6a8454efeb704aacc606f528c03f0faae888f60310e49440496abd84083ce2 -b098a3c49f2aaa28b6b3e85bc40ce6a9cdd02134ee522ae73771e667ad7629c8d82c393fba9f27f5416986af4c261438 -b385f5ca285ff2cfe64dcaa32dcde869c28996ed091542600a0b46f65f3f5a38428cca46029ede72b6cf43e12279e3d3 -8196b03d011e5be5288196ef7d47137d6f9237a635ab913acdf9c595fa521d9e2df722090ec7eb0203544ee88178fc5f -8ed1270211ef928db18e502271b7edf24d0bbd11d97f2786aee772d70c2029e28095cf8f650b0328cc8a4c38d045316d -a52ab60e28d69b333d597a445884d44fd2a7e1923dd60f763951e1e45f83e27a4dac745f3b9eff75977b3280e132c15d -91e9fe78cdac578f4a4687f71b800b35da54b824b1886dafec073a3c977ce7a25038a2f3a5b1e35c2c8c9d1a7312417c -a42832173f9d9491c7bd93b21497fbfa4121687cd4d2ab572e80753d7edcbb42cfa49f460026fbde52f420786751a138 -97b947126d84dcc70c97be3c04b3de3f239b1c4914342fa643b1a4bb8c4fe45c0fcb585700d13a7ed50784790c54bef9 -860e407d353eac070e2418ef6cb80b96fc5f6661d6333e634f6f306779651588037be4c2419562c89c61f9aa2c4947f5 -b2c9d93c3ba4e511b0560b55d3501bf28a510745fd666b3cb532db051e6a8617841ea2f071dda6c9f15619c7bfd2737f -8596f4d239aeeac78311207904d1bd863ef68e769629cc379db60e019aaf05a9d5cd31dc8e630b31e106a3a93e47cbc5 -8b26e14e2e136b65c5e9e5c2022cee8c255834ea427552f780a6ca130a6446102f2a6f334c3f9a0308c53df09e3dba7e -b54724354eb515a3c8bed0d0677ff1db94ac0a07043459b4358cb90e3e1aa38ac23f2caa3072cf9647275d7cd61d0e80 -b7ce9fe0e515e7a6b2d7ddcb92bc0196416ff04199326aea57996eef8c5b1548bd8569012210da317f7c0074691d01b7 -a1a13549c82c877253ddefa36a29ea6a23695ee401fdd48e65f6f61e5ebd956d5e0edeff99484e9075cb35071fec41e2 -838ba0c1e5bd1a6da05611ff1822b8622457ebd019cb065ece36a2d176bd2d889511328120b8a357e44569e7f640c1e6 -b916eccff2a95519400bbf76b5f576cbe53cf200410370a19d77734dc04c05b585cfe382e8864e67142d548cd3c4c2f4 -a610447cb7ca6eea53a6ff1f5fe562377dcb7f4aaa7300f755a4f5e8eba61e863c51dc2aa9a29b35525b550fbc32a0fe -9620e8f0f0ee9a4719aa9685eeb1049c5c77659ba6149ec4c158f999cfd09514794b23388879931fe26fea03fa471fd3 -a9dcf8b679e276583cf5b9360702a185470d09aea463dc474ee9c8aee91ef089dacb073e334e47fbc78ec5417c90465c -8c9adee8410bdd99e5b285744cee61e2593b6300ff31a8a83b0ec28da59475a5c6fb9346fe43aadea2e6c3dad2a8e30a -97d5afe9b3897d7b8bb628b7220cf02d8ee4e9d0b78f5000d500aaf4c1df9251aaaabfd1601626519f9d66f00a821d4e -8a382418157b601ce4c3501d3b8409ca98136a4ef6abcbf62885e16e215b76b035c94d149cc41ff92e42ccd7c43b9b3d -b64b8d11fb3b01abb2646ac99fdb9c02b804ce15d98f9fe0fbf1c9df8440c71417487feb6cdf51e3e81d37104b19e012 -849d7d044f9d8f0aab346a9374f0b3a5d14a9d1faa83dbacccbdc629ad1ef903a990940255564770537f8567521d17f0 -829dbb0c76b996c2a91b4cbbe93ba455ca0d5729755e5f0c92aaee37dff7f36fcdc06f33aca41f1b609c784127b67d88 -85a7c0069047b978422d264d831ab816435f63938015d2e977222b6b5746066c0071b7f89267027f8a975206ed25c1b0 -84b9fbc1cfb302df1acdcf3dc5d66fd1edfe7839f7a3b2fb3a0d5548656249dd556104d7c32b73967bccf0f5bdcf9e3b -972220ac5b807f53eac37dccfc2ad355d8b21ea6a9c9b011c09fe440ddcdf7513e0b43d7692c09ded80d7040e26aa28f -855885ed0b21350baeca890811f344c553cf9c21024649c722453138ba29193c6b02c4b4994cd414035486f923472e28 -841874783ae6d9d0e59daea03e96a01cbbe4ecaced91ae4f2c8386e0d87b3128e6d893c98d17c59e4de1098e1ad519dd -827e50fc9ce56f97a4c3f2f4cbaf0b22f1c3ce6f844ff0ef93a9c57a09b8bf91ebfbd2ba9c7f83c442920bffdaf288cc -a441f9136c7aa4c08d5b3534921b730e41ee91ab506313e1ba5f7c6f19fd2d2e1594e88c219834e92e6fb95356385aa7 -97d75b144471bf580099dd6842b823ec0e6c1fb86dd0da0db195e65524129ea8b6fd4a7a9bbf37146269e938a6956596 -a4b6fa87f09d5a29252efb2b3aaab6b3b6ea9fab343132a651630206254a25378e3e9d6c96c3d14c150d01817d375a8e -a31a671876d5d1e95fe2b8858dc69967231190880529d57d3cab7f9f4a2b9b458ac9ee5bdaa3289158141bf18f559efb -90bee6fff4338ba825974021b3b2a84e36d617e53857321f13d2b3d4a28954e6de3b3c0e629d61823d18a9763313b3bf -96b622a63153f393bb419bfcf88272ea8b3560dbd46b0aa07ada3a6223990d0abdd6c2adb356ef4be5641688c8d83941 -84c202adeaff9293698022bc0381adba2cd959f9a35a4e8472288fd68f96f6de8be9da314c526d88e291c96b1f3d6db9 -8ca01a143b8d13809e5a8024d03e6bc9492e22226073ef6e327edf1328ef4aff82d0bcccee92cb8e212831fa35fe1204 -b2f970dbad15bfbefb38903c9bcc043d1367055c55dc1100a850f5eb816a4252c8c194b3132c929105511e14ea10a67d -a5e36556472a95ad57eb90c3b6623671b03eafd842238f01a081997ffc6e2401f76e781d049bb4aa94d899313577a9cf -8d1057071051772f7c8bedce53a862af6fd530dd56ae6321eaf2b9fc6a68beff5ed745e1c429ad09d5a118650bfd420a -8aadc4f70ace4fcb8d93a78610779748dcffc36182d45b932c226dc90e48238ea5daa91f137c65ed532352c4c4d57416 -a2ea05ae37e673b4343232ae685ee14e6b88b867aef6dfac35db3589cbcd76f99540fed5c2641d5bb5a4a9f808e9bf0d -947f1abad982d65648ae4978e094332b4ecb90f482c9be5741d5d1cf5a28acf4680f1977bf6e49dd2174c37f11e01296 -a27b144f1565e4047ba0e3f4840ef19b5095d1e281eaa463c5358f932114cbd018aa6dcf97546465cf2946d014d8e6d6 -8574e1fc3acade47cd4539df578ce9205e745e161b91e59e4d088711a7ab5aa3b410d517d7304b92109924d9e2af8895 -a48ee6b86b88015d6f0d282c1ae01d2a5b9e8c7aa3d0c18b35943dceb1af580d08a65f54dc6903cde82fd0d73ce94722 -8875650cec543a7bf02ea4f2848a61d167a66c91ffaefe31a9e38dc8511c6a25bde431007eefe27a62af3655aca208dc -999b0a6e040372e61937bf0d68374e230346b654b5a0f591a59d33a4f95bdb2f3581db7c7ccb420cd7699ed709c50713 -878c9e56c7100c5e47bbe77dc8da5c5fe706cec94d37fa729633bca63cace7c40102eee780fcdabb655f5fa47a99600e -865006fb5b475ada5e935f27b96f9425fc2d5449a3c106aa366e55ebed3b4ee42adc3c3f0ac19fd129b40bc7d6bc4f63 -b7a7da847f1202e7bc1672553e68904715e84fd897d529243e3ecda59faa4e17ba99c649a802d53f6b8dfdd51f01fb74 -8b2fb4432c05653303d8c8436473682933a5cb604da10c118ecfcd2c8a0e3132e125afef562bdbcc3df936164e5ce4f2 -808d95762d33ddfa5d0ee3d7d9f327de21a994d681a5f372e2e3632963ea974da7f1f9e5bac8ccce24293509d1f54d27 -932946532e3c397990a1df0e94c90e1e45133e347a39b6714c695be21aeb2d309504cb6b1dde7228ff6f6353f73e1ca2 -9705e7c93f0cdfaa3fa96821f830fe53402ad0806036cd1b48adc2f022d8e781c1fbdab60215ce85c653203d98426da3 -aa180819531c3ec1feb829d789cb2092964c069974ae4faad60e04a6afcce5c3a59aec9f11291e6d110a788d22532bc6 -88f755097f7e25cb7dd3c449520c89b83ae9e119778efabb54fbd5c5714b6f37c5f9e0346c58c6ab09c1aef2483f895d -99fc03ab7810e94104c494f7e40b900f475fde65bdec853e60807ffd3f531d74de43335c3b2646b5b8c26804a7448898 -af2dea9683086bed1a179110efb227c9c00e76cd00a2015b089ccbcee46d1134aa18bda5d6cab6f82ae4c5cd2461ac21 -a500f87ba9744787fdbb8e750702a3fd229de6b8817594348dec9a723b3c4240ddfa066262d002844b9e38240ce55658 -924d0e45c780f5bc1c1f35d15dfc3da28036bdb59e4c5440606750ecc991b85be18bc9a240b6c983bc5430baa4c68287 -865b11e0157b8bf4c5f336024b016a0162fc093069d44ac494723f56648bc4ded13dfb3896e924959ea11c96321afefc -93672d8607d4143a8f7894f1dcca83fb84906dc8d6dd7dd063bb0049cfc20c1efd933e06ca7bd03ea4cb5a5037990bfe -826891efbdff0360446825a61cd1fa04326dd90dae8c33dfb1ed97b045e165766dd070bd7105560994d0b2044bdea418 -93c4a4a8bcbc8b190485cc3bc04175b7c0ed002c28c98a540919effd6ed908e540e6594f6db95cd65823017258fb3b1c -aeb2a0af2d2239fda9aa6b8234b019708e8f792834ff0dd9c487fa09d29800ddceddd6d7929faa9a3edcb9e1b3aa0d6b -87f11de7236d387863ec660d2b04db9ac08143a9a2c4dfff87727c95b4b1477e3bc473a91e5797313c58754905079643 -80dc1db20067a844fe8baceca77f80db171a5ca967acb24e2d480eae9ceb91a3343c31ad1c95b721f390829084f0eae6 -9825c31f1c18da0de3fa84399c8b40f8002c3cae211fb6a0623c76b097b4d39f5c50058f57a16362f7a575909d0a44a2 -a99fc8de0c38dbf7b9e946de83943a6b46a762167bafe2a603fb9b86f094da30d6de7ed55d639aafc91936923ee414b3 -ad594678b407db5d6ea2e90528121f84f2b96a4113a252a30d359a721429857c204c1c1c4ff71d8bb5768c833f82e80e -b33d985e847b54510b9b007e31053732c8a495e43be158bd2ffcea25c6765bcbc7ca815f7c60b36ad088b955dd6e9350 -815f8dfc6f90b3342ca3fbd968c67f324dae8f74245cbf8bc3bef10e9440c65d3a2151f951e8d18959ba01c1b50b0ec1 -94c608a362dd732a1abc56e338637c900d59013db8668e49398b3c7a0cae3f7e2f1d1bf94c0299eeafe6af7f76c88618 -8ebd8446b23e5adfcc393adc5c52fe172f030a73e63cd2d515245ca0dd02782ceed5bcdd9ccd9c1b4c5953dfac9c340c -820437f3f6f9ad0f5d7502815b221b83755eb8dc56cd92c29e9535eb0b48fb8d08c9e4fcc26945f9c8cca60d89c44710 -8910e4e8a56bf4be9cc3bbf0bf6b1182a2f48837a2ed3c2aaec7099bfd7f0c83e14e608876b17893a98021ff4ab2f20d -9633918fde348573eec15ce0ad53ac7e1823aac86429710a376ad661002ae6d049ded879383faaa139435122f64047c6 -a1f5e3fa558a9e89318ca87978492f0fb4f6e54a9735c1b8d2ecfb1d1c57194ded6e0dd82d077b2d54251f3bee1279e1 -b208e22d04896abfd515a95c429ff318e87ff81a5d534c8ac2c33c052d6ffb73ef1dccd39c0bbe0734b596c384014766 -986d5d7d2b5bde6d16336f378bd13d0e671ad23a8ec8a10b3fc09036faeeb069f60662138d7a6df3dfb8e0d36180f770 -a2d4e6c5f5569e9cef1cddb569515d4b6ace38c8aed594f06da7434ba6b24477392cc67ba867c2b079545ca0c625c457 -b5ac32b1d231957d91c8b7fc43115ce3c5c0d8c13ca633374402fa8000b6d9fb19499f9181844f0c10b47357f3f757ce -96b8bf2504b4d28fa34a4ec378e0e0b684890c5f44b7a6bb6e19d7b3db2ab27b1e2686389d1de9fbd981962833a313ea -953bfd7f6c3a0469ad432072b9679a25486f5f4828092401eff494cfb46656c958641a4e6d0d97d400bc59d92dba0030 -876ab3cea7484bbfd0db621ec085b9ac885d94ab55c4bb671168d82b92e609754b86aaf472c55df3d81421d768fd108a -885ff4e67d9ece646d02dd425aa5a087e485c3f280c3471b77532b0db6145b69b0fbefb18aa2e3fa5b64928b43a94e57 -b91931d93f806d0b0e6cc62a53c718c099526140f50f45d94b8bbb57d71e78647e06ee7b42aa5714aed9a5c05ac8533f -a0313eeadd39c720c9c27b3d671215331ab8d0a794e71e7e690f06bcd87722b531d6525060c358f35f5705dbb7109ccb -874c0944b7fedc6701e53344100612ddcb495351e29305c00ec40a7276ea5455465ffb7bded898886c1853139dfb1fc7 -8dc31701a01ee8137059ca1874a015130d3024823c0576aa9243e6942ec99d377e7715ed1444cd9b750a64b85dcaa3e5 -836d2a757405e922ec9a2dfdcf489a58bd48b5f9683dd46bf6047688f778c8dee9bc456de806f70464df0b25f3f3d238 -b30b0a1e454a503ea3e2efdec7483eaf20b0a5c3cefc42069e891952b35d4b2c955cf615f3066285ed8fafd9fcfbb8f6 -8e6d4044b55ab747e83ec8762ea86845f1785cc7be0279c075dadf08aca3ccc5a096c015bb3c3f738f647a4eadea3ba5 -ad7735d16ab03cbe09c029610aa625133a6daecfc990b297205b6da98eda8c136a7c50db90f426d35069708510d5ae9c -8d62d858bbb59ec3c8cc9acda002e08addab4d3ad143b3812098f3d9087a1b4a1bb255dcb1635da2402487d8d0249161 -805beec33238b832e8530645a3254aeef957e8f7ea24bcfc1054f8b9c69421145ebb8f9d893237e8a001c857fedfc77e -b1005644be4b085e3f5775aa9bd3e09a283e87ddada3082c04e7a62d303dcef3b8cf8f92944c200c7ae6bb6bdf63f832 -b4ba0e0790dc29063e577474ffe3b61f5ea2508169f5adc1e394934ebb473e356239413a17962bc3e5d3762d72cce8c2 -a157ba9169c9e3e6748d9f1dd67fbe08b9114ade4c5d8fc475f87a764fb7e6f1d21f66d7905cd730f28a1c2d8378682a -913e52b5c93989b5d15e0d91aa0f19f78d592bc28bcfdfddc885a9980c732b1f4debb8166a7c4083c42aeda93a702898 -90fbfc1567e7cd4e096a38433704d3f96a2de2f6ed3371515ccc30bc4dd0721a704487d25a97f3c3d7e4344472702d8d -89646043028ffee4b69d346907586fd12c2c0730f024acb1481abea478e61031966e72072ff1d5e65cb8c64a69ad4eb1 -b125a45e86117ee11d2fb42f680ab4a7894edd67ff927ae2c808920c66c3e55f6a9d4588eee906f33a05d592e5ec3c04 -aad47f5b41eae9be55fb4f67674ff1e4ae2482897676f964a4d2dcb6982252ee4ff56aac49578b23f72d1fced707525e -b9ddff8986145e33851b4de54d3e81faa3352e8385895f357734085a1616ef61c692d925fe62a5ed3be8ca49f5d66306 -b3cb0963387ed28c0c0adf7fe645f02606e6e1780a24d6cecef5b7c642499109974c81a7c2a198b19862eedcea2c2d8c -ac9c53c885457aaf5cb36c717a6f4077af701e0098eebd7aa600f5e4b14e6c1067255b3a0bc40e4a552025231be7de60 -8e1a8d823c4603f6648ec21d064101094f2a762a4ed37dd2f0a2d9aa97b2d850ce1e76f4a4b8cae58819b058180f7031 -b268b73bf7a179b6d22bd37e5e8cb514e9f5f8968c78e14e4f6d5700ca0d0ca5081d0344bb73b028970eebde3cb4124e -a7f57d71940f0edbd29ed8473d0149cae71d921dd15d1ff589774003e816b54b24de2620871108cec1ab9fa956ad6ce6 -8053e6416c8b120e2b999cc2fc420a6a55094c61ac7f2a6c6f0a2c108a320890e389af96cbe378936132363c0d551277 -b3823f4511125e5aa0f4269e991b435a0d6ceb523ebd91c04d7add5534e3df5fc951c504b4fd412a309fd3726b7f940b -ae6eb04674d04e982ca9a6add30370ab90e303c71486f43ed3efbe431af1b0e43e9d06c11c3412651f304c473e7dbf39 -96ab55e641ed2e677591f7379a3cd126449614181fce403e93e89b1645d82c4af524381ff986cae7f9cebe676878646d -b52423b4a8c37d3c3e2eca8f0ddbf7abe0938855f33a0af50f117fab26415fb0a3da5405908ec5fdc22a2c1f2ca64892 -82a69ce1ee92a09cc709d0e3cd22116c9f69d28ea507fe5901f5676000b5179b9abe4c1875d052b0dd42d39925e186bb -a84c8cb84b9d5cfb69a5414f0a5283a5f2e90739e9362a1e8c784b96381b59ac6c18723a4aa45988ee8ef5c1f45cc97d -afd7efce6b36813082eb98257aae22a4c1ae97d51cac7ea9c852d4a66d05ef2732116137d8432e3f117119725a817d24 -a0f5fe25af3ce021b706fcff05f3d825384a272284d04735574ce5fb256bf27100fad0b1f1ba0e54ae9dcbb9570ecad3 -8751786cb80e2e1ff819fc7fa31c2833d25086534eb12b373d31f826382430acfd87023d2a688c65b5e983927e146336 -8cf5c4b17fa4f3d35c78ce41e1dc86988fd1135cd5e6b2bb0c108ee13538d0d09ae7102609c6070f39f937b439b31e33 -a9108967a2fedd7c322711eca8159c533dd561bedcb181b646de98bf5c3079449478eab579731bee8d215ae8852c7e21 -b54c5171704f42a6f0f4e70767cdb3d96ffc4888c842eece343a01557da405961d53ffdc34d2f902ea25d3e1ed867cad -ae8d4b764a7a25330ba205bf77e9f46182cd60f94a336bbd96773cf8064e3d39caf04c310680943dc89ed1fbad2c6e0d -aa5150e911a8e1346868e1b71c5a01e2a4bb8632c195861fb6c3038a0e9b85f0e09b3822e9283654a4d7bb17db2fc5f4 -9685d3756ce9069bf8bb716cf7d5063ebfafe37e15b137fc8c3159633c4e006ff4887ddd0ae90360767a25c3f90cba7f -82155fd70f107ab3c8e414eadf226c797e07b65911508c76c554445422325e71af8c9a8e77fd52d94412a6fc29417cd3 -abfae52f53a4b6e00760468d973a267f29321997c3dbb5aee36dc1f20619551229c0c45b9d9749f410e7f531b73378e8 -81a76d921f8ef88e774fd985e786a4a330d779b93fad7def718c014685ca0247379e2e2a007ad63ee7f729cd9ed6ce1b -81947c84bc5e28e26e2e533af5ae8fe10407a7b77436dbf8f1d5b0bbe86fc659eae10f974659dc7c826c6dabd03e3a4b -92b8c07050d635b8dd4fd09df9054efe4edae6b86a63c292e73cc819a12a21dd7d104ce51fa56af6539dedf6dbe6f7b6 -b44c579e3881f32b32d20c82c207307eca08e44995dd2aac3b2692d2c8eb2a325626c80ac81c26eeb38c4137ff95add5 -97efab8941c90c30860926dea69a841f2dcd02980bf5413b9fd78d85904588bf0c1021798dbc16c8bbb32cce66c82621 -913363012528b50698e904de0588bf55c8ec5cf6f0367cfd42095c4468fcc64954fbf784508073e542fee242d0743867 -8ed203cf215148296454012bd10fddaf119203db1919a7b3d2cdc9f80e66729464fdfae42f1f2fc5af1ed53a42b40024 -ab84312db7b87d711e9a60824f4fe50e7a6190bf92e1628688dfcb38930fe87b2d53f9e14dd4de509b2216856d8d9188 -880726def069c160278b12d2258eac8fa63f729cd351a710d28b7e601c6712903c3ac1e7bbd0d21e4a15f13ca49db5aa -980699cd51bac6283959765f5174e543ed1e5f5584b5127980cbc2ef18d984ecabba45042c6773b447b8e694db066028 -aeb019cb80dc4cb4207430d0f2cd24c9888998b6f21d9bf286cc638449668d2eec0018a4cf3fe6448673cd6729335e2b -b29852f6aa6c60effdffe96ae88590c88abae732561d35cc19e82d3a51e26cb35ea00986193e07f90060756240f5346e -a0fa855adc5ba469f35800c48414b8921455950a5c0a49945d1ef6e8f2a1881f2e2dfae47de6417270a6bf49deeb091d -b6c7332e3b14813641e7272d4f69ecc7e09081df0037d6dab97ce13a9e58510f5c930d300633f208181d9205c5534001 -85a6c050f42fce560b5a8d54a11c3bbb8407abbadd859647a7b0c21c4b579ec65671098b74f10a16245dc779dff7838e -8f3eb34bb68759d53c6677de4de78a6c24dd32c8962a7fb355ed362572ef8253733e6b52bc21c9f92ecd875020a9b8de -a17dd44181e5dab4dbc128e1af93ec22624b57a448ca65d2d9e246797e4af7d079e09c6e0dfb62db3a9957ce92f098d5 -a56a1b854c3183082543a8685bb34cae1289f86cfa8123a579049dbd059e77982886bfeb61bf6e05b4b1fe4e620932e7 -aedae3033cb2fb7628cb4803435bdd7757370a86f808ae4cecb9a268ad0e875f308c048c80cbcac523de16b609683887 -9344905376aa3982b1179497fac5a1d74b14b7038fd15e3b002db4c11c8bfc7c39430db492cdaf58b9c47996c9901f28 -a3bfafdae011a19f030c749c3b071f83580dee97dd6f949e790366f95618ca9f828f1daaeabad6dcd664fcef81b6556d -81c03d8429129e7e04434dee2c529194ddb01b414feda3adee2271eb680f6c85ec872a55c9fa9d2096f517e13ed5abcc -98205ef3a72dff54c5a9c82d293c3e45d908946fa74bb749c3aabe1ab994ea93c269bcce1a266d2fe67a8f02133c5985 -85a70aeed09fda24412fadbafbbbf5ba1e00ac92885df329e147bfafa97b57629a3582115b780d8549d07d19b7867715 -b0fbe81c719f89a57d9ea3397705f898175808c5f75f8eb81c2193a0b555869ba7bd2e6bc54ee8a60cea11735e21c68c -b03a0bd160495ee626ff3a5c7d95bc79d7da7e5a96f6d10116600c8fa20bedd1132f5170f25a22371a34a2d763f2d6d0 -a90ab04091fbca9f433b885e6c1d60ab45f6f1daf4b35ec22b09909d493a6aab65ce41a6f30c98239cbca27022f61a8b -b66f92aa3bf2549f9b60b86f99a0bd19cbdd97036d4ae71ca4b83d669607f275260a497208f6476cde1931d9712c2402 -b08e1fdf20e6a9b0b4942f14fa339551c3175c1ffc5d0ab5b226b6e6a322e9eb0ba96adc5c8d59ca4259e2bdd04a7eb0 -a2812231e92c1ce74d4f5ac3ab6698520288db6a38398bb38a914ac9326519580af17ae3e27cde26607e698294022c81 -abfcbbcf1d3b9e84c02499003e490a1d5d9a2841a9e50c7babbef0b2dd20d7483371d4dc629ba07faf46db659459d296 -b0fe9f98c3da70927c23f2975a9dc4789194d81932d2ad0f3b00843dd9cbd7fb60747a1da8fe5a79f136a601becf279d -b130a6dba7645165348cb90f023713bed0eefbd90a976b313521c60a36d34f02032e69a2bdcf5361e343ed46911297ec -862f0cffe3020cea7a5fd4703353aa1eb1be335e3b712b29d079ff9f7090d1d8b12013011e1bdcbaa80c44641fd37c9f -8c6f11123b26633e1abb9ed857e0bce845b2b3df91cc7b013b2fc77b477eee445da0285fc6fc793e29d5912977f40916 -91381846126ea819d40f84d3005e9fb233dc80071d1f9bb07f102bf015f813f61e5884ffffb4f5cd333c1b1e38a05a58 -8add7d908de6e1775adbd39c29a391f06692b936518db1f8fde74eb4f533fc510673a59afb86e3a9b52ade96e3004c57 -8780e086a244a092206edcde625cafb87c9ab1f89cc3e0d378bc9ee776313836160960a82ec397bc3800c0a0ec3da283 -a6cb4cd9481e22870fdd757fae0785edf4635e7aacb18072fe8dc5876d0bab53fb99ce40964a7d3e8bcfff6f0ab1332f -af30ff47ecc5b543efba1ba4706921066ca8bb625f40e530fb668aea0551c7647a9d126e8aba282fbcce168c3e7e0130 -91b0bcf408ce3c11555dcb80c4410b5bc2386d3c05caec0b653352377efdcb6bab4827f2018671fc8e4a0e90d772acc1 -a9430b975ef138b6b2944c7baded8fe102d31da4cfe3bd3d8778bda79189c99d38176a19c848a19e2d1ee0bddd9a13c1 -aa5a4eef849d7c9d2f4b018bd01271c1dd83f771de860c4261f385d3bdcc130218495860a1de298f14b703ec32fa235f -b0ce79e7f9ae57abe4ff366146c3b9bfb38b0dee09c28c28f5981a5d234c6810ad4d582751948affb480d6ae1c8c31c4 -b75122748560f73d15c01a8907d36d06dc068e82ce22b84b322ac1f727034493572f7907dec34ebc3ddcc976f2f89ed7 -b0fc7836369a3e4411d34792d6bd5617c14f61d9bba023dda64e89dc5fb0f423244e9b48ee64869258931daa9753a56f -8956d7455ae9009d70c6e4a0bcd7610e55f37494cf9897a8f9e1b904cc8febc3fd2d642ebd09025cfff4609ad7e3bc52 -ad741efe9e472026aa49ae3d9914cb9c1a6f37a54f1a6fe6419bebd8c7d68dca105a751c7859f4389505ede40a0de786 -b52f418797d719f0d0d0ffb0846788b5cba5d0454a69a2925de4b0b80fa4dd7e8c445e5eac40afd92897ed28ca650566 -a0ab65fb9d42dd966cd93b1de01d7c822694669dd2b7a0c04d99cd0f3c3de795f387b9c92da11353412f33af5c950e9a -a0052f44a31e5741a331f7cac515a08b3325666d388880162d9a7b97598fde8b61f9ff35ff220df224eb5c4e40ef0567 -a0101cfdc94e42b2b976c0d89612a720e55d145a5ef6ef6f1f78cf6de084a49973d9b5d45915349c34ce712512191e3c -a0dd99fcf3f5cead5aaf08e82212df3a8bb543c407a4d6fab88dc5130c1769df3f147e934a46f291d6c1a55d92b86917 -a5939153f0d1931bbda5cf6bdf20562519ea55fbfa978d6dbc6828d298260c0da7a50c37c34f386e59431301a96c2232 -9568269f3f5257200f9ca44afe1174a5d3cf92950a7f553e50e279c239e156a9faaa2a67f288e3d5100b4142efe64856 -b746b0832866c23288e07f24991bbf687cad794e7b794d3d3b79367566ca617d38af586cdc8d6f4a85a34835be41d54f -a871ce28e39ab467706e32fec1669fda5a4abba2f8c209c6745df9f7a0fa36bbf1919cf14cb89ea26fa214c4c907ae03 -a08dacdd758e523cb8484f6bd070642c0c20e184abdf8e2a601f61507e93952d5b8b0c723c34fcbdd70a8485eec29db2 -85bdb78d501382bb95f1166b8d032941005661aefd17a5ac32df9a3a18e9df2fc5dc2c1f07075f9641af10353cecc0c9 -98d730c28f6fa692a389e97e368b58f4d95382fad8f0baa58e71a3d7baaea1988ead47b13742ce587456f083636fa98e -a557198c6f3d5382be9fb363feb02e2e243b0c3c61337b3f1801c4a0943f18e38ce1a1c36b5c289c8fa2aa9d58742bab -89174f79201742220ac689c403fc7b243eed4f8e3f2f8aba0bf183e6f5d4907cb55ade3e238e3623d9885f03155c4d2b -b891d600132a86709e06f3381158db300975f73ea4c1f7c100358e14e98c5fbe792a9af666b85c4e402707c3f2db321e -b9e5b2529ef1043278c939373fc0dbafe446def52ddd0a8edecd3e4b736de87e63e187df853c54c28d865de18a358bb6 -8589b2e9770340c64679062c5badb7bbef68f55476289b19511a158a9a721f197da03ece3309e059fc4468b15ac33aa3 -aad8c6cd01d785a881b446f06f1e9cd71bca74ba98674c2dcddc8af01c40aa7a6d469037498b5602e76e9c91a58d3dbd -abaccb1bd918a8465f1bf8dbe2c9ad4775c620b055550b949a399f30cf0d9eb909f3851f5b55e38f9e461e762f88f499 -ae62339d26db46e85f157c0151bd29916d5cc619bd4b832814b3fd2f00af8f38e7f0f09932ffe5bba692005dab2d9a74 -93a6ff30a5c0edf8058c89aba8c3259e0f1b1be1b80e67682de651e5346f7e1b4b4ac3d87cbaebf198cf779524aff6bf -8980a2b1d8f574af45b459193c952400b10a86122b71fca2acb75ee0dbd492e7e1ef5b959baf609a5172115e371f3177 -8c2f49f3666faee6940c75e8c7f6f8edc3f704cca7a858bbb7ee5e96bba3b0cf0993996f781ba6be3b0821ef4cb75039 -b14b9e348215b278696018330f63c38db100b0542cfc5be11dc33046e3bca6a13034c4ae40d9cef9ea8b34fef0910c4e -b59bc3d0a30d66c16e6a411cb641f348cb1135186d5f69fda8b0a0934a5a2e7f6199095ba319ec87d3fe8f1ec4a06368 -8874aca2a3767aa198e4c3fec2d9c62d496bc41ff71ce242e9e082b7f38cdf356089295f80a301a3cf1182bde5308c97 -b1820ebd61376d91232423fc20bf008b2ba37e761199f4ef0648ea2bd70282766799b4de814846d2f4d516d525c8daa7 -a6b202e5dedc16a4073e04a11af3a8509b23dfe5a1952f899adeb240e75c3f5bde0c424f811a81ea48d343591faffe46 -a69becee9c93734805523b92150a59a62eed4934f66056b645728740d42223f2925a1ad38359ba644da24d9414f4cdda -ad72f0f1305e37c7e6b48c272323ee883320994cb2e0d850905d6655fafc9f361389bcb9c66b3ff8d2051dbb58c8aa96 -b563600bd56fad7c8853af21c6a02a16ed9d8a8bbeea2c31731d63b976d83cb05b9779372d898233e8fd597a75424797 -b0abb78ce465bf7051f563c62e8be9c57a2cc997f47c82819300f36e301fefd908894bb2053a9d27ce2d0f8c46d88b5b -a071a85fb8274bac2202e0cb8e0e2028a5e138a82d6e0374d39ca1884a549c7c401312f00071b91f455c3a2afcfe0cda -b931c271513a0f267b9f41444a5650b1918100b8f1a64959c552aff4e2193cc1b9927906c6fa7b8a8c68ef13d79aaa52 -a6a1bb9c7d32cb0ca44d8b75af7e40479fbce67d216b48a2bb680d3f3a772003a49d3cd675fc64e9e0f8fabeb86d6d61 -b98d609858671543e1c3b8564162ad828808bb50ded261a9f8690ded5b665ed8368c58f947365ed6e84e5a12e27b423d -b3dca58cd69ec855e2701a1d66cad86717ff103ef862c490399c771ad28f675680f9500cb97be48de34bcdc1e4503ffd -b34867c6735d3c49865e246ddf6c3b33baf8e6f164db3406a64ebce4768cb46b0309635e11be985fee09ab7a31d81402 -acb966c554188c5b266624208f31fab250b3aa197adbdd14aee5ab27d7fb886eb4350985c553b20fdf66d5d332bfd3fe -943c36a18223d6c870d54c3b051ef08d802b85e9dd6de37a51c932f90191890656c06adfa883c87b906557ae32d09da0 -81bca7954d0b9b6c3d4528aadf83e4bc2ef9ea143d6209bc45ae9e7ae9787dbcd8333c41f12c0b6deee8dcb6805e826a -aba176b92256efb68f574e543479e5cf0376889fb48e3db4ebfb7cba91e4d9bcf19dcfec444c6622d9398f06de29e2b9 -b9f743691448053216f6ece7cd699871fff4217a1409ceb8ab7bdf3312d11696d62c74b0664ba0a631b1e0237a8a0361 -a383c2b6276fa9af346b21609326b53fb14fdf6f61676683076e80f375b603645f2051985706d0401e6fbed7eb0666b6 -a9ef2f63ec6d9beb8f3d04e36807d84bda87bdd6b351a3e4a9bf7edcb5618c46c1f58cfbf89e64b40f550915c6988447 -a141b2d7a82f5005eaea7ae7d112c6788b9b95121e5b70b7168d971812f3381de8b0082ac1f0a82c7d365922ebd2d26a -b1b76ef8120e66e1535c17038b75255a07849935d3128e3e99e56567b842fb1e8d56ef932d508d2fb18b82f7868fe1a9 -8e2e234684c81f21099f5c54f6bbe2dd01e3b172623836c77668a0c49ce1fe218786c3827e4d9ae2ea25c50a8924fb3c -a5caf5ff948bfd3c4ca3ffbdfcd91eec83214a6c6017235f309a0bbf7061d3b0b466307c00b44a1009cf575163898b43 -986415a82ca16ebb107b4c50b0c023c28714281db0bcdab589f6cb13d80e473a3034b7081b3c358e725833f6d845cb14 -b94836bf406ac2cbacb10e6df5bcdfcc9d9124ae1062767ca4e322d287fd5e353fdcebd0e52407cb3cd68571258a8900 -83c6d70a640b33087454a4788dfd9ef3ed00272da084a8d36be817296f71c086b23b576f98178ab8ca6a74f04524b46b -ad4115182ad784cfe11bcfc5ce21fd56229cc2ce77ac82746e91a2f0aa53ca6593a22efd2dc4ed8d00f84542643d9c58 -ab1434c5e5065da826d10c2a2dba0facccab0e52b506ce0ce42fbe47ced5a741797151d9ecc99dc7d6373cfa1779bbf6 -8a8b591d82358d55e6938f67ea87a89097ab5f5496f7260adb9f649abb289da12b498c5b2539c2f9614fb4e21b1f66b0 -964f355d603264bc1f44c64d6d64debca66f37dff39c971d9fc924f2bc68e6c187b48564a6dc82660a98b035f8addb5d -b66235eaaf47456bc1dc4bde454a028e2ce494ece6b713a94cd6bf27cf18c717fd0c57a5681caaa2ad73a473593cdd7a -9103e3bb74304186fa4e3e355a02da77da4aca9b7e702982fc2082af67127ebb23a455098313c88465bc9b7d26820dd5 -b6a42ff407c9dd132670cdb83cbad4b20871716e44133b59a932cd1c3f97c7ac8ff7f61acfaf8628372508d8dc8cad7c -883a9c21c16a167a4171b0f084565c13b6f28ba7c4977a0de69f0a25911f64099e7bbb4da8858f2e93068f4155d04e18 -8dbb3220abc6a43220adf0331e3903d3bfd1d5213aadfbd8dfcdf4b2864ce2e96a71f35ecfb7a07c3bbabf0372b50271 -b4ad08aee48e176bda390b7d9acf2f8d5eb008f30d20994707b757dc6a3974b2902d29cd9b4d85e032810ad25ac49e97 -865bb0f33f7636ec501bb634e5b65751c8a230ae1fa807a961a8289bbf9c7fe8c59e01fbc4c04f8d59b7f539cf79ddd5 -86a54d4c12ad1e3605b9f93d4a37082fd26e888d2329847d89afa7802e815f33f38185c5b7292293d788ad7d7da1df97 -b26c8615c5e47691c9ff3deca3021714662d236c4d8401c5d27b50152ce7e566266b9d512d14eb63e65bc1d38a16f914 -827639d5ce7db43ba40152c8a0eaad443af21dc92636cc8cc2b35f10647da7d475a1e408901cd220552fddad79db74df -a2b79a582191a85dbe22dc384c9ca3de345e69f6aa370aa6d3ff1e1c3de513e30b72df9555b15a46586bd27ea2854d9d -ae0d74644aba9a49521d3e9553813bcb9e18f0b43515e4c74366e503c52f47236be92dfbd99c7285b3248c267b1de5a0 -80fb0c116e0fd6822a04b9c25f456bdca704e2be7bdc5d141dbf5d1c5eeb0a2c4f5d80db583b03ef3e47517e4f9a1b10 -ac3a1fa3b4a2f30ea7e0a114cdc479eb51773573804c2a158d603ad9902ae8e39ffe95df09c0d871725a5d7f9ba71a57 -b56b2b0d601cba7f817fa76102c68c2e518c6f20ff693aad3ff2e07d6c4c76203753f7f91686b1801e8c4659e4d45c48 -89d50c1fc56e656fb9d3915964ebce703cb723fe411ab3c9eaa88ccc5d2b155a9b2e515363d9c600d3c0cee782c43f41 -b24207e61462f6230f3cd8ccf6828357d03e725769f7d1de35099ef9ee4dca57dbce699bb49ed994462bee17059d25ce -b886f17fcbcbfcd08ac07f04bb9543ef58510189decaccea4b4158c9174a067cb67d14b6be3c934e6e2a18c77efa9c9c -b9c050ad9cafd41c6e2e192b70d080076eed59ed38ea19a12bd92fa17b5d8947d58d5546aaf5e8e27e1d3b5481a6ce51 -aaf7a34d3267e3b1ddbc54c641e3922e89303f7c86ebebc7347ebca4cffad5b76117dac0cbae1a133053492799cd936f -a9ee604ada50adef82e29e893070649d2d4b7136cc24fa20e281ce1a07bd736bf0de7c420369676bcbcecff26fb6e900 -9855315a12a4b4cf80ab90b8bd13003223ba25206e52fd4fe6a409232fbed938f30120a3db23eab9c53f308bd8b9db81 -8cd488dd7a24f548a3cf03c54dec7ff61d0685cb0f6e5c46c2d728e3500d8c7bd6bba0156f4bf600466fda53e5b20444 -890ad4942ebac8f5b16c777701ab80c68f56fa542002b0786f8fea0fb073154369920ac3dbfc07ea598b82f4985b8ced -8de0cf9ddc84c9b92c59b9b044387597799246b30b9f4d7626fc12c51f6e423e08ee4cbfe9289984983c1f9521c3e19d -b474dfb5b5f4231d7775b3c3a8744956b3f0c7a871d835d7e4fd9cc895222c7b868d6c6ce250de568a65851151fac860 -86433b6135d9ed9b5ee8cb7a6c40e5c9d30a68774cec04988117302b8a02a11a71a1e03fd8e0264ef6611d219f103007 -80b9ed4adbe9538fb1ef69dd44ec0ec5b57cbfea820054d8d445b4261962624b4c70ac330480594bc5168184378379c3 -8b2e83562ccd23b7ad2d17f55b1ab7ef5fbef64b3a284e6725b800f3222b8bdf49937f4a873917ada9c4ddfb090938c2 -abe78cebc0f5a45d754140d1f685e387489acbfa46d297a8592aaa0d676a470654f417a4f7d666fc0b2508fab37d908e -a9c5f8ff1f8568e252b06d10e1558326db9901840e6b3c26bbd0cd5e850cb5fb3af3f117dbb0f282740276f6fd84126f -975f8dc4fb55032a5df3b42b96c8c0ffecb75456f01d4aef66f973cb7270d4eff32c71520ceefc1adcf38d77b6b80c67 -b043306ed2c3d8a5b9a056565afd8b5e354c8c4569fda66b0d797a50a3ce2c08cffbae9bbe292da69f39e89d5dc7911e -8d2afc36b1e44386ba350c14a6c1bb31ff6ea77128a0c5287584ac3584282d18516901ce402b4644a53db1ed8e7fa581 -8c294058bed53d7290325c363fe243f6ec4f4ea2343692f4bac8f0cb86f115c069ccb8334b53d2e42c067691ad110dba -b92157b926751aaf7ef82c1aa8c654907dccab6376187ee8b3e8c0c82811eae01242832de953faa13ebaff7da8698b3e -a780c4bdd9e4ba57254b09d745075cecab87feda78c88ffee489625c5a3cf96aa6b3c9503a374a37927d9b78de9bd22b -811f548ef3a2e6a654f7dcb28ac9378de9515ed61e5a428515d9594a83e80b35c60f96a5cf743e6fab0d3cb526149f49 -85a4dccf6d90ee8e094731eec53bd00b3887aec6bd81a0740efddf812fd35e3e4fe4f983afb49a8588691c202dabf942 -b152c2da6f2e01c8913079ae2b40a09b1f361a80f5408a0237a8131b429677c3157295e11b365b1b1841924b9efb922e -849b9efee8742502ffd981c4517c88ed33e4dd518a330802caff168abae3cd09956a5ee5eda15900243bc2e829016b74 -955a933f3c18ec0f1c0e38fa931e4427a5372c46a3906ebe95082bcf878c35246523c23f0266644ace1fa590ffa6d119 -911989e9f43e580c886656377c6f856cdd4ff1bd001b6db3bbd86e590a821d34a5c6688a29b8d90f28680e9fdf03ba69 -b73b8b4f1fd6049fb68d47cd96a18fcba3f716e0a1061aa5a2596302795354e0c39dea04d91d232aec86b0bf2ba10522 -90f87456d9156e6a1f029a833bf3c7dbed98ca2f2f147a8564922c25ae197a55f7ea9b2ee1f81bf7383197c4bad2e20c -903cba8b1e088574cb04a05ca1899ab00d8960580c884bd3c8a4c98d680c2ad11410f2b75739d6050f91d7208cac33a5 -9329987d42529c261bd15ecedd360be0ea8966e7838f32896522c965adfc4febf187db392bd441fb43bbd10c38fdf68b -8178ee93acf5353baa349285067b20e9bb41aa32d77b5aeb7384fe5220c1fe64a2461bd7a83142694fe673e8bbf61b7c -a06a8e53abcff271b1394bcc647440f81fb1c1a5f29c27a226e08f961c3353f4891620f2d59b9d1902bf2f5cc07a4553 -aaf5fe493b337810889e777980e6bbea6cac39ac66bc0875c680c4208807ac866e9fda9b5952aa1d04539b9f4a4bec57 -aa058abb1953eceac14ccfa7c0cc482a146e1232905dcecc86dd27f75575285f06bbae16a8c9fe8e35d8713717f5f19f -8f15dd732799c879ca46d2763453b359ff483ca33adb1d0e0a57262352e0476c235987dc3a8a243c74bc768f93d3014c -a61cc8263e9bc03cce985f1663b8a72928a607121005a301b28a278e9654727fd1b22bc8a949af73929c56d9d3d4a273 -98d6dc78502d19eb9f921225475a6ebcc7b44f01a2df6f55ccf6908d65b27af1891be2a37735f0315b6e0f1576c1f8d8 -8bd258b883f3b3793ec5be9472ad1ff3dc4b51bc5a58e9f944acfb927349ead8231a523cc2175c1f98e7e1e2b9f363b8 -aeacc2ecb6e807ad09bedd99654b097a6f39840e932873ace02eabd64ccfbb475abdcb62939a698abf17572d2034c51e -b8ccf78c08ccd8df59fd6eda2e01de328bc6d8a65824d6f1fc0537654e9bc6bf6f89c422dd3a295cce628749da85c864 -8f91fd8cb253ba2e71cc6f13da5e05f62c2c3b485c24f5d68397d04665673167fce1fc1aec6085c69e87e66ec555d3fd -a254baa10cb26d04136886073bb4c159af8a8532e3fd36b1e9c3a2e41b5b2b6a86c4ebc14dbe624ee07b7ccdaf59f9ab -94e3286fe5cd68c4c7b9a7d33ae3d714a7f265cf77cd0e9bc19fc51015b1d1c34ad7e3a5221c459e89f5a043ee84e3a9 -a279da8878af8d449a9539bec4b17cea94f0242911f66fab275b5143ab040825f78c89cb32a793930609415cfa3a1078 -ac846ceb89c9e5d43a2991c8443079dc32298cd63e370e64149cec98cf48a6351c09c856f2632fd2f2b3d685a18bbf8b -a847b27995c8a2e2454aaeb983879fb5d3a23105c33175839f7300b7e1e8ec3efd6450e9fa3f10323609dee7b98c6fd5 -a2f432d147d904d185ff4b2de8c6b82fbea278a2956bc406855b44c18041854c4f0ecccd472d1d0dff1d8aa8e281cb1d -94a48ad40326f95bd63dff4755f863a1b79e1df771a1173b17937f9baba57b39e651e7695be9f66a472f098b339364fc -a12a0ccd8f96e96e1bc6494341f7ebce959899341b3a084aa1aa87d1c0d489ac908552b7770b887bb47e7b8cbc3d8e66 -81a1f1681bda923bd274bfe0fbb9181d6d164fe738e54e25e8d4849193d311e2c4253614ed673c98af2c798f19a93468 -abf71106a05d501e84cc54610d349d7d5eae21a70bd0250f1bebbf412a130414d1c8dbe673ffdb80208fd72f1defa4d4 -96266dc2e0df18d8136d79f5b59e489978eee0e6b04926687fe389d4293c14f36f055c550657a8e27be4118b64254901 -8df5dcbefbfb4810ae3a413ca6b4bf08619ca53cd50eb1dde2a1c035efffc7b7ac7dff18d403253fd80104bd83dc029e -9610b87ff02e391a43324a7122736876d5b3af2a137d749c52f75d07b17f19900b151b7f439d564f4529e77aa057ad12 -a90a5572198b40fe2fcf47c422274ff36c9624df7db7a89c0eb47eb48a73a03c985f4ac5016161c76ca317f64339bce1 -98e5e61a6ab6462ba692124dba7794b6c6bde4249ab4fcc98c9edd631592d5bc2fb5e38466691a0970a38e48d87c2e43 -918cefb8f292f78d4db81462c633daf73b395e772f47b3a7d2cea598025b1d8c3ec0cbff46cdb23597e74929981cde40 -a98918a5dc7cf610fe55f725e4fd24ce581d594cb957bb9b4e888672e9c0137003e1041f83e3f1d7b9caab06462c87d4 -b92b74ac015262ca66c33f2d950221e19d940ba3bf4cf17845f961dc1729ae227aa9e1f2017829f2135b489064565c29 -a053ee339f359665feb178b4e7ee30a85df37debd17cacc5a27d6b3369d170b0114e67ad1712ed26d828f1df641bcd99 -8c3c8bad510b35da5ce5bd84b35c958797fbea024ad1c97091d2ff71d9b962e9222f65a9b776e5b3cc29c36e1063d2ee -af99dc7330fe7c37e850283eb47cc3257888e7c197cb0d102edf94439e1e02267b6a56306d246c326c4c79f9dc8c6986 -afecb2dc34d57a725efbd7eb93d61eb29dbe8409b668ab9ea040791f5b796d9be6d4fc10d7f627bf693452f330cf0435 -93334fedf19a3727a81a6b6f2459db859186227b96fe7a391263f69f1a0884e4235de64d29edebc7b99c44d19e7c7d7a -89579c51ac405ad7e9df13c904061670ce4b38372492764170e4d3d667ed52e5d15c7cd5c5991bbfa3a5e4e3fa16363e -9778f3e8639030f7ef1c344014f124e375acb8045bd13d8e97a92c5265c52de9d1ffebaa5bc3e1ad2719da0083222991 -88f77f34ee92b3d36791bdf3326532524a67d544297dcf1a47ff00b47c1b8219ff11e34034eab7d23b507caa2fd3c6b9 -a699c1e654e7c484431d81d90657892efeb4adcf72c43618e71ca7bd7c7a7ebbb1db7e06e75b75dc4c74efd306b5df3f -81d13153baebb2ef672b5bdb069d3cd669ce0be96b742c94e04038f689ff92a61376341366b286eee6bf3ae85156f694 -81efb17de94400fdacc1deec2550cbe3eecb27c7af99d8207e2f9be397e26be24a40446d2a09536bb5172c28959318d9 -989b21ebe9ceab02488992673dc071d4d5edec24bff0e17a4306c8cb4b3c83df53a2063d1827edd8ed16d6e837f0d222 -8d6005d6536825661b13c5fdce177cb37c04e8b109b7eb2b6d82ea1cb70efecf6a0022b64f84d753d165edc2bba784a3 -a32607360a71d5e34af2271211652d73d7756d393161f4cf0da000c2d66a84c6826e09e759bd787d4fd0305e2439d342 -aaad8d6f6e260db45d51b2da723be6fa832e76f5fbcb77a9a31e7f090dd38446d3b631b96230d78208cae408c288ac4e -abcfe425255fd3c5cffd3a818af7650190c957b6b07b632443f9e33e970a8a4c3bf79ac9b71f4d45f238a04d1c049857 -aeabf026d4c783adc4414b5923dbd0be4b039cc7201219f7260d321f55e9a5b166d7b5875af6129c034d0108fdc5d666 -af49e740c752d7b6f17048014851f437ffd17413c59797e5078eaaa36f73f0017c3e7da020310cfe7d3c85f94a99f203 -8854ca600d842566e3090040cd66bb0b3c46dae6962a13946f0024c4a8aca447e2ccf6f240045f1ceee799a88cb9210c -b6c03b93b1ab1b88ded8edfa1b487a1ed8bdce8535244dddb558ffb78f89b1c74058f80f4db2320ad060d0c2a9c351cc -b5bd7d17372faff4898a7517009b61a7c8f6f0e7ed4192c555db264618e3f6e57fb30a472d169fea01bf2bf0362a19a8 -96eb1d38319dc74afe7e7eb076fcd230d19983f645abd14a71e6103545c01301b31c47ae931e025f3ecc01fb3d2f31fa -b55a8d30d4403067def9b65e16f867299f8f64c9b391d0846d4780bc196569622e7e5b64ce799b5aefac8f965b2a7a7b -8356d199a991e5cbbff608752b6291731b6b6771aed292f8948b1f41c6543e4ab1bedc82dd26d10206c907c03508df06 -97f4137445c2d98b0d1d478049de952610ad698c91c9d0f0e7227d2aae690e9935e914ec4a2ea1fbf3fc1dddfeeacebb -af5621707e0938320b15ddfc87584ab325fbdfd85c30efea36f8f9bd0707d7ec12c344eff3ec21761189518d192df035 -8ac7817e71ea0825b292687928e349da7140285d035e1e1abff0c3704fa8453faaae343a441b7143a74ec56539687cc4 -8a5e0a9e4758449489df10f3386029ada828d1762e4fb0a8ffe6b79e5b6d5d713cb64ed95960e126398b0cdb89002bc9 -81324be4a71208bbb9bca74b77177f8f1abb9d3d5d9db195d1854651f2cf333cd618d35400da0f060f3e1b025124e4b2 -849971d9d095ae067525b3cbc4a7dfae81f739537ade6d6cec1b42fb692d923176197a8770907c58069754b8882822d6 -89f830825416802477cc81fdf11084885865ee6607aa15aa4eb28e351c569c49b8a1b9b5e95ddc04fa0ebafe20071313 -9240aeeaff37a91af55f860b9badd466e8243af9e8c96a7aa8cf348cd270685ab6301bc135b246dca9eda696f8b0e350 -acf74db78cc33138273127599eba35b0fb4e7b9a69fe02dae18fc6692d748ca332bd00b22afa8e654ed587aab11833f3 -b091e6d37b157b50d76bd297ad752220cd5c9390fac16dc838f8557aed6d9833fc920b61519df21265406216315e883f -a6446c429ebf1c7793c622250e23594c836b2fbcaf6c5b3d0995e1595a37f50ea643f3e549b0be8bbdadd69044d72ab9 -93e675353bd60e996bf1c914d5267eeaa8a52fc3077987ccc796710ef9becc6b7a00e3d82671a6bdfb8145ee3c80245a -a2f731e43251d04ed3364aa2f072d05355f299626f2d71a8a38b6f76cf08c544133f7d72dd0ab4162814b674b9fc7fa6 -97a8b791a5a8f6e1d0de192d78615d73d0c38f1e557e4e15d15adc663d649e655bc8da3bcc499ef70112eafe7fb45c7a -98cd624cbbd6c53a94469be4643c13130916b91143425bcb7d7028adbbfede38eff7a21092af43b12d4fab703c116359 -995783ce38fd5f6f9433027f122d4cf1e1ff3caf2d196ce591877f4a544ce9113ead60de2de1827eaff4dd31a20d79a8 -8cf251d6f5229183b7f3fe2f607a90b4e4b6f020fb4ba2459d28eb8872426e7be8761a93d5413640a661d73e34a5b81f -b9232d99620652a3aa7880cad0876f153ff881c4ed4c0c2e7b4ea81d5d42b70daf1a56b869d752c3743c6d4c947e6641 -849716f938f9d37250cccb1bf77f5f9fde53096cdfc6f2a25536a6187029a8f1331cdbed08909184b201f8d9f04b792f -80c7c4de098cbf9c6d17b14eba1805e433b5bc905f6096f8f63d34b94734f2e4ebf4bce8a177efd1186842a61204a062 -b790f410cf06b9b8daadceeb4fd5ff40a2deda820c8df2537e0a7554613ae3948e149504e3e79aa84889df50c8678eeb -813aab8bd000299cd37485b73cd7cba06e205f8efb87f1efc0bae8b70f6db2bc7702eb39510ad734854fb65515fe9d0f -94f0ab7388ac71cdb67f6b85dfd5945748afb2e5abb622f0b5ad104be1d4d0062b651f134ba22385c9e32c2dfdcccce1 -ab6223dca8bd6a4f969e21ccd9f8106fc5251d321f9e90cc42cea2424b3a9c4e5060a47eeef6b23c7976109b548498e8 -859c56b71343fce4d5c5b87814c47bf55d581c50fd1871a17e77b5e1742f5af639d0e94d19d909ec7dfe27919e954e0c -aae0d632b6191b8ad71b027791735f1578e1b89890b6c22e37de0e4a6074886126988fe8319ae228ac9ef3b3bcccb730 -8ca9f32a27a024c3d595ecfaf96b0461de57befa3b331ab71dc110ec3be5824fed783d9516597537683e77a11d334338 -a061df379fb3f4b24816c9f6cd8a94ecb89b4c6dc6cd81e4b8096fa9784b7f97ab3540259d1de9c02eb91d9945af4823 -998603102ac63001d63eb7347a4bb2bf4cf33b28079bb48a169076a65c20d511ccd3ef696d159e54cc8e772fb5d65d50 -94444d96d39450872ac69e44088c252c71f46be8333a608a475147752dbb99db0e36acfc5198f158509401959c12b709 -ac1b51b6c09fe055c1d7c9176eea9adc33f710818c83a1fbfa073c8dc3a7eb3513cbdd3f5960b7845e31e3e83181e6ba -803d530523fc9e1e0f11040d2412d02baef3f07eeb9b177fa9bfa396af42eea898a4276d56e1db998dc96ae47b644cb2 -85a3c9fc7638f5bf2c3e15ba8c2fa1ae87eb1ceb44c6598c67a2948667a9dfa41e61f66d535b4e7fda62f013a5a8b885 -a961cf5654c46a1a22c29baf7a4e77837a26b7f138f410e9d1883480ed5fa42411d522aba32040b577046c11f007388e -ad1154142344f494e3061ef45a34fab1aaacf5fdf7d1b26adbb5fbc3d795655fa743444e39d9a4119b4a4f82a6f30441 -b1d6c30771130c77806e7ab893b73d4deb590b2ff8f2f8b5e54c2040c1f3e060e2bd99afc668cf706a2df666a508bbf6 -a00361fd440f9decabd98d96c575cd251dc94c60611025095d1201ef2dedde51cb4de7c2ece47732e5ed9b3526c2012c -a85c5ab4d17d328bda5e6d839a9a6adcc92ff844ec25f84981e4f44a0e8419247c081530f8d9aa629c7eb4ca21affba6 -a4ddd3eab4527a2672cf9463db38bc29f61460e2a162f426b7852b7a7645fbd62084fd39a8e4d60e1958cce436dd8f57 -811648140080fe55b8618f4cf17f3c5a250adb0cd53d885f2ddba835d2b4433188e41fc0661faac88e4ff910b16278c0 -b85c7f1cfb0ed29addccf7546023a79249e8f15ac2d14a20accbfef4dd9dc11355d599815fa09d2b6b4e966e6ea8cff1 -a10b5d8c260b159043b020d5dd62b3467df2671afea6d480ca9087b7e60ed170c82b121819d088315902842d66c8fb45 -917e191df1bcf3f5715419c1e2191da6b8680543b1ba41fe84ed07ef570376e072c081beb67b375fca3565a2565bcabb -881fd967407390bfd7badc9ab494e8a287559a01eb07861f527207c127eadea626e9bcc5aa9cca2c5112fbac3b3f0e9c -959fd71149af82cc733619e0e5bf71760ca2650448c82984b3db74030d0e10f8ab1ce1609a6de6f470fe8b5bd90df5b3 -a3370898a1c5f33d15adb4238df9a6c945f18b9ada4ce2624fc32a844f9ece4c916a64e9442225b6592afa06d2e015f2 -817efb8a791435e4236f7d7b278181a5fa34587578c629dbc14fbf9a5c26772290611395eecd20222a4c58649fc256d8 -a04c9876acf2cfdc8ef96de4879742709270fa1d03fe4c8511fbef2d59eb0aaf0336fa2c7dfe41a651157377fa217813 -81e15875d7ea7f123e418edf14099f2e109d4f3a6ce0eb65f67fe9fb10d2f809a864a29f60ad3fc949f89e2596b21783 -b49f529975c09e436e6bc202fdc16e3fdcbe056db45178016ad6fdece9faad4446343e83aed096209690b21a6910724f -879e8eda589e1a279f7f49f6dd0580788c040d973748ec4942dbe51ea8fbd05983cc919b78f0c6b92ef3292ae29db875 -81a2b74b2118923f34139a102f3d95e7eee11c4c2929c2576dee200a5abfd364606158535a6c9e4178a6a83dbb65f3c4 -8913f281d8927f2b45fc815d0f7104631cb7f5f7278a316f1327d670d15868daadd2a64e3eb98e1f53fe7e300338cc80 -a6f815fba7ef9af7fbf45f93bc952e8b351f5de6568a27c7c47a00cb39a254c6b31753794f67940fc7d2e9cc581529f4 -b3722a15c66a0014ce4d082de118def8d39190c15678a472b846225585f3a83756ae1b255b2e3f86a26168878e4773b2 -817ae61ab3d0dd5b6e24846b5a5364b1a7dc2e77432d9fed587727520ae2f307264ea0948c91ad29f0aea3a11ff38624 -b3db467464415fcad36dc1de2d6ba7686772a577cc2619242ac040d6734881a45d3b40ed4588db124e4289cfeec4bbf6 -ad66a14f5a54ac69603b16e5f1529851183da77d3cc60867f10aea41339dd5e06a5257982e9e90a352cdd32750f42ee4 -adafa3681ef45d685555601a25a55cf23358319a17f61e2179e704f63df83a73bdd298d12cf6cef86db89bd17119e11d -a379dc44cb6dd3b9d378c07b2ec654fec7ca2f272de6ba895e3d00d20c9e4c5550498a843c8ac67e4221db2115bedc1c -b7bf81c267a78efc6b9e5a904574445a6487678d7ef70054e3e93ea6a23f966c2b68787f9164918e3b16d2175459ed92 -b41d66a13a4afafd5760062b77f79de7e6ab8ccacde9c6c5116a6d886912fb491dc027af435b1b44aacc6af7b3c887f2 -9904d23a7c1c1d2e4bab85d69f283eb0a8e26d46e8b7b30224438015c936729b2f0af7c7c54c03509bb0500acb42d8a4 -ae30d65e9e20c3bfd603994ae2b175ff691d51f3e24b2d058b3b8556d12ca4c75087809062dddd4aaac81c94d15d8a17 -9245162fab42ac01527424f6013310c3eb462982518debef6c127f46ba8a06c705d7dc9f0a41e796ba8d35d60ae6cc64 -87fab853638d7a29a20f3ba2b1a7919d023e9415bfa78ebb27973d8cbc7626f584dc5665d2e7ad71f1d760eba9700d88 -85aac46ecd330608e5272430970e6081ff02a571e8ea444f1e11785ea798769634a22a142d0237f67b75369d3c484a8a -938c85ab14894cc5dfce3d80456f189a2e98eddbc8828f4ff6b1df1dcb7b42b17ca2ff40226a8a1390a95d63dca698dd -a18ce1f846e3e3c4d846822f60271eecf0f5d7d9f986385ac53c5ace9589dc7c0188910448c19b91341a1ef556652fa9 -8611608a9d844f0e9d7584ad6ccf62a5087a64f764caf108db648a776b5390feb51e5120f0ef0e9e11301af3987dd7dc -8106333ba4b4de8d1ae43bc9735d3fea047392e88efd6a2fa6f7b924a18a7a265ca6123c3edc0f36307dd7fb7fe89257 -a91426fa500951ff1b051a248c050b7139ca30dde8768690432d597d2b3c4357b11a577be6b455a1c5d145264dcf81fc -b7f9f90e0e450f37b081297f7f651bad0496a8b9afd2a4cf4120a2671aaaa8536dce1af301258bfbfdb122afa44c5048 -84126da6435699b0c09fa4032dec73d1fca21d2d19f5214e8b0bea43267e9a8dd1fc44f8132d8315e734c8e2e04d7291 -aff064708103884cb4f1a3c1718b3fc40a238d35cf0a7dc24bdf9823693b407c70da50df585bf5bc4e9c07d1c2d203e8 -a8b40fc6533752983a5329c31d376c7a5c13ce6879cc7faee648200075d9cd273537001fb4c86e8576350eaac6ba60c2 -a02db682bdc117a84dcb9312eb28fcbde12d49f4ce915cc92c610bb6965ec3cc38290f8c5b5ec70afe153956692cda95 -86decd22b25d300508472c9ce75d3e465b737e7ce13bc0fcce32835e54646fe12322ba5bc457be18bfd926a1a6ca4a38 -a18666ef65b8c2904fd598791f5627207165315a85ee01d5fb0e6b2e10bdd9b00babc447da5bd63445e3337de33b9b89 -89bb0c06effadefdaf34ffe4b123e1678a90d4451ee856c863df1e752eef41fd984689ded8f0f878bf8916d5dd8e8024 -97cfcba08ebec05d0073992a66b1d7d6fb9d95871f2cdc36db301f78bf8069294d1c259efef5c93d20dc937eedae3a1a -ac2643b14ece79dcb2e289c96776a47e2bebd40dd6dc74fd035df5bb727b5596f40e3dd2d2202141e69b0993717ede09 -a5e6fd88a2f9174d9bd4c6a55d9c30974be414992f22aa852f552c7648f722ed8077acf5aba030abd47939bb451b2c60 -8ad40a612824a7994487731a40b311b7349038c841145865539c6ada75c56de6ac547a1c23df190e0caaafecddd80ccc -953a7cea1d857e09202c438c6108060961f195f88c32f0e012236d7a4b39d840c61b162ec86436e8c38567328bea0246 -80d8b47a46dae1868a7b8ccfe7029445bbe1009dad4a6c31f9ef081be32e8e1ac1178c3c8fb68d3e536c84990cc035b1 -81ecd99f22b3766ce0aca08a0a9191793f68c754fdec78b82a4c3bdc2db122bbb9ebfd02fc2dcc6e1567a7d42d0cc16a -b1dd0446bccc25846fb95d08c1c9cc52fb51c72c4c5d169ffde56ecfe800f108dc1106d65d5c5bd1087c656de3940b63 -b87547f0931e164e96de5c550ca5aa81273648fe34f6e193cd9d69cf729cb432e17aa02e25b1c27a8a0d20a3b795e94e -820a94e69a927e077082aae66f6b292cfbe4589d932edf9e68e268c9bd3d71ef76cf7d169dd445b93967c25db11f58f1 -b0d07ddf2595270c39adfa0c8cf2ab1322979b0546aa4d918f641be53cd97f36c879bb75d205e457c011aca3bbd9f731 -8700b876b35b4b10a8a9372c5230acecd39539c1bb87515640293ad4464a9e02929d7d6a6a11112e8a29564815ac0de4 -a61a601c5bb27dcb97e37c8e2b9ce479c6b192a5e04d9ed5e065833c5a1017ee5f237b77d1a17be5d48f8e7cc0bcacf6 -92fb88fe774c1ba1d4a08cae3c0e05467ad610e7a3f1d2423fd47751759235fe0a3036db4095bd6404716aa03820f484 -b274f140d77a3ce0796f5e09094b516537ccaf27ae1907099bff172e6368ba85e7c3ef8ea2a07457cac48ae334da95b3 -b2292d9181f16581a9a9142490b2bdcdfb218ca6315d1effc8592100d792eb89d5356996c890441f04f2b4a95763503e -8897e73f576d86bc354baa3bd96e553107c48cf5889dcc23c5ba68ab8bcd4e81f27767be2233fdfa13d39f885087e668 -a29eac6f0829791c728d71abc49569df95a4446ecbfc534b39f24f56c88fe70301838dfc1c19751e7f3c5c1b8c6af6a0 -9346dc3720adc5df500a8df27fd9c75ef38dc5c8f4e8ed66983304750e66d502c3c59b8e955be781b670a0afc70a2167 -9566d534e0e30a5c5f1428665590617e95fd05d45f573715f58157854ad596ece3a3cfec61356aee342308d623e029d5 -a464fb8bffe6bd65f71938c1715c6e296cc6d0311a83858e4e7eb5873b7f2cf0c584d2101e3407b85b64ca78b2ac93ce -b54088f7217987c87e9498a747569ac5b2f8afd5348f9c45bf3fd9fbf713a20f495f49c8572d087efe778ac7313ad6d3 -91fa9f5f8000fe050f5b224d90b59fcce13c77e903cbf98ded752e5b3db16adb2bc1f8c94be48b69f65f1f1ad81d6264 -92d04a5b0ac5d8c8e313709b432c9434ecd3e73231f01e9b4e7952b87df60cbfa97b5dedd2200bd033b4b9ea8ba45cc1 -a94b90ad3c3d6c4bbe169f8661a790c40645b40f0a9d1c7220f01cf7fc176e04d80bab0ced9323fcafb93643f12b2760 -94d86149b9c8443b46196f7e5a3738206dd6f3be7762df488bcbb9f9ee285a64c997ed875b7b16b26604fa59020a8199 -82efe4ae2c50a2d7645240c173a047f238536598c04a2c0b69c96e96bd18e075a99110f1206bc213f39edca42ba00cc1 -ab8667685f831bc14d4610f84a5da27b4ea5b133b4d991741a9e64dceb22cb64a3ce8f1b6e101d52af6296df7127c9ad -83ba433661c05dcc5d562f4a9a261c8110dac44b8d833ae1514b1fc60d8b4ee395b18804baea04cb10adb428faf713c3 -b5748f6f660cc5277f1211d2b8649493ed8a11085b871cd33a5aea630abd960a740f08c08be5f9c21574600ac9bf5737 -a5c8dd12af48fb710642ad65ebb97ca489e8206741807f7acfc334f8035d3c80593b1ff2090c9bb7bd138f0c48714ca8 -a2b382fd5744e3babf454b1d806cc8783efeb4761bc42b6914ea48a46a2eae835efbe0a18262b6bc034379e03cf1262b -b3145ffaf603f69f15a64936d32e3219eea5ed49fdfd2f5bf40ea0dfd974b36fb6ff12164d4c2282d892db4cf3ff3ce1 -87a316fb213f4c5e30c5e3face049db66be4f28821bd96034714ec23d3e97849d7b301930f90a4323c7ccf53de23050c -b9de09a919455070fed6220fc179c8b7a4c753062bcd27acf28f5b9947a659c0b364298daf7c85c4ca6fca7f945add1f -806fbd98d411b76979464c40ad88bc07a151628a27fcc1012ba1dfbaf5b5cc9d962fb9b3386008978a12515edce934bc -a15268877fae0d21610ae6a31061ed7c20814723385955fac09fdc9693a94c33dea11db98bb89fdfe68f933490f5c381 -8d633fb0c4da86b2e0b37d8fad5972d62bff2ac663c5ec815d095cd4b7e1fe66ebef2a2590995b57eaf941983c7ad7a4 -8139e5dd9cf405e8ef65f11164f0440827d98389ce1b418b0c9628be983a9ddd6cf4863036ccb1483b40b8a527acd9ed -88b15fa94a08eac291d2b94a2b30eb851ff24addf2cc30b678e72e32cfcb3424cf4b33aa395d741803f3e578ddf524de -b5eaf0c8506e101f1646bcf049ee38d99ea1c60169730da893fd6020fd00a289eb2f415947e44677af49e43454a7b1be -8489822ad0647a7e06aa2aa5595960811858ddd4542acca419dd2308a8c5477648f4dd969a6740bb78aa26db9bfcc555 -b1e9a7b9f3423c220330d45f69e45fa03d7671897cf077f913c252e3e99c7b1b1cf6d30caad65e4228d5d7b80eb86e5e -b28fe9629592b9e6a55a1406903be76250b1c50c65296c10c5e48c64b539fb08fe11f68cf462a6edcbba71b0cee3feb2 -a41acf96a02c96cd8744ff6577c244fc923810d17ade133587e4c223beb7b4d99fa56eae311a500d7151979267d0895c -880798938fe4ba70721be90e666dfb62fcab4f3556fdb7b0dc8ec5bc34f6b4513df965eae78527136eb391889fe2caf9 -98d4d89d358e0fb7e212498c73447d94a83c1b66e98fc81427ab13acddb17a20f52308983f3a5a8e0aaacec432359604 -81430b6d2998fc78ba937a1639c6020199c52da499f68109da227882dc26d005b73d54c5bdcac1a04e8356a8ca0f7017 -a8d906a4786455eb74613aba4ce1c963c60095ffb8658d368df9266fdd01e30269ce10bf984e7465f34b4fd83beba26a -af54167ac1f954d10131d44a8e0045df00d581dd9e93596a28d157543fbe5fb25d213806ed7fb3cba6b8f5b5423562db -8511e373a978a12d81266b9afbd55035d7bc736835cfa921903a92969eeba3624437d1346b55382e61415726ab84a448 -8cf43eea93508ae586fa9a0f1354a1e16af659782479c2040874a46317f9e8d572a23238efa318fdfb87cc63932602b7 -b0bdd3bacff077173d302e3a9678d1d37936188c7ecc34950185af6b462b7c679815176f3cce5db19aac8b282f2d60ad -a355e9b87f2f2672052f5d4d65b8c1c827d24d89b0d8594641fccfb69aef1b94009105f3242058bb31c8bf51caae5a41 -b8baa9e4b950b72ff6b88a6509e8ed1304bc6fd955748b2e59a523a1e0c5e99f52aec3da7fa9ff407a7adf259652466c -840bc3dbb300ea6f27d1d6dd861f15680bd098be5174f45d6b75b094d0635aced539fa03ddbccb453879de77fb5d1fe9 -b4bc7e7e30686303856472bae07e581a0c0bfc815657c479f9f5931cff208d5c12930d2fd1ff413ebd8424bcd7a9b571 -89b5d514155d7999408334a50822508b9d689add55d44a240ff2bdde2eee419d117031f85e924e2a2c1ca77db9b91eea -a8604b6196f87a04e1350302e8aa745bba8dc162115d22657b37a1d1a98cb14876ddf7f65840b5dbd77e80cd22b4256c -83cb7acdb9e03247515bb2ce0227486ccf803426717a14510f0d59d45e998b245797d356f10abca94f7a14e1a2f0d552 -aeb3266a9f16649210ab2df0e1908ac259f34ce1f01162c22b56cf1019096ee4ea5854c36e30bb2feb06c21a71e8a45c -89e72e86edf2aa032a0fc9acf4d876a40865fbb2c8f87cb7e4d88856295c4ac14583e874142fd0c314a49aba68c0aa3c -8c3576eba0583c2a7884976b4ed11fe1fda4f6c32f6385d96c47b0e776afa287503b397fa516a455b4b8c3afeedc76db -a31e5b633bda9ffa174654fee98b5d5930a691c3c42fcf55673d927dbc8d91c58c4e42e615353145431baa646e8bbb30 -89f2f3f7a8da1544f24682f41c68114a8f78c86bd36b066e27da13acb70f18d9f548773a16bd8e24789420e17183f137 -ada27fa4e90a086240c9164544d2528621a415a5497badb79f8019dc3dce4d12eb6b599597e47ec6ac39c81efda43520 -90dc1eb21bf21c0187f359566fc4bf5386abea52799306a0e5a1151c0817c5f5bc60c86e76b1929c092c0f3ff48cedd2 -b702a53ebcc17ae35d2e735a347d2c700e9cbef8eadbece33cac83df483b2054c126593e1f462cfc00a3ce9d737e2af5 -9891b06455ec925a6f8eafffba05af6a38cc5e193acaaf74ffbf199df912c5197106c5e06d72942bbb032ce277b6417f -8c0ee71eb01197b019275bcf96cae94e81d2cdc3115dbf2d8e3080074260318bc9303597e8f72b18f965ad601d31ec43 -8aaf580aaf75c1b7a5f99ccf60503506e62058ef43b28b02f79b8536a96be3f019c9f71caf327b4e6730134730d1bef5 -ae6f9fc21dd7dfa672b25a87eb0a41644f7609fab5026d5cedb6e43a06dbbfd6d6e30322a2598c8dedde88c52eaed626 -8159b953ffece5693edadb2e906ebf76ff080ee1ad22698950d2d3bfc36ac5ea78f58284b2ca180664452d55bd54716c -ab7647c32ca5e9856ac283a2f86768d68de75ceeba9e58b74c5324f8298319e52183739aba4340be901699d66ac9eb3f -a4d85a5701d89bcfaf1572db83258d86a1a0717603d6f24ac2963ffcf80f1265e5ab376a4529ca504f4396498791253c -816080c0cdbfe61b4d726c305747a9eb58ac26d9a35f501dd32ba43c098082d20faf3ccd41aad24600aa73bfa453dfac -84f3afac024f576b0fd9acc6f2349c2fcefc3f77dbe5a2d4964d14b861b88e9b1810334b908cf3427d9b67a8aee74b18 -94b390655557b1a09110018e9b5a14490681ade275bdc83510b6465a1218465260d9a7e2a6e4ec700f58c31dc3659962 -a8c66826b1c04a2dd4c682543242e7a57acae37278bd09888a3d17747c5b5fec43548101e6f46d703638337e2fd3277b -86e6f4608a00007fa533c36a5b054c5768ccafe41ad52521d772dcae4c8a4bcaff8f7609be30d8fab62c5988cbbb6830 -837da4cf09ae8aa0bceb16f8b3bfcc3b3367aecac9eed6b4b56d7b65f55981ef066490764fb4c108792623ecf8cad383 -941ff3011462f9b5bf97d8cbdb0b6f5d37a1b1295b622f5485b7d69f2cb2bcabc83630dae427f0259d0d9539a77d8424 -b99e5d6d82aa9cf7d5970e7f710f4039ac32c2077530e4c2779250c6b9b373bc380adb0a03b892b652f649720672fc8c -a791c78464b2d65a15440b699e1e30ebd08501d6f2720adbc8255d989a82fcded2f79819b5f8f201bed84a255211b141 -84af7ad4a0e31fcbb3276ab1ad6171429cf39adcf78dc03750dc5deaa46536d15591e26d53e953dfb31e1622bc0743ab -a833e62fe97e1086fae1d4917fbaf09c345feb6bf1975b5cb863d8b66e8d621c7989ab3dbecda36bc9eaffc5eaa6fa66 -b4ef79a46a2126f53e2ebe62770feb57fd94600be29459d70a77c5e9cc260fa892be06cd60f886bf48459e48eb50d063 -b43b8f61919ea380bf151c294e54d3a3ff98e20d1ee5efbfe38aa2b66fafbc6a49739793bd5cb1c809f8b30466277c3a -ab37735af2412d2550e62df9d8b3b5e6f467f20de3890bf56faf1abf2bf3bd1d98dc3fa0ad5e7ab3fce0fa20409eb392 -82416b74b1551d484250d85bb151fabb67e29cce93d516125533df585bc80779ab057ea6992801a3d7d5c6dcff87a018 -8145d0787f0e3b5325190ae10c1d6bee713e6765fb6a0e9214132c6f78f4582bb2771aaeae40d3dad4bafb56bf7e36d8 -b6935886349ecbdd5774e12196f4275c97ec8279fdf28ccf940f6a022ebb6de8e97d6d2173c3fe402cbe9643bed3883b -87ef9b4d3dc71ac86369f8ed17e0dd3b91d16d14ae694bc21a35b5ae37211b043d0e36d8ff07dcc513fb9e6481a1f37f -ae1d0ded32f7e6f1dc8fef495879c1d9e01826f449f903c1e5034aeeabc5479a9e323b162b688317d46d35a42d570d86 -a40d16497004db4104c6794e2f4428d75bdf70352685944f3fbe17526df333e46a4ca6de55a4a48c02ecf0bde8ba03c0 -8d45121efba8cc308a498e8ee39ea6fa5cae9fb2e4aab1c2ff9d448aa8494ccbec9a078f978a86fcd97b5d5e7be7522a -a8173865c64634ba4ac2fa432740f5c05056a9deaf6427cb9b4b8da94ca5ddbc8c0c5d3185a89b8b28878194de9cdfcd -b6ec06a74d690f6545f0f0efba236e63d1fdfba54639ca2617408e185177ece28901c457d02b849fd00f1a53ae319d0a -b69a12df293c014a40070e3e760169b6f3c627caf9e50b35a93f11ecf8df98b2bc481b410eecb7ab210bf213bbe944de -97e7dc121795a533d4224803e591eef3e9008bab16f12472210b73aaf77890cf6e3877e0139403a0d3003c12c8f45636 -acdfa6fdd4a5acb7738cc8768f7cba84dbb95c639399b291ae8e4e63df37d2d4096900a84d2f0606bf534a9ccaa4993f -86ee253f3a9446a33e4d1169719b7d513c6b50730988415382faaf751988c10a421020609f7bcdef91be136704b906e2 -aac9438382a856caf84c5a8a234282f71b5fc5f65219103b147e7e6cf565522285fbfd7417b513bdad8277a00f652ca1 -83f3799d8e5772527930f5dc071a2e0a65471618993ec8990a96ccdeee65270e490bda9d26bb877612475268711ffd80 -93f28a81ac8c0ec9450b9d762fae9c7f8feaace87a6ee6bd141ef1d2d0697ef1bbd159fe6e1de640dbdab2b0361fca8a -a0825c95ba69999b90eac3a31a3fd830ea4f4b2b7409bde5f202b61d741d6326852ce790f41de5cb0eccec7af4db30c1 -83924b0e66233edd603c3b813d698daa05751fc34367120e3cf384ea7432e256ccee4d4daf13858950549d75a377107d -956fd9fa58345277e06ba2ec72f49ed230b8d3d4ff658555c52d6cddeb84dd4e36f1a614f5242d5ca0192e8daf0543c2 -944869912476baae0b114cced4ff65c0e4c90136f73ece5656460626599051b78802df67d7201c55d52725a97f5f29fe -865cb25b64b4531fb6fe4814d7c8cd26b017a6c6b72232ff53defc18a80fe3b39511b23f9e4c6c7249d06e03b2282ed2 -81e09ff55214960775e1e7f2758b9a6c4e4cd39edf7ec1adfaad51c52141182b79fe2176b23ddc7df9fd153e5f82d668 -b31006896f02bc90641121083f43c3172b1039334501fbaf1672f7bf5d174ddd185f945adf1a9c6cf77be34c5501483d -88b92f6f42ae45e9f05b16e52852826e933efd0c68b0f2418ac90957fd018df661bc47c8d43c2a7d7bfcf669dab98c3c -92fc68f595853ee8683930751789b799f397135d002eda244fe63ecef2754e15849edde3ba2f0cc8b865c9777230b712 -99ca06a49c5cd0bb097c447793fcdd809869b216a34c66c78c7e41e8c22f05d09168d46b8b1f3390db9452d91bc96dea -b48b9490a5d65296802431852d548d81047bbefc74fa7dc1d4e2a2878faacdfcb365ae59209cb0ade01901a283cbd15d -aff0fdbef7c188b120a02bc9085d7b808e88f73973773fef54707bf2cd772cd066740b1b6f4127b5c349f657bd97e738 -966fd4463b4f43dd8ccba7ad50baa42292f9f8b2e70da23bb6780e14155d9346e275ef03ddaf79e47020dcf43f3738bd -9330c3e1fadd9e08ac85f4839121ae20bbeb0a5103d84fa5aadbd1213805bdcda67bf2fb75fc301349cbc851b5559d20 -993bb99867bd9041a71a55ad5d397755cfa7ab6a4618fc526179bfc10b7dc8b26e4372fe9a9b4a15d64f2b63c1052dda -a29b59bcfab51f9b3c490a3b96f0bf1934265c315349b236012adbd64a56d7f6941b2c8cc272b412044bc7731f71e1dc -a65c9cefe1fc35d089fe8580c2e7671ebefdb43014ac291528ff4deefd4883fd4df274af83711dad610dad0d615f9d65 -944c78c56fb227ae632805d448ca3884cd3d2a89181cead3d2b7835e63297e6d740aa79a112edb1d4727824991636df5 -a73d782da1db7e4e65d7b26717a76e16dd9fab4df65063310b8e917dc0bc24e0d6755df5546c58504d04d9e68c3b474a -af80f0b87811ae3124f68108b4ca1937009403f87928bbc53480e7c5408d072053ace5eeaf5a5aba814dab8a45502085 -88aaf1acfc6e2e19b8387c97da707cb171c69812fefdd4650468e9b2c627bd5ccfb459f4d8e56bdfd84b09ddf87e128f -92c97276ff6f72bab6e9423d02ad6dc127962dbce15a0dd1e4a393b4510c555df6aa27be0f697c0d847033a9ca8b8dfd -a0e07d43d96e2d85b6276b3c60aadb48f0aedf2de8c415756dc597249ea64d2093731d8735231dadc961e5682ac59479 -adc9e6718a8f9298957d1da3842a7751c5399bbdf56f8de6c1c4bc39428f4aee6f1ba6613d37bf46b9403345e9d6fc81 -951da434da4b20d949b509ceeba02e24da7ed2da964c2fcdf426ec787779c696b385822c7dbea4df3e4a35921f1e912c -a04cbce0d2b2e87bbf038c798a12ec828423ca6aca08dc8d481cf6466e3c9c73d4d4a7fa47df9a7e2e15aae9e9f67208 -8f855cca2e440d248121c0469de1f94c2a71b8ee2682bbad3a78243a9e03da31d1925e6760dbc48a1957e040fae9abe8 -b642e5b17c1df4a4e101772d73851180b3a92e9e8b26c918050f51e6dd3592f102d20b0a1e96f0e25752c292f4c903ff -a92454c300781f8ae1766dbbb50a96192da7d48ef4cbdd72dd8cbb44c6eb5913c112cc38e9144615fdc03684deb99420 -8b74f7e6c2304f8e780df4649ef8221795dfe85fdbdaa477a1542d135b75c8be45bf89adbbb6f3ddf54ca40f02e733e9 -85cf66292cbb30cec5fd835ab10c9fcb3aea95e093aebf123e9a83c26f322d76ebc89c4e914524f6c5f6ee7d74fc917d -ae0bfe0cdc97c09542a7431820015f2d16067b30dca56288013876025e81daa8c519e5e347268e19aa1a85fa1dc28793 -921322fc6a47dc091afa0ad6df18ed14cde38e48c6e71550aa513918b056044983aee402de21051235eecf4ce8040fbe -96c030381e97050a45a318d307dcb3c8377b79b4dd5daf6337cded114de26eb725c14171b9b8e1b3c08fe1f5ea6b49e0 -90c23b86b6111818c8baaf53a13eaee1c89203b50e7f9a994bf0edf851919b48edbac7ceef14ac9414cf70c486174a77 -8bf6c301240d2d1c8d84c71d33a6dfc6d9e8f1cfae66d4d0f7a256d98ae12b0bcebfa94a667735ee89f810bcd7170cff -a41a4ffbbea0e36874d65c009ee4c3feffff322f6fc0e30d26ee4dbc1f46040d05e25d9d0ecb378cef0d24a7c2c4b850 -a8d4cdd423986bb392a0a92c12a8bd4da3437eec6ef6af34cf5310944899287452a2eb92eb5386086d5063381189d10e -a81dd26ec057c4032a4ed7ad54d926165273ed51d09a1267b2e477535cf6966835a257c209e4e92d165d74fa75695fa3 -8d7f708c3ee8449515d94fc26b547303b53d8dd55f177bc3b25d3da2768accd9bc8e9f09546090ebb7f15c66e6c9c723 -839ba65cffcd24cfffa7ab3b21faabe3c66d4c06324f07b2729c92f15cad34e474b0f0ddb16cd652870b26a756b731d3 -87f1a3968afec354d92d77e2726b702847c6afcabb8438634f9c6f7766de4c1504317dc4fa9a4a735acdbf985e119564 -91a8a7fd6542f3e0673f07f510d850864b34ac087eb7eef8845a1d14b2b1b651cbdc27fa4049bdbf3fea54221c5c8549 -aef3cf5f5e3a2385ead115728d7059e622146c3457d266c612e778324b6e06fbfb8f98e076624d2f3ce1035d65389a07 -819915d6232e95ccd7693fdd78d00492299b1983bc8f96a08dcb50f9c0a813ed93ae53c0238345d5bea0beda2855a913 -8e9ba68ded0e94935131b392b28218315a185f63bf5e3c1a9a9dd470944509ca0ba8f6122265f8da851b5cc2abce68f1 -b28468e9b04ee9d69003399a3cf4457c9bf9d59f36ab6ceeb8e964672433d06b58beeea198fedc7edbaa1948577e9fa2 -a633005e2c9f2fd94c8bce2dd5bb708fe946b25f1ec561ae65e54e15cdd88dc339f1a083e01f0d39610c8fe24151aaf0 -841d0031e22723f9328dd993805abd13e0c99b0f59435d2426246996b08d00ce73ab906f66c4eab423473b409e972ce0 -85758d1b084263992070ec8943f33073a2d9b86a8606672550c17545507a5b3c88d87382b41916a87ee96ff55a7aa535 -8581b06b0fc41466ef94a76a1d9fb8ae0edca6d018063acf6a8ca5f4b02d76021902feba58972415691b4bdbc33ae3b4 -83539597ff5e327357ee62bc6bf8c0bcaec2f227c55c7c385a4806f0d37fb461f1690bad5066b8a5370950af32fafbef -aee3557290d2dc10827e4791d00e0259006911f3f3fce4179ed3c514b779160613eca70f720bff7804752715a1266ffa -b48d2f0c4e90fc307d5995464e3f611a9b0ef5fe426a289071f4168ed5cc4f8770c9332960c2ca5c8c427f40e6bb389f -847af8973b4e300bb06be69b71b96183fd1a0b9d51b91701bef6fcfde465068f1eb2b1503b07afda380f18d69de5c9e1 -a70a6a80ce407f07804c0051ac21dc24d794b387be94eb24e1db94b58a78e1bcfb48cd0006db8fc1f9bedaece7a44fbe -b40e942b8fa5336910ff0098347df716bff9d1fa236a1950c16eeb966b3bc1a50b8f7b0980469d42e75ae13ced53cead -b208fabaa742d7db3148515330eb7a3577487845abdb7bd9ed169d0e081db0a5816595c33d375e56aeac5b51e60e49d3 -b7c8194b30d3d6ef5ab66ec88ad7ebbc732a3b8a41731b153e6f63759a93f3f4a537eab9ad369705bd730184bdbbdc34 -9280096445fe7394d04aa1bc4620c8f9296e991cc4d6c131bd703cb1cc317510e6e5855ac763f4d958c5edfe7eebeed7 -abc2aa4616a521400af1a12440dc544e3c821313d0ab936c86af28468ef8bbe534837e364598396a81cf8d06274ed5a6 -b18ca8a3325adb0c8c18a666d4859535397a1c3fe08f95eebfac916a7a99bbd40b3c37b919e8a8ae91da38bc00fa56c0 -8a40c33109ecea2a8b3558565877082f79121a432c45ec2c5a5e0ec4d1c203a6788e6b69cb37f1fd5b8c9a661bc5476d -88c47301dd30998e903c84e0b0f2c9af2e1ce6b9f187dab03528d44f834dc991e4c86d0c474a2c63468cf4020a1e24a0 -920c832853e6ab4c851eecfa9c11d3acc7da37c823be7aa1ab15e14dfd8beb5d0b91d62a30cec94763bd8e4594b66600 -98e1addbe2a6b8edc7f12ecb9be81c3250aeeca54a1c6a7225772ca66549827c15f3950d01b8eb44aecb56fe0fff901a -8cfb0fa1068be0ec088402f5950c4679a2eb9218c729da67050b0d1b2d7079f3ddf4bf0f57d95fe2a8db04bc6bcdb20c -b70f381aafe336b024120453813aeab70baac85b9c4c0f86918797b6aee206e6ed93244a49950f3d8ec9f81f4ac15808 -a4c8edf4aa33b709a91e1062939512419711c1757084e46f8f4b7ed64f8e682f4e78b7135920c12f0eb0422fe9f87a6a -b4817e85fd0752d7ebb662d3a51a03367a84bac74ebddfba0e5af5e636a979500f72b148052d333b3dedf9edd2b4031b -a87430169c6195f5d3e314ff2d1c2f050e766fd5d2de88f5207d72dba4a7745bb86d0baca6e9ae156582d0d89e5838c7 -991b00f8b104566b63a12af4826b61ce7aa40f4e5b8fff3085e7a99815bdb4471b6214da1e480214fac83f86a0b93cc5 -b39966e3076482079de0678477df98578377a094054960ee518ef99504d6851f8bcd3203e8da5e1d4f6f96776e1fe6eb -a448846d9dc2ab7a0995fa44b8527e27f6b3b74c6e03e95edb64e6baa4f1b866103f0addb97c84bef1d72487b2e21796 -894bec21a453ae84b592286e696c35bc30e820e9c2fd3e63dd4fbe629e07df16439c891056070faa490155f255bf7187 -a9ec652a491b11f6a692064e955f3f3287e7d2764527e58938571469a1e29b5225b9415bd602a45074dfbfe9c131d6ca -b39d37822e6cbe28244b5f42ce467c65a23765bd16eb6447c5b3e942278069793763483dafd8c4dd864f8917aad357fe -88dba51133f2019cb266641c56101e3e5987d3b77647a2e608b5ff9113dfc5f85e2b7c365118723131fbc0c9ca833c9c -b566579d904b54ecf798018efcb824dccbebfc6753a0fd2128ac3b4bd3b038c2284a7c782b5ca6f310eb7ea4d26a3f0a -a97a55c0a492e53c047e7d6f9d5f3e86fb96f3dddc68389c0561515343b66b4bc02a9c0d5722dff1e3445308240b27f7 -a044028ab4bcb9e1a2b9b4ca4efbf04c5da9e4bf2fff0e8bd57aa1fc12a71e897999c25d9117413faf2f45395dee0f13 -a78dc461decbeaeed8ebd0909369b491a5e764d6a5645a7dac61d3140d7dc0062526f777b0eb866bff27608429ebbdde -b2c2a8991f94c39ca35fea59f01a92cb3393e0eccb2476dfbf57261d406a68bd34a6cff33ed80209991688c183609ef4 -84189eefb521aff730a4fd3fd5b10ddfd29f0d365664caef63bb015d07e689989e54c33c2141dd64427805d37a7e546e -85ac80bd734a52235da288ff042dea9a62e085928954e8eacd2c751013f61904ed110e5b3afe1ab770a7e6485efb7b5e -9183a560393dcb22d0d5063e71182020d0fbabb39e32493eeffeb808df084aa243eb397027f150b55a247d1ed0c8513e -81c940944df7ecc58d3c43c34996852c3c7915ed185d7654627f7af62abae7e0048dd444a6c09961756455000bd96d09 -aa8c34e164019743fd8284b84f06c3b449aae7996e892f419ee55d82ad548cb300fd651de329da0384243954c0ef6a60 -89a7b7bdfc7e300d06a14d463e573d6296d8e66197491900cc9ae49504c4809ff6e61b758579e9091c61085ba1237b83 -878d21809ba540f50bd11f4c4d9590fb6f3ab9de5692606e6e2ef4ed9d18520119e385be5e1f4b3f2e2b09c319f0e8fc -8eb248390193189cf0355365e630b782cd15751e672dc478b39d75dc681234dcd9309df0d11f4610dbb249c1e6be7ef9 -a1d7fb3aecb896df3a52d6bd0943838b13f1bd039c936d76d03de2044c371d48865694b6f532393b27fd10a4cf642061 -a34bca58a24979be442238cbb5ece5bee51ae8c0794dd3efb3983d4db713bc6f28a96e976ac3bd9a551d3ed9ba6b3e22 -817c608fc8cacdd178665320b5a7587ca21df8bdd761833c3018b967575d25e3951cf3d498a63619a3cd2ad4406f5f28 -86c95707db0495689afd0c2e39e97f445f7ca0edffad5c8b4cacd1421f2f3cc55049dfd504f728f91534e20383955582 -99c3b0bb15942c301137765d4e19502f65806f3b126dc01a5b7820c87e8979bce6a37289a8f6a4c1e4637227ad5bf3bf -8aa1518a80ea8b074505a9b3f96829f5d4afa55a30efe7b4de4e5dbf666897fdd2cf31728ca45921e21a78a80f0e0f10 -8d74f46361c79e15128ac399e958a91067ef4cec8983408775a87eca1eed5b7dcbf0ddf30e66f51780457413496c7f07 -a41cde4a786b55387458a1db95171aca4fd146507b81c4da1e6d6e495527c3ec83fc42fad1dfe3d92744084a664fd431 -8c352852c906fae99413a84ad11701f93f292fbf7bd14738814f4c4ceab32db02feb5eb70bc73898b0bc724a39d5d017 -a5993046e8f23b71ba87b7caa7ace2d9023fb48ce4c51838813174880d918e9b4d2b0dc21a2b9c6f612338c31a289df8 -83576d3324bf2d8afbfb6eaecdc5d767c8e22e7d25160414924f0645491df60541948a05e1f4202e612368e78675de8a -b43749b8df4b15bc9a3697e0f1c518e6b04114171739ef1a0c9c65185d8ec18e40e6954d125cbc14ebc652cf41ad3109 -b4eebd5d80a7327a040cafb9ccdb12b2dfe1aa86e6bc6d3ac8a57fadfb95a5b1a7332c66318ff72ba459f525668af056 -9198be7f1d413c5029b0e1c617bcbc082d21abe2c60ec8ce9b54ca1a85d3dba637b72fda39dae0c0ae40d047eab9f55a -8d96a0232832e24d45092653e781e7a9c9520766c3989e67bbe86b3a820c4bf621ea911e7cd5270a4bfea78b618411f6 -8d7160d0ea98161a2d14d46ef01dff72d566c330cd4fabd27654d300e1bc7644c68dc8eabf2a20a59bfe7ba276545f9b -abb60fce29dec7ba37e3056e412e0ec3e05538a1fc0e2c68877378c867605966108bc5742585ab6a405ce0c962b285b6 -8fabffa3ed792f05e414f5839386f6449fd9f7b41a47595c5d71074bd1bb3784cc7a1a7e1ad6b041b455035957e5b2dc -90ff017b4804c2d0533b72461436b10603ab13a55f86fd4ec11b06a70ef8166f958c110519ca1b4cc7beba440729fe2d -b340cfd120f6a4623e3a74cf8c32bfd7cd61a280b59dfd17b15ca8fae4d82f64a6f15fbde4c02f424debc72b7db5fe67 -871311c9c7220c932e738d59f0ecc67a34356d1429fe570ca503d340c9996cb5ee2cd188fad0e3bd16e4c468ec1dbebd -a772470262186e7b94239ba921b29f2412c148d6f97c4412e96d21e55f3be73f992f1ad53c71008f0558ec3f84e2b5a7 -b2a897dcb7ffd6257f3f2947ec966f2077d57d5191a88840b1d4f67effebe8c436641be85524d0a21be734c63ab5965d -a044f6eacc48a4a061fa149500d96b48cbf14853469aa4d045faf3dca973be1bd4b4ce01646d83e2f24f7c486d03205d -981af5dc2daa73f7fa9eae35a93d81eb6edba4a7f673b55d41f6ecd87a37685d31bb40ef4f1c469b3d72f2f18b925a17 -912d2597a07864de9020ac77083eff2f15ceb07600f15755aba61251e8ce3c905a758453b417f04d9c38db040954eb65 -9642b7f6f09394ba5e0805734ef6702c3eddf9eea187ba98c676d5bbaec0e360e3e51dc58433aaa1e2da6060c8659cb7 -8ab3836e0a8ac492d5e707d056310c4c8e0489ca85eb771bff35ba1d658360084e836a6f51bb990f9e3d2d9aeb18fbb5 -879e058e72b73bb1f4642c21ffdb90544b846868139c6511f299aafe59c2d0f0b944dffc7990491b7c4edcd6a9889250 -b9e60b737023f61479a4a8fd253ed0d2a944ea6ba0439bbc0a0d3abf09b0ad1f18d75555e4a50405470ae4990626f390 -b9c2535d362796dcd673640a9fa2ebdaec274e6f8b850b023153b0a7a30fffc87f96e0b72696f647ebe7ab63099a6963 -94aeff145386a087b0e91e68a84a5ede01f978f9dd9fe7bebca78941938469495dc30a96bba9508c0d017873aeea9610 -98b179f8a3d9f0d0a983c30682dd425a2ddc7803be59bd626c623c8951a5179117d1d2a68254c95c9952989877d0ee55 -889ecf5f0ee56938273f74eb3e9ecfb5617f04fb58e83fe4c0e4aef51615cf345bc56f3f61b17f6eed3249d4afd54451 -a0f2b2c39bcea4b50883e2587d16559e246248a66ecb4a4b7d9ab3b51fb39fe98d83765e087eee37a0f86b0ba4144c02 -b2a61e247ed595e8a3830f7973b07079cbda510f28ad8c78c220b26cb6acde4fbb5ee90c14a665f329168ee951b08cf0 -95bd0fcfb42f0d6d8a8e73d7458498a85bcddd2fb132fd7989265648d82ac2707d6d203fac045504977af4f0a2aca4b7 -843e5a537c298666e6cf50fcc044f13506499ef83c802e719ff2c90e85003c132024e04711be7234c04d4b0125512d5d -a46d1797c5959dcd3a5cfc857488f4d96f74277c3d13b98b133620192f79944abcb3a361d939a100187f1b0856eae875 -a1c7786736d6707a48515c38660615fcec67eb8a2598f46657855215f804fd72ab122d17f94fcffad8893f3be658dca7 -b23dc9e610abc7d8bd21d147e22509a0fa49db5be6ea7057b51aae38e31654b3aa044df05b94b718153361371ba2f622 -b00cc8f257d659c22d30e6d641f79166b1e752ea8606f558e4cad6fc01532e8319ea4ee12265ba4140ac45aa4613c004 -ac7019af65221b0cc736287b32d7f1a3561405715ba9a6a122342e04e51637ba911c41573de53e4781f2230fdcb2475f -81a630bc41b3da8b3eb4bf56cba10cd9f93153c3667f009dc332287baeb707d505fb537e6233c8e53d299ec0f013290c -a6b7aea5c545bb76df0f230548539db92bc26642572cb7dd3d5a30edca2b4c386f44fc8466f056b42de2a452b81aff5b -8271624ff736b7b238e43943c81de80a1612207d32036d820c11fc830c737972ccc9c60d3c2359922b06652311e3c994 -8a684106458cb6f4db478170b9ad595d4b54c18bf63b9058f095a2fa1b928c15101472c70c648873d5887880059ed402 -a5cc3c35228122f410184e4326cf61a37637206e589fcd245cb5d0cec91031f8f7586b80503070840fdfd8ce75d3c88b -9443fc631aed8866a7ed220890911057a1f56b0afe0ba15f0a0e295ab97f604b134b1ed9a4245e46ee5f9a93aa74f731 -984b6f7d79835dffde9558c6bb912d992ca1180a2361757bdba4a7b69dc74b056e303adc69fe67414495dd9c2dd91e64 -b15a5c8cba5de080224c274d31c68ed72d2a7126d347796569aef0c4e97ed084afe3da4d4b590b9dda1a07f0c2ff3dfb -991708fe9650a1f9a4e43938b91d45dc68c230e05ee999c95dbff3bf79b1c1b2bb0e7977de454237c355a73b8438b1d9 -b4f7edc7468b176a4a7c0273700c444fa95c726af6697028bed4f77eee887e3400f9c42ee15b782c0ca861c4c3b8c98a -8c60dcc16c51087eb477c13e837031d6c6a3dc2b8bf8cb43c23f48006bc7173151807e866ead2234b460c2de93b31956 -83ad63e9c910d1fc44bc114accfb0d4d333b7ebe032f73f62d25d3e172c029d5e34a1c9d547273bf6c0fead5c8801007 -85de73213cc236f00777560756bdbf2b16841ba4b55902cf2cad9742ecaf5d28209b012ceb41f337456dfeca93010cd7 -a7561f8827ccd75b6686ba5398bb8fc3083351c55a589b18984e186820af7e275af04bcd4c28e1dc11be1e8617a0610b -88c0a4febd4068850557f497ea888035c7fc9f404f6cc7794e7cc8722f048ad2f249e7dc62743e7a339eb7473ad3b0cd -932b22b1d3e6d5a6409c34980d176feb85ada1bf94332ef5c9fc4d42b907dabea608ceef9b5595ef3feee195151f18d8 -a2867bb3f5ab88fbdae3a16c9143ab8a8f4f476a2643c505bb9f37e5b1fd34d216cab2204c9a017a5a67b7ad2dda10e8 -b573d5f38e4e9e8a3a6fd82f0880dc049efa492a946d00283019bf1d5e5516464cf87039e80aef667cb86fdea5075904 -b948f1b5ab755f3f5f36af27d94f503b070696d793b1240c1bdfd2e8e56890d69e6904688b5f8ff5a4bdf5a6abfe195f -917eae95ebc4109a2e99ddd8fec7881d2f7aaa0e25fda44dec7ce37458c2ee832f1829db7d2dcfa4ca0f06381c7fe91d -95751d17ed00a3030bce909333799bb7f4ab641acf585807f355b51d6976dceee410798026a1a004ef4dcdff7ec0f5b8 -b9b7bd266f449a79bbfe075e429613e76c5a42ac61f01c8f0bbbd34669650682efe01ff9dbbc400a1e995616af6aa278 -ac1722d097ce9cd7617161f8ec8c23d68f1fb1c9ca533e2a8b4f78516c2fd8fb38f23f834e2b9a03bb06a9d655693ca9 -a7ad9e96ffd98db2ecdb6340c5d592614f3c159abfd832fe27ee9293519d213a578e6246aae51672ee353e3296858873 -989b8814d5de7937c4acafd000eec2b4cd58ba395d7b25f98cafd021e8efa37029b29ad8303a1f6867923f5852a220eb -a5bfe6282c771bc9e453e964042d44eff4098decacb89aecd3be662ea5b74506e1357ab26f3527110ba377711f3c9f41 -8900a7470b656639721d2abbb7b06af0ac4222ab85a1976386e2a62eb4b88bfb5b72cf7921ddb3cf3a395d7eeb192a2e -95a71b55cd1f35a438cf5e75f8ff11c5ec6a2ebf2e4dba172f50bfad7d6d5dca5de1b1afc541662c81c858f7604c1163 -82b5d62fea8db8d85c5bc3a76d68dedd25794cf14d4a7bc368938ffca9e09f7e598fdad2a5aac614e0e52f8112ae62b9 -997173f07c729202afcde3028fa7f52cefc90fda2d0c8ac2b58154a5073140683e54c49ed1f254481070d119ce0ce02a -aeffb91ccc7a72bbd6ffe0f9b99c9e66e67d59cec2e02440465e9636a613ab3017278cfa72ea8bc4aba9a8dc728cb367 -952743b06e8645894aeb6440fc7a5f62dd3acf96dab70a51e20176762c9751ea5f2ba0b9497ccf0114dc4892dc606031 -874c63baeddc56fbbca2ff6031f8634b745f6e34ea6791d7c439201aee8f08ef5ee75f7778700a647f3b21068513fce6 -85128fec9c750c1071edfb15586435cc2f317e3e9a175bb8a9697bcda1eb9375478cf25d01e7fed113483b28f625122d -85522c9576fd9763e32af8495ae3928ed7116fb70d4378448926bc9790e8a8d08f98cf47648d7da1b6e40d6a210c7924 -97d0f37a13cfb723b848099ca1c14d83e9aaf2f7aeb71829180e664b7968632a08f6a85f557d74b55afe6242f2a36e7c -abaa472d6ad61a5fccd1a57c01aa1bc081253f95abbcba7f73923f1f11c4e79b904263890eeb66926de3e2652f5d1c70 -b3c04945ba727a141e5e8aec2bf9aa3772b64d8fd0e2a2b07f3a91106a95cbcb249adcd074cbe498caf76fffac20d4ef -82c46781a3d730d9931bcabd7434a9171372dde57171b6180e5516d4e68db8b23495c8ac3ab96994c17ddb1cf249b9fb -a202d8b65613c42d01738ccd68ed8c2dbc021631f602d53f751966e04182743ebc8e0747d600b8a8676b1da9ae7f11ab -ae73e7256e9459db04667a899e0d3ea5255211fb486d084e6550b6dd64ca44af6c6b2d59d7aa152de9f96ce9b58d940d -b67d87b176a9722945ec7593777ee461809861c6cfd1b945dde9ee4ff009ca4f19cf88f4bbb5c80c9cbab2fe25b23ac8 -8f0b7a317a076758b0dac79959ee4a06c08b07d0f10538a4b53d3da2eda16e2af26922feb32c090330dc4d969cf69bd3 -90b36bf56adbd8c4b6cb32febc3a8d5f714370c2ac3305c10fa6d168dffb2a026804517215f9a2d4ec8310cdb6bb459b -aa80c19b0682ead69934bf18cf476291a0beddd8ef4ed75975d0a472e2ab5c70f119722a8574ae4973aceb733d312e57 -a3fc9abb12574e5c28dcb51750b4339b794b8e558675eef7d26126edf1de920c35e992333bcbffcbf6a5f5c0d383ce62 -a1573ff23ab972acdcd08818853b111fc757fdd35aa070186d3e11e56b172fb49d840bf297ac0dd222e072fc09f26a81 -98306f2be4caa92c2b4392212d0cbf430b409b19ff7d5b899986613bd0e762c909fc01999aa94be3bd529d67f0113d7f -8c1fc42482a0819074241746d17dc89c0304a2acdae8ed91b5009e9e3e70ff725ba063b4a3e68fdce05b74f5180c545e -a6c6113ebf72d8cf3163b2b8d7f3fa24303b13f55752522c660a98cd834d85d8c79214d900fa649499365e2e7641f77a -ab95eea424f8a2cfd9fb1c78bb724e5b1d71a0d0d1e4217c5d0f98b0d8bbd3f8400a2002abc0a0e4576d1f93f46fefad -823c5a4fd8cf4a75fdc71d5f2dd511b6c0f189b82affeacd2b7cfcad8ad1a5551227dcc9bfdb2e34b2097eaa00efbb51 -b97314dfff36d80c46b53d87a61b0e124dc94018a0bb680c32765b9a2d457f833a7c42bbc90b3b1520c33a182580398d -b17566ee3dcc6bb3b004afe4c0136dfe7dd27df9045ae896dca49fb36987501ae069eb745af81ba3fc19ff037e7b1406 -b0bdc0f55cfd98d331e3a0c4fbb776a131936c3c47c6bffdc3aaf7d8c9fa6803fbc122c2fefbb532e634228687d52174 -aa5d9e60cc9f0598559c28bb9bdd52aa46605ab4ffe3d192ba982398e72cec9a2a44c0d0d938ce69935693cabc0887ea -802b6459d2354fa1d56c592ac1346c428dadea6b6c0a87bf7d309bab55c94e1cf31dd98a7a86bd92a840dd51f218b91b -a526914efdc190381bf1a73dd33f392ecf01350b9d3f4ae96b1b1c3d1d064721c7d6eec5788162c933245a3943f5ee51 -b3b8fcf637d8d6628620a1a99dbe619eabb3e5c7ce930d6efd2197e261bf394b74d4e5c26b96c4b8009c7e523ccfd082 -8f7510c732502a93e095aba744535f3928f893f188adc5b16008385fb9e80f695d0435bfc5b91cdad4537e87e9d2551c -97b90beaa56aa936c3ca45698f79273a68dd3ccd0076eab48d2a4db01782665e63f33c25751c1f2e070f4d1a8525bf96 -b9fb798324b1d1283fdc3e48288e3861a5449b2ab5e884b34ebb8f740225324af86e4711da6b5cc8361c1db15466602f -b6d52b53cea98f1d1d4c9a759c25bf9d8a50b604b144e4912acbdbdc32aab8b9dbb10d64a29aa33a4f502121a6fb481c -9174ffff0f2930fc228f0e539f5cfd82c9368d26b074467f39c07a774367ff6cccb5039ac63f107677d77706cd431680 -a33b6250d4ac9e66ec51c063d1a6a31f253eb29bbaed12a0d67e2eccfffb0f3a52750fbf52a1c2aaba8c7692346426e7 -a97025fd5cbcebe8ef865afc39cd3ea707b89d4e765ec817fd021d6438e02fa51e3544b1fd45470c58007a08efac6edd -b32a78480edd9ff6ba2f1eec4088db5d6ceb2d62d7e59e904ecaef7bb4a2e983a4588e51692b3be76e6ffbc0b5f911a5 -b5ab590ef0bb77191f00495b33d11c53c65a819f7d0c1f9dc4a2caa147a69c77a4fff7366a602d743ee1f395ce934c1e -b3fb0842f9441fb1d0ee0293b6efbc70a8f58d12d6f769b12872db726b19e16f0f65efbc891cf27a28a248b0ef9c7e75 -9372ad12856fefb928ccb0d34e198df99e2f8973b07e9d417a3134d5f69e12e79ff572c4e03ccd65415d70639bc7c73e -aa8d6e83d09ce216bfe2009a6b07d0110d98cf305364d5529c170a23e693aabb768b2016befb5ada8dabdd92b4d012bb -a954a75791eeb0ce41c85200c3763a508ed8214b5945a42c79bfdcfb1ec4f86ad1dd7b2862474a368d4ac31911a2b718 -8e2081cfd1d062fe3ab4dab01f68062bac802795545fede9a188f6c9f802cb5f884e60dbe866710baadbf55dc77c11a4 -a2f06003b9713e7dd5929501ed485436b49d43de80ea5b15170763fd6346badf8da6de8261828913ee0dacd8ff23c0e1 -98eecc34b838e6ffd1931ca65eec27bcdb2fdcb61f33e7e5673a93028c5865e0d1bf6d3bec040c5e96f9bd08089a53a4 -88cc16019741b341060b95498747db4377100d2a5bf0a5f516f7dec71b62bcb6e779de2c269c946d39040e03b3ae12b7 -ad1135ccbc3019d5b2faf59a688eef2500697642be8cfbdf211a1ab59abcc1f24483e50d653b55ff1834675ac7b4978f -a946f05ed9972f71dfde0020bbb086020fa35b482cce8a4cc36dd94355b2d10497d7f2580541bb3e81b71ac8bba3c49f -a83aeed488f9a19d8cfd743aa9aa1982ab3723560b1cd337fc2f91ad82f07afa412b3993afb845f68d47e91ba4869840 -95eebe006bfc316810cb71da919e5d62c2cebb4ac99d8e8ef67be420302320465f8b69873470982de13a7c2e23516be9 -a55f8961295a11e91d1e5deadc0c06c15dacbfc67f04ccba1d069cba89d72aa3b3d64045579c3ea8991b150ac29366ae -b321991d12f6ac07a5de3c492841d1a27b0d3446082fbce93e7e1f9e8d8fe3b45d41253556261c21b70f5e189e1a7a6f -a0b0822f15f652ce7962a4f130104b97bf9529797c13d6bd8e24701c213cc37f18157bd07f3d0f3eae6b7cd1cb40401f -96e2fa4da378aa782cc2d5e6e465fc9e49b5c805ed01d560e9b98abb5c0de8b74a2e7bec3aa5e2887d25cccb12c66f0c -97e4ab610d414f9210ed6f35300285eb3ccff5b0b6a95ed33425100d7725e159708ea78704497624ca0a2dcabce3a2f9 -960a375b17bdb325761e01e88a3ea57026b2393e1d887b34b8fa5d2532928079ce88dc9fd06a728b26d2bb41b12b9032 -8328a1647398e832aadc05bd717487a2b6fcdaa0d4850d2c4da230c6a2ed44c3e78ec4837b6094f3813f1ee99414713f -aa283834ebd18e6c99229ce4b401eda83f01d904f250fedd4e24f1006f8fa0712a6a89a7296a9bf2ce8de30e28d1408e -b29e097f2caadae3e0f0ae3473c072b0cd0206cf6d2e9b22c1a5ad3e07d433e32bd09ed1f4e4276a2da4268633357b7f -9539c5cbba14538b2fe077ecf67694ef240da5249950baaabea0340718b882a966f66d97f08556b08a4320ceb2cc2629 -b4529f25e9b42ae8cf8338d2eface6ba5cd4b4d8da73af502d081388135c654c0b3afb3aa779ffc80b8c4c8f4425dd2b -95be0739c4330619fbe7ee2249c133c91d6c07eab846c18c5d6c85fc21ac5528c5d56dcb0145af68ed0c6a79f68f2ccd -ac0c83ea802227bfc23814a24655c9ff13f729619bcffdb487ccbbf029b8eaee709f8bddb98232ef33cd70e30e45ca47 -b503becb90acc93b1901e939059f93e671900ca52c6f64ae701d11ac891d3a050b505d89324ce267bc43ab8275da6ffe -98e3811b55b1bacb70aa409100abb1b870f67e6d059475d9f278c751b6e1e2e2d6f2e586c81a9fb6597fda06e7923274 -b0b0f61a44053fa6c715dbb0731e35d48dba257d134f851ee1b81fd49a5c51a90ebf5459ec6e489fce25da4f184fbdb1 -b1d2117fe811720bb997c7c93fe9e4260dc50fca8881b245b5e34f724aaf37ed970cdad4e8fcb68e05ac8cf55a274a53 -a10f502051968f14b02895393271776dee7a06db9de14effa0b3471825ba94c3f805302bdddac4d397d08456f620999d -a3dbad2ef060ae0bb7b02eaa4a13594f3f900450faa1854fc09620b01ac94ab896321dfb1157cf2374c27e5718e8026a -b550fdec503195ecb9e079dcdf0cad559d64d3c30818ef369b4907e813e689da316a74ad2422e391b4a8c2a2bef25fc0 -a25ba865e2ac8f28186cea497294c8649a201732ecb4620c4e77b8e887403119910423df061117e5f03fc5ba39042db1 -b3f88174e03fdb443dd6addd01303cf88a4369352520187c739fc5ae6b22fa99629c63c985b4383219dab6acc5f6f532 -97a7503248e31e81b10eb621ba8f5210c537ad11b539c96dfb7cf72b846c7fe81bd7532c5136095652a9618000b7f8d3 -a8bcdc1ce5aa8bfa683a2fc65c1e79de8ff5446695dcb8620f7350c26d2972a23da22889f9e2b1cacb3f688c6a2953dc -8458c111df2a37f5dd91a9bee6c6f4b79f4f161c93fe78075b24a35f9817da8dde71763218d627917a9f1f0c4709c1ed -ac5f061a0541152b876cbc10640f26f1cc923c9d4ae1b6621e4bb3bf2cec59bbf87363a4eb72fb0e5b6d4e1c269b52d5 -a9a25ca87006e8a9203cbb78a93f50a36694aa4aad468b8d80d3feff9194455ca559fcc63838128a0ab75ad78c07c13a -a450b85f5dfffa8b34dfd8bc985f921318efacf8857cf7948f93884ba09fb831482ee90a44224b1a41e859e19b74962f -8ed91e7f92f5c6d7a71708b6132f157ac226ecaf8662af7d7468a4fa25627302efe31e4620ad28719318923e3a59bf82 -ab524165fd4c71b1fd395467a14272bd2b568592deafa039d8492e9ef36c6d3f96927c95c72d410a768dc0b6d1fbbc9b -b662144505aa8432c75ffb8d10318526b6d5777ac7af9ebfad87d9b0866c364f7905a6352743bd8fd79ffd9d5dd4f3e6 -a48f1677550a5cd40663bb3ba8f84caaf8454f332d0ceb1d94dbea52d0412fe69c94997f7749929712fd3995298572f7 -8391cd6e2f6b0c242de1117a612be99776c3dc95cb800b187685ea5bf7e2722275eddb79fd7dfc8be8e389c4524cdf70 -875d3acb9af47833b72900bc0a2448999d638f153c5e97e8a14ec02d0c76f6264353a7e275e1f1a5855daced523d243b -91f1823657d30b59b2f627880a9a9cb530f5aca28a9fd217fe6f2f5133690dfe7ad5a897872e400512db2e788b3f7628 -ad3564332aa56cea84123fc7ca79ea70bb4fef2009fa131cb44e4b15e8613bd11ca1d83b9d9bf456e4b7fee9f2e8b017 -8c530b84001936d5ab366c84c0b105241a26d1fb163669f17c8f2e94776895c2870edf3e1bc8ccd04d5e65531471f695 -932d01fa174fdb0c366f1230cffde2571cc47485f37f23ba5a1825532190cc3b722aeb1f15aed62cf83ccae9403ba713 -88b28c20585aca50d10752e84b901b5c2d58efef5131479fbbe53de7bce2029e1423a494c0298e1497669bd55be97a5d -b914148ca717721144ebb3d3bf3fcea2cd44c30c5f7051b89d8001502f3856fef30ec167174d5b76265b55d70f8716b5 -81d0173821c6ddd2a068d70766d9103d1ee961c475156e0cbd67d54e668a796310474ef698c7ab55abe6f2cf76c14679 -8f28e8d78e2fe7fa66340c53718e0db4b84823c8cfb159c76eac032a62fb53da0a5d7e24ca656cf9d2a890cb2a216542 -8a26360335c73d1ab51cec3166c3cf23b9ea51e44a0ad631b0b0329ef55aaae555420348a544e18d5760969281759b61 -94f326a32ed287545b0515be9e08149eb0a565025074796d72387cc3a237e87979776410d78339e23ef3172ca43b2544 -a785d2961a2fa5e70bffa137858a92c48fe749fee91b02599a252b0cd50d311991a08efd7fa5e96b78d07e6e66ffe746 -94af9030b5ac792dd1ce517eaadcec1482206848bea4e09e55cc7f40fd64d4c2b3e9197027c5636b70d6122c51d2235d -9722869f7d1a3992850fe7be405ec93aa17dc4d35e9e257d2e469f46d2c5a59dbd504056c85ab83d541ad8c13e8bcd54 -b13c4088b61a06e2c03ac9813a75ff1f68ffdfee9df6a8f65095179a475e29cc49119cad2ce05862c3b1ac217f3aace9 -8c64d51774753623666b10ca1b0fe63ae42f82ed6aa26b81dc1d48c86937c5772eb1402624c52a154b86031854e1fb9f -b47e4df18002b7dac3fee945bf9c0503159e1b8aafcce2138818e140753011b6d09ef1b20894e08ba3006b093559061b -93cb5970076522c5a0483693f6a35ffd4ea2aa7aaf3730c4eccd6af6d1bebfc1122fc4c67d53898ae13eb6db647be7e2 -a68873ef80986795ea5ed1a597d1cd99ed978ec25e0abb57fdcc96e89ef0f50aeb779ff46e3dce21dc83ada3157a8498 -8cab67f50949cc8eee6710e27358aea373aae3c92849f8f0b5531c080a6300cdf2c2094fe6fecfef6148de0d28446919 -993e932bcb616dbaa7ad18a4439e0565211d31071ef1b85a0627db74a05d978c60d507695eaeea5c7bd9868a21d06923 -acdadff26e3132d9478a818ef770e9fa0d2b56c6f5f48bd3bd674436ccce9bdfc34db884a73a30c04c5f5e9764cb2218 -a0d3e64c9c71f84c0eef9d7a9cb4fa184224b969db5514d678e93e00f98b41595588ca802643ea225512a4a272f5f534 -91c9140c9e1ba6e330cb08f6b2ce4809cd0d5a0f0516f70032bf30e912b0ed684d07b413b326ab531ee7e5b4668c799b -87bc2ee7a0c21ba8334cd098e35cb703f9af57f35e091b8151b9b63c3a5b0f89bd7701dbd44f644ea475901fa6d9ef08 -9325ccbf64bf5d71b303e31ee85d486298f9802c5e55b2c3d75427097bf8f60fa2ab4fcaffa9b60bf922c3e24fbd4b19 -95d0506e898318f3dc8d28d16dfd9f0038b54798838b3c9be2a2ae3c2bf204eb496166353fc042220b0bd4f6673b9285 -811de529416331fe9c416726d45df9434c29dcd7e949045eb15740f47e97dde8f31489242200e19922cac2a8b7c6fd1f -ade632d04a4c8bbab6ca7df370b2213cb9225023e7973f0e29f4f5e52e8aeaabc65171306bbdd12a67b195dfbb96d48f -88b7f029e079b6ae956042c0ea75d53088c5d0efd750dd018adaeacf46be21bf990897c58578c491f41afd3978d08073 -91f477802de507ffd2be3f4319903119225b277ad24f74eb50f28b66c14d32fae53c7edb8c7590704741af7f7f3e3654 -809838b32bb4f4d0237e98108320d4b079ee16ed80c567e7548bd37e4d7915b1192880f4812ac0e00476d246aec1dbc8 -84183b5fc4a7997a8ae5afedb4d21dce69c480d5966b5cbdafd6dd10d29a9a6377f3b90ce44da0eb8b176ac3af0253bb -8508abbf6d3739a16b9165caf0f95afb3b3ac1b8c38d6d374cf0c91296e2c1809a99772492b539cda184510bce8a0271 -8722054e59bab2062e6419a6e45fc803af77fde912ef2cd23055ad0484963de65a816a2debe1693d93c18218d2b8e81a -8e895f80e485a7c4f56827bf53d34b956281cdc74856c21eb3b51f6288c01cc3d08565a11cc6f3e2604775885490e8c5 -afc92714771b7aa6e60f3aee12efd9c2595e9659797452f0c1e99519f67c8bc3ac567119c1ddfe82a3e961ee9defea9a -818ff0fd9cefd32db87b259e5fa32967201016fc02ef44116cdca3c63ce5e637756f60477a408709928444a8ad69c471 -8251e29af4c61ae806fc5d032347fb332a94d472038149225298389495139ce5678fae739d02dfe53a231598a992e728 -a0ea39574b26643f6f1f48f99f276a8a64b5481989cfb2936f9432a3f8ef5075abfe5c067dc5512143ce8bf933984097 -af67a73911b372bf04e57e21f289fc6c3dfac366c6a01409b6e76fea4769bdb07a6940e52e8d7d3078f235c6d2f632c6 -b5291484ef336024dd2b9b4cf4d3a6b751133a40656d0a0825bcc6d41c21b1c79cb50b0e8f4693f90c29c8f4358641f9 -8bc0d9754d70f2cb9c63f991902165a87c6535a763d5eece43143b5064ae0bcdce7c7a8f398f2c1c29167b2d5a3e6867 -8d7faff53579ec8f6c92f661c399614cc35276971752ce0623270f88be937c414eddcb0997e14724a783905a026c8883 -9310b5f6e675fdf60796f814dbaa5a6e7e9029a61c395761e330d9348a7efab992e4e115c8be3a43d08e90d21290c892 -b5eb4f3eb646038ad2a020f0a42202532d4932e766da82b2c1002bf9c9c2e5336b54c8c0ffcc0e02d19dde2e6a35b6cc -91dabfd30a66710f1f37a891136c9be1e23af4abf8cb751f512a40c022a35f8e0a4fb05b17ec36d4208de02d56f0d53a -b3ded14e82d62ac7a5a036122a62f00ff8308498f3feae57d861babaff5a6628d43f0a0c5fc903f10936bcf4e2758ceb -a88e8348fed2b26acca6784d19ef27c75963450d99651d11a950ea81d4b93acd2c43e0ecce100eaf7e78508263d5baf3 -b1f5bbf7c4756877b87bb42163ac570e08c6667c4528bf68b5976680e19beeff7c5effd17009b0718797077e2955457a -ad2e7b516243f915d4d1415326e98b1a7390ae88897d0b03b66c2d9bd8c3fba283d7e8fe44ed3333296a736454cef6d8 -8f82eae096d5b11f995de6724a9af895f5e1c58d593845ad16ce8fcae8507e0d8e2b2348a0f50a1f66a17fd6fac51a5c -890e4404d0657c6c1ee14e1aac132ecf7a568bb3e04137b85ac0f84f1d333bd94993e8750f88eee033a33fb00f85dcc7 -82ac7d3385e035115f1d39a99fc73e5919de44f5e6424579776d118d711c8120b8e5916372c6f27bed4cc64cac170b6c -85ee16d8901c272cfbbe966e724b7a891c1bd5e68efd5d863043ad8520fc409080af61fd726adc680b3f1186fe0ac8b8 -86dc564c9b545567483b43a38f24c41c6551a49cabeebb58ce86404662a12dbfafd0778d30d26e1c93ce222e547e3898 -a29f5b4522db26d88f5f95f18d459f8feefab02e380c2edb65aa0617a82a3c1a89474727a951cef5f15050bcf7b380fb -a1ce039c8f6cac53352899edb0e3a72c76da143564ad1a44858bd7ee88552e2fe6858d1593bbd74aeee5a6f8034b9b9d -97f10d77983f088286bd7ef3e7fdd8fa275a56bec19919adf33cf939a90c8f2967d2b1b6fc51195cb45ad561202a3ed7 -a25e2772e8c911aaf8712bdac1dd40ee061c84d3d224c466cfaae8e5c99604053f940cde259bd1c3b8b69595781dbfec -b31bb95a0388595149409c48781174c340960d59032ab2b47689911d03c68f77a2273576fbe0c2bf4553e330656058c7 -b8b2e9287ad803fb185a13f0d7456b397d4e3c8ad5078f57f49e8beb2e85f661356a3392dbd7bcf6a900baa5582b86a1 -a3d0893923455eb6e96cc414341cac33d2dbc88fba821ac672708cce131761d85a0e08286663a32828244febfcae6451 -82310cb42f647d99a136014a9f881eb0b9791efd2e01fc1841907ad3fc8a9654d3d1dab6689c3607214b4dc2aca01cee -874022d99c16f60c22de1b094532a0bc6d4de700ad01a31798fac1d5088b9a42ad02bef8a7339af7ed9c0d4f16b186ee -94981369e120265aed40910eebc37eded481e90f4596b8d57c3bec790ab7f929784bd33ddd05b7870aad6c02e869603b -a4f1f50e1e2a73f07095e0dd31cb45154f24968dae967e38962341c1241bcd473102fff1ff668b20c6547e9732d11701 -ae2328f3b0ad79fcda807e69a1b5278145225083f150f67511dafc97e079f860c3392675f1752ae7e864c056e592205b -875d8c971e593ca79552c43d55c8c73b17cd20c81ff2c2fed1eb19b1b91e4a3a83d32df150dbfd5db1092d0aebde1e1f -add2e80aa46aae95da73a11f130f4bda339db028e24c9b11e5316e75ba5e63bc991d2a1da172c7c8e8fee038baae3433 -b46dbe1cb3424002aa7de51e82f600852248e251465c440695d52538d3f36828ff46c90ed77fc1d11534fe3c487df8ef -a5e5045d28b4e83d0055863c30c056628c58d4657e6176fd0536f5933f723d60e851bb726d5bf3c546b8ce4ac4a57ef8 -91fec01e86dd1537e498fff7536ea3ca012058b145f29d9ada49370cd7b7193ac380e116989515df1b94b74a55c45df3 -a7428176d6918cd916a310bdc75483c72de660df48cac4e6e7478eef03205f1827ea55afc0df5d5fa7567d14bbea7fc9 -851d89bef45d9761fe5fdb62972209335193610015e16a675149519f9911373bac0919add226ef118d9f3669cfdf4734 -b74acf5c149d0042021cb2422ea022be4c4f72a77855f42393e71ffd12ebb3eec16bdf16f812159b67b79a9706e7156d -99f35dce64ec99aa595e7894b55ce7b5a435851b396e79036ffb249c28206087db4c85379df666c4d95857db02e21ff9 -b6b9a384f70db9e298415b8ab394ee625dafff04be2886476e59df8d052ca832d11ac68a9b93fba7ab055b7bc36948a4 -898ee4aefa923ffec9e79f2219c7389663eb11eb5b49014e04ed4a336399f6ea1691051d86991f4c46ca65bcd4fdf359 -b0f948217b0d65df7599a0ba4654a5e43c84db477936276e6f11c8981efc6eaf14c90d3650107ed4c09af4cc8ec11137 -aa6286e27ac54f73e63dbf6f41865dd94d24bc0cf732262fcaff67319d162bb43af909f6f8ee27b1971939cfbba08141 -8bca7cdf730cf56c7b2c8a2c4879d61361a6e1dba5a3681a1a16c17a56e168ace0e99cf0d15826a1f5e67e6b8a8a049a -a746d876e8b1ce225fcafca603b099b36504846961526589af977a88c60d31ba2cc56e66a3dec8a77b3f3531bf7524c9 -a11e2e1927e6704cdb8874c75e4f1842cef84d7d43d7a38e339e61dc8ba90e61bbb20dd3c12e0b11d2471d58eed245be -a36395e22bc1d1ba8b0459a235203177737397da5643ce54ded3459d0869ff6d8d89f50c73cb62394bf66a959cde9b90 -8b49f12ba2fdf9aca7e5f81d45c07d47f9302a2655610e7634d1e4bd16048381a45ef2c95a8dd5b0715e4b7cf42273af -91cffa2a17e64eb7f76bccbe4e87280ee1dd244e04a3c9eac12e15d2d04845d876eb24fe2ec6d6d266cce9efb281077f -a6b8afabf65f2dee01788114e33a2f3ce25376fb47a50b74da7c3c25ff1fdc8aa9f41307534abbf48acb6f7466068f69 -8d13db896ccfea403bd6441191995c1a65365cab7d0b97fbe9526da3f45a877bd1f4ef2edef160e8a56838cd1586330e -98c717de9e01bef8842c162a5e757fe8552d53269c84862f4d451e7c656ae6f2ae473767b04290b134773f63be6fdb9d -8c2036ace1920bd13cf018e82848c49eb511fad65fd0ff51f4e4b50cf3bfc294afb63cba682c16f52fb595a98fa84970 -a3520fdff05dbad9e12551b0896922e375f9e5589368bcb2cc303bde252743b74460cb5caf99629325d3620f13adc796 -8d4f83a5bfec05caf5910e0ce538ee9816ee18d0bd44c1d0da2a87715a23cd2733ad4d47552c6dc0eb397687d611dd19 -a7b39a0a6a02823452d376533f39d35029867b3c9a6ad6bca181f18c54132d675613a700f9db2440fb1b4fa13c8bf18a -80bcb114b2544b80f404a200fc36860ed5e1ad31fe551acd4661d09730c452831751baa9b19d7d311600d267086a70bc -90dcce03c6f88fc2b08f2b42771eedde90cc5330fe0336e46c1a7d1b5a6c1641e5fcc4e7b3d5db00bd8afca9ec66ed81 -aec15f40805065c98e2965b1ae12a6c9020cfdb094c2d0549acfc7ea2401a5fb48d3ea7d41133cf37c4e096e7ff53eb9 -80e129b735dba49fa627a615d6c273119acec8e219b2f2c4373a332b5f98d66cbbdd688dfbe72a8f8bfefaccc02c50c1 -a9b596da3bdfe23e6799ece5f7975bf7a1979a75f4f546deeaf8b34dfe3e0d623217cb4cf4ccd504cfa3625b88cd53f1 -abcbbb70b16f6e517c0ab4363ab76b46e4ff58576b5f8340e5c0e8cc0e02621b6e23d742d73b015822a238b17cfd7665 -a046937cc6ea6a2e1adae543353a9fe929c1ae4ad655be1cc051378482cf88b041e28b1e9a577e6ccff2d3570f55e200 -831279437282f315e65a60184ef158f0a3dddc15a648dc552bdc88b3e6fe8288d3cfe9f0031846d81350f5e7874b4b33 -993d7916fa213c6d66e7c4cafafc1eaec9a2a86981f91c31eb8a69c5df076c789cbf498a24c84e0ee77af95b42145026 -823907a3b6719f8d49b3a4b7c181bd9bb29fcf842d7c70660c4f351852a1e197ca46cf5e879b47fa55f616fa2b87ce5e -8d228244e26132b234930ee14c75d88df0943cdb9c276a8faf167d259b7efc1beec2a87c112a6c608ad1600a239e9aae -ab6e55766e5bfb0cf0764ed909a8473ab5047d3388b4f46faeba2d1425c4754c55c6daf6ad4751e634c618b53e549529 -ab0cab6860e55a84c5ad2948a7e0989e2b4b1fd637605634b118361497332df32d9549cb854b2327ca54f2bcb85eed8f -b086b349ae03ef34f4b25a57bcaa5d1b29bd94f9ebf87e22be475adfe475c51a1230c1ebe13506cb72c4186192451658 -8a0b49d8a254ca6d91500f449cbbfbb69bb516c6948ac06808c65595e46773e346f97a5ce0ef7e5a5e0de278af22709c -ac49de11edaaf04302c73c578cc0824bdd165c0d6321be1c421c1950e68e4f3589aa3995448c9699e93c6ebae8803e27 -884f02d841cb5d8f4c60d1402469216b114ab4e93550b5bc1431756e365c4f870a9853449285384a6fa49e12ce6dc654 -b75f3a28fa2cc8d36b49130cb7448a23d73a7311d0185ba803ad55c8219741d451c110f48b786e96c728bc525903a54f -80ae04dbd41f4a35e33f9de413b6ad518af0919e5a30cb0fa1b061b260420780bb674f828d37fd3b52b5a31673cbd803 -b9a8011eb5fcea766907029bf743b45262db3e49d24f84503687e838651ed11cb64c66281e20a0ae9f6aa51acc552263 -90bfdd75e2dc9cf013e22a5d55d2d2b8a754c96103a17524488e01206e67f8b6d52b1be8c4e3d5307d4fe06d0e51f54c -b4af353a19b06203a815ec43e79a88578cc678c46f5a954b85bc5c53b84059dddba731f3d463c23bfd5273885c7c56a4 -aa125e96d4553b64f7140e5453ff5d2330318b69d74d37d283e84c26ad672fa00e3f71e530eb7e28be1e94afb9c4612e -a18e060aee3d49cde2389b10888696436bb7949a79ca7d728be6456a356ea5541b55492b2138da90108bd1ce0e6f5524 -93e55f92bdbccc2de655d14b1526836ea2e52dba65eb3f87823dd458a4cb5079bf22ce6ef625cb6d6bfdd0995ab9a874 -89f5a683526b90c1c3ceebbb8dc824b21cff851ce3531b164f6626e326d98b27d3e1d50982e507d84a99b1e04e86a915 -83d1c38800361633a3f742b1cb2bfc528129496e80232611682ddbe403e92c2ac5373aea0bca93ecb5128b0b2b7a719e -8ecba560ac94905e19ce8d9c7af217bf0a145d8c8bd38e2db82f5e94cc3f2f26f55819176376b51f154b4aab22056059 -a7e2a4a002b60291924850642e703232994acb4cfb90f07c94d1e0ecd2257bb583443283c20fc6017c37e6bfe85b7366 -93ed7316fa50b528f1636fc6507683a672f4f4403e55e94663f91221cc198199595bd02eef43d609f451acc9d9b36a24 -a1220a8ebc5c50ceed76a74bc3b7e0aa77f6884c71b64b67c4310ac29ce5526cb8992d6abc13ef6c8413ce62486a6795 -b2f6eac5c869ad7f4a25161d3347093e2f70e66cd925032747e901189355022fab3038bca4d610d2f68feb7e719c110b -b703fa11a4d511ca01c7462979a94acb40b5d933759199af42670eb48f83df202fa0c943f6ab3b4e1cc54673ea3aab1e -b5422912afbfcb901f84791b04f1ddb3c3fbdc76d961ee2a00c5c320e06d3cc5b5909c3bb805df66c5f10c47a292b13d -ad0934368da823302e1ac08e3ede74b05dfdbfffca203e97ffb0282c226814b65c142e6e15ec1e754518f221f01b30f7 -a1dd302a02e37df15bf2f1147efe0e3c06933a5a767d2d030e1132f5c3ce6b98e216b6145eb39e1e2f74e76a83165b8d -a346aab07564432f802ae44738049a36f7ca4056df2d8f110dbe7fef4a3e047684dea609b2d03dc6bf917c9c2a47608f -b96c5f682a5f5d02123568e50f5d0d186e4b2c4c9b956ec7aabac1b3e4a766d78d19bd111adb5176b898e916e49be2aa -8a96676d56876fc85538db2e806e1cba20fd01aeb9fa3cb43ca6ca94a2c102639f65660db330e5d74a029bb72d6a0b39 -ab0048336bd5c3def1a4064eadd49e66480c1f2abb4df46e03afbd8a3342c2c9d74ee35d79f08f4768c1646681440984 -888427bdf76caec90814c57ee1c3210a97d107dd88f7256f14f883ad0f392334b82be11e36dd8bfec2b37935177c7831 -b622b282becf0094a1916fa658429a5292ba30fb48a4c8066ce1ddcefb71037948262a01c95bab6929ed3a76ba5db9fe -b5b9e005c1f456b6a368a3097634fb455723abe95433a186e8278dceb79d4ca2fbe21f8002e80027b3c531e5bf494629 -a3c6707117a1e48697ed41062897f55d8119403eea6c2ee88f60180f6526f45172664bfee96bf61d6ec0b7fbae6aa058 -b02a9567386a4fbbdb772d8a27057b0be210447348efe6feb935ceec81f361ed2c0c211e54787dc617cdffed6b4a6652 -a9b8364e40ef15c3b5902e5534998997b8493064fa2bea99600def58279bb0f64574c09ba11e9f6f669a8354dd79dc85 -9998a2e553a9aa9a206518fae2bc8b90329ee59ab23005b10972712389f2ec0ee746033c733092ffe43d73d33abbb8ef -843a4b34d9039bf79df96d79f2d15e8d755affb4d83d61872daf540b68c0a3888cf8fc00d5b8b247b38524bcb3b5a856 -84f7128920c1b0bb40eee95701d30e6fc3a83b7bb3709f16d97e72acbb6057004ee7ac8e8f575936ca9dcb7866ab45f7 -918d3e2222e10e05edb34728162a899ad5ada0aaa491aeb7c81572a9c0d506e31d5390e1803a91ff3bd8e2bb15d47f31 -9442d18e2489613a7d47bb1cb803c8d6f3259d088cd079460976d87f7905ee07dea8f371b2537f6e1d792d36d7e42723 -b491976970fe091995b2ed86d629126523ccf3e9daf8145302faca71b5a71a5da92e0e05b62d7139d3efac5c4e367584 -aa628006235dc77c14cef4c04a308d66b07ac92d377df3de1a2e6ecfe3144f2219ad6d7795e671e1cb37a3641910b940 -99d386adaea5d4981d7306feecac9a555b74ffdc218c907c5aa7ac04abaead0ec2a8237300d42a3fbc464673e417ceed -8f78e8b1556f9d739648ea3cab9606f8328b52877fe72f9305545a73b74d49884044ba9c1f1c6db7d9b7c7b7c661caba -8fb357ae49932d0babdf74fc7aa7464a65d3b6a2b3acf4f550b99601d3c0215900cfd67f2b6651ef94cfc323bac79fae -9906f2fa25c0290775aa001fb6198113d53804262454ae8b83ef371b5271bde189c0460a645829cb6c59f9ee3a55ce4d -8f4379b3ebb50e052325b27655ca6a82e6f00b87bf0d2b680d205dd2c7afdc9ff32a9047ae71a1cdf0d0ce6b9474d878 -a85534e88c2bd43c043792eaa75e50914b21741a566635e0e107ae857aed0412035f7576cf04488ade16fd3f35fdbb87 -b4ce93199966d3c23251ca7f28ec5af7efea1763d376b0385352ffb2e0a462ef95c69940950278cf0e3dafd638b7bd36 -b10cb3d0317dd570aa73129f4acf63c256816f007607c19b423fb42f65133ce21f2f517e0afb41a5378cccf893ae14d0 -a9b231c9f739f7f914e5d943ed9bff7eba9e2c333fbd7c34eb1648a362ee01a01af6e2f7c35c9fe962b11152cddf35de -99ff6a899e156732937fb81c0cced80ae13d2d44c40ba99ac183aa246103b31ec084594b1b7feb96da58f4be2dd5c0ed -8748d15d18b75ff2596f50d6a9c4ce82f61ecbcee123a6ceae0e43cab3012a29b6f83cf67b48c22f6f9d757c6caf76b2 -b88ab05e4248b7fb634cf640a4e6a945d13e331237410f7217d3d17e3e384ddd48897e7a91e4516f1b9cbd30f35f238b -8d826deaeeb84a3b2d2c04c2300ca592501f992810582d6ae993e0d52f6283a839dba66c6c72278cff5871802b71173b -b36fed027c2f05a5ef625ca00b0364b930901e9e4420975b111858d0941f60e205546474bb25d6bfa6928d37305ae95f -af2fcfc6b87967567e8b8a13a4ed914478185705724e56ce68fb2df6d1576a0cf34a61e880997a0d35dc2c3276ff7501 -ac351b919cd1fbf106feb8af2c67692bfcddc84762d18cea681cfa7470a5644839caace27efee5f38c87d3df306f4211 -8d6665fb1d4d8d1fa23bd9b8a86e043b8555663519caac214d1e3e3effbc6bee7f2bcf21e645f77de0ced279d69a8a8b -a9fc1c2061756b2a1a169c1b149f212ff7f0d2488acd1c5a0197eba793cffa593fc6d1d1b40718aa75ca3ec77eff10e1 -aff64f0fa009c7a6cf0b8d7a22ddb2c8170c3cb3eec082e60d5aadb00b0040443be8936d728d99581e33c22178c41c87 -82e0b181adc5e3b1c87ff8598447260e839d53debfae941ebea38265575546c3a74a14b4325a030833a62ff6c52d9365 -b7ad43cbb22f6f892c2a1548a41dc120ab1f4e1b8dea0cb6272dd9cb02054c542ecabc582f7e16de709d48f5166cae86 -985e0c61094281532c4afb788ecb2dfcba998e974b5d4257a22040a161883908cdd068fe80f8eb49b8953cfd11acf43a -ae46895c6d67ea6d469b6c9c07b9e5d295d9ae73b22e30da4ba2c973ba83a130d7eef39717ec9d0f36e81d56bf742671 -8600177ea1f7e7ef90514b38b219a37dedfc39cb83297e4c7a5b479817ef56479d48cf6314820960c751183f6edf8b0e -b9208ec1c1d7a1e99b59c62d3e4e61dfb706b0e940d09d3abfc3454c19749083260614d89cfd7e822596c3cdbcc6bb95 -a1e94042c796c2b48bc724352d2e9f3a22291d9a34705993357ddb6adabd76da6fc25dac200a8cb0b5bbd99ecddb7af6 -b29c3adedd0bcad8a930625bc4dfdc3552a9afd5ca6dd9c0d758f978068c7982b50b711aa0eb5b97f2b84ee784637835 -af0632a238bb1f413c7ea8e9b4c3d68f2827bd2e38cd56024391fba6446ac5d19a780d0cfd4a78fe497d537b766a591a -aaf6e7f7d54f8ef5e2e45dd59774ecbeecf8683aa70483b2a75be6a6071b5981bbaf1627512a65d212817acdfab2e428 -8c751496065da2e927cf492aa5ca9013b24f861d5e6c24b30bbf52ec5aaf1905f40f9a28175faef283dd4ed4f2182a09 -8952377d8e80a85cf67d6b45499f3bad5fd452ea7bcd99efc1b066c4720d8e5bff1214cea90fd1f972a7f0baac3d29be -a1946ee543d1a6e21f380453be4d446e4130950c5fc3d075794eb8260f6f52d0a795c1ff91d028a648dc1ce7d9ab6b47 -89f3fefe37af31e0c17533d2ca1ce0884cc1dc97c15cbfab9c331b8debd94781c9396abef4bb2f163d09277a08d6adf0 -a2753f1e6e1a154fb117100a5bd9052137add85961f8158830ac20541ab12227d83887d10acf7fd36dcaf7c2596d8d23 -814955b4198933ee11c3883863b06ff98c7eceb21fc3e09df5f916107827ccf3323141983e74b025f46ae00284c9513b -8cc5c6bb429073bfef47cae7b3bfccb0ffa076514d91a1862c6bda4d581e0df87db53cc6c130bf8a7826304960f5a34e -909f22c1f1cdc87f7be7439c831a73484a49acbf8f23d47087d7cf867c64ef61da3bde85dc57d705682b4c3fc710d36e -8048fee7f276fcd504aed91284f28e73693615e0eb3858fa44bcf79d7285a9001c373b3ef71d9a3054817ba293ebe28c -94400e5cf5d2700ca608c5fe35ce14623f71cc24959f2bc27ca3684092850f76b67fb1f07ca9e5b2ca3062cf8ad17bd4 -81c2ae7d4d1b17f8b6de6a0430acc0d58260993980fe48dc2129c4948269cdc74f9dbfbf9c26b19360823fd913083d48 -8c41fe765128e63f6889d6a979f6a4342300327c8b245a8cfe3ecfbcac1e09c3da30e2a1045b24b78efc6d6d50c8c6ac -a5dd4ae51ae48c8be4b218c312ade226cffce671cf121cb77810f6c0990768d6dd767badecb5c69921d5574d5e8433d3 -b7642e325f4ba97ae2a39c1c9d97b35aafd49d53dba36aed3f3cb0ca816480b3394079f46a48252d46596559c90f4d58 -ae87375b40f35519e7bd4b1b2f73cd0b329b0c2cb9d616629342a71c6c304338445eda069b78ea0fbe44087f3de91e09 -b08918cb6f736855e11d3daca1ddfbdd61c9589b203b5493143227bf48e2c77c2e8c94b0d1aa2fab2226e0eae83f2681 -ac36b84a4ac2ebd4d6591923a449c564e3be8a664c46092c09e875c2998eba16b5d32bfd0882fd3851762868e669f0b1 -a44800a3bb192066fa17a3f29029a23697240467053b5aa49b9839fb9b9b8b12bcdcbfc557f024b61f4f51a9aacdefcb -9064c688fec23441a274cdf2075e5a449caf5c7363cc5e8a5dc9747183d2e00a0c69f2e6b3f6a7057079c46014c93b3b -aa367b021469af9f5b764a79bb3afbe2d87fe1e51862221672d1a66f954b165778b7c27a705e0f93841fab4c8468344d -a1a8bfc593d4ab71f91640bc824de5c1380ab2591cfdafcbc78a14b32de3c0e15f9d1b461d85c504baa3d4232c16bb53 -97df48da1799430f528184d30b6baa90c2a2f88f34cdfb342d715339c5ebd6d019aa693cea7c4993daafc9849063a3aa -abd923831fbb427e06e0dd335253178a9e5791395c84d0ab1433c07c53c1209161097e9582fb8736f8a60bde62d8693e -84cd1a43f1a438b43dc60ffc775f646937c4f6871438163905a3cebf1115f814ccd38a6ccb134130bff226306e412f32 -91426065996b0743c5f689eb3ca68a9f7b9e4d01f6c5a2652b57fa9a03d8dc7cd4bdbdab0ca5a891fee1e97a7f00cf02 -a4bee50249db3df7fd75162b28f04e57c678ba142ce4d3def2bc17bcb29e4670284a45f218dad3969af466c62a903757 -83141ebcc94d4681404e8b67a12a46374fded6df92b506aff3490d875919631408b369823a08b271d006d5b93136f317 -a0ea1c8883d58d5a784da3d8c8a880061adea796d7505c1f903d07c287c5467f71e4563fc0faafbc15b5a5538b0a7559 -89d9d480574f201a87269d26fb114278ed2c446328df431dc3556e3500e80e4cd01fcac196a2459d8646361ebda840df -8bf302978973632dd464bec819bdb91304712a3ec859be071e662040620422c6e75eba6f864f764cffa2799272efec39 -922f666bc0fd58b6d7d815c0ae4f66d193d32fc8382c631037f59eeaeae9a8ca6c72d08e72944cf9e800b8d639094e77 -81ad8714f491cdff7fe4399f2eb20e32650cff2999dd45b9b3d996d54a4aba24cc6c451212e78c9e5550368a1a38fb3f -b58fcf4659d73edb73175bd9139d18254e94c3e32031b5d4b026f2ed37aa19dca17ec2eb54c14340231615277a9d347e -b365ac9c2bfe409b710928c646ea2fb15b28557e0f089d39878e365589b9d1c34baf5566d20bb28b33bb60fa133f6eff -8fcae1d75b53ab470be805f39630d204853ca1629a14158bac2f52632277d77458dec204ff84b7b2d77e641c2045be65 -a03efa6bebe84f4f958a56e2d76b5ba4f95dd9ed7eb479edc7cc5e646c8d4792e5b0dfc66cc86aa4b4afe2f7a4850760 -af1c823930a3638975fb0cc5c59651771b2719119c3cd08404fbd4ce77a74d708cefbe3c56ea08c48f5f10e6907f338f -8260c8299b17898032c761c325ac9cabb4c5b7e735de81eacf244f647a45fb385012f4f8df743128888c29aefcaaad16 -ab2f37a573c82e96a8d46198691cd694dfa860615625f477e41f91b879bc58a745784fccd8ffa13065834ffd150d881d -986c746c9b4249352d8e5c629e8d7d05e716b3c7aab5e529ca969dd1e984a14b5be41528baef4c85d2369a42d7209216 -b25e32da1a8adddf2a6080725818b75bc67240728ad1853d90738485d8924ea1e202df0a3034a60ffae6f965ec55cf63 -a266e627afcebcefea6b6b44cbc50f5c508f7187e87d047b0450871c2a030042c9e376f3ede0afcf9d1952f089582f71 -86c3bbca4c0300606071c0a80dbdec21ce1dd4d8d4309648151c420854032dff1241a1677d1cd5de4e4de4385efda986 -b9a21a1fe2d1f3273a8e4a9185abf2ff86448cc98bfa435e3d68306a2b8b4a6a3ea33a155be3cb62a2170a86f77679a5 -b117b1ea381adce87d8b342cba3a15d492ff2d644afa28f22424cb9cbc820d4f7693dfc1a4d1b3697046c300e1c9b4c8 -9004c425a2e68870d6c69b658c344e3aa3a86a8914ee08d72b2f95c2e2d8a4c7bb0c6e7e271460c0e637cec11117bf8e -86a18aa4783b9ebd9131580c8b17994825f27f4ac427b0929a1e0236907732a1c8139e98112c605488ee95f48bbefbfc -84042243b955286482ab6f0b5df4c2d73571ada00716d2f737ca05a0d2e88c6349e8ee9e67934cfee4a1775dbf7f4800 -92c2153a4733a62e4e1d5b60369f3c26777c7d01cd3c8679212660d572bd3bac9b8a8a64e1f10f7dbf5eaa7579c4e423 -918454b6bb8e44a2afa144695ba8d48ae08d0cdfef4ad078f67709eddf3bb31191e8b006f04e82ea45a54715ef4d5817 -acf0b54f6bf34cf6ed6c2b39cf43194a40d68de6bcf1e4b82c34c15a1343e9ac3737885e1a30b78d01fa3a5125463db8 -a7d60dbe4b6a7b054f7afe9ee5cbbfeca0d05dc619e6041fa2296b549322529faddb8a11e949562309aecefb842ac380 -91ffb53e6d7e5f11159eaf13e783d6dbdfdb1698ed1e6dbf3413c6ea23492bbb9e0932230a9e2caac8fe899a17682795 -b6e8d7be5076ee3565d5765a710c5ecf17921dd3cf555c375d01e958a365ae087d4a88da492a5fb81838b7b92bf01143 -a8c6b763de2d4b2ed42102ef64eccfef31e2fb2a8a2776241c82912fa50fc9f77f175b6d109a97ede331307c016a4b1a -99839f86cb700c297c58bc33e28d46b92931961548deac29ba8df91d3e11721b10ea956c8e16984f9e4acf1298a79b37 -8c2e2c338f25ea5c25756b7131cde0d9a2b35abf5d90781180a00fe4b8e64e62590dc63fe10a57fba3a31c76d784eb01 -9687d7df2f41319ca5469d91978fed0565a5f11f829ebadaa83db92b221755f76c6eacd7700735e75c91e257087512e3 -8795fdfb7ff8439c58b9bf58ed53873d2780d3939b902b9ddaaa4c99447224ced9206c3039a23c2c44bcc461e2bb637f -a803697b744d2d087f4e2307218d48fa88620cf25529db9ce71e2e3bbcc65bac5e8bb9be04777ef7bfb5ed1a5b8e6170 -80f3d3efbbb9346ddd413f0a8e36b269eb5d7ff6809d5525ff9a47c4bcab2c01b70018b117f6fe05253775612ff70c6b -9050e0e45bcc83930d4c505af35e5e4d7ca01cd8681cba92eb55821aececcebe32bb692ebe1a4daac4e7472975671067 -8d206812aac42742dbaf233e0c080b3d1b30943b54b60283515da005de05ea5caa90f91fedcfcba72e922f64d7040189 -a2d44faaeb2eff7915c83f32b13ca6f31a6847b1c1ce114ea240bac3595eded89f09b2313b7915ad882292e2b586d5b4 -961776c8576030c39f214ea6e0a3e8b3d32f023d2600958c098c95c8a4e374deeb2b9dc522adfbd6bda5949bdc09e2a2 -993fa7d8447407af0fbcd9e6d77f815fa5233ab00674efbcf74a1f51c37481445ae291cc7b76db7c178f9cb0e570e0fc -abd5b1c78e05f9d7c8cc99bdaef8b0b6a57f2daf0f02bf492bec48ea4a27a8f1e38b5854da96efff11973326ff980f92 -8f15af4764bc275e6ccb892b3a4362cacb4e175b1526a9a99944e692fe6ccb1b4fc19abf312bb2a089cb1f344d91a779 -a09b27ccd71855512aba1d0c30a79ffbe7f6707a55978f3ced50e674b511a79a446dbc6d7946add421ce111135a460af -94b2f98ce86a9271fbd4153e1fc37de48421fe3490fb3840c00f2d5a4d0ba8810c6a32880b002f6374b59e0a7952518b -8650ac644f93bbcb88a6a0f49fee2663297fd4bc6fd47b6a89b9d8038d32370438ab3a4775ec9b58cb10aea8a95ef7b6 -95e5c2f2e84eed88c6980bbba5a1c0bb375d5a628bff006f7516d45bb7d723da676add4fdd45956f312e7bab0f052644 -b3278a3fa377ac93af7cfc9453f8cb594aae04269bbc99d2e0e45472ff4b6a2f97a26c4c57bf675b9d86f5e77a5d55d1 -b4bcbe6eb666a206e2ea2f877912c1d3b5bdbd08a989fc4490eb06013e1a69ad1ba08bcdac048bf29192312be399077b -a76d70b78c99fffcbf9bb9886eab40f1ea4f99a309710b660b64cbf86057cbcb644d243f6e341711bb7ef0fedf0435a7 -b2093c1ee945dca7ac76ad5aed08eae23af31dd5a77c903fd7b6f051f4ab84425d33a03c3d45bf2907bc93c02d1f3ad8 -904b1f7534e053a265b22d20be859912b9c9ccb303af9a8d6f1d8f6ccdc5c53eb4a45a1762b880d8444d9be0cd55e7f9 -8f664a965d65bc730c9ef1ec7467be984d4b8eb46bd9b0d64e38e48f94e6e55dda19aeac82cbcf4e1473440e64c4ca18 -8bcee65c4cc7a7799353d07b114c718a2aae0cd10a3f22b7eead5185d159dafd64852cb63924bf87627d176228878bce -8c78f2e3675096fef7ebaa898d2615cd50d39ca3d8f02b9bdfb07e67da648ae4be3da64838dffc5935fd72962c4b96c7 -8c40afd3701629421fec1df1aac4e849384ef2e80472c0e28d36cb1327acdf2826f99b357f3d7afdbc58a6347fc40b3c -a197813b1c65a8ea5754ef782522a57d63433ef752215ecda1e7da76b0412ee619f58d904abd2e07e0c097048b6ae1dd -a670542629e4333884ad7410f9ea3bd6f988df4a8f8a424ca74b9add2312586900cf9ae8bd50411f9146e82626b4af56 -a19875cc07ab84e569d98b8b67fb1dbbdfb59093c7b748fae008c8904a6fd931a63ca8d03ab5fea9bc8d263568125a9b -b57e7f68e4eb1bd04aafa917b1db1bdab759a02aa8a9cdb1cba34ba8852b5890f655645c9b4e15d5f19bf37e9f2ffe9f -8abe4e2a4f6462b6c64b3f10e45db2a53c2b0d3c5d5443d3f00a453e193df771eda635b098b6c8604ace3557514027af -8459e4fb378189b22b870a6ef20183deb816cefbf66eca1dc7e86d36a2e011537db893729f500dc154f14ce24633ba47 -930851df4bc7913c0d8c0f7bd3b071a83668987ed7c397d3d042fdc0d9765945a39a3bae83da9c88cb6b686ed8aeeb26 -8078c9e5cd05e1a8c932f8a1d835f61a248b6e7133fcbb3de406bf4ffc0e584f6f9f95062740ba6008d98348886cf76b -addff62bb29430983fe578e3709b0949cdc0d47a13a29bc3f50371a2cb5c822ce53e2448cfaa01bcb6e0aa850d5a380e -9433add687b5a1e12066721789b1db2edf9b6558c3bdc0f452ba33b1da67426abe326e9a34d207bfb1c491c18811bde1 -822beda3389963428cccc4a2918fa9a8a51cf0919640350293af70821967108cded5997adae86b33cb917780b097f1ca -a7a9f52bda45e4148ed56dd176df7bd672e9b5ed18888ccdb405f47920fdb0844355f8565cefb17010b38324edd8315f -b35c3a872e18e607b2555c51f9696a17fa18da1f924d503b163b4ec9fe22ed0c110925275cb6c93ce2d013e88f173d6a -adf34b002b2b26ab84fc1bf94e05bd8616a1d06664799ab149363c56a6e0c807fdc473327d25632416e952ea327fcd95 -ae4a6b9d22a4a3183fac29e2551e1124a8ce4a561a9a2afa9b23032b58d444e6155bb2b48f85c7b6d70393274e230db7 -a2ea3be4fc17e9b7ce3110284038d46a09e88a247b6971167a7878d9dcf36925d613c382b400cfa4f37a3ebea3699897 -8e5863786b641ce3140fbfe37124d7ad3925472e924f814ebfc45959aaf3f61dc554a597610b5defaecc85b59a99b50f -aefde3193d0f700d0f515ab2aaa43e2ef1d7831c4f7859f48e52693d57f97fa9e520090f3ed700e1c966f4b76048e57f -841a50f772956622798e5cd208dc7534d4e39eddee30d8ce133383d66e5f267e389254a0cdae01b770ecd0a9ca421929 -8fbc2bfd28238c7d47d4c03b1b910946c0d94274a199575e5b23242619b1de3497784e646a92aa03e3e24123ae4fcaba -926999579c8eec1cc47d7330112586bdca20b4149c8b2d066f527c8b9f609e61ce27feb69db67eea382649c6905efcf9 -b09f31f305efcc65589adf5d3690a76cf339efd67cd43a4e3ced7b839507466e4be72dd91f04e89e4bbef629d46e68c0 -b917361f6b95f759642638e0b1d2b3a29c3bdef0b94faa30de562e6078c7e2d25976159df3edbacbf43614635c2640b4 -8e7e8a1253bbda0e134d62bfe003a2669d471b47bd2b5cde0ff60d385d8e62279d54022f5ac12053b1e2d3aaa6910b4c -b69671a3c64e0a99d90b0ed108ce1912ff8ed983e4bddd75a370e9babde25ee1f5efb59ec707edddd46793207a8b1fe7 -910b2f4ebd37b7ae94108922b233d0920b4aba0bd94202c70f1314418b548d11d8e9caa91f2cd95aff51b9432d122b7f -82f645c90dfb52d195c1020346287c43a80233d3538954548604d09fbab7421241cde8593dbc4acc4986e0ea39a27dd9 -8fee895f0a140d88104ce442fed3966f58ff9d275e7373483f6b4249d64a25fb5374bbdc6bce6b5ab0270c2847066f83 -84f5bd7aab27b2509397aeb86510dd5ac0a53f2c8f73799bf720f2f87a52277f8d6b0f77f17bc80739c6a7119b7eb062 -9903ceced81099d7e146e661bcf01cbaccab5ba54366b85e2177f07e2d8621e19d9c9c3eee14b9266de6b3f9b6ea75ae -b9c16ea2a07afa32dd6c7c06df0dec39bca2067a9339e45475c98917f47e2320f6f235da353fd5e15b477de97ddc68dd -9820a9bbf8b826bec61ebf886de2c4f404c1ebdc8bab82ee1fea816d9de29127ce1852448ff717a3fe8bbfe9e92012e5 -817224d9359f5da6f2158c2c7bf9165501424f063e67ba9859a07ab72ee2ee62eb00ca6da821cfa19065c3282ca72c74 -94b95c465e6cb00da400558a3c60cfec4b79b27e602ca67cbc91aead08de4b6872d8ea096b0dc06dca4525c8992b8547 -a2b539a5bccd43fa347ba9c15f249b417997c6a38c63517ca38394976baa08e20be384a360969ff54e7e721db536b3e5 -96caf707e34f62811ee8d32ccf28d8d6ec579bc33e424d0473529af5315c456fd026aa910c1fed70c91982d51df7d3ca -8a77b73e890b644c6a142bdbac59b22d6a676f3b63ddafb52d914bb9d395b8bf5aedcbcc90429337df431ebd758a07a6 -8857830a7351025617a08bc44caec28d2fae07ebf5ffc9f01d979ce2a53839a670e61ae2783e138313929129790a51a1 -aa3e420321ed6f0aa326d28d1a10f13facec6f605b6218a6eb9cbc074801f3467bf013a456d1415a5536f12599efa3d3 -824aed0951957b00ea2f3d423e30328a3527bf6714cf9abbae84cf27e58e5c35452ba89ccc011de7c68c75d6e021d8f1 -a2e87cc06bf202e953fb1081933d8b4445527dde20e38ed1a4f440144fd8fa464a2b73e068b140562e9045e0f4bd3144 -ae3b8f06ad97d7ae3a5e5ca839efff3e4824dc238c0c03fc1a8d2fc8aa546cdfd165b784a31bb4dec7c77e9305b99a4b -b30c3e12395b1fb8b776f3ec9f87c70e35763a7b2ddc68f0f60a4982a84017f27c891a98561c830038deb033698ed7fc -874e507757cd1177d0dff0b0c62ce90130324442a33da3b2c8ee09dbca5d543e3ecfe707e9f1361e7c7db641c72794bb -b53012dd10b5e7460b57c092eaa06d6502720df9edbbe3e3f61a9998a272bf5baaac4a5a732ad4efe35d6fac6feca744 -85e6509d711515534d394e6cacbed6c81da710074d16ef3f4950bf2f578d662a494d835674f79c4d6315bced4defc5f0 -b6132b2a34b0905dcadc6119fd215419a7971fe545e52f48b768006944b4a9d7db1a74b149e2951ea48c083b752d0804 -989867da6415036d19b4bacc926ce6f4df7a556f50a1ba5f3c48eea9cefbb1c09da81481c8009331ee83f0859185e164 -960a6c36542876174d3fbc1505413e29f053ed87b8d38fef3af180491c7eff25200b45dd5fe5d4d8e63c7e8c9c00f4c8 -9040b59bd739d9cc2e8f6e894683429e4e876a8106238689ff4c22770ae5fdae1f32d962b30301fa0634ee163b524f35 -af3fcd0a45fe9e8fe256dc7eab242ef7f582dd832d147444483c62787ac820fafc6ca55d639a73f76bfa5e7f5462ab8f -b934c799d0736953a73d91e761767fdb78454355c4b15c680ce08accb57ccf941b13a1236980001f9e6195801cffd692 -8871e8e741157c2c326b22cf09551e78da3c1ec0fc0543136f581f1550f8bab03b0a7b80525c1e99812cdbf3a9698f96 -a8a977f51473a91d178ee8cfa45ffef8d6fd93ab1d6e428f96a3c79816d9c6a93cd70f94d4deda0125fd6816e30f3bea -a7688b3b0a4fc1dd16e8ba6dc758d3cfe1b7cf401c31739484c7fa253cce0967df1b290769bcefc9d23d3e0cb19e6218 -8ae84322662a57c6d729e6ff9d2737698cc2da2daeb1f39e506618750ed23442a6740955f299e4a15dda6db3e534d2c6 -a04a961cdccfa4b7ef83ced17ab221d6a043b2c718a0d6cc8e6f798507a31f10bf70361f70a049bc8058303fa7f96864 -b463e39732a7d9daec8a456fb58e54b30a6e160aa522a18b9a9e836488cce3342bcbb2e1deab0f5e6ec0a8796d77197d -b1434a11c6750f14018a2d3bcf94390e2948f4f187e93bb22070ca3e5393d339dc328cbfc3e48815f51929465ffe7d81 -84ff81d73f3828340623d7e3345553610aa22a5432217ef0ebd193cbf4a24234b190c65ca0873c22d10ea7b63bd1fbed -b6fe2723f0c47757932c2ddde7a4f8434f665612f7b87b4009c2635d56b6e16b200859a8ade49276de0ef27a2b6c970a -9742884ed7cd52b4a4a068a43d3faa02551a424136c85a9313f7cb58ea54c04aa83b0728fd741d1fe39621e931e88f8f -b7d2d65ea4d1ad07a5dee39e40d6c03a61264a56b1585b4d76fc5b2a68d80a93a42a0181d432528582bf08d144c2d6a9 -88c0f66bada89f8a43e5a6ead2915088173d106c76f724f4a97b0f6758aed6ae5c37c373c6b92cdd4aea8f6261f3a374 -81f9c43582cb42db3900747eb49ec94edb2284999a499d1527f03315fd330e5a509afa3bff659853570e9886aab5b28b -821f9d27d6beb416abf9aa5c79afb65a50ed276dbda6060103bc808bcd34426b82da5f23e38e88a55e172f5c294b4d40 -8ba307b9e7cb63a6c4f3851b321aebfdb6af34a5a4c3bd949ff7d96603e59b27ff4dc4970715d35f7758260ff942c9e9 -b142eb6c5f846de33227d0bda61d445a7c33c98f0a8365fe6ab4c1fabdc130849be597ef734305894a424ea715372d08 -a732730ae4512e86a741c8e4c87fee8a05ee840fec0e23b2e037d58dba8dde8d10a9bc5191d34d00598941becbbe467f -adce6f7c30fd221f6b10a0413cc76435c4bb36c2d60bca821e5c67409fe9dbb2f4c36ef85eb3d734695e4be4827e9fd3 -a74f00e0f9b23aff7b2527ce69852f8906dab9d6abe62ecd497498ab21e57542e12af9918d4fd610bb09e10b0929c510 -a593b6b0ef26448ce4eb3ab07e84238fc020b3cb10d542ff4b16d4e2be1bcde3797e45c9cf753b8dc3b0ffdb63984232 -aed3913afccf1aa1ac0eb4980eb8426d0baccebd836d44651fd72af00d09fac488a870223c42aca3ceb39752070405ae -b2c44c66a5ea7fde626548ba4cef8c8710191343d3dadfd3bb653ce715c0e03056a5303a581d47dde66e70ea5a2d2779 -8e5029b2ccf5128a12327b5103f7532db599846e422531869560ceaff392236434d87159f597937dbf4054f810c114f4 -82beed1a2c4477e5eb39fc5b0e773b30cfec77ef2b1bf17eadaf60eb35b6d0dd9d8cf06315c48d3546badb3f21cd0cca -90077bd6cc0e4be5fff08e5d07a5a158d36cebd1d1363125bc4fae0866ffe825b26f933d4ee5427ba5cd0c33c19a7b06 -a7ec0d8f079970e8e34f0ef3a53d3e0e45428ddcef9cc776ead5e542ef06f3c86981644f61c5a637e4faf001fb8c6b3e -ae6d4add6d1a6f90b22792bc9d40723ee6850c27d0b97eefafd5b7fd98e424aa97868b5287cc41b4fbd7023bca6a322c -831aa917533d077da07c01417feaa1408846363ba2b8d22c6116bb858a95801547dd88b7d7fa1d2e3f0a02bdeb2e103d -96511b860b07c8a5ed773f36d4aa9d02fb5e7882753bf56303595bcb57e37ccc60288887eb83bef08c657ec261a021a2 -921d2a3e7e9790f74068623de327443666b634c8443aba80120a45bba450df920b2374d96df1ce3fb1b06dd06f8cf6e3 -aa74451d51fe82b4581ead8e506ec6cd881010f7e7dd51fc388eb9a557db5d3c6721f81c151d08ebd9c2591689fbc13e -a972bfbcf4033d5742d08716c927c442119bdae336bf5dff914523b285ccf31953da2733759aacaa246a9af9f698342c -ad1fcd0cae0e76840194ce4150cb8a56ebed728ec9272035f52a799d480dfc85840a4d52d994a18b6edb31e79be6e8ad -a2c69fe1d36f235215432dad48d75887a44c99dfa0d78149acc74087da215a44bdb5f04e6eef88ff7eff80a5a7decc77 -a94ab2af2b6ee1bc6e0d4e689ca45380d9fbd3c5a65b9bd249d266a4d4c07bf5d5f7ef2ae6000623aee64027892bf8fe -881ec1fc514e926cdc66480ac59e139148ff8a2a7895a49f0dff45910c90cdda97b66441a25f357d6dd2471cddd99bb3 -884e6d3b894a914c8cef946a76d5a0c8351843b2bffa2d1e56c6b5b99c84104381dd1320c451d551c0b966f4086e60f9 -817c6c10ce2677b9fc5223500322e2b880583254d0bb0d247d728f8716f5e05c9ff39f135854342a1afecd9fbdcf7c46 -aaf4a9cb686a14619aa1fc1ac285dd3843ac3dd99f2b2331c711ec87b03491c02f49101046f3c5c538dc9f8dba2a0ac2 -97ecea5ce53ca720b5d845227ae61d70269a2f53540089305c86af35f0898bfd57356e74a8a5e083fa6e1ea70080bd31 -a22d811e1a20a75feac0157c418a4bfe745ccb5d29466ffa854dca03e395b6c3504a734341746b2846d76583a780b32e -940cbaa0d2b2db94ae96b6b9cf2deefbfd059e3e5745de9aec4a25f0991b9721e5cd37ef71c631575d1a0c280b01cd5b -ae33cb4951191258a11044682de861bf8d92d90ce751b354932dd9f3913f542b6a0f8a4dc228b3cd9244ac32c4582832 -a580df5e58c4274fe0f52ac2da1837e32f5c9db92be16c170187db4c358f43e5cfdda7c5911dcc79d77a5764e32325f5 -81798178cb9d8affa424f8d3be67576ba94d108a28ccc01d330c51d5a63ca45bb8ca63a2f569b5c5fe1303cecd2d777f -89975b91b94c25c9c3660e4af4047a8bacf964783010820dbc91ff8281509379cb3b24c25080d5a01174dd9a049118d5 -a7327fcb3710ed3273b048650bde40a32732ef40a7e58cf7f2f400979c177944c8bc54117ba6c80d5d4260801dddab79 -92b475dc8cb5be4b90c482f122a51bcb3b6c70593817e7e2459c28ea54a7845c50272af38119406eaadb9bcb993368d0 -9645173e9ecefc4f2eae8363504f7c0b81d85f8949a9f8a6c01f2d49e0a0764f4eacecf3e94016dd407fc14494fce9f9 -9215fd8983d7de6ae94d35e6698226fc1454977ae58d42d294be9aad13ac821562ad37d5e7ee5cdfe6e87031d45cd197 -810360a1c9b88a9e36f520ab5a1eb8bed93f52deefbe1312a69225c0a08edb10f87cc43b794aced9c74220cefcc57e7d -ad7e810efd61ed4684aeda9ed8bb02fb9ae4b4b63fda8217d37012b94ff1b91c0087043bfa4e376f961fff030c729f3b -8b07c95c6a06db8738d10bb03ec11b89375c08e77f0cab7e672ce70b2685667ca19c7e1c8b092821d31108ea18dfd4c7 -968825d025ded899ff7c57245250535c732836f7565eab1ae23ee7e513201d413c16e1ba3f5166e7ac6cf74de8ceef4f -908243370c5788200703ade8164943ad5f8c458219186432e74dbc9904a701ea307fd9b94976c866e6c58595fd891c4b -959969d16680bc535cdc6339e6186355d0d6c0d53d7bbfb411641b9bf4b770fd5f575beef5deec5c4fa4d192d455c350 -ad177f4f826a961adeac76da40e2d930748effff731756c797eddc4e5aa23c91f070fb69b19221748130b0961e68a6bb -82f8462bcc25448ef7e0739425378e9bb8a05e283ce54aae9dbebaf7a3469f57833c9171672ad43a79778366c72a5e37 -a28fb275b1845706c2814d9638573e9bc32ff552ebaed761fe96fdbce70395891ca41c400ae438369264e31a2713b15f -8a9c613996b5e51dadb587a787253d6081ea446bf5c71096980bf6bd3c4b69905062a8e8a3792de2d2ece3b177a71089 -8d5aefef9f60cb27c1db2c649221204dda48bb9bf8bf48f965741da051340e8e4cab88b9d15c69f3f84f4c854709f48a -93ebf2ca6ad85ab6deace6de1a458706285b31877b1b4d7dcb9d126b63047efaf8c06d580115ec9acee30c8a7212fa55 -b3ee46ce189956ca298057fa8223b7fd1128cf52f39159a58bca03c71dd25161ac13f1472301f72aef3e1993fe1ab269 -a24d7a8d066504fc3f5027ccb13120e2f22896860e02c45b5eba1dbd512d6a17c28f39155ea581619f9d33db43a96f92 -ae9ceacbfe12137db2c1a271e1b34b8f92e4816bad1b3b9b6feecc34df0f8b3b0f7ed0133acdf59c537d43d33fc8d429 -83967e69bf2b361f86361bd705dce0e1ad26df06da6c52b48176fe8dfcbeb03c462c1a4c9e649eff8c654b18c876fdef -9148e6b814a7d779c19c31e33a068e97b597de1f8100513db3c581190513edc4d544801ce3dd2cf6b19e0cd6daedd28a -94ccdafc84920d320ed22de1e754adea072935d3c5f8c2d1378ebe53d140ea29853f056fb3fb1e375846061a038cc9bc -afb43348498c38b0fa5f971b8cdd3a62c844f0eb52bc33daf2f67850af0880fce84ecfb96201b308d9e6168a0d443ae3 -86d5736520a83538d4cd058cc4b4e84213ed00ebd6e7af79ae787adc17a92ba5359e28ba6c91936d967b4b28d24c3070 -b5210c1ff212c5b1e9ef9126e08fe120a41e386bb12c22266f7538c6d69c7fd8774f11c02b81fd4e88f9137b020801fe -b78cfd19f94d24e529d0f52e18ce6185cb238edc6bd43086270fd51dd99f664f43dd4c7d2fe506762fbd859028e13fcf -a6e7220598c554abdcc3fdc587b988617b32c7bb0f82c06205467dbedb58276cc07cae317a190f19d19078773f4c2bbb -b88862809487ee430368dccd85a5d72fa4d163ca4aad15c78800e19c1a95be2192719801e315d86cff7795e0544a77e4 -87ecb13a03921296f8c42ceb252d04716f10e09c93962239fcaa0a7fef93f19ab3f2680bc406170108bc583e9ff2e721 -a810cd473832b6581c36ec4cb403f2849357ba2d0b54df98ef3004b8a530c078032922a81d40158f5fb0043d56477f6e -a247b45dd85ca7fbb718b328f30a03f03c84aef2c583fbdc9fcc9eb8b52b34529e8c8f535505c10598b1b4dac3d7c647 -96ee0b91313c68bac4aa9e065ce9e1d77e51ca4cff31d6a438718c58264dee87674bd97fc5c6b8008be709521e4fd008 -837567ad073e42266951a9a54750919280a2ac835a73c158407c3a2b1904cf0d17b7195a393c71a18ad029cbd9cf79ee -a6a469c44b67ebf02196213e7a63ad0423aab9a6e54acc6fcbdbb915bc043586993454dc3cd9e4be8f27d67c1050879b -8712d380a843b08b7b294f1f06e2f11f4ad6bcc655fdde86a4d8bc739c23916f6fad2b902fe47d6212f03607907e9f0e -920adfb644b534789943cdae1bdd6e42828dda1696a440af2f54e6b97f4f97470a1c6ea9fa6a2705d8f04911d055acd1 -a161c73adf584a0061e963b062f59d90faac65c9b3a936b837a10d817f02fcabfa748824607be45a183dd40f991fe83f -874f4ecd408c76e625ea50bc59c53c2d930ee25baf4b4eca2440bfbffb3b8bc294db579caa7c68629f4d9ec24187c1ba -8bff18087f112be7f4aa654e85c71fef70eee8ae480f61d0383ff6f5ab1a0508f966183bb3fc4d6f29cb7ca234aa50d3 -b03b46a3ca3bc743a173cbc008f92ab1aedd7466b35a6d1ca11e894b9482ea9dc75f8d6db2ddd1add99bfbe7657518b7 -8b4f3691403c3a8ad9e097f02d130769628feddfa8c2b3dfe8cff64e2bed7d6e5d192c1e2ba0ac348b8585e94acd5fa1 -a0d9ca4a212301f97591bf65d5ef2b2664766b427c9dd342e23cb468426e6a56be66b1cb41fea1889ac5d11a8e3c50a5 -8c93ed74188ca23b3df29e5396974b9cc135c91fdefdea6c0df694c8116410e93509559af55533a3776ac11b228d69b1 -82dd331fb3f9e344ebdeeb557769b86a2cc8cc38f6c298d7572a33aea87c261afa9dbd898989139b9fc16bc1e880a099 -a65faedf326bcfd8ef98a51410c78b021d39206704e8291cd1f09e096a66b9b0486be65ff185ca224c45918ac337ddeb -a188b37d363ac072a766fd5d6fa27df07363feff1342217b19e3c37385e42ffde55e4be8355aceaa2f267b6d66b4ac41 -810fa3ba3e96d843e3bafd3f2995727f223d3567c8ba77d684c993ba1773c66551eb5009897c51b3fe9b37196984f5ec -87631537541852da323b4353af45a164f68b304d24c01183bf271782e11687f3fcf528394e1566c2a26cb527b3148e64 -b721cb2b37b3c477a48e3cc0044167d51ff568a5fd2fb606e5aec7a267000f1ddc07d3db919926ae12761a8e017c767c -904dfad4ba2cc1f6e60d1b708438a70b1743b400164cd981f13c064b8328d5973987d4fb9cf894068f29d3deaf624dfb -a70491538893552c20939fae6be2f07bfa84d97e2534a6bbcc0f1729246b831103505e9f60e97a8fa7d2e6c1c2384579 -8726cf1b26b41f443ff7485adcfddc39ace2e62f4d65dd0bb927d933e262b66f1a9b367ded5fbdd6f3b0932553ac1735 -ae8a11cfdf7aa54c08f80cb645e3339187ab3886babe9fae5239ba507bb3dd1c0d161ca474a2df081dcd3d63e8fe445e -92328719e97ce60e56110f30a00ac5d9c7a2baaf5f8d22355d53c1c77941e3a1fec7d1405e6fbf8959665fe2ba7a8cad -8d9d6255b65798d0018a8cccb0b6343efd41dc14ff2058d3eed9451ceaad681e4a0fa6af67b0a04318aa628024e5553d -b70209090055459296006742d946a513f0cba6d83a05249ee8e7a51052b29c0ca9722dc4af5f9816a1b7938a5dac7f79 -aab7b766b9bf91786dfa801fcef6d575dc6f12b77ecc662eb4498f0312e54d0de9ea820e61508fc8aeee5ab5db529349 -a8104b462337748b7f086a135d0c3f87f8e51b7165ca6611264b8fb639d9a2f519926cb311fa2055b5fadf03da70c678 -b0d2460747d5d8b30fc6c6bd0a87cb343ddb05d90a51b465e8f67d499cfc5e3a9e365da05ae233bbee792cdf90ec67d5 -aa55f5bf3815266b4a149f85ed18e451c93de9163575e3ec75dd610381cc0805bb0a4d7c4af5b1f94d10231255436d2c -8d4c6a1944ff94426151909eb5b99cfd92167b967dabe2bf3aa66bb3c26c449c13097de881b2cfc1bf052862c1ef7b03 -8862296162451b9b6b77f03bf32e6df71325e8d7485cf3335d66fd48b74c2a8334c241db8263033724f26269ad95b395 -901aa96deb26cda5d9321190ae6624d357a41729d72ef1abfd71bebf6139af6d690798daba53b7bc5923462115ff748a -96c195ec4992728a1eb38cdde42d89a7bce150db43adbc9e61e279ea839e538deec71326b618dd39c50d589f78fc0614 -b6ff8b8aa0837b99a1a8b46fb37f20ad4aecc6a98381b1308697829a59b8442ffc748637a88cb30c9b1f0f28a926c4f6 -8d807e3dca9e7bef277db1d2cfb372408dd587364e8048b304eff00eacde2c723bfc84be9b98553f83cba5c7b3cba248 -8800c96adb0195c4fc5b24511450dee503c32bf47044f5e2e25bd6651f514d79a2dd9b01cd8c09f3c9d3859338490f57 -89fe366096097e38ec28dd1148887112efa5306cc0c3da09562aafa56f4eb000bf46ff79bf0bdd270cbde6bf0e1c8957 -af409a90c2776e1e7e3760b2042507b8709e943424606e31e791d42f17873a2710797f5baaab4cc4a19998ef648556b0 -8d761863c9b6edbd232d35ab853d944f5c950c2b643f84a1a1327ebb947290800710ff01dcfa26dc8e9828481240e8b1 -90b95e9be1e55c463ed857c4e0617d6dc3674e99b6aa62ed33c8e79d6dfcf7d122f4f4cc2ee3e7c5a49170cb617d2e2e -b3ff381efefabc4db38cc4727432e0301949ae4f16f8d1dea9b4f4de611cf5a36d84290a0bef160dac4e1955e516b3b0 -a8a84564b56a9003adcadb3565dc512239fc79572762cda7b5901a255bc82656bb9c01212ad33d6bef4fbbce18dacc87 -90a081890364b222eef54bf0075417f85e340d2fec8b7375995f598aeb33f26b44143ebf56fca7d8b4ebb36b5747b0eb -ade6ee49e1293224ddf2d8ab7f14bb5be6bc6284f60fd5b3a1e0cf147b73cff57cf19763b8a36c5083badc79c606b103 -b2fa99806dd2fa3de09320b615a2570c416c9bcdb052e592b0aead748bbe407ec9475a3d932ae48b71c2627eb81986a6 -91f3b7b73c8ccc9392542711c45fe6f236057e6efad587d661ad5cb4d6e88265f86b807bb1151736b1009ab74fd7acb4 -8800e2a46af96696dfbdcbf2ca2918b3dcf28ad970170d2d1783b52b8d945a9167d052beeb55f56c126da7ffa7059baa -9862267a1311c385956b977c9aa08548c28d758d7ba82d43dbc3d0a0fd1b7a221d39e8399997fea9014ac509ff510ac4 -b7d24f78886fd3e2d283e18d9ad5a25c1a904e7d9b9104bf47da469d74f34162e27e531380dbbe0a9d051e6ffd51d6e7 -b0f445f9d143e28b9df36b0f2c052da87ee2ca374d9d0fbe2eff66ca6fe5fe0d2c1951b428d58f7314b7e74e45d445ea -b63fc4083eabb8437dafeb6a904120691dcb53ce2938b820bb553da0e1eecd476f72495aacb72600cf9cad18698fd3db -b9ffd8108eaebd582d665f8690fe8bb207fd85185e6dd9f0b355a09bac1bbff26e0fdb172bc0498df025414e88fe2eda -967ed453e1f1a4c5b7b6834cc9f75c13f6889edc0cc91dc445727e9f408487bbf05c337103f61397a10011dfbe25d61d -98ceb673aff36e1987d5521a3984a07079c3c6155974bb8b413e8ae1ce84095fe4f7862fba7aefa14753eb26f2a5805f -85f01d28603a8fdf6ce6a50cb5c44f8a36b95b91302e3f4cd95c108ce8f4d212e73aec1b8d936520d9226802a2bd9136 -88118e9703200ca07910345fbb789e7a8f92bd80bbc79f0a9e040e8767d33df39f6eded403a9b636eabf9101e588482a -90833a51eef1b10ed74e8f9bbd6197e29c5292e469c854eed10b0da663e2bceb92539710b1858bbb21887bd538d28d89 -b513b905ec19191167c6193067b5cfdf5a3d3828375360df1c7e2ced5815437dfd37f0c4c8f009d7fb29ff3c8793f560 -b1b6d405d2d18f9554b8a358cc7e2d78a3b34269737d561992c8de83392ac9a2857be4bf15de5a6c74e0c9d0f31f393c -b828bd3e452b797323b798186607849f85d1fb20c616833c0619360dfd6b3e3aa000fd09dafe4b62d74abc41072ff1a9 -8efde67d0cca56bb2c464731879c9ac46a52e75bac702a63200a5e192b4f81c641f855ca6747752b84fe469cb7113b6c -b2762ba1c89ac3c9a983c242e4d1c2610ff0528585ed5c0dfc8a2c0253551142af9b59f43158e8915a1da7cc26b9df67 -8a3f1157fb820d1497ef6b25cd70b7e16bb8b961b0063ad340d82a79ee76eb2359ca9e15e6d42987ed7f154f5eeaa2da -a75e29f29d38f09c879f971c11beb5368affa084313474a5ecafa2896180b9e47ea1995c2733ec46f421e395a1d9cffe -8e8c3dd3e7196ef0b4996b531ec79e4a1f211db5d5635e48ceb80ff7568b2ff587e845f97ee703bb23a60945ad64314a -8e7f32f4a3e3c584af5e3d406924a0aa34024c42eca74ef6cc2a358fd3c9efaf25f1c03aa1e66bb94b023a2ee2a1cace -ab7dce05d59c10a84feb524fcb62478906b3fa045135b23afbede3bb32e0c678d8ebe59feabccb5c8f3550ea76cae44b -b38bb4b44d827f6fd3bd34e31f9186c59e312dbfadd4a7a88e588da10146a78b1f8716c91ad8b806beb8da65cab80c4c -9490ce9442bbbd05438c7f5c4dea789f74a7e92b1886a730544b55ba377840740a3ae4f2f146ee73f47c9278b0e233bc -83c003fab22a7178eed1a668e0f65d4fe38ef3900044e9ec63070c23f2827d36a1e73e5c2b883ec6a2afe2450171b3b3 -9982f02405978ddc4fca9063ebbdb152f524c84e79398955e66fe51bc7c1660ec1afc3a86ec49f58d7b7dde03505731c -ab337bd83ccdd2322088ffa8d005f450ced6b35790f37ab4534313315ee84312adc25e99cce052863a8bedee991729ed -8312ce4bec94366d88f16127a17419ef64285cd5bf9e5eda010319b48085966ed1252ed2f5a9fd3e0259b91bb65f1827 -a60d5a6327c4041b0c00a1aa2f0af056520f83c9ce9d9ccd03a0bd4d9e6a1511f26a422ea86bd858a1f77438adf07e6c -b84a0a0b030bdad83cf5202aa9afe58c9820e52483ab41f835f8c582c129ee3f34aa096d11c1cd922eda02ea1196a882 -8077d105317f4a8a8f1aadeb05e0722bb55f11abcb490c36c0904401107eb3372875b0ac233144829e734f0c538d8c1d -9202503bd29a6ec198823a1e4e098f9cfe359ed51eb5174d1ca41368821bfeebcbd49debfd02952c41359d1c7c06d2b1 -abc28c155e09365cb77ffead8dc8f602335ef93b2f44e4ef767ce8fc8ef9dd707400f3a722e92776c2e0b40192c06354 -b0f6d1442533ca45c9399e0a63a11f85ff288d242cea6cb3b68c02e77bd7d158047cae2d25b3bcd9606f8f66d9b32855 -b01c3d56a0db84dc94575f4b6ee2de4beca3230e86bed63e2066beb22768b0a8efb08ebaf8ac3dedb5fe46708b084807 -8c8634b0432159f66feaabb165842d1c8ac378f79565b1b90c381aa8450eb4231c3dad11ec9317b9fc2b155c3a771e32 -8e67f623d69ecd430c9ee0888520b6038f13a2b6140525b056dc0951f0cfed2822e62cf11d952a483107c5c5acac4826 -9590bb1cba816dd6acd5ac5fba5142c0a19d53573e422c74005e0bcf34993a8138c83124cad35a3df65879dba6134edd -801cd96cde0749021a253027118d3ea135f3fcdbe895db08a6c145641f95ebd368dd6a1568d995e1d0084146aebe224a -848b5d196427f6fc1f762ee3d36e832b64a76ec1033cfedc8b985dea93932a7892b8ef1035c653fb9dcd9ab2d9a44ac8 -a1017eb83d5c4e2477e7bd2241b2b98c4951a3b391081cae7d75965cadc1acaec755cf350f1f3d29741b0828e36fedea -8d6d2785e30f3c29aad17bd677914a752f831e96d46caf54446d967cb2432be2c849e26f0d193a60bee161ea5c6fe90a -935c0ba4290d4595428e034b5c8001cbd400040d89ab00861108e8f8f4af4258e41f34a7e6b93b04bc253d3b9ffc13bf -aac02257146246998477921cef2e9892228590d323b839f3e64ea893b991b463bc2f47e1e5092ddb47e70b2f5bce7622 -b921fde9412970a5d4c9a908ae8ce65861d06c7679af577cf0ad0d5344c421166986bee471fd6a6cecb7d591f06ec985 -8ef4c37487b139d6756003060600bb6ebac7ea810b9c4364fc978e842f13ac196d1264fbe5af60d76ff6d9203d8e7d3f -94b65e14022b5cf6a9b95f94be5ace2711957c96f4211c3f7bb36206bd39cfbd0ea82186cab5ad0577a23214a5c86e9e -a31c166d2a2ca1d5a75a5920fef7532681f62191a50d8555fdaa63ba4581c3391cc94a536fc09aac89f64eafceec3f90 -919a8cc128de01e9e10f5d83b08b52293fdd41bde2b5ae070f3d95842d4a16e5331cf2f3d61c765570c8022403610fa4 -b23d6f8331eef100152d60483cfa14232a85ee712c8538c9b6417a5a7c5b353c2ac401390c6c215cb101f5cee6b5f43e -ab357160c08a18319510a571eafff154298ce1020de8e1dc6138a09fcb0fcbcdd8359f7e9386bda00b7b9cdea745ffdc -ab55079aea34afa5c0bd1124b9cdfe01f325b402fdfa017301bf87812eaa811ea5798c3aaf818074d420d1c782b10ada -ade616010dc5009e7fc4f8d8b00dc716686a5fa0a7816ad9e503e15839d3b909b69d9dd929b7575376434ffec0d2bea8 -863997b97ed46898a8a014599508fa3079f414b1f4a0c4fdc6d74ae8b444afa350f327f8bfc2a85d27f9e2d049c50135 -8d602ff596334efd4925549ed95f2aa762b0629189f0df6dbb162581657cf3ea6863cd2287b4d9c8ad52813d87fcd235 -b70f68c596dcdeed92ad5c6c348578b26862a51eb5364237b1221e840c47a8702f0fbc56eb520a22c0eed99795d3903e -9628088f8e0853cefadee305a8bf47fa990c50fa96a82511bbe6e5dc81ef4b794e7918a109070f92fc8384d77ace226f -97e26a46e068b605ce96007197ecd943c9a23881862f4797a12a3e96ba2b8d07806ad9e2a0646796b1889c6b7d75188c -b1edf467c068cc163e2d6413cc22b16751e78b3312fe47b7ea82b08a1206d64415b2c8f2a677fa89171e82cc49797150 -a44d15ef18745b251429703e3cab188420e2d974de07251501799b016617f9630643fcd06f895634d8ecdd579e1bf000 -abd126df3917ba48c618ee4dbdf87df506193462f792874439043fa1b844466f6f4e0ff2e42516e63b5b23c0892b2695 -a2a67f57c4aa3c2aa1eeddbfd5009a89c26c2ce8fa3c96a64626aba19514beb125f27df8559506f737de3eae0f1fc18f -a633e0132197e6038197304b296ab171f1d8e0d0f34dcf66fe9146ac385b0239232a8470b9205a4802ab432389f4836d -a914b3a28509a906c3821463b936455d58ff45dcbe158922f9efb2037f2eb0ce8e92532d29b5d5a3fcd0d23fa773f272 -a0e1412ce4505daf1a2e59ce4f0fc0e0023e335b50d2b204422f57cd65744cc7a8ed35d5ef131a42c70b27111d3115b7 -a2339e2f2b6072e88816224fdd612c04d64e7967a492b9f8829db15367f565745325d361fd0607b0def1be384d010d9e -a7309fc41203cb99382e8193a1dcf03ac190a7ce04835304eb7e341d78634e83ea47cb15b885601956736d04cdfcaa01 -81f3ccd6c7f5b39e4e873365f8c37b214e8ab122d04a606fbb7339dc3298c427e922ec7418002561d4106505b5c399ee -92c121cf914ca549130e352eb297872a63200e99b148d88fbc9506ad882bec9d0203d65f280fb5b0ba92e336b7f932e8 -a4b330cf3f064f5b131578626ad7043ce2a433b6f175feb0b52d36134a454ca219373fd30d5e5796410e005b69082e47 -86fe5774112403ad83f9c55d58317eeb17ad8e1176d9f2f69c2afb7ed83bc718ed4e0245ceab4b377f5f062dcd4c00e7 -809d152a7e2654c7fd175b57f7928365a521be92e1ed06c05188a95864ddb25f7cab4c71db7d61bbf4cae46f3a1d96ce -b82d663e55c2a5ada7e169e9b1a87bc1c0177baf1ec1c96559b4cb1c5214ce1ddf2ab8d345014cab6402f3774235cf5a -86580af86df1bd2c385adb8f9a079e925981b7184db66fc5fe5b14cddb82e7d836b06eaeef14924ac529487b23dae111 -b5f5f4c5c94944ecc804df6ab8687d64e27d988cbfeae1ba7394e0f6adbf778c5881ead7cd8082dd7d68542b9bb4ecd5 -a6016916146c2685c46e8fdd24186394e2d5496e77e08c0c6a709d4cd7dfa97f1efcef94922b89196819076a91ad37b5 -b778e7367ded3b6eab53d5fc257f7a87e8faf74a593900f2f517220add2125be3f6142022660d8181df8d164ad9441ce -8581b2d36abe6f553add4d24be761bec1b8efaa2929519114346615380b3c55b59e6ad86990e312f7e234d0203bdf59b -9917e74fd45c3f71a829ff5498a7f6b5599b48c098dda2339bf04352bfc7f368ccf1a407f5835901240e76452ae807d7 -afd196ce6f9335069138fd2e3d133134da253978b4ce373152c0f26affe77a336505787594022e610f8feb722f7cc1fb -a477491a1562e329764645e8f24d8e228e5ef28c9f74c6b5b3abc4b6a562c15ffb0f680d372aed04d9e1bf944dece7be -9767440d58c57d3077319d3a330e5322b9ba16981ec74a5a14d53462eab59ae7fd2b14025bfc63b268862094acb444e6 -80986d921be3513ef69264423f351a61cb48390c1be8673aee0f089076086aaebea7ebe268fd0aa7182695606116f679 -a9554c5c921c07b450ee04e34ec58e054ac1541b26ce2ce5a393367a97348ba0089f53db6660ad76b60278b66fd12e3e -95097e7d2999b3e84bf052c775581cf361325325f4a50192521d8f4693c830bed667d88f482dc1e3f833aa2bd22d2cbf -9014c91d0f85aefd28436b5228c12f6353c055a9326c7efbf5e071e089e2ee7c070fcbc84c5fafc336cbb8fa6fec1ca1 -90f57ba36ee1066b55d37384942d8b57ae00f3cf9a3c1d6a3dfee1d1af42d4b5fa9baeb0cd7e46687d1d6d090ddb931d -8e4b1db12fd760a17214c9e47f1fce6e43c0dbb4589a827a13ac61aaae93759345697bb438a00edab92e0b7b62414683 -8022a959a513cdc0e9c705e0fc04eafd05ff37c867ae0f31f6d01cddd5df86138a426cab2ff0ac8ff03a62e20f7e8f51 -914e9a38829834c7360443b8ed86137e6f936389488eccf05b4b4db7c9425611705076ecb3f27105d24b85c852be7511 -957fb10783e2bd0db1ba66b18e794df710bc3b2b05776be146fa5863c15b1ebdd39747b1a95d9564e1772cdfc4f37b8a -b6307028444daed8ed785ac9d0de76bc3fe23ff2cc7e48102553613bbfb5afe0ebe45e4212a27021c8eb870721e62a1f -8f76143597777d940b15a01b39c5e1b045464d146d9a30a6abe8b5d3907250e6c7f858ff2308f8591e8b0a7b3f3c568a -96163138ac0ce5fd00ae9a289648fd9300a0ca0f63a88481d703ecd281c06a52a3b5178e849e331f9c85ca4ba398f4cc -a63ef47c3e18245b0482596a09f488a716df3cbd0f9e5cfabed0d742843e65db8961c556f45f49762f3a6ac8b627b3ef -8cb595466552e7c4d42909f232d4063e0a663a8ef6f6c9b7ce3a0542b2459cde04e0e54c7623d404acb5b82775ac04f6 -b47fe69960eb45f399368807cff16d941a5a4ebad1f5ec46e3dc8a2e4d598a7e6114d8f0ca791e9720fd786070524e2b -89eb5ff83eea9df490e5beca1a1fbbbbcf7184a37e2c8c91ede7a1e654c81e8cd41eceece4042ea7918a4f4646b67fd6 -a84f5d155ed08b9054eecb15f689ba81e44589e6e7207a99790c598962837ca99ec12344105b16641ca91165672f7153 -a6cc8f25c2d5b2d2f220ec359e6a37a52b95fa6af6e173c65e7cd55299eff4aa9e6d9e6f2769e6459313f1f2aecb0fab -afcde944411f017a9f7979755294981e941cc41f03df5e10522ef7c7505e5f1babdd67b3bf5258e8623150062eb41d9b -8fab39f39c0f40182fcd996ade2012643fe7731808afbc53f9b26900b4d4d1f0f5312d9d40b3df8baa4739970a49c732 -ae193af9726da0ebe7df1f9ee1c4846a5b2a7621403baf8e66c66b60f523e719c30c6b4f897bb14b27d3ff3da8392eeb -8ac5adb82d852eba255764029f42e6da92dcdd0e224d387d1ef94174038db9709ac558d90d7e7c57ad4ce7f89bbfc38c -a2066b3458fdf678ee487a55dd5bfb74fde03b54620cb0e25412a89ee28ad0d685e309a51e3e4694be2fa6f1593a344c -88d031745dd0ae07d61a15b594be5d4b2e2a29e715d081649ad63605e3404b0c3a5353f0fd9fad9c05c18e93ce674fa1 -8283cfb0ef743a043f2b77ecaeba3005e2ca50435585b5dd24777ee6bce12332f85e21b446b536da38508807f0f07563 -b376de22d5f6b0af0b59f7d9764561f4244cf8ffe22890ecd3dcf2ff1832130c9b821e068c9d8773136f4796721e5963 -ae3afc50c764f406353965363840bf28ee85e7064eb9d5f0bb3c31c64ab10f48c853e942ee2c9b51bae59651eaa08c2f -948b204d103917461a01a6c57a88f2d66b476eae5b00be20ec8c747650e864bc8a83aee0aff59cb7584b7a3387e0ee48 -81ab098a082b07f896c5ffd1e4446cb7fb44804cbbf38d125208b233fc82f8ec9a6a8d8dd1c9a1162dc28ffeec0dde50 -a149c6f1312821ced2969268789a3151bdda213451760b397139a028da609c4134ac083169feb0ee423a0acafd10eceb -b0ac9e27a5dadaf523010f730b28f0ebac01f460d3bbbe277dc9d44218abb5686f4fac89ae462682fef9edbba663520a -8d0e0073cca273daaaa61b6fc54bfe5a009bc3e20ae820f6c93ba77b19eca517d457e948a2de5e77678e4241807157cb -ad61d3a2edf7c7533a04964b97499503fd8374ca64286dba80465e68fe932e96749b476f458c6fc57cb1a7ca85764d11 -90eb5e121ae46bc01a30881eaa556f46bd8457a4e80787cf634aab355082de34ac57d7f497446468225f7721e68e2a47 -8cdac557de7c42d1f3780e33dec1b81889f6352279be81c65566cdd4952d4c15d79e656cbd46035ab090b385e90245ef -82b67e61b88b84f4f4d4f65df37b3e3dcf8ec91ea1b5c008fdccd52da643adbe6468a1cfdb999e87d195afe2883a3b46 -8503b467e8f5d6048a4a9b78496c58493a462852cab54a70594ae3fd064cfd0deb4b8f336a262155d9fedcaa67d2f6fd -8db56c5ac763a57b6ce6832930c57117058e3e5a81532b7d19346346205e2ec614eb1a2ee836ef621de50a7bc9b7f040 -ad344699198f3c6e8c0a3470f92aaffc805b76266734414c298e10b5b3797ca53578de7ccb2f458f5e0448203f55282b -80602032c43c9e2a09154cc88b83238343b7a139f566d64cb482d87436b288a98f1ea244fd3bff8da3c398686a900c14 -a6385bd50ecd548cfb37174cdbb89e10025b5cadaf3cff164c95d7aef5a33e3d6a9bf0c681b9e11db9ef54ebeee2a0c1 -abf2d95f4aa34b0581eb9257a0cc8462b2213941a5deb8ba014283293e8b36613951b61261cc67bbd09526a54cbbff76 -a3d5de52f48df72c289ff713e445991f142390798cd42bd9d9dbefaee4af4f5faf09042d126b975cf6b98711c3072553 -8e627302ff3d686cff8872a1b7c2a57b35f45bf2fc9aa42b049d8b4d6996a662b8e7cbac6597f0cb79b0cc4e29fbf133 -8510702e101b39a1efbf4e504e6123540c34b5689645e70d0bac1ecc1baf47d86c05cef6c4317a4e99b4edaeb53f2d00 -aa173f0ecbcc6088f878f8726d317748c81ebf501bba461f163b55d66099b191ec7c55f7702f351a9c8eb42cfa3280e2 -b560a697eafab695bcef1416648a0a664a71e311ecbe5823ae903bd0ed2057b9d7574b9a86d3fe22aa3e6ddce38ea513 -8df6304a3d9cf40100f3f687575419c998cd77e5cc27d579cf4f8e98642de3609af384a0337d145dd7c5635172d26a71 -8105c7f3e4d30a29151849673853b457c1885c186c132d0a98e63096c3774bc9deb956cf957367e633d0913680bda307 -95373fc22c0917c3c2044ac688c4f29a63ed858a45c0d6d2d0fe97afd6f532dcb648670594290c1c89010ecc69259bef -8c2fae9bcadab341f49b55230310df93cac46be42d4caa0d42e45104148a91e527af1b4209c0d972448162aed28fab64 -b05a77baab70683f76209626eaefdda2d36a0b66c780a20142d23c55bd479ddd4ad95b24579384b6cf62c8eb4c92d021 -8e6bc6a7ea2755b4aaa19c1c1dee93811fcde514f03485fdc3252f0ab7f032c315614f6336e57cea25dcfb8fb6084eeb -b656a27d06aade55eadae2ad2a1059198918ea6cc3fd22c0ed881294d34d5ac7b5e4700cc24350e27d76646263b223aa -a296469f24f6f56da92d713afcd4dd606e7da1f79dc4e434593c53695847eefc81c7c446486c4b3b8c8d00c90c166f14 -87a326f57713ac2c9dffeb3af44b9f3c613a8f952676fc46343299122b47ee0f8d792abaa4b5db6451ced5dd153aabd0 -b689e554ba9293b9c1f6344a3c8fcb6951d9f9eac4a2e2df13de021aade7c186be27500e81388e5b8bcab4c80f220a31 -87ae0aa0aa48eac53d1ca5a7b93917de12db9e40ceabf8fdb40884ae771cfdf095411deef7c9f821af0b7070454a2608 -a71ffa7eae8ace94e6c3581d4cb2ad25d48cbd27edc9ec45baa2c8eb932a4773c3272b2ffaf077b40f76942a1f3af7f2 -94c218c91a9b73da6b7a495b3728f3028df8ad9133312fc0c03e8c5253b7ccb83ed14688fd4602e2fd41f29a0bc698bd -ae1e77b90ca33728af07a4c03fb2ef71cd92e2618e7bf8ed4d785ce90097fc4866c29999eb84a6cf1819d75285a03af2 -b7a5945b277dab9993cf761e838b0ac6eaa903d7111fca79f9fde3d4285af7a89bf6634a71909d095d7619d913972c9c -8c43b37be02f39b22029b20aca31bff661abce4471dca88aa3bddefd9c92304a088b2dfc8c4795acc301ca3160656af2 -b32e5d0fba024554bd5fe8a793ebe8003335ddd7f585876df2048dcf759a01285fecb53daae4950ba57f3a282a4d8495 -85ea7fd5e10c7b659df5289b2978b2c89e244f269e061b9a15fcab7983fc1962b63546e82d5731c97ec74b6804be63ef -96b89f39181141a7e32986ac02d7586088c5a9662cec39843f397f3178714d02f929af70630c12cbaba0268f8ba2d4fa -929ab1a2a009b1eb37a2817c89696a06426529ebe3f306c586ab717bd34c35a53eca2d7ddcdef36117872db660024af9 -a696dccf439e9ca41511e16bf3042d7ec0e2f86c099e4fc8879d778a5ea79e33aa7ce96b23dc4332b7ba26859d8e674d -a8fe69a678f9a194b8670a41e941f0460f6e2dbc60470ab4d6ae2679cc9c6ce2c3a39df2303bee486dbfde6844e6b31a -95f58f5c82de2f2a927ca99bf63c9fc02e9030c7e46d0bf6b67fe83a448d0ae1c99541b59caf0e1ccab8326231af09a5 -a57badb2c56ca2c45953bd569caf22968f76ed46b9bac389163d6fe22a715c83d5e94ae8759b0e6e8c2f27bff7748f3f -868726fd49963b24acb5333364dffea147e98f33aa19c7919dc9aca0fd26661cfaded74ede7418a5fadbe7f5ae67b67b -a8d8550dcc64d9f1dd7bcdab236c4122f2b65ea404bb483256d712c7518f08bb028ff8801f1da6aed6cbfc5c7062e33b -97e25a87dae23155809476232178538d4bc05d4ff0882916eb29ae515f2a62bfce73083466cc0010ca956aca200aeacc -b4ea26be3f4bd04aa82d7c4b0913b97bcdf5e88b76c57eb1a336cbd0a3eb29de751e1bc47c0e8258adec3f17426d0c71 -99ee555a4d9b3cf2eb420b2af8e3bc99046880536116d0ce7193464ac40685ef14e0e3c442f604e32f8338cb0ef92558 -8c64efa1da63cd08f319103c5c7a761221080e74227bbc58b8fb35d08aa42078810d7af3e60446cbaff160c319535648 -8d9fd88040076c28420e3395cbdfea402e4077a3808a97b7939d49ecbcf1418fe50a0460e1c1b22ac3f6e7771d65169a -ae3c19882d7a9875d439265a0c7003c8d410367627d21575a864b9cb4918de7dbdb58a364af40c5e045f3df40f95d337 -b4f7bfacab7b2cafe393f1322d6dcc6f21ffe69cd31edc8db18c06f1a2b512c27bd0618091fd207ba8df1808e9d45914 -94f134acd0007c623fb7934bcb65ef853313eb283a889a3ffa79a37a5c8f3665f3d5b4876bc66223610c21dc9b919d37 -aa15f74051171daacdc1f1093d3f8e2d13da2833624b80a934afec86fc02208b8f55d24b7d66076444e7633f46375c6a -a32d6bb47ef9c836d9d2371807bafbbbbb1ae719530c19d6013f1d1f813c49a60e4fa51d83693586cba3a840b23c0404 -b61b3599145ea8680011aa2366dc511a358b7d67672d5b0c5be6db03b0efb8ca5a8294cf220ea7409621f1664e00e631 -859cafc3ee90b7ececa1ed8ef2b2fc17567126ff10ca712d5ffdd16aa411a5a7d8d32c9cab1fbf63e87dce1c6e2f5f53 -a2fef1b0b2874387010e9ae425f3a9676d01a095d017493648bcdf3b31304b087ccddb5cf76abc4e1548b88919663b6b -939e18c73befc1ba2932a65ede34c70e4b91e74cc2129d57ace43ed2b3af2a9cc22a40fbf50d79a63681b6d98852866d -b3b4259d37b1b14aee5b676c9a0dd2d7f679ab95c120cb5f09f9fbf10b0a920cb613655ddb7b9e2ba5af4a221f31303c -997255fe51aaca6e5a9cb3359bcbf25b2bb9e30649bbd53a8a7c556df07e441c4e27328b38934f09c09d9500b5fabf66 -abb91be2a2d860fd662ed4f1c6edeefd4da8dc10e79251cf87f06029906e7f0be9b486462718f0525d5e049472692cb7 -b2398e593bf340a15f7801e1d1fbda69d93f2a32a889ec7c6ae5e8a37567ac3e5227213c1392ee86cfb3b56ec2787839 -8ddf10ccdd72922bed36829a36073a460c2118fc7a56ff9c1ac72581c799b15c762cb56cb78e3d118bb9f6a7e56cb25e -93e6bc0a4708d16387cacd44cf59363b994dc67d7ada7b6d6dbd831c606d975247541b42b2a309f814c1bfe205681fc6 -b93fc35c05998cffda2978e12e75812122831523041f10d52f810d34ff71944979054b04de0117e81ddf5b0b4b3e13c0 -92221631c44d60d68c6bc7b287509f37ee44cbe5fdb6935cee36b58b17c7325098f98f7910d2c3ca5dc885ad1d6dabc7 -a230124424a57fad3b1671f404a94d7c05f4c67b7a8fbacfccea28887b78d7c1ed40b92a58348e4d61328891cd2f6cee -a6a230edb8518a0f49d7231bc3e0bceb5c2ac427f045819f8584ba6f3ae3d63ed107a9a62aad543d7e1fcf1f20605706 -845be1fe94223c7f1f97d74c49d682472585d8f772762baad8a9d341d9c3015534cc83d102113c51a9dea2ab10d8d27b -b44262515e34f2db597c8128c7614d33858740310a49cdbdf9c8677c5343884b42c1292759f55b8b4abc4c86e4728033 -805592e4a3cd07c1844bc23783408310accfdb769cca882ad4d07d608e590a288b7370c2cb327f5336e72b7083a0e30f -95153e8b1140df34ee864f4ca601cb873cdd3efa634af0c4093fbaede36f51b55571ab271e6a133020cd34db8411241f -82878c1285cfa5ea1d32175c9401f3cc99f6bb224d622d3fd98cc7b0a27372f13f7ab463ce3a33ec96f9be38dbe2dfe3 -b7588748f55783077c27fc47d33e20c5c0f5a53fc0ac10194c003aa09b9f055d08ec971effa4b7f760553997a56967b3 -b36b4de6d1883b6951f59cfae381581f9c6352fcfcf1524fccdab1571a20f80441d9152dc6b48bcbbf00371337ca0bd5 -89c5523f2574e1c340a955cbed9c2f7b5fbceb260cb1133160dabb7d41c2f613ec3f6e74bbfab3c4a0a6f0626dbe068f -a52f58cc39f968a9813b1a8ddc4e83f4219e4dd82c7aa1dd083bea7edf967151d635aa9597457f879771759b876774e4 -8300a67c2e2e123f89704abfde095463045dbd97e20d4c1157bab35e9e1d3d18f1f4aaba9cbe6aa2d544e92578eaa1b6 -ac6a7f2918768eb6a43df9d3a8a04f8f72ee52f2e91c064c1c7d75cad1a3e83e5aba9fe55bb94f818099ac91ccf2e961 -8d64a2b0991cf164e29835c8ddef6069993a71ec2a7de8157bbfa2e00f6367be646ed74cbaf524f0e9fe13fb09fa15fd -8b2ffe5a545f9f680b49d0a9797a4a11700a2e2e348c34a7a985fc278f0f12def6e06710f40f9d48e4b7fbb71e072229 -8ab8f71cd337fa19178924e961958653abf7a598e3f022138b55c228440a2bac4176cea3aea393549c03cd38a13eb3fc -8419d28318c19ea4a179b7abb43669fe96347426ef3ac06b158d79c0acf777a09e8e770c2fb10e14b3a0421705990b23 -8bacdac310e1e49660359d0a7a17fe3d334eb820e61ae25e84cb52f863a2f74cbe89c2e9fc3283745d93a99b79132354 -b57ace3fa2b9f6b2db60c0d861ace7d7e657c5d35d992588aeed588c6ce3a80b6f0d49f8a26607f0b17167ab21b675e4 -83e265cde477f2ecc164f49ddc7fb255bb05ff6adc347408353b7336dc3a14fdedc86d5a7fb23f36b8423248a7a67ed1 -a60ada971f9f2d79d436de5d3d045f5ab05308cae3098acaf5521115134b2a40d664828bb89895840db7f7fb499edbc5 -a63eea12efd89b62d3952bf0542a73890b104dd1d7ff360d4755ebfa148fd62de668edac9eeb20507967ea37fb220202 -a0275767a270289adc991cc4571eff205b58ad6d3e93778ddbf95b75146d82517e8921bd0d0564e5b75fa0ccdab8e624 -b9b03fd3bf07201ba3a039176a965d736b4ef7912dd9e9bf69fe1b57c330a6aa170e5521fe8be62505f3af81b41d7806 -a95f640e26fb1106ced1729d6053e41a16e4896acac54992279ff873e5a969aad1dcfa10311e28b8f409ac1dab7f03bb -b144778921742418053cb3c70516c63162c187f00db2062193bb2c14031075dbe055d020cde761b26e8c58d0ea6df2c1 -8432fbb799e0435ef428d4fefc309a05dd589bce74d7a87faf659823e8c9ed51d3e42603d878e80f439a38be4321c2fa -b08ddef14e42d4fd5d8bf39feb7485848f0060d43b51ed5bdda39c05fe154fb111d29719ee61a23c392141358c0cfcff -8ae3c5329a5e025b86b5370e06f5e61177df4bda075856fade20a17bfef79c92f54ed495f310130021ba94fb7c33632b -92b6d3c9444100b4d7391febfc1dddaa224651677c3695c47a289a40d7a96d200b83b64e6d9df51f534564f272a2c6c6 -b432bc2a3f93d28b5e506d68527f1efeb2e2570f6be0794576e2a6ef9138926fdad8dd2eabfa979b79ab7266370e86bc -8bc315eacedbcfc462ece66a29662ca3dcd451f83de5c7626ef8712c196208fb3d8a0faf80b2e80384f0dd9772f61a23 -a72375b797283f0f4266dec188678e2b2c060dfed5880fc6bb0c996b06e91a5343ea2b695adaab0a6fd183b040b46b56 -a43445036fbaa414621918d6a897d3692fdae7b2961d87e2a03741360e45ebb19fcb1703d23f1e15bb1e2babcafc56ac -b9636b2ffe305e63a1a84bd44fb402442b1799bd5272638287aa87ca548649b23ce8ce7f67be077caed6aa2dbc454b78 -99a30bf0921d854c282b83d438a79f615424f28c2f99d26a05201c93d10378ab2cd94a792b571ddae5d4e0c0013f4006 -8648e3c2f93d70b392443be116b48a863e4b75991bab5db656a4ef3c1e7f645e8d536771dfe4e8d1ceda3be8d32978b0 -ab50dc9e6924c1d2e9d2e335b2d679fc7d1a7632e84964d3bac0c9fe57e85aa5906ec2e7b0399d98ddd022e9b19b5904 -ab729328d98d295f8f3272afaf5d8345ff54d58ff9884da14f17ecbdb7371857fdf2f3ef58080054e9874cc919b46224 -83fa5da7592bd451cad3ad7702b4006332b3aae23beab4c4cb887fa6348317d234bf62a359e665b28818e5410c278a09 -8bdbff566ae9d368f114858ef1f009439b3e9f4649f73efa946e678d6c781d52c69af195df0a68170f5f191b2eac286b -91245e59b4425fd4edb2a61d0d47c1ccc83d3ced8180de34887b9655b5dcda033d48cde0bdc3b7de846d246c053a02e8 -a2cb00721e68f1cad8933947456f07144dc69653f96ceed845bd577d599521ba99cdc02421118971d56d7603ed118cbf -af8cd66d303e808b22ec57860dd909ca64c27ec2c60e26ffecfdc1179d8762ffd2739d87b43959496e9fee4108df71df -9954136812dffcd5d3f167a500e7ab339c15cfc9b3398d83f64b0daa3dd5b9a851204f424a3493b4e326d3de81e50a62 -93252254d12511955f1aa464883ad0da793f84d900fea83e1df8bca0f2f4cf5b5f9acbaec06a24160d33f908ab5fea38 -997cb55c26996586ba436a95566bd535e9c22452ca5d2a0ded2bd175376557fa895f9f4def4519241ff386a063f2e526 -a12c78ad451e0ac911260ade2927a768b50cb4125343025d43474e7f465cdc446e9f52a84609c5e7e87ae6c9b3f56cda -a789d4ca55cbba327086563831b34487d63d0980ba8cf55197c016702ed6da9b102b1f0709ce3da3c53ff925793a3d73 -a5d76acbb76741ce85be0e655b99baa04f7f587347947c0a30d27f8a49ae78cce06e1cde770a8b618d3db402be1c0c4b -873c0366668c8faddb0eb7c86f485718d65f8c4734020f1a18efd5fa123d3ea8a990977fe13592cd01d17e60809cb5ff -b659b71fe70f37573ff7c5970cc095a1dc0da3973979778f80a71a347ef25ad5746b2b9608bad4ab9a4a53a4d7df42d7 -a34cbe05888e5e5f024a2db14cb6dcdc401a9cbd13d73d3c37b348f68688f87c24ca790030b8f84fef9e74b4eab5e412 -94ce8010f85875c045b0f014db93ef5ab9f1f6842e9a5743dce9e4cb872c94affd9e77c1f1d1ab8b8660b52345d9acb9 -adefa9b27a62edc0c5b019ddd3ebf45e4de846165256cf6329331def2e088c5232456d3de470fdce3fa758bfdd387512 -a6b83821ba7c1f83cc9e4529cf4903adb93b26108e3d1f20a753070db072ad5a3689643144bdd9c5ea06bb9a7a515cd0 -a3a9ddedc2a1b183eb1d52de26718151744db6050f86f3580790c51d09226bf05f15111691926151ecdbef683baa992c -a64bac89e7686932cdc5670d07f0b50830e69bfb8c93791c87c7ffa4913f8da881a9d8a8ce8c1a9ce5b6079358c54136 -a77b5a63452cb1320b61ab6c7c2ef9cfbcade5fd4727583751fb2bf3ea330b5ca67757ec1f517bf4d503ec924fe32fbd -8746fd8d8eb99639d8cd0ca34c0d9c3230ed5a312aab1d3d925953a17973ee5aeb66e68667e93caf9cb817c868ea8f3d -88a2462a26558fc1fbd6e31aa8abdc706190a17c27fdc4217ffd2297d1b1f3321016e5c4b2384c5454d5717dc732ed03 -b78893a97e93d730c8201af2e0d3b31cb923d38dc594ffa98a714e627c473d42ea82e0c4d2eeb06862ee22a9b2c54588 -920cc8b5f1297cf215a43f6fc843e379146b4229411c44c0231f6749793d40f07b9af7699fd5d21fd69400b97febe027 -a0f0eafce1e098a6b58c7ad8945e297cd93aaf10bc55e32e2e32503f02e59fc1d5776936577d77c0b1162cb93b88518b -98480ba0064e97a2e7a6c4769b4d8c2a322cfc9a3b2ca2e67e9317e2ce04c6e1108169a20bd97692e1cb1f1423b14908 -83dbbb2fda7e287288011764a00b8357753a6a44794cc8245a2275237f11affdc38977214e463ad67aec032f3dfa37e9 -86442fff37598ce2b12015ff19b01bb8a780b40ad353d143a0f30a06f6d23afd5c2b0a1253716c855dbf445cc5dd6865 -b8a4c60c5171189414887847b9ed9501bff4e4c107240f063e2d254820d2906b69ef70406c585918c4d24f1dd052142b -919f33a98e84015b2034b57b5ffe9340220926b2c6e45f86fd79ec879dbe06a148ae68b77b73bf7d01bd638a81165617 -95c13e78d89474a47fbc0664f6f806744b75dede95a479bbf844db4a7f4c3ae410ec721cb6ffcd9fa9c323da5740d5ae -ab7151acc41fffd8ec6e90387700bcd7e1cde291ea669567295bea1b9dd3f1df2e0f31f3588cd1a1c08af8120aca4921 -80e74c5c47414bd6eeef24b6793fb1fa2d8fb397467045fcff887c52476741d5bc4ff8b6d3387cb53ad285485630537f -a296ad23995268276aa351a7764d36df3a5a3cffd7dbeddbcea6b1f77adc112629fdeffa0918b3242b3ccd5e7587e946 -813d2506a28a2b01cb60f49d6bd5e63c9b056aa56946faf2f33bd4f28a8d947569cfead3ae53166fc65285740b210f86 -924b265385e1646287d8c09f6c855b094daaee74b9e64a0dddcf9ad88c6979f8280ba30c8597b911ef58ddb6c67e9fe3 -8d531513c70c2d3566039f7ca47cd2352fd2d55b25675a65250bdb8b06c3843db7b2d29c626eed6391c238fc651cf350 -82b338181b62fdc81ceb558a6843df767b6a6e3ceedc5485664b4ea2f555904b1a45fbb35f6cf5d96f27da10df82a325 -92e62faaedea83a37f314e1d3cb4faaa200178371d917938e59ac35090be1db4b4f4e0edb78b9c991de202efe4f313d8 -99d645e1b642c2dc065bac9aaa0621bc648c9a8351efb6891559c3a41ba737bd155fb32d7731950514e3ecf4d75980e4 -b34a13968b9e414172fb5d5ece9a39cf2eb656128c3f2f6cc7a9f0c69c6bae34f555ecc8f8837dc34b5e470e29055c78 -a2a0bb7f3a0b23a2cbc6585d59f87cd7e56b2bbcb0ae48f828685edd9f7af0f5edb4c8e9718a0aaf6ef04553ba71f3b7 -8e1a94bec053ed378e524b6685152d2b52d428266f2b6eadd4bcb7c4e162ed21ab3e1364879673442ee2162635b7a4d8 -9944adaff14a85eab81c73f38f386701713b52513c4d4b838d58d4ffa1d17260a6d056b02334850ea9a31677c4b078bd -a450067c7eceb0854b3eca3db6cf38669d72cb7143c3a68787833cbca44f02c0be9bfbe082896f8a57debb13deb2afb1 -8be4ad3ac9ef02f7df09254d569939757101ee2eda8586fefcd8c847adc1efe5bdcb963a0cafa17651befaafb376a531 -90f6de91ea50255f148ac435e08cf2ac00c772a466e38155bd7e8acf9197af55662c7b5227f88589b71abe9dcf7ba343 -86e5a24f0748b106dee2d4d54e14a3b0af45a96cbee69cac811a4196403ebbee17fd24946d7e7e1b962ac7f66dbaf610 -afdd96fbcda7aa73bf9eeb2292e036c25753d249caee3b9c013009cc22e10d3ec29e2aa6ddbb21c4e949b0c0bccaa7f4 -b5a4e7436d5473647c002120a2cb436b9b28e27ad4ebdd7c5f122b91597c507d256d0cbd889d65b3a908531936e53053 -b632414c3da704d80ac2f3e5e0e9f18a3637cdc2ebeb613c29300745582427138819c4e7b0bec3099c1b8739dac1807b -a28df1464d3372ce9f37ef1db33cc010f752156afae6f76949d98cd799c0cf225c20228ae86a4da592d65f0cffe3951b -898b93d0a31f7d3f11f253cb7a102db54b669fd150da302d8354d8e02b1739a47cb9bd88015f3baf12b00b879442464e -96fb88d89a12049091070cb0048a381902965e67a8493e3991eaabe5d3b7ff7eecd5c94493a93b174df3d9b2c9511755 -b899cb2176f59a5cfba3e3d346813da7a82b03417cad6342f19cc8f12f28985b03bf031e856a4743fd7ebe16324805b0 -a60e2d31bc48e0c0579db15516718a03b73f5138f15037491f4dae336c904e312eda82d50862f4debd1622bb0e56d866 -979fc8b987b5cef7d4f4b58b53a2c278bd25a5c0ea6f41c715142ea5ff224c707de38451b0ad3aa5e749aa219256650a -b2a75bff18e1a6b9cf2a4079572e41205741979f57e7631654a3c0fcec57c876c6df44733c9da3d863db8dff392b44a3 -b7a0f0e811222c91e3df98ff7f286b750bc3b20d2083966d713a84a2281744199e664879401e77470d44e5a90f3e5181 -82b74ba21c9d147fbc338730e8f1f8a6e7fc847c3110944eb17a48bea5e06eecded84595d485506d15a3e675fd0e5e62 -a7f44eef817d5556f0d1abcf420301217d23c69dd2988f44d91ea1f1a16c322263cbacd0f190b9ba22b0f141b9267b4f -aadb68164ede84fc1cb3334b3194d84ba868d5a88e4c9a27519eef4923bc4abf81aab8114449496c073c2a6a0eb24114 -b5378605fabe9a8c12a5dc55ef2b1de7f51aedb61960735c08767a565793cea1922a603a6983dc25f7cea738d0f7c40d -a97a4a5cd8d51302e5e670aee78fe6b5723f6cc892902bbb4f131e82ca1dfd5de820731e7e3367fb0c4c1922a02196e3 -8bdfeb15c29244d4a28896f2b2cb211243cd6a1984a3f5e3b0ebe5341c419beeab3304b390a009ffb47588018034b0ea -a9af3022727f2aa2fca3b096968e97edad3f08edcbd0dbca107b892ae8f746a9c0485e0d6eb5f267999b23a845923ed0 -8e7594034feef412f055590fbb15b6322dc4c6ab7a4baef4685bd13d71a83f7d682b5781bdfa0d1c659489ce9c2b8000 -84977ca6c865ebee021c58106c1a4ad0c745949ecc5332948002fd09bd9b890524878d0c29da96fd11207621136421fe -8687551a79158e56b2375a271136756313122132a6670fa51f99a1b5c229ed8eea1655a734abae13228b3ebfd2a825dd -a0227d6708979d99edfc10f7d9d3719fd3fc68b0d815a7185b60307e4c9146ad2f9be2b8b4f242e320d4288ceeb9504c -89f75583a16735f9dd8b7782a130437805b34280ccea8dac6ecaee4b83fe96947e7b53598b06fecfffdf57ffc12cc445 -a0056c3353227f6dd9cfc8e3399aa5a8f1d71edf25d3d64c982910f50786b1e395c508d3e3727ac360e3e040c64b5298 -b070e61a6d813626144b312ded1788a6d0c7cec650a762b2f8df6e4743941dd82a2511cd956a3f141fc81e15f4e092da -b4e6db232e028a1f989bb5fc13416711f42d389f63564d60851f009dcffac01acfd54efa307aa6d4c0f932892d4e62b0 -89b5991a67db90024ddd844e5e1a03ef9b943ad54194ae0a97df775dde1addf31561874f4e40fbc37a896630f3bbda58 -ad0e8442cb8c77d891df49cdb9efcf2b0d15ac93ec9be1ad5c3b3cca1f4647b675e79c075335c1f681d56f14dc250d76 -b5d55a6ae65bb34dd8306806cb49b5ccb1c83a282ee47085cf26c4e648e19a52d9c422f65c1cd7e03ca63e926c5e92ea -b749501347e5ec07e13a79f0cb112f1b6534393458b3678a77f02ca89dca973fa7b30e55f0b25d8b92b97f6cb0120056 -94144b4a3ffc5eec6ba35ce9c245c148b39372d19a928e236a60e27d7bc227d18a8cac9983851071935d8ffb64b3a34f -92bb4f9f85bc8c028a3391306603151c6896673135f8a7aefedd27acb322c04ef5dac982fc47b455d6740023e0dd3ea3 -b9633a4a101461a782fc2aa092e9dbe4e2ad00987578f18cd7cf0021a909951d60fe79654eb7897806795f93c8ff4d1c -809f0196753024821b48a016eca5dbb449a7c55750f25981bb7a4b4c0e0846c09b8f6128137905055fc43a3f0deb4a74 -a27dc9cdd1e78737a443570194a03d89285576d3d7f3a3cf15cc55b3013e42635d4723e2e8fe1d0b274428604b630db9 -861f60f0462e04cd84924c36a28163def63e777318d00884ab8cb64c8df1df0bce5900342163edb60449296484a6c5bf -b7bc23fb4e14af4c4704a944253e760adefeca8caee0882b6bbd572c84434042236f39ae07a8f21a560f486b15d82819 -b9a6eb492d6dd448654214bd01d6dc5ff12067a11537ab82023fc16167507ee25eed2c91693912f4155d1c07ed9650b3 -97678af29c68f9a5e213bf0fb85c265303714482cfc4c2c00b4a1e8a76ed08834ee6af52357b143a1ca590fb0265ea5a -8a15b499e9eca5b6cac3070b5409e8296778222018ad8b53a5d1f6b70ad9bb10c68a015d105c941ed657bf3499299e33 -b487fefede2e8091f2c7bfe85770db2edff1db83d4effe7f7d87bff5ab1ace35e9b823a71adfec6737fede8d67b3c467 -8b51b916402aa2c437fce3bcad6dad3be8301a1a7eab9d163085b322ffb6c62abf28637636fe6114573950117fc92898 -b06a2106d031a45a494adec0881cb2f82275dff9dcdd2bc16807e76f3bec28a6734edd3d54f0be8199799a78cd6228ad -af0a185391bbe2315eb97feac98ad6dd2e5d931d012c621abd6e404a31cc188b286fef14871762190acf086482b2b5e2 -8e78ee8206506dd06eb7729e32fceda3bebd8924a64e4d8621c72e36758fda3d0001af42443851d6c0aea58562870b43 -a1ba52a569f0461aaf90b49b92be976c0e73ec4a2c884752ee52ffb62dd137770c985123d405dfb5de70692db454b54a -8d51b692fa1543c51f6b62b9acb8625ed94b746ef96c944ca02859a4133a5629da2e2ce84e111a7af8d9a5b836401c64 -a7a20d45044cf6492e0531d0b8b26ffbae6232fa05a96ed7f06bdb64c2b0f5ca7ec59d5477038096a02579e633c7a3ff -84df867b98c53c1fcd4620fef133ee18849c78d3809d6aca0fb6f50ff993a053a455993f216c42ab6090fa5356b8d564 -a7227c439f14c48e2577d5713c97a5205feb69acb0b449152842e278fa71e8046adfab468089c8b2288af1fc51fa945b -855189b3a105670779997690876dfaa512b4a25a24931a912c2f0f1936971d2882fb4d9f0b3d9daba77eaf660e9d05d5 -b5696bd6706de51c502f40385f87f43040a5abf99df705d6aac74d88c913b8ecf7a99a63d7a37d9bdf3a941b9e432ff5 -ab997beb0d6df9c98d5b49864ef0b41a2a2f407e1687dfd6089959757ba30ed02228940b0e841afe6911990c74d536c4 -b36b65f85546ebfdbe98823d5555144f96b4ab39279facd19c0de3b8919f105ba0315a0784dce4344b1bc62d8bb4a5a3 -b8371f0e4450788720ac5e0f6cd3ecc5413d33895083b2c168d961ec2b5c3de411a4cc0712481cbe8df8c2fa1a7af006 -98325d8026b810a8b7a114171ae59a57e8bbc9848e7c3df992efc523621729fd8c9f52114ce01d7730541a1ada6f1df1 -8d0e76dbd37806259486cd9a31bc8b2306c2b95452dc395546a1042d1d17863ef7a74c636b782e214d3aa0e8d717f94a -a4e15ead76da0214d702c859fb4a8accdcdad75ed08b865842bd203391ec4cba2dcc916455e685f662923b96ee0c023f -8618190972086ebb0c4c1b4a6c94421a13f378bc961cc8267a301de7390c5e73c3333864b3b7696d81148f9d4843fd02 -85369d6cc7342e1aa15b59141517d8db8baaaeb7ab9670f3ba3905353948d575923d283b7e5a05b13a30e7baf1208a86 -87c51ef42233c24a6da901f28c9a075d9ba3c625687c387ad6757b72ca6b5a8885e6902a3082da7281611728b1e45f26 -aa6348a4f71927a3106ad0ea8b02fc8d8c65531e4ab0bd0a17243e66f35afe252e40ab8eef9f13ae55a72566ffdaff5c -96a3bc976e9d03765cc3fee275fa05b4a84c94fed6b767e23ca689394501e96f56f7a97cffddc579a6abff632bf153be -97dbf96c6176379fdb2b888be4e757b2bca54e74124bd068d3fa1dbd82a011bbeb75079da38e0cd22a761fe208ecad9b -b70cf0a1d14089a4129ec4e295313863a59da8c7e26bf74cc0e704ed7f0ee4d7760090d0ddf7728180f1bf2c5ac64955 -882d664714cc0ffe53cbc9bef21f23f3649824f423c4dbad1f893d22c4687ab29583688699efc4d5101aa08b0c3e267a -80ecb7cc963e677ccaddbe3320831dd6ee41209acf4ed41b16dc4817121a3d86a1aac9c4db3d8c08a55d28257088af32 -a25ba667d832b145f9ce18c3f9b1bd00737aa36db020e1b99752c8ef7d27c6c448982bd8d352e1b6df266b8d8358a8d5 -83734841c13dee12759d40bdd209b277e743b0d08cc0dd1e0b7afd2d65bfa640400eefcf6be4a52e463e5b3d885eeac6 -848d16505b04804afc773aebabb51b36fd8aacfbb0e09b36c0d5d57df3c0a3b92f33e7d5ad0a7006ec46ebb91df42b8c -909a8d793f599e33bb9f1dc4792a507a97169c87cd5c087310bc05f30afcd247470b4b56dec59894c0fb1d48d39bb54e -8e558a8559df84a1ba8b244ece667f858095c50bb33a5381e60fcc6ba586b69693566d8819b4246a27287f16846c1dfa -84d6b69729f5aaa000cd710c2352087592cfbdf20d5e1166977e195818e593fa1a50d1e04566be23163a2523dc1612f1 -9536d262b7a42125d89f4f32b407d737ba8d9242acfc99d965913ab3e043dcac9f7072a43708553562cac4cba841df30 -9598548923ca119d6a15fd10861596601dd1dedbcccca97bb208cdc1153cf82991ea8cc17686fbaa867921065265970c -b87f2d4af6d026e4d2836bc3d390a4a18e98a6e386282ce96744603bab74974272e97ac2da281afa21885e2cbb3a8001 -991ece62bf07d1a348dd22191868372904b9f8cf065ae7aa4e44fd24a53faf6d851842e35fb472895963aa1992894918 -a8c53dea4c665b30e51d22ca6bc1bc78aaf172b0a48e64a1d4b93439b053877ec26cb5221c55efd64fa841bbf7d5aff4 -93487ec939ed8e740f15335b58617c3f917f72d07b7a369befd479ae2554d04deb240d4a14394b26192efae4d2f4f35d -a44793ab4035443f8f2968a40e043b4555960193ffa3358d22112093aadfe2c136587e4139ffd46d91ed4107f61ea5e0 -b13fe033da5f0d227c75927d3dacb06dbaf3e1322f9d5c7c009de75cdcba5e308232838785ab69a70f0bedea755e003f -970a29b075faccd0700fe60d1f726bdebf82d2cc8252f4a84543ebd3b16f91be42a75c9719a39c4096139f0f31393d58 -a4c3eb1f7160f8216fc176fb244df53008ff32f2892363d85254002e66e2de21ccfe1f3b1047589abee50f29b9d507e3 -8c552885eab04ba40922a8f0c3c38c96089c95ff1405258d3f1efe8d179e39e1295cbf67677894c607ae986e4e6b1fb0 -b3671746fa7f848c4e2ae6946894defadd815230b906b419143523cc0597bc1d6c0a4c1e09d49b66b4a2c11cde3a4de3 -937a249a95813a5e2ef428e355efd202e15a37d73e56cfb7e57ea9f943f2ce5ca8026f2f1fd25bf164ba89d07077d858 -83646bdf6053a04aa9e2f112499769e5bd5d0d10f2e13db3ca89bd45c0b3b7a2d752b7d137fb3909f9c62b78166c9339 -b4eac4b91e763666696811b7ed45e97fd78310377ebea1674b58a2250973f80492ac35110ed1240cd9bb2d17493d708c -82db43a99bc6573e9d92a3fd6635dbbb249ac66ba53099c3c0c8c8080b121dd8243cd5c6e36ba0a4d2525bae57f5c89c -a64d6a264a681b49d134c655d5fc7756127f1ee7c93d328820f32bca68869f53115c0d27fef35fe71f7bc4fdaed97348 -8739b7a9e2b4bc1831e7f04517771bc7cde683a5e74e052542517f8375a2f64e53e0d5ac925ef722327e7bb195b4d1d9 -8f337cdd29918a2493515ebb5cf702bbe8ecb23b53c6d18920cc22f519e276ca9b991d3313e2d38ae17ae8bdfa4f8b7e -b0edeab9850e193a61f138ef2739fc42ceec98f25e7e8403bfd5fa34a7bc956b9d0898250d18a69fa4625a9b3d6129da -a9920f26fe0a6d51044e623665d998745c9eca5bce12051198b88a77d728c8238f97d4196f26e43b24f8841500b998d0 -86e655d61502b979eeeeb6f9a7e1d0074f936451d0a1b0d2fa4fb3225b439a3770767b649256fe481361f481a8dbc276 -84d3b32fa62096831cc3bf013488a9f3f481dfe293ae209ed19585a03f7db8d961a7a9dd0db82bd7f62d612707575d9c -81c827826ec9346995ffccf62a241e3b2d32f7357acd1b1f8f7a7dbc97022d3eb51b8a1230e23ce0b401d2e535e8cd78 -94a1e40c151191c5b055b21e86f32e69cbc751dcbdf759a48580951834b96a1eed75914c0d19a38aefd21fb6c8d43d0c -ab890222b44bc21b71f7c75e15b6c6e16bb03371acce4f8d4353ff3b8fcd42a14026589c5ed19555a3e15e4d18bfc3a3 -accb0be851e93c6c8cc64724cdb86887eea284194b10e7a43c90528ed97e9ec71ca69c6fac13899530593756dd49eab2 -b630220aa9e1829c233331413ee28c5efe94ea8ea08d0c6bfd781955078b43a4f92915257187d8526873e6c919c6a1de -add389a4d358c585f1274b73f6c3c45b58ef8df11f9d11221f620e241bf3579fba07427b288c0c682885a700cc1fa28d -a9fe6ca8bf2961a3386e8b8dcecc29c0567b5c0b3bcf3b0f9169f88e372b80151af883871fc5229815f94f43a6f5b2b0 -ad839ae003b92b37ea431fa35998b46a0afc3f9c0dd54c3b3bf7a262467b13ff3c323ada1c1ae02ac7716528bdf39e3e -9356d3fd0edcbbb65713c0f2a214394f831b26f792124b08c5f26e7f734b8711a87b7c4623408da6a091c9aef1f6af3c -896b25b083c35ac67f0af3784a6a82435b0e27433d4d74cd6d1eafe11e6827827799490fb1c77c11de25f0d75f14e047 -8bfa019391c9627e8e5f05c213db625f0f1e51ec68816455f876c7e55b8f17a4f13e5aae9e3fb9e1cf920b1402ee2b40 -8ba3a6faa6a860a8f3ce1e884aa8769ceded86380a86520ab177ab83043d380a4f535fe13884346c5e51bee68da6ab41 -a8292d0844084e4e3bb7af92b1989f841a46640288c5b220fecfad063ee94e86e13d3d08038ec2ac82f41c96a3bfe14d -8229bb030b2fc566e11fd33c7eab7a1bb7b49fed872ea1f815004f7398cb03b85ea14e310ec19e1f23e0bdaf60f8f76c -8cfbf869ade3ec551562ff7f63c2745cc3a1f4d4dc853a0cd42dd5f6fe54228f86195ea8fe217643b32e9f513f34a545 -ac52a3c8d3270ddfe1b5630159da9290a5ccf9ccbdef43b58fc0a191a6c03b8a5974cf6e2bbc7bd98d4a40a3581482d7 -ab13decb9e2669e33a7049b8eca3ca327c40dea15ad6e0e7fa63ed506db1d258bc36ac88b35f65cae0984e937eb6575d -b5e748eb1a7a1e274ff0cc56311c198f2c076fe4b7e73e5f80396fe85358549df906584e6bb2c8195b3e2be7736850a5 -b5cb911325d8f963c41f691a60c37831c7d3bbd92736efa33d1f77a22b3fde7f283127256c2f47e197571e6fe0b46149 -8a01dc6ed1b55f26427a014faa347130738b191a06b800e32042a46c13f60b49534520214359d68eb2e170c31e2b8672 -a72fa874866e19b2efb8e069328362bf7921ec375e3bcd6b1619384c3f7ee980f6cf686f3544e9374ff54b4d17a1629c -8db21092f7c5f110fba63650b119e82f4b42a997095d65f08f8237b02dd66fdf959f788df2c35124db1dbd330a235671 -8c65d50433d9954fe28a09fa7ba91a70a590fe7ba6b3060f5e4be0f6cef860b9897fa935fb4ebc42133524eb071dd169 -b4614058e8fa21138fc5e4592623e78b8982ed72aa35ee4391b164f00c68d277fa9f9eba2eeefc890b4e86eba5124591 -ab2ad3a1bce2fbd55ca6b7c23786171fe1440a97d99d6df4d80d07dd56ac2d7203c294b32fc9e10a6c259381a73f24a1 -812ae3315fdc18774a8da3713a4679e8ed10b9405edc548c00cacbe25a587d32040566676f135e4723c5dc25df5a22e9 -a464b75f95d01e5655b54730334f443c8ff27c3cb79ec7af4b2f9da3c2039c609908cd128572e1fd0552eb597e8cef8d -a0db3172e93ca5138fe419e1c49a1925140999f6eff7c593e5681951ee0ec1c7e454c851782cbd2b8c9bc90d466e90e0 -806db23ba7d00b87d544eed926b3443f5f9c60da6b41b1c489fba8f73593b6e3b46ebfcab671ee009396cd77d5e68aa1 -8bfdf2c0044cc80260994e1c0374588b6653947b178e8b312be5c2a05e05767e98ea15077278506aee7df4fee1aaf89e -827f6558c16841b5592ff089c9c31e31eb03097623524394813a2e4093ad2d3f8f845504e2af92195aaa8a1679d8d692 -925c4f8eab2531135cd71a4ec88e7035b5eea34ba9d799c5898856080256b4a15ed1a746e002552e2a86c9c157e22e83 -a9f9a368f0e0b24d00a35b325964c85b69533013f9c2cfad9708be5fb87ff455210f8cb8d2ce3ba58ca3f27495552899 -8ac0d3bebc1cae534024187e7c71f8927ba8fcc6a1926cb61c2b6c8f26bb7831019e635a376146c29872a506784a4aaa -97c577be2cbbfdb37ad754fae9df2ada5fc5889869efc7e18a13f8e502fbf3f4067a509efbd46fd990ab47ce9a70f5a8 -935e7d82bca19f16614aa43b4a3474e4d20d064e4bfdf1cea2909e5c9ab72cfe3e54dc50030e41ee84f3588cebc524e9 -941aafc08f7c0d94cebfbb1f0aad5202c02e6e37f2c12614f57e727efa275f3926348f567107ee6d8914dd71e6060271 -af0fbc1ba05b4b5b63399686df3619968be5d40073de0313cbf5f913d3d4b518d4c249cdd2176468ccaa36040a484f58 -a0c414f23f46ca6d69ce74c6f8a00c036cb0edd098af0c1a7d39c802b52cfb2d5dbdf93fb0295453d4646e2af7954d45 -909cf39e11b3875bb63b39687ae1b5d1f5a15445e39bf164a0b14691b4ddb39a8e4363f584ef42213616abc4785b5d66 -a92bac085d1194fbd1c88299f07a061d0bdd3f980b663e81e6254dbb288bf11478c0ee880e28e01560f12c5ccb3c0103 -841705cd5cd76b943e2b7c5e845b9dd3c8defe8ef67e93078d6d5e67ade33ad4b0fd413bc196f93b0a4073c855cd97d4 -8e7eb8364f384a9161e81d3f1d52ceca9b65536ae49cc35b48c3e2236322ba4ae9973e0840802d9fa4f4d82ea833544f -aed3ab927548bc8bec31467ba80689c71a168e34f50dcb6892f19a33a099f5aa6b3f9cb79f5c0699e837b9a8c7f27efe -b8fbf7696210a36e20edabd77839f4dfdf50d6d015cdf81d587f90284a9bcef7d2a1ff520728d7cc69a4843d6c20dedd -a9d533769ce6830211c884ae50a82a7bf259b44ac71f9fb11f0296fdb3981e6b4c1753fe744647b247ebc433a5a61436 -8b4bdf90d33360b7f428c71cde0a49fb733badba8c726876945f58c620ce7768ae0e98fc8c31fa59d8955a4823336bb1 -808d42238e440e6571c59e52a35ae32547d502dc24fd1759d8ea70a7231a95859baf30b490a4ba55fa2f3aaa11204597 -85594701f1d2fee6dc1956bc44c7b31db93bdeec2f3a7d622c1a08b26994760773e3d57521a44cfd7e407ac3fd430429 -a66de045ce7173043a6825e9dc440ac957e2efb6df0a337f4f8003eb0c719d873a52e6eba3cb0d69d977ca37d9187674 -87a1c6a1fdff993fa51efa5c3ba034c079c0928a7d599b906336af7c2dcab9721ceaf3108c646490af9dff9a754f54b3 -926424223e462ceb75aed7c22ade8a7911a903b7e5dd4bc49746ddce8657f4616325cd12667d4393ac52cdd866396d0e -b5dc96106593b42b30f06f0b0a1e0c1aafc70432e31807252d3674f0b1ea5e58eac8424879d655c9488d85a879a3e572 -997ca0987735cc716507cb0124b1d266d218b40c9d8e0ecbf26a1d65719c82a637ce7e8be4b4815d307df717bde7c72a -92994d3f57a569b7760324bb5ae4e8e14e1633d175dab06aa57b8e391540e05f662fdc08b8830f489a063f59b689a688 -a8087fcc6aa4642cb998bea11facfe87eb33b90a9aa428ab86a4124ad032fc7d2e57795311a54ec9f55cc120ebe42df1 -a9bd7d1de6c0706052ca0b362e2e70e8c8f70f1f026ea189b4f87a08ce810297ebfe781cc8004430776c54c1a05ae90c -856d33282e8a8e33a3d237fb0a0cbabaf77ba9edf2fa35a831fdafcadf620561846aa6cbb6bdc5e681118e1245834165 -9524a7aa8e97a31a6958439c5f3339b19370f03e86b89b1d02d87e4887309dbbe9a3a8d2befd3b7ed5143c8da7e0a8ad -824fdf433e090f8acbd258ac7429b21f36f9f3b337c6d0b71d1416a5c88a767883e255b2888b7c906dd2e9560c4af24c -88c7fee662ca7844f42ed5527996b35723abffd0d22d4ca203b9452c639a5066031207a5ae763dbc0865b3299d19b1ec -919dca5c5595082c221d5ab3a5bc230f45da7f6dec4eb389371e142c1b9c6a2c919074842479c2844b72c0d806170c0c -b939be8175715e55a684578d8be3ceff3087f60fa875fff48e52a6e6e9979c955efef8ff67cfa2b79499ea23778e33b0 -873b6db725e7397d11bc9bed9ac4468e36619135be686790a79bc6ed4249058f1387c9a802ea86499f692cf635851066 -aeae06db3ec47e9e5647323fa02fac44e06e59b885ad8506bf71b184ab3895510c82f78b6b22a5d978e8218e7f761e9f -b99c0a8359c72ab88448bae45d4bf98797a26bca48b0d4460cd6cf65a4e8c3dd823970ac3eb774ae5d0cea4e7fadf33e -8f10c8ec41cdfb986a1647463076a533e6b0eec08520c1562401b36bb063ac972aa6b28a0b6ce717254e35940b900e3c -a106d9be199636d7add43b942290269351578500d8245d4aae4c083954e4f27f64740a3138a66230391f2d0e6043a8de -a469997908244578e8909ff57cffc070f1dbd86f0098df3cfeb46b7a085cfecc93dc69ee7cad90ff1dc5a34d50fe580c -a4ef087bea9c20eb0afc0ee4caba7a9d29dfa872137828c721391273e402fb6714afc80c40e98bbd8276d3836bffa080 -b07a013f73cd5b98dae0d0f9c1c0f35bff8a9f019975c4e1499e9bee736ca6fcd504f9bc32df1655ff333062382cff04 -b0a77188673e87cc83348c4cc5db1eecf6b5184e236220c8eeed7585e4b928db849944a76ec60ef7708ef6dac02d5592 -b1284b37e59b529f0084c0dacf0af6c0b91fc0f387bf649a8c74819debf606f7b07fc3e572500016fb145ec2b24e9f17 -97b20b5b4d6b9129da185adfbf0d3d0b0faeba5b9715f10299e48ea0521709a8296a9264ce77c275a59c012b50b6519a -b9d37e946fae5e4d65c1fbfacc8a62e445a1c9d0f882e60cca649125af303b3b23af53c81d7bac544fb7fcfc7a314665 -8e5acaac379f4bb0127efbef26180f91ff60e4c525bc9b798fc50dfaf4fe8a5aa84f18f3d3cfb8baead7d1e0499af753 -b0c0b8ab1235bf1cda43d4152e71efc1a06c548edb964eb4afceb201c8af24240bf8ab5cae30a08604e77432b0a5faf0 -8cc28d75d5c8d062d649cbc218e31c4d327e067e6dbd737ec0a35c91db44fbbd0d40ec424f5ed79814add16947417572 -95ae6219e9fd47efaa9cb088753df06bc101405ba50a179d7c9f7c85679e182d3033f35b00dbba71fdcd186cd775c52e -b5d28fa09f186ebc5aa37453c9b4d9474a7997b8ae92748ecb940c14868792292ac7d10ade01e2f8069242b308cf97e5 -8c922a0faa14cc6b7221f302df3342f38fc8521ec6c653f2587890192732c6da289777a6cd310747ea7b7d104af95995 -b9ad5f660b65230de54de535d4c0fcae5bc6b59db21dea5500fdc12eea4470fb8ea003690fdd16d052523418d5e01e8c -a39a9dd41a0ff78c82979483731f1cd68d3921c3e9965869662c22e02dde3877802e180ba93f06e7346f96d9fa9261d2 -8b32875977ec372c583b24234c27ed73aef00cdff61eb3c3776e073afbdeade548de9497c32ec6d703ff8ad0a5cb7fe4 -9644cbe755a5642fe9d26cfecf170d3164f1848c2c2e271d5b6574a01755f3980b3fc870b98cf8528fef6ecef4210c16 -81ea9d1fdd9dd66d60f40ce0712764b99da9448ae0b300f8324e1c52f154e472a086dda840cb2e0b9813dc8ce8afd4b5 -906aaa4a7a7cdf01909c5cfbc7ded2abc4b869213cbf7c922d4171a4f2e637e56f17020b852ad339d83b8ac92f111666 -939b5f11acbdeff998f2a080393033c9b9d8d5c70912ea651c53815c572d36ee822a98d6dfffb2e339f29201264f2cf4 -aba4898bf1ccea9b9e2df1ff19001e05891581659c1cbbde7ee76c349c7fc7857261d9785823c9463a8aea3f40e86b38 -83ca1a56b8a0be4820bdb5a9346357c68f9772e43f0b887729a50d2eb2a326bbcede676c8bf2e51d7c89bbd8fdb778a6 -94e86e9fe6addfe2c3ee3a547267ed921f4230d877a85bb4442c2d9350c2fa9a9c54e6fe662de82d1a2407e4ab1691c2 -a0cc3bdef671a59d77c6984338b023fa2b431b32e9ed2abe80484d73edc6540979d6f10812ecc06d4d0c5d4eaca7183c -b5343413c1b5776b55ea3c7cdd1f3af1f6bd802ea95effe3f2b91a523817719d2ecc3f8d5f3cc2623ace7e35f99ca967 -92085d1ed0ed28d8cabe3e7ff1905ed52c7ceb1eac5503760c52fb5ee3a726aba7c90b483c032acc3f166b083d7ec370 -8ec679520455275cd957fca8122724d287db5df7d29f1702a322879b127bff215e5b71d9c191901465d19c86c8d8d404 -b65eb2c63d8a30332eb24ee8a0c70156fc89325ebbb38bacac7cf3f8636ad8a472d81ccca80423772abc00192d886d8a -a9fe1c060b974bee4d590f2873b28635b61bfcf614e61ff88b1be3eee4320f4874e21e8d666d8ac8c9aba672efc6ecae -b3fe2a9a389c006a831dea7e777062df84b5c2803f9574d7fbe10b7e1c125817986af8b6454d6be9d931a5ac94cfe963 -95418ad13b734b6f0d33822d9912c4c49b558f68d08c1b34a0127fcfa666bcae8e6fda8832d2c75bb9170794a20e4d7c -a9a7df761e7f18b79494bf429572140c8c6e9d456c4d4e336184f3f51525a65eb9582bea1e601bdb6ef8150b7ca736a5 -a0de03b1e75edf7998c8c1ac69b4a1544a6fa675a1941950297917366682e5644a4bda9cdeedfaf9473d7fccd9080b0c -a61838af8d95c95edf32663a68f007d95167bf6e41b0c784a30b22d8300cfdd5703bd6d16e86396638f6db6ae7e42a85 -8866d62084d905c145ff2d41025299d8b702ac1814a7dec4e277412c161bc9a62fed735536789cb43c88693c6b423882 -91da22c378c81497fe363e7f695c0268443abee50f8a6625b8a41e865638a643f07b157ee566de09ba09846934b4e2d7 -941d21dd57c9496aa68f0c0c05507405fdd413acb59bc668ce7e92e1936c68ec4b065c3c30123319884149e88228f0b2 -a77af9b094bc26966ddf2bf9e1520c898194a5ccb694915950dadc204facbe3066d3d89f50972642d76b14884cfbaa21 -8e76162932346869f4618bde744647f7ab52ab498ad654bdf2a4feeb986ac6e51370841e5acbb589e38b6e7142bb3049 -b60979ace17d6937ece72e4f015da4657a443dd01cebc7143ef11c09e42d4aa8855999a65a79e2ea0067f31c9fc2ab0f -b3e2ffdd5ee6fd110b982fd4fad4b93d0fca65478f986d086eeccb0804960bfaa1919afa743c2239973ea65091fe57d2 -8ce0ce05e7d7160d44574011da687454dbd3c8b8290aa671731b066e2c82f8cf2d63cb8e932d78c6122ec610e44660e6 -ab005dd8d297045c39e2f72fb1c48edb501ccf3575d3d04b9817b3afee3f0bb0f3f53f64bda37d1d9cde545aae999bae -95bd7edb4c4cd60e3cb8a72558845a3cce6bb7032ccdf33d5a49ebb6ddf203bc3c79e7b7e550735d2d75b04c8b2441e8 -889953ee256206284094e4735dbbb17975bafc7c3cb94c9fbfee4c3e653857bfd49e818f64a47567f721b98411a3b454 -b188423e707640ab0e75a061e0b62830cde8afab8e1ad3dae30db69ffae4e2fc005bababbdcbd7213b918ed4f70e0c14 -a97e0fafe011abd70d4f99a0b36638b3d6e7354284588f17a88970ed48f348f88392779e9a038c6cbc9208d998485072 -87db11014a91cb9b63e8dfaa82cdebca98272d89eb445ee1e3ff9dbaf2b3fad1a03b888cffc128e4fe208ed0dddece0f -aad2e40364edd905d66ea4ac9d51f9640d6fda9a54957d26ba233809851529b32c85660fa401dbee3679ec54fa6dd966 -863e99336ca6edf03a5a259e59a2d0f308206e8a2fb320cfc0be06057366df8e0f94b33a28f574092736b3c5ada84270 -b34bcc56a057589f34939a1adc51de4ff6a9f4fee9c7fa9aa131e28d0cf0759a0c871b640162acdfbf91f3f1b59a3703 -935dd28f2896092995c5eff1618e5b6efe7a40178888d7826da9b0503c2d6e68a28e7fac1a334e166d0205f0695ef614 -b842cd5f8f5de5ca6c68cb4a5c1d7b451984930eb4cc18fd0934d52fdc9c3d2d451b1c395594d73bc3451432bfba653f -9014537885ce2debad736bc1926b25fdab9f69b216bf024f589c49dc7e6478c71d595c3647c9f65ff980b14f4bb2283b -8e827ccca1dd4cd21707140d10703177d722be0bbe5cac578db26f1ef8ad2909103af3c601a53795435b27bf95d0c9ed -8a0b8ad4d466c09d4f1e9167410dbe2edc6e0e6229d4b3036d30f85eb6a333a18b1c968f6ca6d6889bb08fecde017ef4 -9241ee66c0191b06266332dc9161dede384c4bb4e116dbd0890f3c3790ec5566da4568243665c4725b718ac0f6b5c179 -aeb4d5fad81d2b505d47958a08262b6f1b1de9373c2c9ba6362594194dea3e002ab03b8cbb43f867be83065d3d370f19 -8781bc83bb73f7760628629fe19e4714b494dbed444c4e4e4729b7f6a8d12ee347841a199888794c2234f51fa26fc2b9 -b58864f0acd1c2afa29367e637cbde1968d18589245d9936c9a489c6c495f54f0113ecdcbe4680ac085dd3c397c4d0c3 -94a24284afaeead61e70f3e30f87248d76e9726759445ca18cdb9360586c60cc9f0ec1c397f9675083e0b56459784e2e -aed358853f2b54dcbddf865e1816c2e89be12e940e1abfa661e2ee63ffc24a8c8096be2072fa83556482c0d89e975124 -b95374e6b4fc0765708e370bc881e271abf2e35c08b056a03b847e089831ef4fe3124b9c5849d9c276eb2e35b3daf264 -b834cdbcfb24c8f84bfa4c552e7fadc0028a140952fd69ed13a516e1314a4cd35d4b954a77d51a1b93e1f5d657d0315d -8fb6d09d23bfa90e7443753d45a918d91d75d8e12ec7d016c0dfe94e5c592ba6aaf483d2f16108d190822d955ad9cdc3 -aa315cd3c60247a6ad4b04f26c5404c2713b95972843e4b87b5a36a89f201667d70f0adf20757ebe1de1b29ae27dda50 -a116862dca409db8beff5b1ccd6301cdd0c92ca29a3d6d20eb8b87f25965f42699ca66974dd1a355200157476b998f3b -b4c2f5fe173c4dc8311b60d04a65ce1be87f070ac42e13cd19c6559a2931c6ee104859cc2520edebbc66a13dc7d30693 -8d4a02bf99b2260c334e7d81775c5cf582b00b0c982ce7745e5a90624919028278f5e9b098573bad5515ce7fa92a80c8 -8543493bf564ce6d97bd23be9bff1aba08bd5821ca834f311a26c9139c92a48f0c2d9dfe645afa95fec07d675d1fd53b -9344239d13fde08f98cb48f1f87d34cf6abe8faecd0b682955382a975e6eed64e863fa19043290c0736261622e00045c -aa49d0518f343005ca72b9e6c7dcaa97225ce6bb8b908ebbe7b1a22884ff8bfb090890364e325a0d414ad180b8f161d1 -907d7fd3e009355ab326847c4a2431f688627faa698c13c03ffdd476ecf988678407f029b8543a475dcb3dafdf2e7a9c -845f1f10c6c5dad2adc7935f5cd2e2b32f169a99091d4f1b05babe7317b9b1cdce29b5e62f947dc621b9acbfe517a258 -8f3be8e3b380ea6cdf9e9c237f5e88fd5a357e5ded80ea1fc2019810814de82501273b4da38916881125b6fa0cfd4459 -b9c7f487c089bf1d20c822e579628db91ed9c82d6ca652983aa16d98b4270c4da19757f216a71b9c13ddee3e6e43705f -8ba2d8c88ad2b872db104ea8ddbb006ec2f3749fd0e19298a804bb3a5d94de19285cc7fb19fee58a66f7851d1a66c39f -9375ecd3ed16786fe161af5d5c908f56eeb467a144d3bbddfc767e90065b7c94fc53431adebecba2b6c9b5821184d36e -a49e069bfadb1e2e8bff6a4286872e2a9765d62f0eaa4fcb0e5af4bbbed8be3510fb19849125a40a8a81d1e33e81c3eb -9522cc66757b386aa6b88619525c8ce47a5c346d590bb3647d12f991e6c65c3ab3c0cfc28f0726b6756c892eae1672be -a9a0f1f51ff877406fa83a807aeb17b92a283879f447b8a2159653db577848cc451cbadd01f70441e351e9ed433c18bc -8ff7533dcff6be8714df573e33f82cf8e9f2bcaaa43e939c4759d52b754e502717950de4b4252fb904560fc31dce94a4 -959724671e265a28d67c29d95210e97b894b360da55e4cf16e6682e7912491ed8ca14bfaa4dce9c25a25b16af580494f -92566730c3002f4046c737032487d0833c971e775de59fe02d9835c9858e2e3bc37f157424a69764596c625c482a2219 -a84b47ceff13ed9c3e5e9cdf6739a66d3e7c2bd8a6ba318fefb1a9aecf653bb2981da6733ddb33c4b0a4523acc429d23 -b4ddf571317e44f859386d6140828a42cf94994e2f1dcbcc9777f4eebbfc64fc1e160b49379acc27c4672b8e41835c5d -8ab95c94072b853d1603fdd0a43b30db617d13c1d1255b99075198e1947bfa5f59aed2b1147548a1b5e986cd9173d15c -89511f2eab33894fd4b3753d24249f410ff7263052c1fef6166fc63a79816656b0d24c529e45ccce6be28de6e375d916 -a0866160ca63d4f2be1b4ea050dac6b59db554e2ebb4e5b592859d8df339b46fd7cb89aaed0951c3ee540aee982c238a -8fcc5cbba1b94970f5ff2eb1922322f5b0aa7d918d4b380c9e7abfd57afd8b247c346bff7b87af82efbce3052511cd1b -99aeb2a5e846b0a2874cca02c66ed40d5569eb65ab2495bc3f964a092e91e1517941f2688e79f8cca49cd3674c4e06dc -b7a096dc3bad5ca49bee94efd884aa3ff5615cf3825cf95fbe0ce132e35f46581d6482fa82666c7ef5f1643eaee8f1ca -94393b1da6eaac2ffd186b7725eca582f1ddc8cdd916004657f8a564a7c588175cb443fc6943b39029f5bbe0add3fad8 -884b85fe012ccbcd849cb68c3ad832d83b3ef1c40c3954ffdc97f103b1ed582c801e1a41d9950f6bddc1d11f19d5ec76 -b00061c00131eded8305a7ce76362163deb33596569afb46fe499a7c9d7a0734c084d336b38d168024c2bb42b58e7660 -a439153ac8e6ca037381e3240e7ba08d056c83d7090f16ed538df25901835e09e27de2073646e7d7f3c65056af6e4ce7 -830fc9ca099097d1f38b90e6843dc86f702be9d20bdacc3e52cae659dc41df5b8d2c970effa6f83a5229b0244a86fe22 -b81ea2ffaaff2bb00dd59a9ab825ba5eed4db0d8ac9c8ed1a632ce8f086328a1cddd045fbe1ace289083c1325881b7e7 -b51ea03c58daf2db32c99b9c4789b183365168cb5019c72c4cc91ac30b5fb7311d3db76e6fa41b7cd4a8c81e2f6cdc94 -a4170b2c6d09ca5beb08318730419b6f19215ce6c631c854116f904be3bc30dd85a80c946a8ab054d3e307afaa3f8fbc -897cc42ff28971ff54d2a55dd6b35cfb8610ac902f3c06e3a5cea0e0a257e870c471236a8e84709211c742a09c5601a6 -a18f2e98d389dace36641621488664ecbb422088ab03b74e67009b8b8acacaaa24fdcf42093935f355207d934adc52a8 -92adcfb678cc2ba19c866f3f2b988fdcb4610567f3ab436cc0cb9acaf5a88414848d71133ebdbec1983e38e6190f1b5f -a86d43c2ce01b366330d3b36b3ca85f000c3548b8297e48478da1ee7d70d8576d4650cba7852ed125c0d7cb6109aa7f3 -8ed31ceed9445437d7732dce78a762d72ff32a7636bfb3fd7974b7ae15db414d8184a1766915244355deb354fbc5803b -9268f70032584f416e92225d65af9ea18c466ebc7ae30952d56a4e36fd9ea811dde0a126da9220ba3c596ec54d8a335e -9433b99ee94f2d3fbdd63b163a2bdf440379334c52308bd24537f7defd807145a062ff255a50d119a7f29f4b85d250e3 -90ce664f5e4628a02278f5cf5060d1a34f123854634b1870906e5723ac9afd044d48289be283b267d45fcbf3f4656aaf -aaf21c4d59378bb835d42ae5c5e5ab7a3c8c36a59e75997989313197752b79a472d866a23683b329ea69b048b87fa13e -b83c0589b304cec9ede549fde54f8a7c2a468c6657da8c02169a6351605261202610b2055c639b9ed2d5b8c401fb8f56 -9370f326ea0f170c2c05fe2c5a49189f20aec93b6b18a5572a818cd4c2a6adb359e68975557b349fb54f065d572f4c92 -ac3232fa5ce6f03fca238bef1ce902432a90b8afce1c85457a6bee5571c033d4bceefafc863af04d4e85ac72a4d94d51 -80d9ea168ff821b22c30e93e4c7960ce3ad3c1e6deeebedd342a36d01bd942419b187e2f382dbfd8caa34cca08d06a48 -a387a3c61676fb3381eefa2a45d82625635a666e999aba30e3b037ec9e040f414f9e1ad9652abd3bcad63f95d85038db -a1b229fe32121e0b391b0f6e0180670b9dc89d79f7337de4c77ea7ad0073e9593846f06797c20e923092a08263204416 -92164a9d841a2b828cedf2511213268b698520f8d1285852186644e9a0c97512cafa4bfbe29af892c929ebccd102e998 -82ee2fa56308a67c7db4fd7ef539b5a9f26a1c2cc36da8c3206ba4b08258fbb3cec6fe5cdbd111433fb1ba2a1e275927 -8c77bfe9e191f190a49d46f05600603fa42345592539b82923388d72392404e0b29a493a15e75e8b068dddcd444c2928 -80b927f93ccf79dcf5c5b20bcf5a7d91d7a17bc0401bb7cc9b53a6797feac31026eb114257621f5a64a52876e4474cc1 -b6b68b6501c37804d4833d5a063dd108a46310b1400549074e3cac84acc6d88f73948b7ad48d686de89c1ec043ae8c1a -ab3da00f9bdc13e3f77624f58a3a18fc3728956f84b5b549d62f1033ae4b300538e53896e2d943f160618e05af265117 -b6830e87233b8eace65327fdc764159645b75d2fd4024bf8f313b2dd5f45617d7ecfb4a0b53ccafb5429815a9a1adde6 -b9251cfe32a6dc0440615aadcd98b6b1b46e3f4e44324e8f5142912b597ee3526bea2431e2b0282bb58f71be5b63f65e -af8d70711e81cdddfb39e67a1b76643292652584c1ce7ce4feb1641431ad596e75c9120e85f1a341e7a4da920a9cdd94 -98cd4e996594e89495c078bfd52a4586b932c50a449a7c8dfdd16043ca4cda94dafbaa8ad1b44249c99bbcc52152506e -b9fc6d1c24f48404a4a64fbe3e43342738797905db46e4132aee5f086aaa4c704918ad508aaefa455cfe1b36572e6242 -a365e871d30ba9291cedaba1be7b04e968905d003e9e1af7e3b55c5eb048818ae5b913514fb08b24fb4fbdccbb35d0b8 -93bf99510971ea9af9f1e364f1234c898380677c8e8de9b0dd24432760164e46c787bc9ec42a7ad450500706cf247b2d -b872f825a5b6e7b9c7a9ddfeded3516f0b1449acc9b4fd29fc6eba162051c17416a31e5be6d3563f424d28e65bab8b8f -b06b780e5a5e8eb4f4c9dc040f749cf9709c8a4c9ef15e925f442b696e41e5095db0778a6c73bcd329b265f2c6955c8b -848f1a981f5fc6cd9180cdddb8d032ad32cdfa614fc750d690dbae36cc0cd355cbf1574af9b3ffc8b878f1b2fafb9544 -a03f48cbff3e9e8a3a655578051a5ae37567433093ac500ed0021c6250a51b767afac9bdb194ee1e3eac38a08c0eaf45 -b5be78ce638ff8c4aa84352b536628231d3f7558c5be3bf010b28feac3022e64691fa672f358c8b663904aebe24a54ed -a9d4da70ff676fa55d1728ba6ab03b471fa38b08854d99e985d88c2d050102d8ccffbe1c90249a5607fa7520b15fe791 -8fe9f7092ffb0b69862c8e972fb1ecf54308c96d41354ed0569638bb0364f1749838d6d32051fff1599112978c6e229c -ae6083e95f37770ecae0df1e010456f165d96cfe9a7278c85c15cffd61034081ce5723e25e2bede719dc9341ec8ed481 -a260891891103089a7afbd9081ea116cfd596fd1015f5b65e10b0961eb37fab7d09c69b7ce4be8bf35e4131848fb3fe4 -8d729fa32f6eb9fd2f6a140bef34e8299a2f3111bffd0fe463aa8622c9d98bfd31a1df3f3e87cd5abc52a595f96b970e -a30ec6047ae4bc7da4daa7f4c28c93aedb1112cfe240e681d07e1a183782c9ff6783ac077c155af23c69643b712a533f -ac830726544bfe7b5467339e5114c1a75f2a2a8d89453ce86115e6a789387e23551cd64620ead6283dfa4538eb313d86 -8445c135b7a48068d8ed3e011c6d818cfe462b445095e2fbf940301e50ded23f272d799eea47683fc027430ce14613ef -95785411715c9ae9d8293ce16a693a2aa83e3cb1b4aa9f76333d0da2bf00c55f65e21e42e50e6c5772ce213dd7b4f7a0 -b273b024fa18b7568c0d1c4d2f0c4e79ec509dafac8c5951f14192d63ddbcf2d8a7512c1c1b615cc38fa3e336618e0c5 -a78b9d3ea4b6a90572eb27956f411f1d105fdb577ee2ffeec9f221da9b45db84bfe866af1f29597220c75e0c37a628d8 -a4be2bf058c36699c41513c4d667681ce161a437c09d81383244fc55e1c44e8b1363439d0cce90a3e44581fb31d49493 -b6eef13040f17dd4eba22aaf284d2f988a4a0c4605db44b8d2f4bf9567ac794550b543cc513c5f3e2820242dd704152e -87eb00489071fa95d008c5244b88e317a3454652dcb1c441213aa16b28cd3ecaa9b22fec0bdd483c1df71c37119100b1 -92d388acdcb49793afca329cd06e645544d2269234e8b0b27d2818c809c21726bc9cf725651b951e358a63c83dedee24 -ae27e219277a73030da27ab5603c72c8bd81b6224b7e488d7193806a41343dff2456132274991a4722fdb0ef265d04cd -97583e08ecb82bbc27c0c8476d710389fa9ffbead5c43001bd36c1b018f29faa98de778644883e51870b69c5ffb558b5 -90a799a8ce73387599babf6b7da12767c0591cadd36c20a7990e7c05ea1aa2b9645654ec65308ee008816623a2757a6a -a1b47841a0a2b06efd9ab8c111309cc5fc9e1d5896b3e42ed531f6057e5ade8977c29831ce08dbda40348386b1dcc06d -b92b8ef59bbddb50c9457691bc023d63dfcc54e0fd88bd5d27a09e0d98ac290fc90e6a8f6b88492043bf7c87fac8f3e4 -a9d6240b07d62e22ec8ab9b1f6007c975a77b7320f02504fc7c468b4ee9cfcfd945456ff0128bc0ef2174d9e09333f8d -8e96534c94693226dc32bca79a595ca6de503af635f802e86442c67e77564829756961d9b701187fe91318da515bf0e6 -b6ba290623cd8dd5c2f50931c0045d1cfb0c30877bc8fe58cbc3ff61ee8da100045a39153916efa1936f4aee0892b473 -b43baa7717fac02d4294f5b3bb5e58a65b3557747e3188b482410388daac7a9c177f762d943fd5dcf871273921213da8 -b9cf00f8fb5e2ef2b836659fece15e735060b2ea39b8e901d3dcbdcf612be8bf82d013833718c04cd46ffaa70b85f42e -8017d0c57419e414cbba504368723e751ef990cc6f05dad7b3c2de6360adc774ad95512875ab8337d110bf39a42026fa -ae7401048b838c0dcd4b26bb6c56d79d51964a0daba780970b6c97daee4ea45854ea0ac0e4139b3fe60dac189f84df65 -887b237b0cd0f816b749b21db0b40072f9145f7896c36916296973f9e6990ede110f14e5976c906d08987c9836cca57f -a88c3d5770148aee59930561ca1223aceb2c832fb5417e188dca935905301fc4c6c2c9270bc1dff7add490a125eb81c6 -b6cf9b02c0cd91895ad209e38c54039523f137b5848b9d3ad33ae43af6c20c98434952db375fe378de7866f2d0e8b18a -84ef3d322ff580c8ad584b1fe4fe346c60866eb6a56e982ba2cf3b021ecb1fdb75ecc6c29747adda86d9264430b3f816 -a0561c27224baf0927ad144cb71e31e54a064c598373fcf0d66aebf98ab7af1d8e2f343f77baefff69a6da750a219e11 -aa5cc43f5b8162b016f5e1b61214c0c9d15b1078911c650b75e6cdfb49b85ee04c6739f5b1687d15908444f691f732de -ad4ac099b935589c7b8fdfdf3db332b7b82bb948e13a5beb121ebd7db81a87d278024a1434bcf0115c54ca5109585c3d -8a00466abf3f109a1dcd19e643b603d3af23d42794ef8ca2514dd507ecea44a031ac6dbc18bd02f99701168b25c1791e -b00b5900dfad79645f8bee4e5adc7b84eb22e5b1e67df77ccb505b7fc044a6c08a8ea5faca662414eb945f874f884cea -950e204e5f17112250b22ea6bb8423baf522fc0af494366f18fe0f949f51d6e6812074a80875cf1ed9c8e7420058d541 -91e5cbf8bb1a1d50c81608c9727b414d0dd2fb467ebc92f100882a3772e54f94979cfdf8e373fdef7c7fcdd60fec9e00 -a093f6a857b8caaff80599c2e89c962b415ecbaa70d8fd973155fa976a284c6b29a855f5f7a3521134d00d2972755188 -b4d55a3551b00da54cc010f80d99ddd2544bde9219a3173dfaadf3848edc7e4056ab532fb75ac26f5f7141e724267663 -a03ea050fc9b011d1b04041b5765d6f6453a93a1819cd9bd6328637d0b428f08526466912895dcc2e3008ee58822e9a7 -99b12b3665e473d01bc6985844f8994fb65cb15745024fb7af518398c4a37ff215da8f054e8fdf3286984ae36a73ca5e -9972c7e7a7fb12e15f78d55abcaf322c11249cd44a08f62c95288f34f66b51f146302bce750ff4d591707075d9123bd2 -a64b4a6d72354e596d87cda213c4fc2814009461570ccb27d455bbe131f8d948421a71925425b546d8cf63d5458cd64b -91c215c73b195795ede2228b7ed1f6e37892e0c6b0f4a0b5a16c57aa1100c84df9239054a173b6110d6c2b7f4bf1ce52 -88807198910ec1303480f76a3683870246a995e36adaeadc29c22f0bdba8152fe705bd070b75de657b04934f7d0ccf80 -b37c0026c7b32eb02cacac5b55cb5fe784b8e48b2945c64d3037af83ece556a117f0ff053a5968c2f5fa230e291c1238 -94c768384ce212bc2387e91ce8b45e4ff120987e42472888a317abc9dcdf3563b62e7a61c8e98d7cdcbe272167d91fc6 -a10c2564936e967a390cb14ef6e8f8b04ea9ece5214a38837eda09e79e0c7970b1f83adf017c10efd6faa8b7ffa2c567 -a5085eed3a95f9d4b1269182ea1e0d719b7809bf5009096557a0674bde4201b0ddc1f0f16a908fc468846b3721748ce3 -87468eb620b79a0a455a259a6b4dfbc297d0d53336537b771254dd956b145dc816b195b7002647ea218552e345818a3f -ace2b77ffb87366af0a9cb5d27d6fc4a14323dbbf1643f5f3c4559306330d86461bb008894054394cbfaefeaa0bc2745 -b27f56e840a54fbd793f0b7a7631aa4cee64b5947e4382b2dfb5eb1790270288884c2a19afebe5dc0c6ef335d4531c1c -876e438633931f7f895062ee16c4b9d10428875f7bc79a8e156a64d379a77a2c45bf5430c5ab94330f03da352f1e9006 -a2512a252587d200d2092b44c914df54e04ff8bcef36bf631f84bde0cf5a732e3dc7f00f662842cfd74b0b0f7f24180e -827f1bc8f54a35b7a4bd8154f79bcc055e45faed2e74adf7cf21cca95df44d96899e847bd70ead6bb27b9c0ed97bbd8b -a0c92cf5a9ed843714f3aea9fe7b880f622d0b4a3bf66de291d1b745279accf6ba35097849691370f41732ba64b5966b -a63f5c1e222775658421c487b1256b52626c6f79cb55a9b7deb2352622cedffb08502042d622eb3b02c97f9c09f9c957 -8cc093d52651e65fb390e186db6cc4de559176af4624d1c44cb9b0e836832419dacac7b8db0627b96288977b738d785d -aa7b6a17dfcec146134562d32a12f7bd7fe9522e300859202a02939e69dbd345ed7ff164a184296268f9984f9312e8fc -8ac76721f0d2b679f023d06cbd28c85ae5f4b43c614867ccee88651d4101d4fd352dbdb65bf36bfc3ebc0109e4b0c6f9 -8d350f7c05fc0dcd9a1170748846fb1f5d39453e4cb31e6d1457bed287d96fc393b2ecc53793ca729906a33e59c6834a -b9913510dfc5056d7ec5309f0b631d1ec53e3a776412ada9aefdaf033c90da9a49fdde6719e7c76340e86599b1f0eec2 -94955626bf4ce87612c5cfffcf73bf1c46a4c11a736602b9ba066328dc52ad6d51e6d4f53453d4ed55a51e0aad810271 -b0fcab384fd4016b2f1e53f1aafd160ae3b1a8865cd6c155d7073ecc1664e05b1d8bca1def39c158c7086c4e1103345e -827de3f03edfbde08570b72de6662c8bfa499b066a0a27ebad9b481c273097d17a5a0a67f01553da5392ec3f149b2a78 -ab7940384c25e9027c55c40df20bd2a0d479a165ced9b1046958353cd69015eeb1e44ed2fd64e407805ba42df10fc7bf -8ad456f6ff8cd58bd57567d931f923d0c99141978511b17e03cab7390a72b9f62498b2893e1b05c7c22dd274e9a31919 -ac75399e999effe564672db426faa17a839e57c5ef735985c70cd559a377adec23928382767b55ed5a52f7b11b54b756 -b17f975a00b817299ac7af5f2024ea820351805df58b43724393bfb3920a8cd747a3bbd4b8286e795521489db3657168 -a2bed800a6d95501674d9ee866e7314063407231491d794f8cf57d5be020452729c1c7cefd8c50dc1540181f5caab248 -9743f5473171271ffdd3cc59a3ae50545901a7b45cd4bc3570db487865f3b73c0595bebabbfe79268809ee1862e86e4a -b7eab77c2d4687b60d9d7b04e842b3880c7940140012583898d39fcc22d9b9b0a9be2c2e3788b3e6f30319b39c338f09 -8e2b8f797a436a1b661140e9569dcf3e1eea0a77c7ff2bc4ff0f3e49af04ed2de95e255df8765f1d0927fb456a9926b1 -8aefea201d4a1f4ff98ffce94e540bb313f2d4dfe7e9db484a41f13fc316ed02b282e1acc9bc6f56cad2dc2e393a44c9 -b950c17c0e5ca6607d182144aa7556bb0efe24c68f06d79d6413a973b493bfdf04fd147a4f1ab03033a32004cc3ea66f -b7b8dcbb179a07165f2dc6aa829fad09f582a71b05c3e3ea0396bf9e6fe73076f47035c031c2101e8e38e0d597eadd30 -a9d77ed89c77ec1bf8335d08d41c3c94dcca9fd1c54f22837b4e54506b212aa38d7440126c80648ab7723ff18e65ed72 -a819d6dfd4aef70e52b8402fe5d135f8082d40eb7d3bb5c4d7997395b621e2bb10682a1bad2c9caa33dd818550fc3ec6 -8f6ee34128fac8bbf13ce2d68b2bb363eb4fd65b297075f88e1446ddeac242500eeb4ef0735e105882ff5ba8c44c139b -b4440e48255c1644bcecf3a1e9958f1ec4901cb5b1122ee5b56ffd02cad1c29c4266999dbb85aa2605c1b125490074d4 -a43304a067bede5f347775d5811cf65a6380a8d552a652a0063580b5c5ef12a0867a39c7912fa219e184f4538eba1251 -a891ad67a790089ffc9f6d53e6a3d63d3556f5f693e0cd8a7d0131db06fd4520e719cfcc3934f0a8f62a95f90840f1d4 -aea6df8e9bb871081aa0fc5a9bafb00be7d54012c5baf653791907d5042a326aeee966fd9012a582cc16695f5baf7042 -8ffa2660dc52ed1cd4eff67d6a84a8404f358a5f713d04328922269bee1e75e9d49afeec0c8ad751620f22352a438e25 -87ec6108e2d63b06abed350f8b363b7489d642486f879a6c3aa90e5b0f335efc2ff2834eef9353951a42136f8e6a1b32 -865619436076c2760d9e87ddc905023c6de0a8d56eef12c98a98c87837f2ca3f27fd26a2ad752252dbcbe2b9f1d5a032 -980437dce55964293cb315c650c5586ffd97e7a944a83f6618af31c9d92c37b53ca7a21bb5bc557c151b9a9e217e7098 -95d128fc369df4ad8316b72aea0ca363cbc7b0620d6d7bb18f7076a8717a6a46956ff140948b0cc4f6d2ce33b5c10054 -8c7212d4a67b9ec70ebbca04358ad2d36494618d2859609163526d7b3acc2fc935ca98519380f55e6550f70a9bc76862 -893a2968819401bf355e85eee0f0ed0406a6d4a7d7f172d0017420f71e00bb0ba984f6020999a3cdf874d3cd8ebcd371 -9103c1af82dece25d87274e89ea0acd7e68c2921c4af3d8d7c82ab0ed9990a5811231b5b06113e7fa43a6bd492b4564f -99cfd87a94eab7d35466caa4ed7d7bb45e5c932b2ec094258fb14bf205659f83c209b83b2f2c9ccb175974b2a33e7746 -874b6b93e4ee61be3f00c32dd84c897ccd6855c4b6251eb0953b4023634490ed17753cd3223472873cbc6095b2945075 -84a32c0dc4ea60d33aac3e03e70d6d639cc9c4cc435c539eff915017be3b7bdaba33349562a87746291ebe9bc5671f24 -a7057b24208928ad67914e653f5ac1792c417f413d9176ba635502c3f9c688f7e2ee81800d7e3dc0a340c464da2fd9c5 -a03fb9ed8286aacfa69fbd5d953bec591c2ae4153400983d5dbb6cd9ea37fff46ca9e5cceb9d117f73e9992a6c055ad2 -863b2de04e89936c9a4a2b40380f42f20aefbae18d03750fd816c658aee9c4a03df7b12121f795c85d01f415baaeaa59 -8526eb9bd31790fe8292360d7a4c3eed23be23dd6b8b8f01d2309dbfdc0cfd33ad1568ddd7f8a610f3f85a9dfafc6a92 -b46ab8c5091a493d6d4d60490c40aa27950574a338ea5bbc045be3a114af87bdcb160a8c80435a9b7ad815f3cb56a3f3 -aeadc47b41a8d8b4176629557646202f868b1d728b2dda58a347d937e7ffc8303f20d26d6c00b34c851b8aeec547885d -aebb19fc424d72c1f1822aa7adc744cd0ef7e55727186f8df8771c784925058c248406ebeeaf3c1a9ee005a26e9a10c6 -8ff96e81c1a4a2ab1b4476c21018fae0a67e92129ee36120cae8699f2d7e57e891f5c624902cb1b845b944926a605cc3 -8251b8d2c43fadcaa049a9e7aff838dae4fb32884018d58d46403ac5f3beb5c518bfd45f03b8abb710369186075eb71c -a8b2a64f865f51a5e5e86a66455c093407933d9d255d6b61e1fd81ffafc9538d73caaf342338a66ba8ee166372a3d105 -aad915f31c6ba7fdc04e2aaac62e84ef434b7ee76a325f07dc430d12c84081999720181067b87d792efd0117d7ee1eab -a13db3bb60389883fd41d565c54fb5180d9c47ce2fe7a169ae96e01d17495f7f4fa928d7e556e7c74319c4c25d653eb2 -a4491b0198459b3f552855d680a59214eb74e6a4d6c5fa3b309887dc50ebea2ecf6d26c040550f7dc478b452481466fb -8f017f13d4b1e3f0c087843582b52d5f8d13240912254d826dd11f8703a99a2f3166dfbdfdffd9a3492979d77524276b -96c3d5dcd032660d50d7cd9db2914f117240a63439966162b10c8f1f3cf74bc83b0f15451a43b31dbd85e4a7ce0e4bb1 -b479ec4bb79573d32e0ec93b92bdd7ec8c26ddb5a2d3865e7d4209d119fd3499eaac527615ffac78c440e60ef3867ae0 -b2c49c4a33aa94b52b6410b599e81ff15490aafa7e43c8031c865a84e4676354a9c81eb4e7b8be6825fdcefd1e317d44 -906dc51d6a90c089b6704b47592805578a6eed106608eeb276832f127e1b8e858b72e448edcbefb497d152447e0e68ff -b0e81c63b764d7dfbe3f3fddc9905aef50f3633e5d6a4af6b340495124abedcff5700dfd1577bbbed7b6bf97d02719cb -9304c64701e3b4ed6d146e48a881f7d83a17f58357cca0c073b2bb593afd2d94f6e2a7a1ec511d0a67ad6ff4c3be5937 -b6fdbd12ba05aa598d80b83f70a15ef90e5cba7e6e75fa038540ee741b644cd1f408a6cecfd2a891ef8d902de586c6b5 -b80557871a6521b1b3c74a1ba083ae055b575df607f1f7b04c867ba8c8c181ea68f8d90be6031f4d25002cca27c44da2 -aa7285b8e9712e06b091f64163f1266926a36607f9d624af9996856ed2aaf03a580cb22ce407d1ade436c28b44ca173f -8148d72b975238b51e6ea389e5486940d22641b48637d7dfadfa603a605bfc6d74a016480023945d0b85935e396aea5d -8a014933a6aea2684b5762af43dcf4bdbb633cd0428d42d71167a2b6fc563ece5e618bff22f1db2ddb69b845b9a2db19 -990d91740041db770d0e0eb9d9d97d826f09fd354b91c41e0716c29f8420e0e8aac0d575231efba12fe831091ec38d5a -9454d0d32e7e308ddec57cf2522fb1b67a2706e33fb3895e9e1f18284129ab4f4c0b7e51af25681d248d7832c05eb698 -a5bd434e75bac105cb3e329665a35bce6a12f71dd90c15165777d64d4c13a82bceedb9b48e762bd24034e0fc9fbe45f4 -b09e3b95e41800d4dc29c6ffdaab2cd611a0050347f6414f154a47ee20ee59bf8cf7181454169d479ebce1eb5c777c46 -b193e341d6a047d15eea33766d656d807b89393665a783a316e9ba10518e5515c8e0ade3d6e15641d917a8a172a5a635 -ade435ec0671b3621dde69e07ead596014f6e1daa1152707a8c18877a8b067bde2895dd47444ffa69db2bbef1f1d8816 -a7fd3d6d87522dfc56fb47aef9ce781a1597c56a8bbfd796baba907afdc872f753d732bfda1d3402aee6c4e0c189f52d -a298cb4f4218d0464b2fab393e512bbc477c3225aa449743299b2c3572f065bc3a42d07e29546167ed9e1b6b3b3a3af3 -a9ee57540e1fd9c27f4f0430d194b91401d0c642456c18527127d1f95e2dba41c2c86d1990432eb38a692fda058fafde -81d6c1a5f93c04e6d8e5a7e0678c1fc89a1c47a5c920bcd36180125c49fcf7c114866b90e90a165823560b19898a7c16 -a4b7a1ec9e93c899b9fd9aaf264c50e42c36c0788d68296a471f7a3447af4dbc81e4fa96070139941564083ec5b5b5a1 -b3364e327d381f46940c0e11e29f9d994efc6978bf37a32586636c0070b03e4e23d00650c1440f448809e1018ef9f6d8 -8056e0913a60155348300e3a62e28b5e30629a90f7dd4fe11289097076708110a1d70f7855601782a3cdc5bdb1ca9626 -b4980fd3ea17bac0ba9ee1c470b17e575bb52e83ebdd7d40c93f4f87bebeaff1c8a679f9d3d09d635f068d37d5bd28bd -905a9299e7e1853648e398901dfcd437aa575c826551f83520df62984f5679cb5f0ea86aa45ed3e18b67ddc0dfafe809 -ab99553bf31a84f2e0264eb34a08e13d8d15e2484aa9352354becf9a15999c76cc568d68274b70a65e49703fc23540d0 -a43681597bc574d2dae8964c9a8dc1a07613d7a1272bdcb818d98c85d44e16d744250c33f3b5e4d552d97396b55e601f -a54e5a31716fccb50245898c99865644405b8dc920ded7a11f3d19bdc255996054b268e16f2e40273f11480e7145f41e -8134f3ad5ef2ad4ba12a8a4e4d8508d91394d2bcdc38b7c8c8c0b0a820357ac9f79d286c65220f471eb1adca1d98fc68 -94e2f755e60471578ab2c1adb9e9cea28d4eec9b0e92e0140770bca7002c365fcabfe1e5fb4fe6cfe79a0413712aa3ef -ad48f8d0ce7eb3cc6e2a3086ad96f562e5bed98a360721492ae2e74dc158586e77ec8c35d5fd5927376301b7741bad2b -8614f0630bdd7fbad3a31f55afd9789f1c605dc85e7dc67e2edfd77f5105f878bb79beded6e9f0b109e38ea7da67e8d5 -9804c284c4c5e77dabb73f655b12181534ca877c3e1e134aa3f47c23b7ec92277db34d2b0a5d38d2b69e5d1c3008a3e3 -a51b99c3088e473afdaa9e0a9f7e75a373530d3b04e44e1148da0726b95e9f5f0c7e571b2da000310817c36f84b19f7f -ac4ff909933b3b76c726b0a382157cdc74ab851a1ac6cef76953c6444441804cc43abb883363f416592e8f6cfbc4550b -ae7d915eb9fc928b65a29d6edbc75682d08584d0014f7bcf17d59118421ae07d26a02137d1e4de6938bcd1ab8ef48fad -852f7e453b1af89b754df6d11a40d5d41ea057376e8ecacd705aacd2f917457f4a093d6b9a8801837fa0f62986ad7149 -92c6bf5ada5d0c3d4dd8058483de36c215fa98edab9d75242f3eff9db07c734ad67337da6f0eefe23a487bf75a600dee -a2b42c09d0db615853763552a48d2e704542bbd786aae016eb58acbf6c0226c844f5fb31e428cb6450b9db855f8f2a6f -880cc07968266dbfdcfbc21815cd69e0eddfee239167ac693fb0413912d816f2578a74f7716eecd6deefa68c6eccd394 -b885b3ace736cd373e8098bf75ba66fa1c6943ca1bc4408cd98ac7074775c4478594f91154b8a743d9c697e1b29f5840 -a51ce78de512bd87bfa0835de819941dffbf18bec23221b61d8096fc9436af64e0693c335b54e7bfc763f287bdca2db6 -a3c76166a3bdb9b06ef696e57603b58871bc72883ee9d45171a30fe6e1d50e30bc9c51b4a0f5a7270e19a77b89733850 -acefc5c6f8a1e7c24d7b41e0fc7f6f3dc0ede6cf3115ffb9a6e54b1d954cbca9bda8ad7a084be9be245a1b8e9770d141 -b420ed079941842510e31cfad117fa11fb6b4f97dfbc6298cb840f27ebaceba23eeaf3f513bcffbf5e4aae946310182d -95c3bb5ef26c5ed2f035aa5d389c6b3c15a6705b9818a3fefaed28922158b35642b2e8e5a1a620fdad07e75ad4b43af4 -825149f9081ecf07a2a4e3e8b5d21bade86c1a882475d51c55ee909330b70c5a2ac63771c8600c6f38df716af61a3ea1 -873b935aae16d9f08adbc25353cee18af2f1b8d5f26dec6538d6bbddc515f2217ed7d235dcfea59ae61b428798b28637 -9294150843a2bedcedb3bb74c43eb28e759cf9499582c5430bccefb574a8ddd4f11f9929257ff4c153990f9970a2558f -b619563a811cc531da07f4f04e5c4c6423010ff9f8ed7e6ec9449162e3d501b269fb1c564c09c0429431879b0f45df02 -91b509b87eb09f007d839627514658c7341bc76d468920fe8a740a8cb96a7e7e631e0ea584a7e3dc1172266f641d0f5c -8b8aceace9a7b9b4317f1f01308c3904d7663856946afbcea141a1c615e21ccad06b71217413e832166e9dd915fbe098 -87b3b36e725833ea0b0f54753c3728c0dbc87c52d44d705ffc709f2d2394414c652d3283bab28dcce09799504996cee0 -b2670aad5691cbf308e4a6a77a075c4422e6cbe86fdba24e9f84a313e90b0696afb6a067eebb42ba2d10340d6a2f6e51 -876784a9aff3d54faa89b2bacd3ff5862f70195d0b2edc58e8d1068b3c9074c0da1cfa23671fe12f35e33b8a329c0ccd -8b48b9e758e8a8eae182f5cbec96f67d20cca6d3eee80a2d09208eb1d5d872e09ef23d0df8ebbb9b01c7449d0e3e3650 -b79303453100654c04a487bdcadc9e3578bc80930c489a7069a52e8ca1dba36c492c8c899ce025f8364599899baa287d -961b35a6111da54ece6494f24dacd5ea46181f55775b5f03df0e370c34a5046ac2b4082925855325bb42bc2a2c98381d -a31feb1be3f5a0247a1f7d487987eb622e34fca817832904c6ee3ee60277e5847945a6f6ea1ac24542c72e47bdf647df -a12a2aa3e7327e457e1aae30e9612715dd2cfed32892c1cd6dcda4e9a18203af8a44afb46d03b2eed89f6b9c5a2c0c23 -a08265a838e69a2ca2f80fead6ccf16f6366415b920c0b22ee359bcd8d4464ecf156f400a16a7918d52e6d733dd64211 -b723d6344e938d801cca1a00032af200e541d4471fd6cbd38fb9130daa83f6a1dffbbe7e67fc20f9577f884acd7594b2 -a6733d83ec78ba98e72ddd1e7ff79b7adb0e559e256760d0c590a986e742445e8cdf560d44b29439c26d87edd0b07c8c -a61c2c27d3f7b9ff4695a17afedf63818d4bfba390507e1f4d0d806ce8778d9418784430ce3d4199fd3bdbc2504d2af3 -8332f3b63a6dc985376e8b1b25eeae68be6160fbe40053ba7bcf6f073204f682da72321786e422d3482fd60c9e5aa034 -a280f44877583fbb6b860d500b1a3f572e3ee833ec8f06476b3d8002058e25964062feaa1e5bec1536d734a5cfa09145 -a4026a52d277fcea512440d2204f53047718ebfcae7b48ac57ea7f6bfbc5de9d7304db9a9a6cbb273612281049ddaec5 -95cdf69c831ab2fad6c2535ede9c07e663d2ddccc936b64e0843d2df2a7b1c31f1759c3c20f1e7a57b1c8f0dbb21b540 -95c96cec88806469c277ab567863c5209027cecc06c7012358e5f555689c0d9a5ffb219a464f086b45817e8536b86d2f -afe38d4684132a0f03d806a4c8df556bf589b25271fbc6fe2e1ed16de7962b341c5003755da758d0959d2e6499b06c68 -a9b77784fda64987f97c3a23c5e8f61b918be0f7c59ba285084116d60465c4a2aaafc8857eb16823282cc83143eb9126 -a830f05881ad3ce532a55685877f529d32a5dbe56cea57ffad52c4128ee0fad0eeaf0da4362b55075e77eda7babe70e5 -992b3ad190d6578033c13ed5abfee4ef49cbc492babb90061e3c51ee4b5790cdd4c8fc1abff1fa2c00183b6b64f0bbbe -b1015424d9364aeff75de191652dc66484fdbec3e98199a9eb9671ec57bec6a13ff4b38446e28e4d8aedb58dd619cd90 -a745304604075d60c9db36cada4063ac7558e7ec2835d7da8485e58d8422e817457b8da069f56511b02601289fbb8981 -a5ba4330bc5cb3dbe0486ddf995632a7260a46180a08f42ae51a2e47778142132463cc9f10021a9ad36986108fefa1a9 -b419e9fd4babcaf8180d5479db188bb3da232ae77a1c4ed65687c306e6262f8083070a9ac32220cddb3af2ec73114092 -a49e23dc5f3468f3bf3a0bb7e4a114a788b951ff6f23a3396ae9e12cbff0abd1240878a3d1892105413dbc38818e807c -b7ecc7b4831f650202987e85b86bc0053f40d983f252e9832ef503aea81c51221ce93279da4aa7466c026b2d2070e55d -96a8c35cb87f84fa84dcd6399cc2a0fd79cc9158ef4bdde4bae31a129616c8a9f2576cd19baa3f497ca34060979aed7d -8681b2c00aa62c2b519f664a95dcb8faef601a3b961bb4ce5d85a75030f40965e2983871d41ea394aee934e859581548 -85c229a07efa54a713d0790963a392400f55fbb1a43995a535dc6c929f20d6a65cf4efb434e0ad1cb61f689b8011a3bc -90856f7f3444e5ad44651c28e24cc085a5db4d2ffe79aa53228c26718cf53a6e44615f3c5cda5aa752d5f762c4623c66 -978999b7d8aa3f28a04076f74d11c41ef9c89fdfe514936c4238e0f13c38ec97e51a5c078ebc6409e517bfe7ccb42630 -a099914dd7ed934d8e0d363a648e9038eb7c1ec03fa04dbcaa40f7721c618c3ef947afef7a16b4d7ac8c12aa46637f03 -ab2a104fed3c83d16f2cda06878fa5f30c8c9411de71bfb67fd2fc9aa454dcbcf3d299d72f8cc12e919466a50fcf7426 -a4471d111db4418f56915689482f6144efc4664cfb0311727f36c864648d35734351becc48875df96f4abd3cfcf820f9 -83be11727cd30ea94ccc8fa31b09b81c9d6a9a5d3a4686af9da99587332fe78c1f94282f9755854bafd6033549afec91 -88020ff971dc1a01a9e993cd50a5d2131ffdcbb990c1a6aaa54b20d8f23f9546a70918ea57a21530dcc440c1509c24ad -ae24547623465e87905eaffa1fa5d52bb7c453a8dbd89614fa8819a2abcedaf455c2345099b7324ae36eb0ad7c8ef977 -b59b0c60997de1ee00b7c388bc7101d136c9803bf5437b1d589ba57c213f4f835a3e4125b54738e78abbc21b000f2016 -a584c434dfe194546526691b68fa968c831c31da42303a1d735d960901c74011d522246f37f299555416b8cf25c5a548 -80408ce3724f4837d4d52376d255e10f69eb8558399ae5ca6c11b78b98fe67d4b93157d2b9b639f1b5b64198bfe87713 -abb941e8d406c2606e0ddc35c113604fdd9d249eacc51cb64e2991e551b8639ce44d288cc92afa7a1e7fc599cfc84b22 -b223173f560cacb1c21dba0f1713839e348ad02cbfdef0626748604c86f89e0f4c919ed40b583343795bdd519ba952c8 -af1c70512ec3a19d98b8a1fc3ff7f7f5048a27d17d438d43f561974bbdd116fcd5d5c21040f3447af3f0266848d47a15 -8a44809568ebe50405bede19b4d2607199159b26a1b33e03d180e6840c5cf59d991a4fb150d111443235d75ecad085b7 -b06207cdca46b125a27b3221b5b50cf27af4c527dd7c80e2dbcebbb09778a96df3af67e50f07725239ce3583dad60660 -993352d9278814ec89b26a11c4a7c4941bf8f0e6781ae79559d14749ee5def672259792db4587f85f0100c7bb812f933 -9180b8a718b971fd27bc82c8582d19c4b4f012453e8c0ffeeeffe745581fc6c07875ab28be3af3fa3896d19f0c89ac5b -8b8e1263eb48d0fe304032dd5ea1f30e73f0121265f7458ba9054d3626894e8a5fef665340abd2ede9653045c2665938 -99a2beee4a10b7941c24b2092192faf52b819afd033e4a2de050fd6c7f56d364d0cf5f99764c3357cf32399e60fc5d74 -946a4aad7f8647ea60bee2c5fcdeb6f9a58fb2cfca70c4d10e458027a04846e13798c66506151be3df9454b1e417893f -a672a88847652d260b5472d6908d1d57e200f1e492d30dd1cecc441cdfc9b76e016d9bab560efd4d7f3c30801de884a9 -9414e1959c156cde1eb24e628395744db75fc24b9df4595350aaad0bc38e0246c9b4148f6443ef68b8e253a4a6bcf11c -9316e9e4ec5fab4f80d6540df0e3a4774db52f1d759d2e5b5bcd3d7b53597bb007eb1887cb7dc61f62497d51ffc8d996 -902d6d77bb49492c7a00bc4b70277bc28c8bf9888f4307bb017ac75a962decdedf3a4e2cf6c1ea9f9ba551f4610cbbd7 -b07025a18b0e32dd5e12ec6a85781aa3554329ea12c4cd0d3b2c22e43d777ef6f89876dd90a9c8fb097ddf61cf18adc5 -b355a849ad3227caa4476759137e813505ec523cbc2d4105bc7148a4630f9e81918d110479a2d5f5e4cd9ccec9d9d3e3 -b49532cfdf02ee760109881ad030b89c48ee3bb7f219ccafc13c93aead754d29bdafe345be54c482e9d5672bd4505080 -9477802410e263e4f938d57fa8f2a6cac7754c5d38505b73ee35ea3f057aad958cb9722ba6b7b3cfc4524e9ca93f9cdc -9148ea83b4436339580f3dbc9ba51509e9ab13c03063587a57e125432dd0915f5d2a8f456a68f8fff57d5f08c8f34d6e -b00b6b5392b1930b54352c02b1b3b4f6186d20bf21698689bbfc7d13e86538a4397b90e9d5c93fd2054640c4dbe52a4f -926a9702500441243cd446e7cbf15dde16400259726794694b1d9a40263a9fc9e12f7bcbf12a27cb9aaba9e2d5848ddc -a0c6155f42686cbe7684a1dc327100962e13bafcf3db97971fc116d9f5c0c8355377e3d70979cdbd58fd3ea52440901c -a277f899f99edb8791889d0817ea6a96c24a61acfda3ad8c3379e7c62b9d4facc4b965020b588651672fd261a77f1bfc -8f528cebb866b501f91afa50e995234bef5bf20bff13005de99cb51eaac7b4f0bf38580cfd0470de40f577ead5d9ba0f -963fc03a44e9d502cc1d23250efef44d299befd03b898d07ce63ca607bb474b5cf7c965a7b9b0f32198b04a8393821f7 -ab087438d0a51078c378bf4a93bd48ef933ff0f1fa68d02d4460820df564e6642a663b5e50a5fe509527d55cb510ae04 -b0592e1f2c54746bb076be0fa480e1c4bebc4225e1236bcda3b299aa3853e3afb401233bdbcfc4a007b0523a720fbf62 -851613517966de76c1c55a94dc4595f299398a9808f2d2f0a84330ba657ab1f357701d0895f658c18a44cb00547f6f57 -a2fe9a1dd251e72b0fe4db27be508bb55208f8f1616b13d8be288363ec722826b1a1fd729fc561c3369bf13950bf1fd6 -b896cb2bc2d0c77739853bc59b0f89b2e008ba1f701c9cbe3bef035f499e1baee8f0ff1e794854a48c320586a2dfc81a -a1b60f98e5e5106785a9b81a85423452ee9ef980fa7fa8464f4366e73f89c50435a0c37b2906052b8e58e212ebd366cf -a853b0ebd9609656636df2e6acd5d8839c0fda56f7bf9288a943b06f0b67901a32b95e016ca8bc99bd7b5eab31347e72 -b290fa4c1346963bd5225235e6bdf7c542174dab4c908ab483d1745b9b3a6015525e398e1761c90e4b49968d05e30eea -b0f65a33ad18f154f1351f07879a183ad62e5144ad9f3241c2d06533dad09cbb2253949daff1bb02d24d16a3569f7ef0 -a00db59b8d4218faf5aeafcd39231027324408f208ec1f54d55a1c41228b463b88304d909d16b718cfc784213917b71e -b8d695dd33dc2c3bc73d98248c535b2770ad7fa31aa726f0aa4b3299efb0295ba9b4a51c71d314a4a1bd5872307534d1 -b848057cca2ca837ee49c42b88422303e58ea7d2fc76535260eb5bd609255e430514e927cc188324faa8e657396d63ec -92677836061364685c2aaf0313fa32322746074ed5666fd5f142a7e8f87135f45cd10e78a17557a4067a51dfde890371 -a854b22c9056a3a24ab164a53e5c5cf388616c33e67d8ebb4590cb16b2e7d88b54b1393c93760d154208b5ca822dc68f -86fff174920388bfab841118fb076b2b0cdec3fdb6c3d9a476262f82689fb0ed3f1897f7be9dbf0932bb14d346815c63 -99661cf4c94a74e182752bcc4b98a8c2218a8f2765642025048e12e88ba776f14f7be73a2d79bd21a61def757f47f904 -8a8893144d771dca28760cba0f950a5d634195fd401ec8cf1145146286caffb0b1a6ba0c4c1828d0a5480ce49073c64c -938a59ae761359ee2688571e7b7d54692848eb5dde57ffc572b473001ea199786886f8c6346a226209484afb61d2e526 -923f68a6aa6616714cf077cf548aeb845bfdd78f2f6851d8148cba9e33a374017f2f3da186c39b82d14785a093313222 -ac923a93d7da7013e73ce8b4a2b14b8fd0cc93dc29d5de941a70285bdd19be4740fedfe0c56b046689252a3696e9c5bc -b49b32c76d4ec1a2c68d4989285a920a805993bc6fcce6dacd3d2ddae73373050a5c44ba8422a3781050682fa0ef6ba2 -8a367941c07c3bdca5712524a1411bad7945c7c48ffc7103b1d4dff2c25751b0624219d1ccde8c3f70c465f954be5445 -b838f029df455efb6c530d0e370bbbf7d87d61a9aea3d2fe5474c5fe0a39cf235ceecf9693c5c6c5820b1ba8f820bd31 -a8983b7c715eaac7f13a001d2abc462dfc1559dab4a6b554119c271aa8fe00ffcf6b6949a1121f324d6d26cb877bcbae -a2afb24ad95a6f14a6796315fbe0d8d7700d08f0cfaf7a2abe841f5f18d4fecf094406cbd54da7232a159f9c5b6e805e -87e8e95ad2d62f947b2766ff405a23f7a8afba14e7f718a691d95369c79955cdebe24c54662553c60a3f55e6322c0f6f -87c2cbcecb754e0cc96128e707e5c5005c9de07ffd899efa3437cadc23362f5a1d3fcdd30a1f5bdc72af3fb594398c2a -91afd6ee04f0496dc633db88b9370d41c428b04fd991002502da2e9a0ef051bcd7b760e860829a44fbe5539fa65f8525 -8c50e5d1a24515a9dd624fe08b12223a75ca55196f769f24748686315329b337efadca1c63f88bee0ac292dd0a587440 -8a07e8f912a38d94309f317c32068e87f68f51bdfa082d96026f5f5f8a2211621f8a3856dda8069386bf15fb2d28c18f -94ad1dbe341c44eeaf4dc133eed47d8dbfe752575e836c075745770a6679ff1f0e7883b6aa917462993a7f469d74cab5 -8745f8bd86c2bb30efa7efb7725489f2654f3e1ac4ea95bd7ad0f3cfa223055d06c187a16192d9d7bdaea7b050c6a324 -900d149c8d79418cda5955974c450a70845e02e5a4ecbcc584a3ca64d237df73987c303e3eeb79da1af83bf62d9e579f -8f652ab565f677fb1a7ba03b08004e3cda06b86c6f1b0b9ab932e0834acf1370abb2914c15b0d08327b5504e5990681c -9103097d088be1f75ab9d3da879106c2f597e2cc91ec31e73430647bdd5c33bcfd771530d5521e7e14df6acda44f38a6 -b0fec7791cfb0f96e60601e1aeced9a92446b61fedab832539d1d1037558612d78419efa87ff5f6b7aab8fd697d4d9de -b9d2945bdb188b98958854ba287eb0480ef614199c4235ce5f15fc670b8c5ffe8eeb120c09c53ea8a543a022e6a321ac -a9461bb7d5490973ebaa51afc0bb4a5e42acdccb80e2f939e88b77ac28a98870e103e1042899750f8667a8cc9123bae9 -a37fdf11d4bcb2aed74b9f460a30aa34afea93386fa4cdb690f0a71bc58f0b8df60bec56e7a24f225978b862626fa00e -a214420e183e03d531cf91661466ea2187d84b6e814b8b20b3730a9400a7d25cf23181bb85589ebc982cec414f5c2923 -ad09a45a698a6beb3e0915f540ef16e9af7087f53328972532d6b5dfe98ce4020555ece65c6cbad8bd6be8a4dfefe6fd -ab6742800b02728c92d806976764cb027413d6f86edd08ad8bb5922a2969ee9836878cd39db70db0bd9a2646862acc4f -974ca9305bd5ea1dc1755dff3b63e8bfe9f744321046c1395659bcea2a987b528e64d5aa96ac7b015650b2253b37888d -84eee9d6bce039c52c2ebc4fccc0ad70e20c82f47c558098da4be2f386a493cbc76adc795b5488c8d11b6518c2c4fab8 -875d7bda46efcb63944e1ccf760a20144df3b00d53282b781e95f12bfc8f8316dfe6492c2efbf796f1150e36e436e9df -b68a2208e0c587b5c31b5f6cb32d3e6058a9642e2d9855da4f85566e1412db528475892060bb932c55b3a80877ad7b4a -ba006368ecab5febb6ab348644d9b63de202293085ed468df8bc24d992ae8ce468470aa37f36a73630c789fb9c819b30 -90a196035150846cd2b482c7b17027471372a8ce7d914c4d82b6ea7fa705d8ed5817bd42d63886242585baf7d1397a1c -a223b4c85e0daa8434b015fd9170b5561fe676664b67064974a1e9325066ecf88fc81f97ab5011c59fad28cedd04b240 -82e8ec43139cf15c6bbeed484b62e06cded8a39b5ce0389e4cbe9c9e9c02f2f0275d8d8d4e8dfec8f69a191bef220408 -81a3fc07a7b68d92c6ee4b6d28f5653ee9ec85f7e2ee1c51c075c1b130a8c5097dc661cf10c5aff1c7114b1a6a19f11a -8ed2ef8331546d98819a5dd0e6c9f8cb2630d0847671314a28f277faf68da080b53891dd75c82cbcf7788b255490785d -acecabf84a6f9bbed6b2fc2e7e4b48f02ef2f15e597538a73aea8f98addc6badda15e4695a67ecdb505c1554e8f345ec -b8f51019b2aa575f8476e03dcadf86cc8391f007e5f922c2a36b2daa63f5a503646a468990cd5c65148d323942193051 -aaa595a84b403ec65729bc1c8055a94f874bf9adddc6c507b3e1f24f79d3ad359595a672b93aab3394db4e2d4a7d8970 -895144c55fcbd0f64d7dd69e6855cfb956e02b5658eadf0f026a70703f3643037268fdd673b0d21b288578a83c6338dd -a2e92ae6d0d237d1274259a8f99d4ea4912a299816350b876fba5ebc60b714490e198a916e1c38c6e020a792496fa23c -a45795fda3b5bb0ad1d3c628f6add5b2a4473a1414c1a232e80e70d1cfffd7f8a8d9861f8df2946999d7dbb56bf60113 -b6659bf7f6f2fef61c39923e8c23b8c70e9c903028d8f62516d16755cd3fba2fe41c285aa9432dc75ab08f8a1d8a81fc -a735609a6bc5bfd85e58234fc439ff1f58f1ff1dd966c5921d8b649e21f006bf2b8642ad8a75063c159aaf6935789293 -a3c622eb387c9d15e7bda2e3e84d007cb13a6d50d655c3f2f289758e49d3b37b9a35e4535d3cc53d8efd51f407281f19 -8afe147b53ad99220f5ef9d763bfc91f9c20caecbcf823564236fb0e6ede49414c57d71eec4772c8715cc65a81af0047 -b5f0203233cf71913951e9c9c4e10d9243e3e4a1f2cb235bf3f42009120ba96e04aa414c9938ea8873b63148478927e8 -93c52493361b458d196172d7ba982a90a4f79f03aa8008edc322950de3ce6acf4c3977807a2ffa9e924047e02072b229 -b9e72b805c8ac56503f4a86c82720afbd5c73654408a22a2ac0b2e5caccdfb0e20b59807433a6233bc97ae58cf14c70a -af0475779b5cee278cca14c82da2a9f9c8ef222eb885e8c50cca2315fea420de6e04146590ed0dd5a29c0e0812964df5 -b430ccab85690db02c2d0eb610f3197884ca12bc5f23c51e282bf3a6aa7e4a79222c3d8761454caf55d6c01a327595f9 -830032937418b26ee6da9b5206f3e24dc76acd98589e37937e963a8333e5430abd6ce3dd93ef4b8997bd41440eed75d6 -8820a6d73180f3fe255199f3f175c5eb770461ad5cfdde2fb11508041ed19b8c4ce66ad6ecebf7d7e836cc2318df47ca -aef1393e7d97278e77bbf52ef6e1c1d5db721ccf75fe753cf47a881fa034ca61eaa5098ee5a344c156d2b14ff9e284ad -8a4a26c07218948c1196c45d927ef4d2c42ade5e29fe7a91eaebe34a29900072ce5194cf28d51f746f4c4c649daf4396 -84011dc150b7177abdcb715efbd8c201f9cb39c36e6069af5c50a096021768ba40cef45b659c70915af209f904ede3b6 -b1bd90675411389bb66910b21a4bbb50edce5330850c5ab0b682393950124252766fc81f5ecfc72fb7184387238c402e -8dfdcd30583b696d2c7744655f79809f451a60c9ad5bf1226dc078b19f4585d7b3ef7fa9d54e1ac09520d95cbfd20928 -b351b4dc6d98f75b8e5a48eb7c6f6e4b78451991c9ba630e5a1b9874c15ac450cd409c1a024713bf2cf82dc400e025ef -a462b8bc97ac668b97b28b3ae24b9f5de60e098d7b23ecb600d2194cd35827fb79f77c3e50d358f5bd72ee83fef18fa0 -a183753265c5f7890270821880cce5f9b2965b115ba783c6dba9769536f57a04465d7da5049c7cf8b3fcf48146173c18 -a8a771b81ed0d09e0da4d79f990e58eabcd2be3a2680419502dd592783fe52f657fe55125b385c41d0ba3b9b9cf54a83 -a71ec577db46011689d073245e3b1c3222a9b1fe6aa5b83629adec5733dd48617ebea91346f0dd0e6cdaa86e4931b168 -a334b8b244f0d598a02da6ae0f918a7857a54dce928376c4c85df15f3b0f2ba3ac321296b8b7c9dd47d770daf16c8f8c -a29037f8ef925c417c90c4df4f9fb27fb977d04e2b3dd5e8547d33e92ab72e7a00f5461de21e28835319eae5db145eb7 -b91054108ae78b00e3298d667b913ebc44d8f26e531eae78a8fe26fdfb60271c97efb2dee5f47ef5a3c15c8228138927 -926c13efbe90604f6244be9315a34f72a1f8d1aab7572df431998949c378cddbf2fe393502c930fff614ff06ae98a0ce -995c758fd5600e6537089b1baa4fbe0376ab274ff3e82a17768b40df6f91c2e443411de9cafa1e65ea88fb8b87d504f4 -9245ba307a7a90847da75fca8d77ec03fdfc812c871e7a2529c56a0a79a6de16084258e7a9ac4ae8a3756f394336e21c -99e0cfa2bb57a7e624231317044c15e52196ecce020db567c8e8cb960354a0be9862ee0c128c60b44777e65ac315e59f -ad4f6b3d27bbbb744126601053c3dc98c07ff0eb0b38a898bd80dce778372846d67e5ab8fb34fb3ad0ef3f235d77ba7f -a0f12cae3722bbbca2e539eb9cc7614632a2aefe51410430070a12b5bc5314ecec5857b7ff8f41e9980cac23064f7c56 -b487f1bc59485848c98222fd3bc36c8c9bb3d2912e2911f4ceca32c840a7921477f9b1fe00877e05c96c75d3eecae061 -a6033db53925654e18ecb3ce715715c36165d7035db9397087ac3a0585e587998a53973d011ac6d48af439493029cee6 -a6b4d09cd01c70a3311fd131d3710ccf97bde3e7b80efd5a8c0eaeffeb48cca0f951ced905290267b115b06d46f2693b -a9dff1df0a8f4f218a98b6f818a693fb0d611fed0fc3143537cbd6578d479af13a653a8155e535548a2a0628ae24fa58 -a58e469f65d366b519f9a394cacb7edaddac214463b7b6d62c2dbc1316e11c6c5184ce45c16de2d77f990dcdd8b55430 -989e71734f8119103586dc9a3c5f5033ddc815a21018b34c1f876cdfc112efa868d5751bf6419323e4e59fa6a03ece1c -a2da00e05036c884369e04cf55f3de7d659cd5fa3f849092b2519dd263694efe0f051953d9d94b7e121f0aee8b6174d7 -968f3c029f57ee31c4e1adea89a7f92e28483af9a74f30fbdb995dc2d40e8e657dff8f8d340d4a92bf65f54440f2859f -932778df6f60ac1639c1453ef0cbd2bf67592759dcccb3e96dcc743ff01679e4c7dd0ef2b0833dda548d32cb4eba49e2 -a805a31139f8e0d6dae1ac87d454b23a3dc9fc653d4ca18d4f8ebab30fc189c16e73981c2cb7dd6f8c30454a5208109d -a9ba0991296caa2aaa4a1ceacfb205544c2a2ec97088eace1d84ee5e2767656a172f75d2f0c4e16a3640a0e0dec316e0 -b1e49055c968dced47ec95ae934cf45023836d180702e20e2df57e0f62fb85d7ac60d657ba3ae13b8560b67210449459 -a94e1da570a38809c71e37571066acabff7bf5632737c9ab6e4a32856924bf6211139ab3cedbf083850ff2d0e0c0fcfc -88ef1bb322000c5a5515b310c838c9af4c1cdbb32eab1c83ac3b2283191cd40e9573747d663763a28dad0d64adc13840 -a987ce205f923100df0fbd5a85f22c9b99b9b9cbe6ddfa8dfda1b8fe95b4f71ff01d6c5b64ca02eb24edb2b255a14ef0 -84fe8221a9e95d9178359918a108de4763ebfa7a6487facb9c963406882a08a9a93f492f8e77cf9e7ea41ae079c45993 -aa1cf3dc7c5dcfa15bbbc811a4bb6dbac4fba4f97fb1ed344ab60264d7051f6eef19ea9773441d89929ee942ed089319 -8f6a7d610d59d9f54689bbe6a41f92d9f6096cde919c1ab94c3c7fcecf0851423bc191e5612349e10f855121c0570f56 -b5af1fa7894428a53ea520f260f3dc3726da245026b6d5d240625380bfb9c7c186df0204bb604efac5e613a70af5106e -a5bce6055ff812e72ce105f147147c7d48d7a2313884dd1f488b1240ee320f13e8a33f5441953a8e7a3209f65b673ce1 -b9b55b4a1422677d95821e1d042ab81bbf0bf087496504021ec2e17e238c2ca6b44fb3b635a5c9eac0871a724b8d47c3 -941c38e533ce4a673a3830845b56786585e5fe49c427f2e5c279fc6db08530c8f91db3e6c7822ec6bb4f956940052d18 -a38e191d66c625f975313c7007bbe7431b5a06ed2da1290a7d5d0f2ec73770d476efd07b8e632de64597d47df175cbb0 -94ba76b667abf055621db4c4145d18743a368d951565632ed4e743dd50dd3333507c0c34f286a5c5fdbf38191a2255cd -a5ca38c60be5602f2bfa6e00c687ac96ac36d517145018ddbee6f12eb0faa63dd57909b9eeed26085fe5ac44e55d10ab -b00fea3b825e60c1ed1c5deb4b551aa65a340e5af36b17d5262c9cd2c508711e4dc50dc2521a2c16c7c901902266e64a -971b86fc4033485e235ccb0997a236206ba25c6859075edbcdf3c943116a5030b7f75ebca9753d863a522ba21a215a90 -b3b31f52370de246ee215400975b674f6da39b2f32514fe6bd54e747752eedca22bb840493b44a67df42a3639c5f901f -affbbfac9c1ba7cbfa1839d2ae271dd6149869b75790bf103230637da41857fc326ef3552ff31c15bda0694080198143 -a95d42aa7ef1962520845aa3688f2752d291926f7b0d73ea2ee24f0612c03b43f2b0fe3c9a9a99620ffc8d487b981bc2 -914a266065caf64985e8c5b1cb2e3f4e3fe94d7d085a1881b1fefa435afef4e1b39a98551d096a62e4f5cc1a7f0fdc2e -81a0b4a96e2b75bc1bf2dbd165d58d55cfd259000a35504d1ffb18bc346a3e6f07602c683723864ffb980f840836fd8d -91c1556631cddd4c00b65b67962b39e4a33429029d311c8acf73a18600e362304fb68bccb56fde40f49e95b7829e0b87 -8befbacc19e57f7c885d1b7a6028359eb3d80792fe13b92a8400df21ce48deb0bb60f2ddb50e3d74f39f85d7eab23adc -92f9458d674df6e990789690ec9ca73dacb67fc9255b58c417c555a8cc1208ace56e8e538f86ba0f3615573a0fbac00d -b4b1b3062512d6ae7417850c08c13f707d5838e43d48eb98dd4621baf62eee9e82348f80fe9b888a12874bfa538771f8 -a13c4a3ac642ede37d9c883f5319e748d2b938f708c9d779714108a449b343f7b71a6e3ef4080fee125b416762920273 -af44983d5fc8cceee0551ef934e6e653f2d3efa385e5c8a27a272463a6f333e290378cc307c2b664eb923c78994e706e -a389fd6c59fe2b4031cc244e22d3991e541bd203dd5b5e73a6159e72df1ab41d49994961500dcde7989e945213184778 -8d2141e4a17836c548de9598d7b298b03f0e6c73b7364979a411c464e0628e21cff6ac3d6decdba5d1c4909eff479761 -980b22ef53b7bdf188a3f14bc51b0dbfdf9c758826daa3cbc1e3986022406a8aa9a6a79e400567120b88c67faa35ce5f -a28882f0a055f96df3711de5d0aa69473e71245f4f3e9aa944e9d1fb166e02caa50832e46da6d3a03b4801735fd01b29 -8db106a37d7b88f5d995c126abb563934dd8de516af48e85695d02b1aea07f79217e3cdd03c6f5ca57421830186c772b -b5a7e50da0559a675c472f7dfaee456caab6695ab7870541b2be8c2b118c63752427184aad81f0e1afc61aef1f28c46f -9962118780e20fe291d10b64f28d09442a8e1b5cffd0f3dd68d980d0614050a626c616b44e9807fbee7accecae00686a -b38ddf33745e8d2ad6a991aefaf656a33c5f8cbe5d5b6b6fd03bd962153d8fd0e01b5f8f96d80ae53ab28d593ab1d4e7 -857dc12c0544ff2c0c703761d901aba636415dee45618aba2e3454ff9cbc634a85c8b05565e88520ff9be2d097c8b2b1 -a80d465c3f8cc63af6d74a6a5086b626c1cb4a8c0fee425964c3bd203d9d7094e299f81ce96d58afc20c8c9a029d9dae -89e1c8fbde8563763be483123a3ed702efac189c6d8ab4d16c85e74bbaf856048cc42d5d6e138633a38572ba5ec3f594 -893a594cf495535f6d216508f8d03c317dcf03446668cba688da90f52d0111ac83d76ad09bf5ea47056846585ee5c791 -aadbd8be0ae452f7f9450c7d2957598a20cbf10139a4023a78b4438172d62b18b0de39754dd2f8862dbd50a3a0815e53 -ae7d39670ecca3eb6db2095da2517a581b0e8853bdfef619b1fad9aacd443e7e6a40f18209fadd44038a55085c5fe8b2 -866ef241520eacb6331593cfcb206f7409d2f33d04542e6e52cba5447934e02d44c471f6c9a45963f9307e9809ab91d9 -b1a09911ad3864678f7be79a9c3c3eb5c84a0a45f8dcb52c67148f43439aeaaa9fd3ed3471276b7e588b49d6ebe3033a -add07b7f0dbb34049cd8feeb3c18da5944bf706871cfd9f14ff72f6c59ad217ebb1f0258b13b167851929387e4e34cfe -ae048892d5c328eefbdd4fba67d95901e3c14d974bfc0a1fc68155ca9f0d59e61d7ba17c6c9948b120cf35fd26e6fee9 -9185b4f3b7da0ddb4e0d0f09b8a9e0d6943a4611e43f13c3e2a767ed8592d31e0ba3ebe1914026a3627680274291f6e5 -a9c022d4e37b0802284ce3b7ee9258628ab4044f0db4de53d1c3efba9de19d15d65cc5e608dbe149c21c2af47d0b07b5 -b24dbd5852f8f24921a4e27013b6c3fa8885b973266cb839b9c388efad95821d5d746348179dcc07542bd0d0aefad1ce -b5fb4f279300876a539a27a441348764908bc0051ebd66dc51739807305e73db3d2f6f0f294ffb91b508ab150eaf8527 -ace50841e718265b290c3483ed4b0fdd1175338c5f1f7530ae9a0e75d5f80216f4de37536adcbc8d8c95982e88808cd0 -b19cadcde0f63bd1a9c24bd9c2806f53c14c0b9735bf351601498408ba503ddbd2037c891041cbba47f58b8c483f3b21 -b6061e63558d312eb891b97b39aa552fa218568d79ee26fe6dd5b864aea9e3216d8f2e2f3b093503be274766dac41426 -89730fdb2876ab6f0fe780d695f6e12090259027e789b819956d786e977518057e5d1d7f5ab24a3ae3d5d4c97773bd2b -b6fa841e81f9f2cad0163a02a63ae96dc341f7ae803b616efc6e1da2fbea551c1b96b11ad02c4afbdf6d0cc9f23da172 -8fb66187182629c861ddb6896d7ed3caf2ad050c3dba8ab8eb0d7a2c924c3d44c48d1a148f9e33fb1f061b86972f8d21 -86022ac339c1f84a7fa9e05358c1a5b316b4fc0b83dbe9c8c7225dc514f709d66490b539359b084ce776e301024345fa -b50b9c321468da950f01480bb62b6edafd42f83c0001d6e97f2bd523a1c49a0e8574fb66380ea28d23a7c4d54784f9f0 -a31c05f7032f30d1dac06678be64d0250a071fd655e557400e4a7f4c152be4d5c7aa32529baf3e5be7c4bd49820054f6 -b95ac0848cd322684772119f5b682d90a66bbf9dac411d9d86d2c34844bbd944dbaf8e47aa41380455abd51687931a78 -ae4a6a5ce9553b65a05f7935e61e496a4a0f6fd8203367a2c627394c9ce1e280750297b74cdc48fd1d9a31e93f97bef4 -a22daf35f6e9b05e52e0b07f7bd1dbbebd2c263033fb0e1b2c804e2d964e2f11bc0ece6aca6af079dd3a9939c9c80674 -902150e0cb1f16b9b59690db35281e28998ce275acb313900da8b2d8dfd29fa1795f8ca3ff820c31d0697de29df347c1 -b17b5104a5dc665cdd7d47e476153d715eb78c6e5199303e4b5445c21a7fa7cf85fe7cfd08d7570f4e84e579b005428c -a03f49b81c15433f121680aa02d734bb9e363af2156654a62bcb5b2ba2218398ccb0ff61104ea5d7df5b16ea18623b1e -802101abd5d3c88876e75a27ffc2f9ddcce75e6b24f23dba03e5201281a7bd5cc7530b6a003be92d225093ca17d3c3bb -a4d183f63c1b4521a6b52226fc19106158fc8ea402461a5cccdaa35fee93669df6a8661f45c1750cd01308149b7bf08e -8d17c22e0c8403b69736364d460b3014775c591032604413d20a5096a94d4030d7c50b9fe3240e31d0311efcf9816a47 -947225acfcce5992eab96276f668c3cbe5f298b90a59f2bb213be9997d8850919e8f496f182689b5cbd54084a7332482 -8df6f4ed216fc8d1905e06163ba1c90d336ab991a18564b0169623eb39b84e627fa267397da15d3ed754d1f3423bff07 -83480007a88f1a36dea464c32b849a3a999316044f12281e2e1c25f07d495f9b1710b4ba0d88e9560e72433addd50bc2 -b3019d6e591cf5b33eb972e49e06c6d0a82a73a75d78d383dd6f6a4269838289e6e07c245f54fed67f5c9bb0fd5e1c5f -92e8ce05e94927a9fb02debadb99cf30a26172b2705003a2c0c47b3d8002bf1060edb0f6a5750aad827c98a656b19199 -ac2aff801448dbbfc13cca7d603fd9c69e82100d997faf11f465323b97255504f10c0c77401e4d1890339d8b224f5803 -b0453d9903d08f508ee27e577445dc098baed6cde0ac984b42e0f0efed62760bd58d5816cf1e109d204607b7b175e30c -ae68dc4ba5067e825d46d2c7c67f1009ceb49d68e8d3e4c57f4bcd299eb2de3575d42ea45e8722f8f28497a6e14a1cfe -b22486c2f5b51d72335ce819bbafb7fa25eb1c28a378a658f13f9fc79cd20083a7e573248d911231b45a5cf23b561ca7 -89d1201d1dbd6921867341471488b4d2fd0fc773ae1d4d074c78ae2eb779a59b64c00452c2a0255826fca6b3d03be2b1 -a2998977c91c7a53dc6104f5bc0a5b675e5350f835e2f0af69825db8af4aeb68435bdbcc795f3dd1f55e1dd50bc0507f -b0be4937a925b3c05056ed621910d535ccabf5ab99fd3b9335080b0e51d9607d0fd36cb5781ff340018f6acfca4a9736 -aea145a0f6e0ba9df8e52e84bb9c9de2c2dc822f70d2724029b153eb68ee9c17de7d35063dcd6a39c37c59fdd12138f7 -91cb4545d7165ee8ffbc74c874baceca11fdebbc7387908d1a25877ca3c57f2c5def424dab24148826832f1e880bede0 -b3b579cb77573f19c571ad5eeeb21f65548d7dff9d298b8d7418c11f3e8cd3727c5b467f013cb87d6861cfaceee0d2e3 -b98a1eeec2b19fecc8378c876d73645aa52fb99e4819903735b2c7a885b242787a30d1269a04bfb8573d72d9bbc5f0f0 -940c1f01ed362bd588b950c27f8cc1d52276c71bb153d47f07ec85b038c11d9a8424b7904f424423e714454d5e80d1cd -aa343a8ecf09ce11599b8cf22f7279cf80f06dbf9f6d62cb05308dbbb39c46fd0a4a1240b032665fbb488a767379b91b -87c3ac72084aca5974599d3232e11d416348719e08443acaba2b328923af945031f86432e170dcdd103774ec92e988c9 -91d6486eb5e61d2b9a9e742c20ec974a47627c6096b3da56209c2b4e4757f007e793ebb63b2b246857c9839b64dc0233 -aebcd3257d295747dd6fc4ff910d839dd80c51c173ae59b8b2ec937747c2072fa85e3017f9060aa509af88dfc7529481 -b3075ba6668ca04eff19efbfa3356b92f0ab12632dcda99cf8c655f35b7928c304218e0f9799d68ef9f809a1492ff7db -93ba7468bb325639ec2abd4d55179c69fd04eaaf39fc5340709227bbaa4ad0a54ea8b480a1a3c8d44684e3be0f8d1980 -a6aef86c8c0d92839f38544d91b767c582568b391071228ff5a5a6b859c87bf4f81a7d926094a4ada1993ddbd677a920 -91dcd6d14207aa569194aa224d1e5037b999b69ade52843315ca61ba26abe9a76412c9e88259bc5cf5d7b95b97d9c3bc -b3b483d31c88f78d49bd065893bc1e3d2aa637e27dedb46d9a7d60be7660ce7a10aaaa7deead362284a52e6d14021178 -8e5730070acf8371461ef301cc4523e8e672aa0e3d945d438a0e0aa6bdf8cb9c685dcf38df429037b0c8aff3955c6f5b -b8c6d769890a8ee18dc4f9e917993315877c97549549b34785a92543cbeec96a08ae3a28d6e809c4aacd69de356c0012 -95ca86cd384eaceaa7c077c5615736ca31f36824bd6451a16142a1edc129fa42b50724aeed7c738f08d7b157f78b569e -94df609c6d71e8eee7ab74226e371ccc77e01738fe0ef1a6424435b4570fe1e5d15797b66ed0f64eb88d4a3a37631f0e -89057b9783212add6a0690d6bb99097b182738deff2bd9e147d7fd7d6c8eacb4c219923633e6309ad993c24572289901 -83a0f9f5f265c5a0e54defa87128240235e24498f20965009fef664f505a360b6fb4020f2742565dfc7746eb185bcec0 -91170da5306128931349bc3ed50d7df0e48a68b8cc8420975170723ac79d8773e4fa13c5f14dc6e3fafcad78379050b1 -b7178484d1b55f7e56a4cc250b6b2ec6040437d96bdfddfa7b35ed27435860f3855c2eb86c636f2911b012eb83b00db8 -ac0b00c4322d1e4208e09cd977b4e54d221133ff09551f75b32b0b55d0e2be80941dda26257b0e288c162e63c7e9cf68 -9690ed9e7e53ed37ff362930e4096b878b12234c332fd19d5d064824084245952eda9f979e0098110d6963e468cf513e -b6fa547bb0bb83e5c5be0ed462a8783fba119041c136a250045c09d0d2af330c604331e7de960df976ff76d67f8000cd -814603907c21463bcf4e59cfb43066dfe1a50344ae04ef03c87c0f61b30836c3f4dea0851d6fa358c620045b7f9214c8 -9495639e3939fad2a3df00a88603a5a180f3c3a0fe4d424c35060e2043e0921788003689887b1ed5be424d9a89bb18bb -aba4c02d8d57f2c92d5bc765885849e9ff8393d6554f5e5f3e907e5bfac041193a0d8716d7861104a4295d5a03c36b03 -8ead0b56c1ca49723f94a998ba113b9058059321da72d9e395a667e6a63d5a9dac0f5717cec343f021695e8ced1f72af -b43037f7e3852c34ed918c5854cd74e9d5799eeddfe457d4f93bb494801a064735e326a76e1f5e50a339844a2f4a8ec9 -99db8422bb7302199eb0ff3c3d08821f8c32f53a600c5b6fb43e41205d96adae72be5b460773d1280ad1acb806af9be8 -8a9be08eae0086c0f020838925984df345c5512ff32e37120b644512b1d9d4fecf0fd30639ca90fc6cf334a86770d536 -81b43614f1c28aa3713a309a88a782fb2bdfc4261dd52ddc204687791a40cf5fd6a263a8179388596582cccf0162efc2 -a9f3a8b76912deb61d966c75daf5ddb868702ebec91bd4033471c8e533183df548742a81a2671de5be63a502d827437d -902e2415077f063e638207dc7e14109652e42ab47caccd6204e2870115791c9defac5425fd360b37ac0f7bd8fe7011f8 -aa18e4fdc1381b59c18503ae6f6f2d6943445bd00dd7d4a2ad7e5adad7027f2263832690be30d456e6d772ad76f22350 -a348b40ba3ba7d81c5d4631f038186ebd5e5f314f1ea737259151b07c3cc8cf0c6ed4201e71bcc1c22fefda81a20cde6 -aa1306f7ac1acbfc47dc6f7a0cb6d03786cec8c8dc8060388ccda777bca24bdc634d03e53512c23dba79709ff64f8620 -818ccfe46e700567b7f3eb400e5a35f6a5e39b3db3aa8bc07f58ace35d9ae5a242faf8dbccd08d9a9175bbce15612155 -b7e3da2282b65dc8333592bb345a473f03bd6df69170055fec60222de9897184536bf22b9388b08160321144d0940279 -a4d976be0f0568f4e57de1460a1729129252b44c552a69fceec44e5b97c96c711763360d11f9e5bf6d86b4976bf40d69 -85d185f0397c24c2b875b09b6328a23b87982b84ee880f2677a22ff4c9a1ba9f0fea000bb3f7f66375a00d98ebafce17 -b4ccbb8c3a2606bd9b87ce022704663af71d418351575f3b350d294f4efc68c26f9a2ce49ff81e6ff29c3b63d746294e -93ffd3265fddb63724dfde261d1f9e22f15ecf39df28e4d89e9fea03221e8e88b5dd9b77628bacaa783c6f91802d47cc -b1fd0f8d7a01378e693da98d03a2d2fda6b099d03454b6f2b1fa6472ff6bb092751ce6290059826b74ac0361eab00e1e -a89f440c71c561641589796994dd2769616b9088766e983c873fae0716b95c386c8483ab8a4f367b6a68b72b7456dd32 -af4fe92b01d42d03dd5d1e7fa55e96d4bbcb7bf7d4c8c197acd16b3e0f3455807199f683dcd263d74547ef9c244b35cc -a8227f6e0a344dfe76bfbe7a1861be32c4f4bed587ccce09f9ce2cf481b2dda8ae4f566154bc663d15f962f2d41761bd -a7b361663f7495939ed7f518ba45ea9ff576c4e628995b7aea026480c17a71d63fc2c922319f0502eb7ef8f14a406882 -8ddcf382a9f39f75777160967c07012cfa89e67b19714a7191f0c68eaf263935e5504e1104aaabd0899348c972a8d3c6 -98c95b9f6f5c91f805fb185eedd06c6fc4457d37dd248d0be45a6a168a70031715165ea20606245cbdf8815dc0ac697f -805b44f96e001e5909834f70c09be3efcd3b43632bcac5b6b66b6d227a03a758e4b1768ce2a723045681a1d34562aaeb -b0e81b07cdc45b3dca60882676d9badb99f25c461b7efe56e3043b80100bb62d29e1873ae25eb83087273160ece72a55 -b0c53f0abe78ee86c7b78c82ae1f7c070bb0b9c45c563a8b3baa2c515d482d7507bb80771e60b38ac13f78b8af92b4a9 -a7838ef6696a9e4d2e5dfd581f6c8d6a700467e8fd4e85adabb5f7a56f514785dd4ab64f6f1b48366f7d94728359441b -88c76f7700a1d23c30366a1d8612a796da57b2500f97f88fdf2d76b045a9d24e7426a8ffa2f4e86d3046937a841dad58 -ad8964baf98c1f02e088d1d9fcb3af6b1dfa44cdfe0ed2eae684e7187c33d3a3c28c38e8f4e015f9c04d451ed6f85ff6 -90e9d00a098317ececaa9574da91fc149eda5b772dedb3e5a39636da6603aa007804fa86358550cfeff9be5a2cb7845e -a56ff4ddd73d9a6f5ab23bb77efa25977917df63571b269f6a999e1ad6681a88387fcc4ca3b26d57badf91b236503a29 -97ad839a6302c410a47e245df84c01fb9c4dfef86751af3f9340e86ff8fc3cd52fa5ff0b9a0bd1d9f453e02ca80658a6 -a4c8c44cbffa804129e123474854645107d1f0f463c45c30fd168848ebea94880f7c0c5a45183e9eb837f346270bdb35 -a72e53d0a1586d736e86427a93569f52edd2f42b01e78aee7e1961c2b63522423877ae3ac1227a2cf1e69f8e1ff15bc3 -8559f88a7ef13b4f09ac82ae458bbae6ab25671cfbf52dae7eac7280d6565dd3f0c3286aec1a56a8a16dc3b61d78ce47 -8221503f4cdbed550876c5dc118a3f2f17800c04e8be000266633c83777b039a432d576f3a36c8a01e8fd18289ebc10b -99bfbe5f3e46d4d898a578ba86ed26de7ed23914bd3bcdf3c791c0bcd49398a52419077354a5ab75cea63b6c871c6e96 -aa134416d8ff46f2acd866c1074af67566cfcf4e8be8d97329dfa0f603e1ff208488831ce5948ac8d75bfcba058ddcaa -b02609d65ebfe1fe8e52f21224a022ea4b5ea8c1bd6e7b9792eed8975fc387cdf9e3b419b8dd5bcce80703ab3a12a45f -a4f14798508698fa3852e5cac42a9db9797ecee7672a54988aa74037d334819aa7b2ac7b14efea6b81c509134a6b7ad2 -884f01afecbcb987cb3e7c489c43155c416ed41340f61ecb651d8cba884fb9274f6d9e7e4a46dd220253ae561614e44c -a05523c9e71dce1fe5307cc71bd721feb3e1a0f57a7d17c7d1c9fb080d44527b7dbaa1f817b1af1c0b4322e37bc4bb1e -8560aec176a4242b39f39433dd5a02d554248c9e49d3179530815f5031fee78ba9c71a35ceeb2b9d1f04c3617c13d8f0 -996aefd402748d8472477cae76d5a2b92e3f092fc834d5222ae50194dd884c9fb8b6ed8e5ccf8f6ed483ddbb4e80c747 -8fd09900320000cbabc40e16893e2fcf08815d288ec19345ad7b6bb22f7d78a52b6575a3ca1ca2f8bc252d2eafc928ec -939e51f73022bc5dc6862a0adf8fb8a3246b7bfb9943cbb4b27c73743926cc20f615a036c7e5b90c80840e7f1bfee0e7 -a0a6258700cadbb9e241f50766573bf9bdb7ad380b1079dc3afb4054363d838e177b869cad000314186936e40359b1f2 -972699a4131c8ed27a2d0e2104d54a65a7ff1c450ad9da3a325c662ab26869c21b0a84d0700b98c8b5f6ce3b746873d7 -a454c7fe870cb8aa6491eafbfb5f7872d6e696033f92e4991d057b59d70671f2acdabef533e229878b60c7fff8f748b1 -a167969477214201f09c79027b10221e4707662e0c0fde81a0f628249f2f8a859ce3d30a7dcc03b8ecca8f7828ad85c7 -8ff6b7265175beb8a63e1dbf18c9153fb2578c207c781282374f51b40d57a84fd2ef2ea2b9c6df4a54646788a62fd17f -a3d7ebeccde69d73d8b3e76af0da1a30884bb59729503ff0fb0c3bccf9221651b974a6e72ea33b7956fc3ae758226495 -b71ef144c9a98ce5935620cb86c1590bd4f48e5a2815d25c0cdb008fde628cf628c31450d3d4f67abbfeb16178a74cfd -b5e0a16d115134f4e2503990e3f2035ed66b9ccf767063fe6747870d97d73b10bc76ed668550cb82eedc9a2ca6f75524 -b30ffaaf94ee8cbc42aa2c413175b68afdb207dbf351fb20be3852cb7961b635c22838da97eaf43b103aff37e9e725cc -98aa7d52284f6c1f22e272fbddd8c8698cf8f5fbb702d5de96452141fafb559622815981e50b87a72c2b1190f59a7deb -81fbacda3905cfaf7780bb4850730c44166ed26a7c8d07197a5d4dcd969c09e94a0461638431476c16397dd7bdc449f9 -95e47021c1726eac2e5853f570d6225332c6e48e04c9738690d53e07c6b979283ebae31e2af1fc9c9b3e59f87e5195b1 -ac024a661ba568426bb8fce21780406537f518075c066276197300841e811860696f7588188bc01d90bace7bc73d56e3 -a4ebcaf668a888dd404988ab978594dee193dad2d0aec5cdc0ccaf4ec9a7a8228aa663db1da8ddc52ec8472178e40c32 -a20421b8eaf2199d93b083f2aff37fb662670bd18689d046ae976d1db1fedd2c2ff897985ecc6277b396db7da68bcb27 -8bc33d4b40197fd4d49d1de47489d10b90d9b346828f53a82256f3e9212b0cbc6930b895e879da9cec9fedf026aadb3e -aaafdd1bec8b757f55a0433eddc0a39f818591954fd4e982003437fcceb317423ad7ee74dbf17a2960380e7067a6b4e2 -aad34277ebaed81a6ec154d16736866f95832803af28aa5625bf0461a71d02b1faba02d9d9e002be51c8356425a56867 -976e9c8b150d08706079945bd0e84ab09a648ecc6f64ded9eb5329e57213149ae409ae93e8fbd8eda5b5c69f5212b883 -8097fae1653247d2aed4111533bc378171d6b2c6d09cbc7baa9b52f188d150d645941f46d19f7f5e27b7f073c1ebd079 -83905f93b250d3184eaba8ea7d727c4464b6bdb027e5cbe4f597d8b9dc741dcbea709630bd4fd59ce24023bec32fc0f3 -8095030b7045cff28f34271386e4752f9a9a0312f8df75de4f424366d78534be2b8e1720a19cb1f9a2d21105d790a225 -a7b7b73a6ae2ed1009c49960374b0790f93c74ee03b917642f33420498c188a169724945a975e5adec0a1e83e07fb1b2 -856a41c54df393b6660b7f6354572a4e71c8bfca9cabaffb3d4ef2632c015e7ee2bc10056f3eccb3dbed1ad17d939178 -a8f7a55cf04b38cd4e330394ee6589da3a07dc9673f74804fdf67b364e0b233f14aec42e783200a2e4666f7c5ff62490 -82c529f4e543c6bca60016dc93232c115b359eaee2798a9cf669a654b800aafe6ab4ba58ea8b9cdda2b371c8d62fa845 -8caab020c1baddce77a6794113ef1dfeafc5f5000f48e97f4351b588bf02f1f208101745463c480d37f588d5887e6d8c -8fa91b3cc400f48b77b6fd77f3b3fbfb3f10cdff408e1fd22d38f77e087b7683adad258804409ba099f1235b4b4d6fea -8aa02787663d6be9a35677d9d8188b725d5fcd770e61b11b64e3def8808ea5c71c0a9afd7f6630c48634546088fcd8e2 -b5635b7b972e195cab878b97dea62237c7f77eb57298538582a330b1082f6207a359f2923864630136d8b1f27c41b9aa -8257bb14583551a65975946980c714ecd6e5b629672bb950b9caacd886fbd22704bc9e3ba7d30778adab65dc74f0203a -ab5fe1cd12634bfa4e5c60d946e2005cbd38f1063ec9a5668994a2463c02449a0a185ef331bd86b68b6e23a8780cb3ba -a7d3487da56cda93570cc70215d438204f6a2709bfb5fda6c5df1e77e2efc80f4235c787e57fbf2c74aaff8cbb510a14 -b61cff7b4c49d010e133319fb828eb900f8a7e55114fc86b39c261a339c74f630e1a7d7e1350244ada566a0ff3d46c4b -8d4d1d55d321d278db7a85522ccceca09510374ca81d4d73e3bb5249ace7674b73900c35a531ec4fa6448fabf7ad00dc -966492248aee24f0f56c8cfca3c8ec6ba3b19abb69ae642041d4c3be8523d22c65c4dafcab4c58989ccc4e0bd2f77919 -b20c320a90cb220b86e1af651cdc1e21315cd215da69f6787e28157172f93fc8285dcd59b039c626ed8ca4633cba1a47 -aae9e6b22f018ceb5c0950210bb8182cb8cb61014b7e14581a09d36ebd1bbfebdb2b82afb7fdb0cf75e58a293d9c456d -875547fb67951ad37b02466b79f0c9b985ccbc500cfb431b17823457dc79fb9597ec42cd9f198e15523fcd88652e63a4 -92afce49773cb2e20fb21e4f86f18e0959ebb9c33361547ddb30454ee8e36b1e234019cbdca0e964cb292f7f77df6b90 -8af85343dfe1821464c76ba11c216cbef697b5afc69c4d821342e55afdac047081ec2e3f7b09fc14b518d9a23b78c003 -b7de4a1648fd63f3a918096ea669502af5357438e69dac77cb8102b6e6c15c76e033cfaa80dafc806e535ede5c1a20aa -ac80e9b545e8bd762951d96c9ce87f629d01ffcde07efc2ef7879ca011f1d0d8a745abf26c9d452541008871304fac00 -a4cf0f7ed724e481368016c38ea5816698a5f68eb21af4d3c422d2ba55f96a33e427c2aa40de1b56a7cfac7f7cf43ab0 -899b0a678bb2db2cae1b44e75a661284844ebcdd87abf308fedeb2e4dbe5c5920c07db4db7284a7af806a2382e8b111a -af0588a2a4afce2b1b13c1230816f59e8264177e774e4a341b289a101dcf6af813638fed14fb4d09cb45f35d5d032609 -a4b8df79e2be76e9f5fc5845f06fe745a724cf37c82fcdb72719b77bdebea3c0e763f37909373e3a94480cc5e875cba0 -83e42c46d88930c8f386b19fd999288f142d325e2ebc86a74907d6d77112cb0d449bc511c95422cc810574031a8cbba9 -b5e39534070de1e5f6e27efbdd3dc917d966c2a9b8cf2d893f964256e95e954330f2442027dc148c776d63a95bcde955 -958607569dc28c075e658cd4ae3927055c6bc456eef6212a6fea8205e48ed8777a8064f584cda38fe5639c371e2e7fba -812adf409fa63575113662966f5078a903212ffb65c9b0bbe62da0f13a133443a7062cb8fd70f5e5dd5559a32c26d2c8 -a679f673e5ce6a3cce7fa31f22ee3785e96bcb55e5a776e2dd3467bef7440e3555d1a9b87cb215e86ee9ed13a090344b -afedbb34508b159eb25eb2248d7fe328f86ef8c7d84c62d5b5607d74aae27cc2cc45ee148eb22153b09898a835c58df4 -b75505d4f6b67d31e665cfaf5e4acdb5838ae069166b7fbcd48937c0608a59e40a25302fcc1873d2e81c1782808c70f0 -b62515d539ec21a155d94fc00ea3c6b7e5f6636937bce18ed5b618c12257fb82571886287fd5d1da495296c663ebc512 -ab8e1a9446bbdd588d1690243b1549d230e6149c28f59662b66a8391a138d37ab594df38e7720fae53217e5c3573b5be -b31e8abf4212e03c3287bb2c0a153065a7290a16764a0bac8f112a72e632185a654bb4e88fdd6053e6c7515d9719fadb -b55165477fe15b6abd2d0f4fddaa9c411710dcc4dd712daba3d30e303c9a3ee5415c256f9dc917ecf18c725b4dbab059 -a0939d4f57cacaae549b78e87cc234de4ff6a35dc0d9cd5d7410abc30ebcd34c135e008651c756e5a9d2ca79c40ef42b -8cf10e50769f3443340844aad4d56ec790850fed5a41fcbd739abac4c3015f0a085a038fbe7fae9f5ad899cce5069f6b -924055e804d82a99ea4bb160041ea4dc14b568abf379010bc1922fde5d664718c31d103b8b807e3a1ae809390e708c73 -8ec0f9d26f71b0f2e60a179e4fd1778452e2ffb129d50815e5d7c7cb9415fa69ae5890578086e8ef6bfde35ad2a74661 -98c7f12b15ec4426b59f737f73bf5faea4572340f4550b7590dfb7f7ffedb2372e3e555977c63946d579544c53210ad0 -8a935f7a955c78f69d66f18eee0092e5e833fa621781c9581058e219af4d7ceee48b84e472e159dda6199715fb2f9acf -b78d4219f95a2dbfaa7d0c8a610c57c358754f4f43c2af312ab0fe8f10a5f0177e475332fb8fd23604e474fc2abeb051 -8d086a14803392b7318c28f1039a17e3cfdcece8abcaca3657ec3d0ac330842098a85c0212f889fabb296dfb133ce9aa -a53249f417aac82f2c2a50c244ce21d3e08a5e5a8bd33bec2a5ab0d6cd17793e34a17edfa3690899244ce201e2fb9986 -8619b0264f9182867a1425be514dc4f1ababc1093138a728a28bd7e4ecc99b9faaff68c23792264bc6e4dce5f52a5c52 -8c171edbbbde551ec19e31b2091eb6956107dd9b1f853e1df23bff3c10a3469ac77a58335eee2b79112502e8e163f3de -a9d19ec40f0ca07c238e9337c6d6a319190bdba2db76fb63902f3fb459aeeb50a1ac30db5b25ee1b4201f3ca7164a7f4 -b9c6ec14b1581a03520b8d2c1fbbc31fb8ceaef2c0f1a0d0080b6b96e18442f1734bea7ef7b635d787c691de4765d469 -8cb437beb4cfa013096f40ccc169a713dc17afee6daa229a398e45fd5c0645a9ad2795c3f0cd439531a7151945d7064d -a6e8740cc509126e146775157c2eb278003e5bb6c48465c160ed27888ca803fa12eee1f6a8dd7f444f571664ed87fdc1 -b75c1fecc85b2732e96b3f23aefb491dbd0206a21d682aee0225838dc057d7ed3b576176353e8e90ae55663f79e986e4 -ad8d249b0aea9597b08358bce6c77c1fd552ef3fbc197d6a1cfe44e5e6f89b628b12a6fb04d5dcfcbacc51f46e4ae7bb -b998b2269932cbd58d04b8e898d373ac4bb1a62e8567484f4f83e224061bc0f212459f1daae95abdbc63816ae6486a55 -827988ef6c1101cddc96b98f4a30365ff08eea2471dd949d2c0a9b35c3bbfa8c07054ad1f4c88c8fbf829b20bb5a9a4f -8692e638dd60babf7d9f2f2d2ce58e0ac689e1326d88311416357298c6a2bffbfebf55d5253563e7b3fbbf5072264146 -a685d75b91aea04dbc14ab3c1b1588e6de96dae414c8e37b8388766029631b28dd860688079b12d09cd27f2c5af11adf -b57eced93eec3371c56679c259b34ac0992286be4f4ff9489d81cf9712403509932e47404ddd86f89d7c1c3b6391b28c -a1c8b4e42ebcbd8927669a97f1b72e236fb19249325659e72be7ddaaa1d9e81ca2abb643295d41a8c04a2c01f9c0efd7 -877c33de20d4ed31674a671ba3e8f01a316581e32503136a70c9c15bf0b7cb7b1cba6cd4eb641fad165fb3c3c6c235fd -a2a469d84ec478da40838f775d11ad38f6596eb41caa139cc190d6a10b5108c09febae34ffdafac92271d2e73c143693 -972f817caedb254055d52e963ed28c206848b6c4cfdb69dbc961c891f8458eaf582a6d4403ce1177d87bc2ea410ef60a -accbd739e138007422f28536381decc54bb6bd71d93edf3890e54f9ef339f83d2821697d1a4ac1f5a98175f9a9ecb9b5 -8940f8772e05389f823b62b3adc3ed541f91647f0318d7a0d3f293aeeb421013de0d0a3664ea53dd24e5fbe02d7efef6 -8ecce20f3ef6212edef07ec4d6183fda8e0e8cad2c6ccd0b325e75c425ee1faba00b5c26b4d95204238931598d78f49d -97cc72c36335bd008afbed34a3b0c7225933faba87f7916d0a6d2161e6f82e0cdcda7959573a366f638ca75d30e9dab1 -9105f5de8699b5bdb6bd3bb6cc1992d1eac23929c29837985f83b22efdda92af64d9c574aa9640475087201bbbe5fd73 -8ffb33c4f6d05c413b9647eb6933526a350ed2e4278ca2ecc06b0e8026d8dbe829c476a40e45a6df63a633090a3f82ef -8bfc6421fdc9c2d2aaa68d2a69b1a2728c25b84944cc3e6a57ff0c94bfd210d1cbf4ff3f06702d2a8257024d8be7de63 -a80e1dc1dddfb41a70220939b96dc6935e00b32fb8be5dff4eed1f1c650002ff95e4af481c43292e3827363b7ec4768a -96f714ebd54617198bd636ba7f7a7f8995a61db20962f2165078d9ed8ee764d5946ef3cbdc7ebf8435bb8d5dd4c1deac -8cdb0890e33144d66391d2ae73f5c71f5a861f72bc93bff6cc399fc25dd1f9e17d8772592b44593429718784802ac377 -8ccf9a7f80800ee770b92add734ed45a73ecc31e2af0e04364eefc6056a8223834c7c0dc9dfc52495bdec6e74ce69994 -aa0875f423bd68b5f10ba978ddb79d3b96ec093bfbac9ff366323193e339ed7c4578760fb60f60e93598bdf1e5cc4995 -a9214f523957b59c7a4cb61a40251ad72aba0b57573163b0dc0f33e41d2df483fb9a1b85a5e7c080e9376c866790f8cb -b6224b605028c6673a536cc8ff9aeb94e7a22e686fda82cf16068d326469172f511219b68b2b3affb7933af0c1f80d07 -b6d58968d8a017c6a34e24c2c09852f736515a2c50f37232ac6b43a38f8faa7572cc31dade543b594b61b5761c4781d0 -8a97cefe5120020c38deeb861d394404e6c993c6cbd5989b6c9ebffe24f46ad11b4ba6348e2991cbf3949c28cfc3c99d -95bf046f8c3a9c0ce2634be4de3713024daec3fc4083e808903b25ce3ac971145af90686b451efcc72f6b22df0216667 -a6a4e2f71b8fa28801f553231eff2794c0f10d12e7e414276995e21195abc9c2983a8997e41af41e78d19ff6fbb2680b -8e5e62a7ca9c2f58ebaab63db2ff1fb1ff0877ae94b7f5e2897f273f684ae639dff44cc65718f78a9c894787602ab26a -8542784383eec4f565fcb8b9fc2ad8d7a644267d8d7612a0f476fc8df3aff458897a38003d506d24142ad18f93554f2b -b7db68ba4616ea072b37925ec4fb39096358c2832cc6d35169e032326b2d6614479f765ae98913c267105b84afcb9bf2 -8b31dbb9457d23d416c47542c786e07a489af35c4a87dadb8ee91bea5ac4a5315e65625d78dad2cf8f9561af31b45390 -a8545a1d91ac17257732033d89e6b7111db8242e9c6ebb0213a88906d5ef407a2c6fdb444e29504b06368b6efb4f4839 -b1bd85d29ebb28ccfb05779aad8674906b267c2bf8cdb1f9a0591dd621b53a4ee9f2942687ee3476740c0b4a7621a3ae -a2b54534e152e46c50d91fff03ae9cd019ff7cd9f4168b2fe7ac08ef8c3bbc134cadd3f9d6bd33d20ae476c2a8596c8a -b19b571ff4ae3e9f5d95acda133c455e72c9ea9973cae360732859836c0341c4c29ab039224dc5bc3deb824e031675d8 -940b5f80478648bac025a30f3efeb47023ce20ee98be833948a248bca6979f206bb28fc0f17b90acf3bb4abd3d14d731 -8f106b40588586ac11629b96d57808ad2808915d89539409c97414aded90b4ff23286a692608230a52bff696055ba5d6 -ae6bda03aa10da3d2abbc66d764ca6c8d0993e7304a1bdd413eb9622f3ca1913baa6da1e9f4f9e6cf847f14f44d6924d -a18e7796054a340ef826c4d6b5a117b80927afaf2ebd547794c400204ae2caf277692e2eabb55bc2f620763c9e9da66d -8d2d25180dc2c65a4844d3e66819ccfcf48858f0cc89e1c77553b463ec0f7feb9a4002ce26bc618d1142549b9850f232 -863f413a394de42cc8166c1c75d513b91d545fff1de6b359037a742c70b008d34bf8e587afa2d62c844d0c6f0ea753e7 -83cd0cf62d63475e7fcad18a2e74108499cdbf28af2113cfe005e3b5887794422da450b1944d0a986eb7e1f4c3b18f25 -b4f8b350a6d88fea5ab2e44715a292efb12eb52df738c9b2393da3f1ddee68d0a75b476733ccf93642154bceb208f2b8 -b3f52aaa4cd4221cb9fc45936cc67fd3864bf6d26bf3dd86aa85aa55ecfc05f5e392ecce5e7cf9406b4b1c4fce0398c8 -b33137084422fb643123f40a6df2b498065e65230fc65dc31791c330e898c51c3a65ff738930f32c63d78f3c9315f85b -91452bfa75019363976bb7337fe3a73f1c10f01637428c135536b0cdc7da5ce558dae3dfc792aa55022292600814a8ef -ad6ba94c787cd4361ca642c20793ea44f1f127d4de0bb4a77c7fbfebae0fcadbf28e2cb6f0c12c12a07324ec8c19761d -890aa6248b17f1501b0f869c556be7bf2b1d31a176f9978bb97ab7a6bd4138eed32467951c5ef1871944b7f620542f43 -82111db2052194ee7dd22ff1eafffac0443cf969d3762cceae046c9a11561c0fdce9c0711f88ac01d1bed165f8a7cee3 -b1527b71df2b42b55832f72e772a466e0fa05743aacc7814f4414e4bcc8d42a4010c9e0fd940e6f254cafedff3cd6543 -922370fa49903679fc565f09c16a5917f8125e72acfeb060fcdbadbd1644eb9f4016229756019c93c6d609cda5d5d174 -aa4c7d98a96cab138d2a53d4aee8ebff6ef903e3b629a92519608d88b3bbd94de5522291a1097e6acf830270e64c8ee1 -b3dc21608a389a72d3a752883a382baaafc61ecc44083b832610a237f6a2363f24195acce529eb4aed4ef0e27a12b66e -94619f5de05e07b32291e1d7ab1d8b7337a2235e49d4fb5f3055f090a65e932e829efa95db886b32b153bdd05a53ec8c -ade1e92722c2ffa85865d2426fb3d1654a16477d3abf580cfc45ea4b92d5668afc9d09275d3b79283e13e6b39e47424d -b7201589de7bed094911dd62fcd25c459a8e327ac447b69f541cdba30233063e5ddffad0b67e9c3e34adcffedfd0e13d -809d325310f862d6549e7cb40f7e5fc9b7544bd751dd28c4f363c724a0378c0e2adcb5e42ec8f912f5f49f18f3365c07 -a79c20aa533de7a5d671c99eb9eb454803ba54dd4f2efa3c8fec1a38f8308e9905c71e9282955225f686146388506ff6 -a85eeacb5e8fc9f3ed06a3fe2dc3108ab9f8c5877b148c73cf26e4e979bf5795edbe2e63a8d452565fd1176ed40402b2 -97ef55662f8a1ec0842b22ee21391227540adf7708f491436044f3a2eb18c471525e78e1e14fa292507c99d74d7437c6 -93110d64ed5886f3d16ce83b11425576a3a7a9bb831cd0de3f9a0b0f2270a730d68136b4ef7ff035ede004358f419b5c -ac9ed0a071517f0ae4f61ce95916a90ba9a77a3f84b0ec50ef7298acdcd44d1b94525d191c39d6bd1bb68f4471428760 -98abd6a02c7690f5a339adf292b8c9368dfc12e0f8069cf26a5e0ce54b4441638f5c66ea735142f3c28e00a0024267e6 -b51efb73ba6d44146f047d69b19c0722227a7748b0e8f644d0fc9551324cf034c041a2378c56ce8b58d06038fb8a78de -8f115af274ef75c1662b588b0896b97d71f8d67986ae846792702c4742ab855952865ce236b27e2321967ce36ff93357 -b3c4548f14d58b3ab03c222da09e4381a0afe47a72d18d50a94e0008797f78e39e99990e5b4757be62310d400746e35a -a9b1883bd5f31f909b8b1b6dcb48c1c60ed20aa7374b3ffa7f5b2ed036599b5bef33289d23c80a5e6420d191723b92f7 -85d38dffd99487ae5bb41ab4a44d80a46157bbbe8ef9497e68f061721f74e4da513ccc3422936b059575975f6787c936 -adf870fcb96e972c033ab7a35d28ae79ee795f82bc49c3bd69138f0e338103118d5529c53f2d72a9c0d947bf7d312af2 -ab4c7a44e2d9446c6ff303eb49aef0e367a58b22cc3bb27b4e69b55d1d9ee639c9234148d2ee95f9ca8079b1457d5a75 -a386420b738aba2d7145eb4cba6d643d96bda3f2ca55bb11980b318d43b289d55a108f4bc23a9606fb0bccdeb3b3bb30 -847020e0a440d9c4109773ecca5d8268b44d523389993b1f5e60e541187f7c597d79ebd6e318871815e26c96b4a4dbb1 -a530aa7e5ca86fcd1bec4b072b55cc793781f38a666c2033b510a69e110eeabb54c7d8cbcb9c61fee531a6f635ffa972 -87364a5ea1d270632a44269d686b2402da737948dac27f51b7a97af80b66728b0256547a5103d2227005541ca4b7ed04 -8816fc6e16ea277de93a6d793d0eb5c15e9e93eb958c5ef30adaf8241805adeb4da8ce19c3c2167f971f61e0b361077d -8836a72d301c42510367181bb091e4be377777aed57b73c29ef2ce1d475feedd7e0f31676284d9a94f6db01cc4de81a2 -b0d9d8b7116156d9dde138d28aa05a33e61f8a85839c1e9071ccd517b46a5b4b53acb32c2edd7150c15bc1b4bd8db9e3 -ae931b6eaeda790ba7f1cd674e53dc87f6306ff44951fa0df88d506316a5da240df9794ccbd7215a6470e6b31c5ea193 -8c6d5bdf87bd7f645419d7c6444e244fe054d437ed1ba0c122fde7800603a5fadc061e5b836cb22a6cfb2b466f20f013 -90d530c6d0cb654999fa771b8d11d723f54b8a8233d1052dc1e839ea6e314fbed3697084601f3e9bbb71d2b4eaa596df -b0d341a1422588c983f767b1ed36c18b141774f67ef6a43cff8e18b73a009da10fc12120938b8bba27f225bdfd3138f9 -a131b56f9537f460d304e9a1dd75702ace8abd68cb45419695cb8dee76998139058336c87b7afd6239dc20d7f8f940cc -aa6c51fa28975f709329adee1bbd35d49c6b878041841a94465e8218338e4371f5cb6c17f44a63ac93644bf28f15d20f -88440fb584a99ebd7f9ea04aaf622f6e44e2b43bbb49fb5de548d24a238dc8f26c8da2ccf03dd43102bda9f16623f609 -9777b8695b790e702159a4a750d5e7ff865425b95fa0a3c15495af385b91c90c00a6bd01d1b77bffe8c47d01baae846f -8b9d764ece7799079e63c7f01690c8eff00896a26a0d095773dea7a35967a8c40db7a6a74692f0118bf0460c26739af4 -85808c65c485520609c9e61fa1bb67b28f4611d3608a9f7a5030ee61c3aa3c7e7dc17fff48af76b4aecee2cb0dbd22ac -ad2783a76f5b3db008ef5f7e67391fda4e7e36abde6b3b089fc4835b5c339370287935af6bd53998bed4e399eda1136d -96f18ec03ae47c205cc4242ca58e2eff185c9dca86d5158817e2e5dc2207ab84aadda78725f8dc080a231efdc093b940 -97de1ab6c6cc646ae60cf7b86df73b9cf56cc0cd1f31b966951ebf79fc153531af55ca643b20b773daa7cab784b832f7 -870ba266a9bfa86ef644b1ef025a0f1b7609a60de170fe9508de8fd53170c0b48adb37f19397ee8019b041ce29a16576 -ad990e888d279ac4e8db90619d663d5ae027f994a3992c2fbc7d262b5990ae8a243e19157f3565671d1cb0de17fe6e55 -8d9d5adcdd94c5ba3be4d9a7428133b42e485f040a28d16ee2384758e87d35528f7f9868de9bd23d1a42a594ce50a567 -85a33ed75d514ece6ad78440e42f7fcdb59b6f4cff821188236d20edae9050b3a042ce9bc7d2054296e133d033e45022 -92afd2f49a124aaba90de59be85ff269457f982b54c91b06650c1b8055f9b4b0640fd378df02a00e4fc91f7d226ab980 -8c0ee09ec64bd831e544785e3d65418fe83ed9c920d9bb4d0bf6dd162c1264eb9d6652d2def0722e223915615931581c -8369bedfa17b24e9ad48ebd9c5afea4b66b3296d5770e09b00446c5b0a8a373d39d300780c01dcc1c6752792bccf5fd0 -8b9e960782576a59b2eb2250d346030daa50bbbec114e95cdb9e4b1ba18c3d34525ae388f859708131984976ca439d94 -b682bface862008fea2b5a07812ca6a28a58fd151a1d54c708fc2f8572916e0d678a9cb8dc1c10c0470025c8a605249e -a38d5e189bea540a824b36815fc41e3750760a52be0862c4cac68214febdc1a754fb194a7415a8fb7f96f6836196d82a -b9e7fbda650f18c7eb8b40e42cc42273a7298e65e8be524292369581861075c55299ce69309710e5b843cb884de171bd -b6657e5e31b3193874a1bace08f42faccbd3c502fb73ad87d15d18a1b6c2a146f1baa929e6f517db390a5a47b66c0acf -ae15487312f84ed6265e4c28327d24a8a0f4d2d17d4a5b7c29b974139cf93223435aaebe3af918f5b4bb20911799715f -8bb4608beb06bc394e1a70739b872ce5a2a3ffc98c7547bf2698c893ca399d6c13686f6663f483894bccaabc3b9c56ad -b58ac36bc6847077584308d952c5f3663e3001af5ecf2e19cb162e1c58bd6c49510205d453cffc876ca1dc6b8e04a578 -924f65ced61266a79a671ffb49b300f0ea44c50a0b4e3b02064faa99fcc3e4f6061ea8f38168ab118c5d47bd7804590e -8d67d43b8a06b0ff4fafd7f0483fa9ed1a9e3e658a03fb49d9d9b74e2e24858dc1bed065c12392037b467f255d4e5643 -b4d4f87813125a6b355e4519a81657fa97c43a6115817b819a6caf4823f1d6a1169683fd68f8d025cdfa40ebf3069acb -a7fd4d2c8e7b59b8eed3d4332ae94b77a89a2616347402f880bc81bde072220131e6dbec8a605be3a1c760b775375879 -8d4a7d8fa6f55a30df37bcf74952e2fa4fd6676a2e4606185cf154bdd84643fd01619f8fb8813a564f72e3f574f8ce30 -8086fb88e6260e9a9c42e9560fde76315ff5e5680ec7140f2a18438f15bc2cc7d7d43bfb5880b180b738c20a834e6134 -916c4c54721de03934fee6f43de50bb04c81f6f8dd4f6781e159e71c40c60408aa54251d457369d133d4ba3ed7c12cb4 -902e5bf468f11ed9954e2a4a595c27e34abe512f1d6dc08bbca1c2441063f9af3dc5a8075ab910a10ff6c05c1c644a35 -a1302953015e164bf4c15f7d4d35e3633425a78294406b861675667eec77765ff88472306531e5d3a4ec0a2ff0dd6a9e -87874461df3c9aa6c0fa91325576c0590f367075f2f0ecfeb34afe162c04c14f8ce9d608c37ac1adc8b9985bc036e366 -84b50a8a61d3cc609bfb0417348133e698fe09a6d37357ce3358de189efcf35773d78c57635c2d26c3542b13cc371752 -acaed2cff8633d12c1d12bb7270c54d65b0b0733ab084fd47f81d0a6e1e9b6f300e615e79538239e6160c566d8bb8d29 -889e6a0e136372ca4bac90d1ab220d4e1cad425a710e8cdd48b400b73bb8137291ceb36a39440fa84305783b1d42c72f -90952e5becec45b2b73719c228429a2c364991cf1d5a9d6845ae5b38018c2626f4308daa322cab1c72e0f6c621bb2b35 -8f5a97a801b6e9dcd66ccb80d337562c96f7914e7169e8ff0fda71534054c64bf2a9493bb830623d612cfe998789be65 -84f3df8b9847dcf1d63ca470dc623154898f83c25a6983e9b78c6d2d90a97bf5e622445be835f32c1e55e6a0a562ea78 -91d12095cd7a88e7f57f254f02fdb1a1ab18984871dead2f107404bcf8069fe68258c4e6f6ebd2477bddf738135400bb -b771a28bc04baef68604d4723791d3712f82b5e4fe316d7adc2fc01b935d8e644c06d59b83bcb542afc40ebafbee0683 -872f6341476e387604a7e93ae6d6117e72d164e38ebc2b825bc6df4fcce815004d7516423c190c1575946b5de438c08d -90d6b4aa7d40a020cdcd04e8b016d041795961a8e532a0e1f4041252131089114a251791bf57794cadb7d636342f5d1c -899023ba6096a181448d927fed7a0fe858be4eac4082a42e30b3050ee065278d72fa9b9d5ce3bc1372d4cbd30a2f2976 -a28f176571e1a9124f95973f414d5bdbf5794d41c3839d8b917100902ac4e2171eb940431236cec93928a60a77ede793 -838dbe5bcd29c4e465d02350270fa0036cd46f8730b13d91e77afb7f5ed16525d0021d3b2ae173a76c378516a903e0cb -8e105d012dd3f5d20f0f1c4a7e7f09f0fdd74ce554c3032e48da8cce0a77260d7d47a454851387770f5c256fa29bcb88 -8f4df0f9feeb7a487e1d138d13ea961459a6402fd8f8cabb226a92249a0d04ded5971f3242b9f90d08da5ff66da28af6 -ad1cfda4f2122a20935aa32fb17c536a3653a18617a65c6836700b5537122af5a8206befe9eaea781c1244c43778e7f1 -832c6f01d6571964ea383292efc8c8fa11e61c0634a25fa180737cc7ab57bc77f25e614aac9a2a03d98f27b3c1c29de2 -903f89cc13ec6685ac7728521898781fecb300e9094ef913d530bf875c18bcc3ceed7ed51e7b482d45619ab4b025c2e9 -a03c474bb915aad94f171e8d96f46abb2a19c9470601f4c915512ec8b9e743c3938450a2a5b077b4618b9df8809e1dc1 -83536c8456f306045a5f38ae4be2e350878fa7e164ea408d467f8c3bc4c2ee396bd5868008c089183868e4dfad7aa50b -88f26b4ea1b236cb326cd7ad7e2517ec8c4919598691474fe15d09cabcfc37a8d8b1b818f4d112432ee3a716b0f37871 -a44324e3fe96e9c12b40ded4f0f3397c8c7ee8ff5e96441118d8a6bfad712d3ac990b2a6a23231a8f691491ac1fd480f -b0de4693b4b9f932191a21ee88629964878680152a82996c0019ffc39f8d9369bbe2fe5844b68d6d9589ace54af947e4 -8e5d8ba948aea5fd26035351a960e87f0d23efddd8e13236cc8e4545a3dda2e9a85e6521efb8577e03772d3637d213d9 -93efc82d2017e9c57834a1246463e64774e56183bb247c8fc9dd98c56817e878d97b05f5c8d900acf1fbbbca6f146556 -8731176363ad7658a2862426ee47a5dce9434216cef60e6045fa57c40bb3ce1e78dac4510ae40f1f31db5967022ced32 -b10c9a96745722c85bdb1a693100104d560433d45b9ac4add54c7646a7310d8e9b3ca9abd1039d473ae768a18e489845 -a2ac374dfbb464bf850b4a2caf15b112634a6428e8395f9c9243baefd2452b4b4c61b0cb2836d8eae2d57d4900bf407e -b69fe3ded0c4f5d44a09a0e0f398221b6d1bf5dbb8bc4e338b93c64f1a3cac1e4b5f73c2b8117158030ec03787f4b452 -8852cdbaf7d0447a8c6f211b4830711b3b5c105c0f316e3a6a18dcfbb9be08bd6f4e5c8ae0c3692da08a2dfa532f9d5c -93bbf6d7432a7d98ade3f94b57bf9f4da9bc221a180a370b113066dd42601bb9e09edd79e2e6e04e00423399339eebda -a80941c391f1eeafc1451c59e4775d6a383946ff22997aeaadf806542ba451d3b0f0c6864eeba954174a296efe2c1550 -a045fe2bb011c2a2f71a0181a8f457a3078470fb74c628eab8b59aef69ffd0d649723bf74d6885af3f028bc5a104fb39 -b9d8c35911009c4c8cad64692139bf3fc16b78f5a19980790cb6a7aea650a25df4231a4437ae0c351676a7e42c16134f -94c79501ded0cfcbab99e1841abe4a00a0252b3870e20774c3da16c982d74c501916ec28304e71194845be6e3113c7ab -900a66418b082a24c6348d8644ddb1817df5b25cb33044a519ef47cc8e1f7f1e38d2465b7b96d32ed472d2d17f8414c6 -b26f45d393b8b2fcb29bdbb16323dc7f4b81c09618519ab3a39f8ee5bd148d0d9f3c0b5dfab55b5ce14a1cb9206d777b -aa1a87735fc493a80a96a9a57ca40a6d9c32702bfcaa9869ce1a116ae65d69cefe2f3e79a12454b4590353e96f8912b4 -a922b188d3d0b69b4e4ea2a2aa076566962844637da12c0832105d7b31dea4a309eee15d12b7a336be3ea36fcbd3e3b7 -8f3841fcf4105131d8c4d9885e6e11a46c448226401cf99356c291fadb864da9fa9d30f3a73c327f23f9fd99a11d633e -9791d1183fae270e226379af6c497e7da803ea854bb20afa74b253239b744c15f670ee808f708ede873e78d79a626c9a -a4cad52e3369491ada61bf28ada9e85de4516d21c882e5f1cd845bea9c06e0b2887b0c5527fcff6fc28acd3c04f0a796 -b9ac86a900899603452bd11a7892a9bfed8054970bfcbeaa8c9d1930db891169e38d6977f5258c25734f96c8462eee3b -a3a154c28e5580656a859f4efc2f5ebfa7eaa84ca40e3f134fa7865e8581586db74992dbfa4036aa252fba103773ddde -95cc2a0c1885a029e094f5d737e3ecf4d26b99036453a8773c77e360101f9f98676ee246f6f732a377a996702d55691f -842651bbe99720438d8d4b0218feb60481280c05beb17750e9ca0d8c0599a60f873b7fbdcc7d8835ba9a6d57b16eec03 -81ee54699da98f5620307893dcea8f64670609fa20e5622265d66283adeac122d458b3308c5898e6c57c298db2c8b24f -b97868b0b2bc98032d68352a535a1b341b9ff3c7af4e3a7f3ebc82d3419daa1b5859d6aedc39994939623c7cd878bd9b -b60325cd5d36461d07ef253d826f37f9ee6474a760f2fff80f9873d01fd2b57711543cdc8d7afa1c350aa753c2e33dea -8c205326c11d25a46717b780c639d89714c7736c974ae71287e3f4b02e6605ac2d9b4928967b1684f12be040b7bf2dd3 -95a392d82db51e26ade6c2ccd3396d7e40aff68fa570b5951466580d6e56dda51775dce5cf3a74a7f28c3cb2eb551c4d -8f2cc8071eb56dffb70bda6dd433b556221dc8bba21c53353c865f00e7d4d86c9e39f119ea9a8a12ef583e9a55d9a6b6 -9449a71af9672aaf8856896d7e3d788b22991a7103f75b08c0abbcc2bfe60fda4ed8ce502cea4511ff0ea52a93e81222 -857090ab9fdb7d59632d068f3cc8cf27e61f0d8322d30e6b38e780a1f05227199b4cd746aac1311c36c659ef20931f28 -98a891f4973e7d9aaf9ac70854608d4f7493dffc7e0987d7be9dd6029f6ea5636d24ef3a83205615ca1ff403750058e1 -a486e1365bbc278dd66a2a25d258dc82f46b911103cb16aab3945b9c95ae87b386313a12b566df5b22322ede0afe25ad -a9a1eb399ed95d396dccd8d1ac718043446f8b979ec62bdce51c617c97a312f01376ab7fb87d27034e5f5570797b3c33 -b7abc3858d7a74bb446218d2f5a037e0fae11871ed9caf44b29b69c500c1fa1dcfad64c9cdccc9d80d5e584f06213deb -8cfb09fe2e202faa4cebad932b1d35f5ca204e1c2a0c740a57812ac9a6792130d1312aabd9e9d4c58ca168bfebd4c177 -a90a305c2cd0f184787c6be596fa67f436afd1f9b93f30e875f817ac2aae8bdd2e6e656f6be809467e6b3ad84adb86b1 -80a9ef993c2b009ae172cc8f7ec036f5734cf4f4dfa06a7db4d54725e7fbfae5e3bc6f22687bdbb6961939d6f0c87537 -848ade1901931e72b955d7db1893f07003e1708ff5d93174bac5930b9a732640f0578839203e9b77eb27965c700032d3 -93fdf4697609c5ae9c33b9ca2f5f1af44abeb2b98dc4fdf732cf7388de086f410730dc384d9b7a7f447bb009653c8381 -89ce3fb805aea618b5715c0d22a9f46da696b6fa86794f56fdf1d44155a33d42daf1920bcbe36cbacf3cf4c92df9cbc7 -829ce2c342cf82aa469c65f724f308f7a750bd1494adc264609cd790c8718b8b25b5cab5858cf4ee2f8f651d569eea67 -af2f0cee7bf413204be8b9df59b9e4991bc9009e0d6dbe6815181df0ec2ca93ab8f4f3135b1c14d8f53d74bff0bd6f27 -b87998cecf7b88cde93d1779f10a521edd5574a2fbd240102978639ec57433ba08cdb53849038a329cebbe74657268d2 -a64542a1261a6ed3d720c2c3a802303aad8c4c110c95d0f12e05c1065e66f42da494792b6bfc5b9272363f3b1d457f58 -86a6fd042e4f282fadf07a4bfee03fc96a3aea49f7a00f52bf249a20f1ec892326855410e61f37fbb27d9305eb2fc713 -967ea5bc403b6db269682f7fd0df90659350d7e1aa66bc4fab4c9dfcd75ed0bba4b52f1cebc5f34dc8ba810793727629 -a52990f9f3b8616ce3cdc2c74cd195029e6a969753dcf2d1630438700e7d6ebde36538532b3525ac516f5f2ce9dd27a3 -a64f7ff870bab4a8bf0d4ef6f5c744e9bf1021ed08b4c80903c7ad318e80ba1817c3180cc45cb5a1cae1170f0241655f -b00f706fa4de1f663f021e8ad3d155e84ce6084a409374b6e6cd0f924a0a0b51bebaaaf1d228c77233a73b0a5a0df0e9 -8b882cc3bff3e42babdb96df95fb780faded84887a0a9bab896bef371cdcf169d909f5658649e93006aa3c6e1146d62e -9332663ef1d1dcf805c3d0e4ce7a07d9863fb1731172e766b3cde030bf81682cc011e26b773fb9c68e0477b4ae2cfb79 -a8aa8151348dbd4ef40aaeb699b71b4c4bfd3218560c120d85036d14f678f6736f0ec68e80ce1459d3d35feccc575164 -a16cd8b729768f51881c213434aa28301fa78fcb554ddd5f9012ee1e4eae7b5cb3dd88d269d53146dea92d10790faf0b -86844f0ef9d37142faf3b1e196e44fbe280a3ba4189aa05c356778cb9e3b388a2bff95eed305ada8769935c9974e4c57 -ae2eec6b328fccf3b47bcdac32901ac2744a51beb410b04c81dea34dee4912b619466a4f5e2780d87ecefaebbe77b46d -915df4c38d301c8a4eb2dc5b1ba0ffaad67cbb177e0a80095614e9c711f4ef24a4cef133f9d982a63d2a943ba6c8669d -ae6a2a4dedfc2d1811711a8946991fede972fdf2a389b282471280737536ffc0ac3a6d885b1f8bda0366eb0b229b9979 -a9b628c63d08b8aba6b1317f6e91c34b2382a6c85376e8ef2410a463c6796740ae936fc4e9e0737cb9455d1daa287bd8 -848e30bf7edf2546670b390d5cf9ab71f98fcb6add3c0b582cb34996c26a446dee5d1bde4fdcde4fc80c10936e117b29 -907d6096c7c8c087d1808dd995d5d2b9169b3768c3f433475b50c2e2bd4b082f4d543afd8b0b0ddffa9c66222a72d51d -a59970a2493b07339124d763ac9d793c60a03354539ecbcf6035bc43d1ea6e35718202ae6d7060b7d388f483d971573c -b9cfef2af9681b2318f119d8611ff6d9485a68d8044581b1959ab1840cbca576dbb53eec17863d2149966e9feb21122f -ad47271806161f61d3afa45cdfe2babceef5e90031a21779f83dc8562e6076680525b4970b2f11fe9b2b23c382768323 -8e425a99b71677b04fe044625d338811fbb8ee32368a424f6ab2381c52e86ee7a6cecedf777dc97181519d41c351bc22 -86b55b54d7adefc12954a9252ee23ae83efe8b5b4b9a7dc307904413e5d69868c7087a818b2833f9b004213d629be8ad -a14fda6b93923dd11e564ae4457a66f397741527166e0b16a8eb91c6701c244fd1c4b63f9dd3515193ec88fa6c266b35 -a9b17c36ae6cd85a0ed7f6cabc5b47dc8f80ced605db327c47826476dc1fb8f8669aa7a7dc679fbd4ee3d8e8b4bd6a6f -82a0829469c1458d959c821148f15dacae9ea94bf56c59a6ab2d4dd8b3d16d73e313b5a3912a6c1f131d73a8f06730c4 -b22d56d549a53eaef549595924bdb621ff807aa4513feedf3fdcbf7ba8b6b9cfa4481c2f67fc642db397a6b794a8b63a -974c59c24392e2cb9294006cbe3c52163e255f3bd0c2b457bdc68a6338e6d5b6f87f716854492f8d880a6b896ccf757c -b70d247ba7cad97c50b57f526c2ba915786e926a94e8f8c3eebc2e1be6f4255411b9670e382060049c8f4184302c40b2 -ad80201fe75ef21c3ddbd98cf23591e0d7a3ba1036dfe77785c32f44755a212c31f0ceb0a0b6f5ee9b6dc81f358d30c3 -8c656e841f9bb90b9a42d425251f3fdbc022a604d75f5845f479ed4be23e02aaf9e6e56cde351dd7449c50574818a199 -8b88dd3fa209d3063b7c5b058f7249ee9900fbc2287d16da61a0704a0a1d71e45d9c96e1cda7fdf9654534ec44558b22 -961da00cc8750bd84d253c08f011970ae1b1158ad6778e8ed943d547bceaf52d6d5a212a7de3bf2706688c4389b827d2 -a5dd379922549a956033e3d51a986a4b1508e575042b8eaa1df007aa77cf0b8c2ab23212f9c075702788fa9c53696133 -ac8fcfde3a349d1e93fc8cf450814e842005c545c4844c0401bc80e6b96cdb77f29285a14455e167c191d4f312e866cd -ac63d79c799783a8466617030c59dd5a8f92ee6c5204676fd8d881ce5f7f8663bdbeb0379e480ea9b6340ab0dc88e574 -805874fde19ce359041ae2bd52a39e2841acabfd31f965792f2737d7137f36d4e4722ede8340d8c95afa6af278af8acb -8d2f323a228aa8ba7b7dc1399138f9e6b41df1a16a7069003ab8104b8b68506a45141bc5fe66acf430e23e13a545190b -a1610c721a2d9af882bb6b39bea97cff1527a3aea041d25934de080214ae77c959e79957164440686d15ab301e897d4d -aba16d29a47fc36f12b654fde513896723e2c700c4190f11b26aa4011da57737ad717daa02794aa3246e4ae5f0b0cc3a -a406db2f15fdd135f346cc4846623c47edd195e80ba8c7cb447332095314d565e4040694ca924696bb5ee7f8996ea0ba -8b30e2cd9b47d75ba57b83630e40f832249af6c058d4f490416562af451993eec46f3e1f90bc4d389e4c06abd1b32a46 -aacf9eb7036e248e209adbfc3dd7ce386569ea9b312caa4b240726549db3c68c4f1c8cbf8ed5ea9ea60c7e57c9df3b8e -b20fcac63bf6f5ee638a42d7f89be847f348c085ddcbec3fa318f4323592d136c230495f188ef2022aa355cc2b0da6f9 -811eff750456a79ec1b1249d76d7c1547065b839d8d4aaad860f6d4528eb5b669473dcceeeea676cddbc3980b68461b7 -b52d14ae33f4ab422f953392ae76a19c618cc31afc96290bd3fe2fb44c954b5c92c4789f3f16e8793f2c0c1691ade444 -a7826dafeeba0db5b66c4dfcf2b17fd7b40507a5a53ac2e42942633a2cb30b95ba1739a6e9f3b7a0e0f1ec729bf274e2 -8acfd83ddf7c60dd7c8b20c706a3b972c65d336b8f9b3d907bdd8926ced271430479448100050b1ef17578a49c8fa616 -af0c69f65184bb06868029ad46f8465d75c36814c621ac20a5c0b06a900d59305584f5a6709683d9c0e4b6cd08d650a6 -b6cc8588191e00680ee6c3339bd0f0a17ad8fd7f4be57d5d7075bede0ea593a19e67f3d7c1a20114894ee5bfcab71063 -a82fd4f58635129dbb6cc3eb9391cf2d28400018b105fc41500fbbd12bd890b918f97d3d359c29dd3b4c4e34391dfab0 -92fc544ed65b4a3625cf03c41ddff7c039bc22d22c0d59dcc00efd5438401f2606adb125a1d5de294cca216ec8ac35a3 -906f67e4a32582b71f15940523c0c7ce370336935e2646bdaea16a06995256d25e99df57297e39d6c39535e180456407 -97510337ea5bbd5977287339197db55c60533b2ec35c94d0a460a416ae9f60e85cee39be82abeeacd5813cf54df05862 -87e6894643815c0ea48cb96c607266c5ee4f1f82ba5fe352fb77f9b6ed14bfc2b8e09e80a99ac9047dfcf62b2ae26795 -b6fd55dd156622ad7d5d51b7dde75e47bd052d4e542dd6449e72411f68275775c846dde301e84613312be8c7bce58b07 -b98461ac71f554b2f03a94e429b255af89eec917e208a8e60edf5fc43b65f1d17a20de3f31d2ce9f0cb573c25f2f4d98 -96f0dea40ca61cefbee41c4e1fe9a7d81fbe1f49bb153d083ab70f5d0488a1f717fd28cedcf6aa18d07cce2c62801898 -8d7c3ab310184f7dc34b6ce4684e4d29a31e77b09940448ea4daac730b7eb308063125d4dd229046cf11bfd521b771e0 -96f0564898fe96687918bbf0a6adead99cf72e3a35ea3347e124af9d006221f8e82e5a9d2fe80094d5e8d48e610f415e -ad50fcb92c2675a398cf07d4c40a579e44bf8d35f27cc330b57e54d5ea59f7d898af0f75dccfe3726e5471133d70f92b -828beed62020361689ae7481dd8f116902b522fb0c6c122678e7f949fdef70ead011e0e6bffd25678e388744e17cdb69 -8349decac1ca16599eee2efc95bcaabf67631107da1d34a2f917884bd70dfec9b4b08ab7bc4379d6c73b19c0b6e54fb8 -b2a6a2e50230c05613ace9e58bb2e98d94127f196f02d9dddc53c43fc68c184549ca12d713cb1b025d8260a41e947155 -94ff52181aadae832aed52fc3b7794536e2a31a21fc8be3ea312ca5c695750d37f08002f286b33f4023dba1e3253ecfa -a21d56153c7e5972ee9a319501be4faff199fdf09bb821ea9ce64aa815289676c00f105e6f00311b3a5b627091b0d0fc -a27a60d219f1f0c971db73a7f563b371b5c9fc3ed1f72883b2eac8a0df6698400c9954f4ca17d7e94e44bd4f95532afb -a2fc56fae99b1f18ba5e4fe838402164ce82f8a7f3193d0bbd360c2bac07c46f9330c4c7681ffb47074c6f81ee6e7ac6 -b748e530cd3afb96d879b83e89c9f1a444f54e55372ab1dcd46a0872f95ce8f49cf2363fc61be82259e04f555937ed16 -8bf8993e81080c7cbba1e14a798504af1e4950b2f186ab3335b771d6acaee4ffe92131ae9c53d74379d957cb6344d9cd -96774d0ef730d22d7ab6d9fb7f90b9ead44285219d076584a901960542756700a2a1603cdf72be4708b267200f6c36a9 -b47703c2ab17be1e823cc7bf3460db1d6760c0e33862c90ca058845b2ff234b0f9834ddba2efb2ee1770eb261e7d8ffd -84319e67c37a9581f8b09b5e4d4ae88d0a7fb4cbb6908971ab5be28070c3830f040b1de83ee663c573e0f2f6198640e4 -96811875fa83133e0b3c0e0290f9e0e28bca6178b77fdf5350eb19344d453dbd0d71e55a0ef749025a5a2ca0ad251e81 -81a423423e9438343879f2bfd7ee9f1c74ebebe7ce3cfffc8a11da6f040cc4145c3b527bd3cf63f9137e714dbcb474ef -b8c3535701ddbeec2db08e17a4fa99ba6752d32ece5331a0b8743676f421fcb14798afc7c783815484f14693d2f70db8 -81aee980c876949bf40782835eec8817d535f6f3f7e00bf402ddd61101fdcd60173961ae90a1cf7c5d060339a18c959d -87e67b928d97b62c49dac321ce6cb680233f3a394d4c9a899ac2e8db8ccd8e00418e66cdfd68691aa3cb8559723b580c -8eac204208d99a2b738648df96353bbb1b1065e33ee4f6bba174b540bbbd37d205855e1f1e69a6b7ff043ca377651126 -848e6e7a54ad64d18009300b93ea6f459ce855971dddb419b101f5ac4c159215626fadc20cc3b9ab1701d8f6dfaddd8b -88aa123d9e0cf309d46dddb6acf634b1ade3b090a2826d6e5e78669fa1220d6df9a6697d7778cd9b627db17eea846126 -9200c2a629b9144d88a61151b661b6c4256cc5dadfd1e59a8ce17a013c2d8f7e754aabe61663c3b30f1bc47784c1f8cf -b6e1a2827c3bdda91715b0e1b1f10dd363cef337e7c80cac1f34165fc0dea7c8b69747e310563db5818390146ce3e231 -92c333e694f89f0d306d54105b2a5dcc912dbe7654d9e733edab12e8537350815be472b063e56cfde5286df8922fdecb -a6fac04b6d86091158ebb286586ccfec2a95c9786e14d91a9c743f5f05546073e5e3cc717635a0c602cad8334e922346 -a581b4af77feebc1fb897d49b5b507c6ad513d8f09b273328efbb24ef0d91eb740d01b4d398f2738125dacfe550330cd -81c4860cccf76a34f8a2bc3f464b7bfd3e909e975cce0d28979f457738a56e60a4af8e68a3992cf273b5946e8d7f76e2 -8d1eaa09a3180d8af1cbaee673db5223363cc7229a69565f592fa38ba0f9d582cedf91e15dabd06ebbf2862fc0feba54 -9832f49b0147f4552402e54593cfa51f99540bffada12759b71fcb86734be8e500eea2d8b3d036710bdf04c901432de9 -8bdb0e8ec93b11e5718e8c13cb4f5de545d24829fd76161216340108098dfe5148ed25e3b57a89a516f09fa79043734d -ab96f06c4b9b0b2c0571740b24fca758e6976315053a7ecb20119150a9fa416db2d3a2e0f8168b390bb063f0c1caf785 -ab777f5c52acd62ecf4d1f168b9cc8e1a9b45d4ec6a8ff52c583e867c2239aba98d7d3af977289b367edce03d9c2dfb1 -a09d3ce5e748da84802436951acc3d3ea5d8ec1d6933505ed724d6b4b0d69973ab0930daec9c6606960f6e541e4a3ce2 -8ef94f7be4d85d5ad3d779a5cf4d7b2fc3e65c52fb8e1c3c112509a4af77a0b5be994f251e5e40fabeeb1f7d5615c22b -a7406a5bf5708d9e10922d3c5c45c03ef891b8d0d74ec9f28328a72be4cdc05b4f2703fa99366426659dfca25d007535 -b7f52709669bf92a2e070bfe740f422f0b7127392c5589c7f0af71bb5a8428697c762d3c0d74532899da24ea7d8695c2 -b9dfb0c8df84104dbf9239ccefa4672ef95ddabb8801b74997935d1b81a78a6a5669a3c553767ec19a1281f6e570f4ff -ae4d5c872156061ce9195ac640190d8d71dd406055ee43ffa6f9893eb24b870075b74c94d65bc1d5a07a6573282b5520 -afe6bd3eb72266d333f1807164900dcfa02a7eb5b1744bb3c86b34b3ee91e3f05e38fa52a50dc64eeb4bdb1dd62874b8 -948043cf1bc2ef3c01105f6a78dc06487f57548a3e6ef30e6ebc51c94b71e4bf3ff6d0058c72b6f3ecc37efd7c7fa8c0 -a22fd17c2f7ffe552bb0f23fa135584e8d2d8d75e3f742d94d04aded2a79e22a00dfe7acbb57d44e1cdb962fb22ae170 -8cd0f4e9e4fb4a37c02c1bde0f69359c43ab012eb662d346487be0c3758293f1ca560122b059b091fddce626383c3a8f -90499e45f5b9c81426f3d735a52a564cafbed72711d9279fdd88de8038e953bc48c57b58cba85c3b2e4ce56f1ddb0e11 -8c30e4c034c02958384564cac4f85022ef36ab5697a3d2feaf6bf105049675bbf23d01b4b6814711d3d9271abff04cac -81f7999e7eeea30f3e1075e6780bbf054f2fb6f27628a2afa4d41872a385b4216dd5f549da7ce6cf39049b2251f27fb7 -b36a7191f82fc39c283ffe53fc1f5a9a00b4c64eee7792a8443475da9a4d226cf257f226ea9d66e329af15d8f04984ec -aad4da528fdbb4db504f3041c747455baff5fcd459a2efd78f15bdf3aea0bdb808343e49df88fe7a7c8620009b7964a3 -99ebd8c6dd5dd299517fb6381cfc2a7f443e6e04a351440260dd7c2aee3f1d8ef06eb6c18820b394366ecdfd2a3ce264 -8873725b81871db72e4ec3643084b1cdce3cbf80b40b834b092767728605825c19b6847ad3dcf328438607e8f88b4410 -b008ee2f895daa6abd35bd39b6f7901ae4611a11a3271194e19da1cdcc7f1e1ea008fe5c5440e50d2c273784541ad9c5 -9036feafb4218d1f576ef89d0e99124e45dacaa6d816988e34d80f454d10e96809791d5b78f7fd65f569e90d4d7238c5 -92073c1d11b168e4fa50988b0288638b4868e48bbc668c5a6dddf5499875d53be23a285acb5e4bad60114f6cf6c556e9 -88c87dfcb8ba6cbfe7e1be081ccfadbd589301db2cb7c99f9ee5d7db90aa297ed1538d5a867678a763f2deede5fd219a -b42a562805c661a50f5dea63108002c0f27c0da113da6a9864c9feb5552225417c0356c4209e8e012d9bcc9d182c7611 -8e6317d00a504e3b79cd47feb4c60f9df186467fe9ca0f35b55c0364db30528f5ff071109dabb2fc80bb9cd4949f0c24 -b7b1ea6a88694f8d2f539e52a47466695e39e43a5eb9c6f23bca15305fe52939d8755cc3ac9d6725e60f82f994a3772f -a3cd55161befe795af93a38d33290fb642b8d80da8b786c6e6fb02d393ea308fbe87f486994039cbd7c7b390414594b6 -b416d2d45b44ead3b1424e92c73c2cf510801897b05d1724ff31cbd741920cd858282fb5d6040fe1f0aa97a65bc49424 -950ee01291754feace97c2e933e4681e7ddfbc4fcd079eb6ff830b0e481d929c93d0c7fb479c9939c28ca1945c40da09 -869bd916aee8d86efe362a49010382674825d49195b413b4b4018e88ce43fe091b475d0b863ff0ba2259400f280c2b23 -9782f38cd9c9d3385ec286ebbc7cba5b718d2e65a5890b0a5906b10a89dc8ed80d417d71d7c213bf52f2af1a1f513ea7 -91cd33bc2628d096269b23faf47ee15e14cb7fdc6a8e3a98b55e1031ea0b68d10ba30d97e660f7e967d24436d40fad73 -8becc978129cc96737034c577ae7225372dd855da8811ae4e46328e020c803833b5bdbc4a20a93270e2b8bd1a2feae52 -a36b1d8076783a9522476ce17f799d78008967728ce920531fdaf88303321bcaf97ecaa08e0c01f77bc32e53c5f09525 -b4720e744943f70467983aa34499e76de6d59aa6fadf86f6b787fdce32a2f5b535b55db38fe2da95825c51002cfe142d -91ad21fc502eda3945f6de874d1b6bf9a9a7711f4d61354f9e5634fc73f9c06ada848de15ab0a75811d3250be862827d -84f78e2ebf5fc077d78635f981712daf17e2475e14c2a96d187913006ad69e234746184a51a06ef510c9455b38acb0d7 -960aa7906e9a2f11db64a26b5892ac45f20d2ccb5480f4888d89973beb6fa0dfdc06d68d241ff5ffc7f1b82b1aac242d -a99365dcd1a00c66c9db6924b97c920f5c723380e823b250db85c07631b320ec4e92e586f7319e67a522a0578f7b6d6c -a25d92d7f70cf6a88ff317cfec071e13774516da664f5fac0d4ecaa65b8bf4eb87a64a4d5ef2bd97dfae98d388dbf5cc -a7af47cd0041295798f9779020a44653007444e8b4ef0712982b06d0dcdd434ec4e1f7c5f7a049326602cb605c9105b7 -aefe172eac5568369a05980931cc476bebd9dea573ba276d59b9d8c4420784299df5a910033b7e324a6c2dfc62e3ef05 -b69bc9d22ffa645baa55e3e02522e9892bb2daa7fff7c15846f13517d0799766883ee09ae0869df4139150c5b843ca8a -95a10856140e493354fdd12722c7fdded21b6a2ffbc78aa2697104af8ad0c8e2206f44b0bfee077ef3949d46bbf7c16b -891f2fcd2c47cbea36b7fa715968540c233313f05333f09d29aba23c193f462ed490dd4d00969656e89c53155fdfe710 -a6c33e18115e64e385c843dde34e8a228222795c7ca90bc2cc085705d609025f3351d9be61822c69035a49fb3e48f2d5 -b87fb12f12c0533b005adad0487f03393ff682e13575e3cb57280c3873b2c38ba96a63c49eef7a442753d26b7005230b -b905c02ba451bfd411c135036d92c27af3b0b1c9c2f1309d6948544a264b125f39dd41afeff4666b12146c545adc168a -8b29c513f43a78951cf742231cf5457a6d9d55edf45df5481a0f299a418d94effef561b15d2c1a01d1b8067e7153fda9 -b9941cccd51dc645920d2781c81a317e5a33cb7cf76427b60396735912cb6d2ca9292bb4d36b6392467d390d2c58d9f3 -a8546b627c76b6ef5c93c6a98538d8593dbe21cb7673fd383d5401b0c935eea0bdeeefeb1af6ad41bad8464fb87bbc48 -aa286b27de2812de63108a1aec29d171775b69538dc6198640ac1e96767c2b83a50391f49259195957d457b493b667c9 -a932fb229f641e9abbd8eb2bd874015d97b6658ab6d29769fc23b7db9e41dd4f850382d4c1f08af8f156c5937d524473 -a1412840fcc86e2aeec175526f2fb36e8b3b8d21a78412b7266daf81e51b3f68584ed8bd42a66a43afdd8c297b320520 -89c78be9efb624c97ebca4fe04c7704fa52311d183ffd87737f76b7dadc187c12c982bd8e9ed7cd8beb48cdaafd2fd01 -a3f5ddec412a5bec0ce15e3bcb41c6214c2b05d4e9135a0d33c8e50a78eaba71e0a5a6ea8b45854dec5c2ed300971fc2 -9721f9cec7a68b7758e3887548790de49fa6a442d0396739efa20c2f50352a7f91d300867556d11a703866def2d5f7b5 -a23764e140a87e5991573521af039630dd28128bf56eed2edbed130fd4278e090b60cf5a1dca9de2910603d44b9f6d45 -a1a6494a994215e48ab55c70efa8ffdddce6e92403c38ae7e8dd2f8288cad460c6c7db526bbdf578e96ca04d9fe12797 -b1705ea4cb7e074efe0405fc7b8ee2ec789af0426142f3ec81241cacd4f7edcd88e39435e4e4d8e7b1df64f3880d6613 -85595d061d677116089a6064418b93eb44ff79e68d12bd9625078d3bbc440a60d0b02944eff6054433ee34710ae6fbb4 -9978d5e30bedb7526734f9a1febd973a70bfa20890490e7cc6f2f9328feab1e24f991285dbc3711d892514e2d7d005ad -af30243c66ea43b9f87a061f947f7bce745f09194f6e95f379c7582b9fead920e5d6957eaf05c12ae1282ada4670652f -a1930efb473f88001e47aa0b2b2a7566848cccf295792e4544096ecd14ee5d7927c173a8576b405bfa2eec551cd67eb5 -b0446d1c590ee5a45f7e22d269c044f3848c97aec1d226b44bfd0e94d9729c28a38bccddc3a1006cc5fe4e3c24f001f2 -b8a8380172df3d84b06176df916cf557966d4f2f716d3e9437e415d75b646810f79f2b2b71d857181b7fc944018883a3 -a563afec25b7817bfa26e19dc9908bc00aa8fc3d19be7d6de23648701659009d10e3e4486c28e9c6b13d48231ae29ac5 -a5a8e80579de886fb7d6408f542791876885947b27ad6fa99a8a26e381f052598d7b4e647b0115d4b5c64297e00ce28e -8f87afcc7ad33c51ac719bade3cd92da671a37a82c14446b0a2073f4a0a23085e2c8d31913ed2d0be928f053297de8f6 -a43c455ce377e0bc434386c53c752880687e017b2f5ae7f8a15c044895b242dffde4c92fb8f8bb50b18470b17351b156 -8368f8b12a5bceb1dba25adb3a2e9c7dc9b1a77a1f328e5a693f5aec195cd1e06b0fe9476b554c1c25dac6c4a5b640a3 -919878b27f3671fc78396f11531c032f3e2bd132d04cc234fa4858676b15fb1db3051c0b1db9b4fc49038216f11321ce -b48cd67fb7f1242696c1f877da4bdf188eac676cd0e561fbac1a537f7b8229aff5a043922441d603a26aae56a15faee4 -a3e0fdfd4d29ea996517a16f0370b54787fefe543c2fe73bfc6f9e560c1fd30dad8409859e2d7fa2d44316f24746c712 -8bb156ade8faf149df7bea02c140c7e392a4742ae6d0394d880a849127943e6f26312033336d3b9fdc0092d71b5efe87 -8845e5d5cc555ca3e0523244300f2c8d7e4d02aaebcb5bd749d791208856c209a6f84dd99fd55968c9f0ab5f82916707 -a3e90bb5c97b07789c2f32dff1aec61d0a2220928202f5ad5355ae71f8249237799d6c8a22602e32e572cb12eabe0c17 -b150bcc391884c996149dc3779ce71f15dda63a759ee9cc05871f5a8379dcb62b047098922c0f26c7bd04deb394c33f9 -95cd4ad88d51f0f2efcfd0c2df802fe252bb9704d1afbf9c26a248df22d55da87bdfaf41d7bc6e5df38bd848f0b13f42 -a05a49a31e91dff6a52ac8b9c2cfdd646a43f0d488253f9e3cfbce52f26667166bbb9b608fc358763a65cbf066cd6d05 -a59c3c1227fdd7c2e81f5e11ef5c406da44662987bac33caed72314081e2eed66055d38137e01b2268e58ec85dd986c0 -b7020ec3bd73a99861f0f1d88cf5a19abab1cbe14b7de77c9868398c84bb8e18dbbe9831838a96b6d6ca06e82451c67b -98d1ff2525e9718ee59a21d8900621636fcd873d9a564b8dceb4be80a194a0148daf1232742730b3341514b2e5a5436c -886d97b635975fc638c1b6afc493e5998ca139edba131b75b65cfe5a8e814f11bb678e0eeee5e6e5cd913ad3f2fefdfc -8fb9fd928d38d5d813b671c924edd56601dd7163b686c13f158645c2f869d9250f3859aa5463a39258c90fef0f41190a -aac35e1cd655c94dec3580bb3800bd9c2946c4a9856f7d725af15fbea6a2d8ca51c8ad2772abed60ee0e3fb9cb24046b -b8d71fa0fa05ac9e443c9b4929df9e7f09a919be679692682e614d24227e04894bfc14a5c73a62fb927fedff4a0e4aa7 -a45a19f11fbbb531a704badbb813ed8088ab827c884ee4e4ebf363fa1132ff7cfa9d28be9c85b143e4f7cdbc94e7cf1a -82b54703a4f295f5471b255ab59dce00f0fe90c9fb6e06b9ee48b15c91d43f4e2ef4a96c3118aeb03b08767be58181bb -8283264c8e6d2a36558f0d145c18576b6600ff45ff99cc93eca54b6c6422993cf392668633e5df396b9331e873d457e5 -8c549c03131ead601bc30eb6b9537b5d3beb7472f5bb1bcbbfd1e9f3704477f7840ab3ab7f7dc13bbbbcdff886a462d4 -afbb0c520ac1b5486513587700ad53e314cb74bfbc12e0b5fbdcfdaac36d342e8b59856196a0d84a25cff6e6e1d17e76 -89e4c22ffb51f2829061b3c7c1983c5c750cad158e3a825d46f7cf875677da5d63f653d8a297022b5db5845c9271b32b -afb27a86c4c2373088c96b9adf4433f2ebfc78ac5c526e9f0510670b6e4e5e0057c0a4f75b185e1a30331b9e805c1c15 -a18e16b57445f88730fc5d3567bf5a176861dc14c7a08ed2996fe80eed27a0e7628501bcb78a1727c5e9ac55f29c12c4 -93d61bf88b192d6825cf4e1120af1c17aa0f994d158b405e25437eaeefae049f7b721a206e7cc8a04fdc29d3c42580a1 -a99f2995a2e3ed2fd1228d64166112038de2f516410aa439f4c507044e2017ea388604e2d0f7121256fadf7fbe7023d1 -914fd91cffc23c32f1c6d0e98bf660925090d873367d543034654389916f65f552e445b0300b71b61b721a72e9a5983c -b42a578a7787b71f924e7def425d849c1c777156b1d4170a8ee7709a4a914e816935131afd9a0412c4cb952957b20828 -82fb30590e84b9e45db1ec475a39971cf554dc01bcc7050bc89265740725c02e2be5a972168c5170c86ae83e5b0ad2c0 -b14f8d8e1e93a84976289e0cf0dfa6f3a1809e98da16ee5c4932d0e1ed6bf8a07697fdd4dd86a3df84fb0003353cdcc0 -85d7a2f4bda31aa2cb208b771fe03291a4ebdaf6f1dc944c27775af5caec412584c1f45bc741fca2a6a85acb3f26ad7d -af02e56ce886ff2253bc0a68faad76f25ead84b2144e5364f3fb9b648f03a50ee9dc0b2c33ebacf7c61e9e43201ef9ef -87e025558c8a0b0abd06dfc350016847ea5ced7af2d135a5c9eec9324a4858c4b21510fb0992ec52a73447f24945058e -80fff0bafcd058118f5e7a4d4f1ae0912efeb281d2cbe4d34ba8945cc3dbe5d8baf47fb077343b90b8d895c90b297aca -b6edcf3a40e7b1c3c0148f47a263cd819e585a51ef31c2e35a29ce6f04c53e413f743034c0d998d9c00a08ba00166f31 -abb87ed86098c0c70a76e557262a494ff51a30fb193f1c1a32f8e35eafa34a43fcc07aa93a3b7a077d9e35afa07b1a3d -a280214cd3bb0fb7ecd2d8bcf518cbd9078417f2b91d2533ec2717563f090fb84f2a5fcfdbbeb2a2a1f8a71cc5aa5941 -a63083ca7238ea2b57d15a475963cf1d4f550d8cd76db290014a0461b90351f1f26a67d674c837b0b773b330c7c3d534 -a8fa39064cb585ece5263e2f42f430206476bf261bd50f18d2b694889bd79d04d56410664cecad62690e5c5a20b3f6ff -85ba52ce9d700a5dcf6c5b00559acbe599d671ce5512467ff4b6179d7fad550567ce2a9c126a50964e3096458ea87920 -b913501e1008f076e5eac6d883105174f88b248e1c9801e568fefaffa1558e4909364fc6d9512aa4d125cbd7cc895f05 -8eb33b5266c8f2ed4725a6ad147a322e44c9264cf261c933cbbe230a43d47fca0f29ec39756b20561dabafadd5796494 -850ebc8b661a04318c9db5a0515066e6454fa73865aa4908767a837857ecd717387f614acb614a88e075d4edc53a2f5a -a08d6b92d866270f29f4ce23a3f5d99b36b1e241a01271ede02817c8ec3f552a5c562db400766c07b104a331835c0c64 -8131804c89bb3e74e9718bfc4afa547c1005ff676bd4db9604335032b203390cfa54478d45c6c78d1fe31a436ed4be9f -9106d94f23cc1eacec8316f16d6f0a1cc160967c886f51981fdb9f3f12ee1182407d2bb24e5b873de58cb1a3ee915a6b -a13806bfc3eae7a7000c9d9f1bd25e10218d4e67f59ae798b145b098bca3edad2b1040e3fc1e6310e612fb8818f459ac -8c69fbca502046cb5f6db99900a47b34117aef3f4b241690cdb3b84ca2a2fc7833e149361995dc41fa78892525bce746 -852c473150c91912d58ecb05769222fa18312800c3f56605ad29eec9e2d8667b0b81c379048d3d29100ed2773bb1f3c5 -b1767f6074426a00e01095dbb1795beb4e4050c6411792cbad6537bc444c3165d1058bafd1487451f9c5ddd209e0ae7e -80c600a5fe99354ce59ff0f84c760923dc8ff66a30bf47dc0a086181785ceb01f9b951c4e66df800ea6d705e8bc47055 -b5cf19002fbc88a0764865b82afcb4d64a50196ea361e5c71dff7de084f4dcbbc34ec94a45cc9e0247bd51da565981aa -93e67a254ea8ce25e112d93cc927fadaa814152a2c4ec7d9a56eaa1ed47aec99b7e9916b02e64452cc724a6641729bbb -ace70b32491bda18eee4a4d041c3bc9effae9340fe7e6c2f5ad975ee0874c17f1a7da7c96bd85fccff9312c518fac6e9 -ab4cfa02065017dd7f1aadc66f2c92f78f0f11b8597c03a5d69d82cb2eaf95a4476a836ac102908f137662472c8d914b -a40b8cd8deb8ae503d20364d64cab7c2801b7728a9646ed19c65edea6a842756a2f636283494299584ad57f4bb12cd0b -8594e11d5fc2396bcd9dbf5509ce4816dbb2b7305168021c426171fb444d111da5a152d6835ad8034542277011c26c0e -8024de98c26b4c994a66628dc304bb737f4b6859c86ded552c5abb81fd4c6c2e19d5a30beed398a694b9b2fdea1dd06a -8843f5872f33f54df8d0e06166c1857d733995f67bc54abb8dfa94ad92407cf0179bc91b0a50bbb56cdc2b350d950329 -b8bab44c7dd53ef9edf497dcb228e2a41282c90f00ba052fc52d57e87b5c8ab132d227af1fcdff9a12713d1f980bcaae -982b4d7b29aff22d527fd82d2a52601d95549bfb000429bb20789ed45e5abf1f4b7416c7b7c4b79431eb3574b29be658 -8eb1f571b6a1878e11e8c1c757e0bc084bab5e82e897ca9be9b7f4b47b91679a8190bf0fc8f799d9b487da5442415857 -a6e74b588e5af935c8b243e888582ef7718f8714569dd4992920740227518305eb35fab674d21a5551cca44b3e511ef2 -a30fc2f3a4cb4f50566e82307de73cd7bd8fe2c1184e9293c136a9b9e926a018d57c6e4f308c95b9eb8299e94d90a2a1 -a50c5869ca5d2b40722c056a32f918d47e0b65ca9d7863ca7d2fb4a7b64fe523fe9365cf0573733ceaadebf20b48fff8 -83bbdd32c04d17581418cf360749c7a169b55d54f2427390defd9f751f100897b2d800ce6636c5bbc046c47508d60c8c -a82904bdf614de5d8deaff688c8a5e7ac5b3431687acbcda8fa53960b7c417a39c8b2e462d7af91ce6d79260f412db8e -a4362e31ff4b05d278b033cf5eebea20de01714ae16d4115d04c1da4754269873afc8171a6f56c5104bfd7b0db93c3e7 -b5b8daa63a3735581e74a021b684a1038cea77168fdb7fdf83c670c2cfabcfc3ab2fc7359069b5f9048188351aef26b5 -b48d723894b7782d96ac8433c48faca1bdfa5238019c451a7f47d958097cce3ae599b876cf274269236b9d6ff8b6d7ca -98ffff6a61a3a6205c7820a91ca2e7176fab5dba02bc194c4d14942ac421cb254183c705506ab279e4f8db066f941c6c -ae7db24731da2eaa6efc4f7fcba2ecc26940ddd68038dce43acf2cee15b72dc4ef42a7bfdd32946d1ed78786dd7696b3 -a656db14f1de9a7eb84f6301b4acb2fbf78bfe867f48a270e416c974ab92821eb4df1cb881b2d600cfed0034ac784641 -aa315f8ecba85a5535e9a49e558b15f39520fce5d4bf43131bfbf2e2c9dfccc829074f9083e8d49f405fb221d0bc4c3c -90bffba5d9ff40a62f6c8e9fc402d5b95f6077ed58d030c93e321b8081b77d6b8dac3f63a92a7ddc01585cf2c127d66c -abdd733a36e0e0f05a570d0504e73801bf9b5a25ff2c78786f8b805704997acb2e6069af342538c581144d53149fa6d3 -b4a723bb19e8c18a01bd449b1bb3440ddb2017f10bb153da27deb7a6a60e9bb37619d6d5435fbb1ba617687838e01dd0 -870016b4678bab3375516db0187a2108b2e840bae4d264b9f4f27dbbc7cc9cac1d7dc582d7a04d6fd1ed588238e5e513 -80d33d2e20e8fc170aa3cb4f69fffb72aeafb3b5bb4ea0bc79ab55da14142ca19b2d8b617a6b24d537366e3b49cb67c3 -a7ee76aec273aaae03b3b87015789289551969fb175c11557da3ab77e39ab49d24634726f92affae9f4d24003050d974 -8415ea4ab69d779ebd42d0fe0c6aef531d6a465a5739e429b1fcf433ec45aa8296c527e965a20f0ec9f340c9273ea3cf -8c7662520794e8b4405d0b33b5cac839784bc86a5868766c06cbc1fa306dbe334978177417b31baf90ce7b0052a29c56 -902b2abecc053a3dbdea9897ee21e74821f3a1b98b2d560a514a35799f4680322550fd3a728d4f6d64e1de98033c32b8 -a05e84ed9ecab8d508d670c39f2db61ad6e08d2795ec32a3c9d0d3737ef3801618f4fc2a95f90ec2f068606131e076c5 -8b9208ff4d5af0c2e3f53c9375da666773ac57197dfabb0d25b1c8d0588ba7f3c15ee9661bb001297f322ea2fbf6928b -a3c827741b34a03254d4451b5ab74a96f2b9f7fb069e2f5adaf54fd97cc7a4d516d378db5ca07da87d8566d6eef13726 -8509d8a3f4a0ed378e0a1e28ea02f6bf1d7f6c819c6c2f5297c7df54c895b848f841653e32ba2a2c22c2ff739571acb8 -a0ce988b7d3c40b4e496aa83a09e4b5472a2d98679622f32bea23e6d607bc7de1a5374fb162bce0549a67dad948519be -aa8a3dd12bd60e3d2e05f9c683cdcb8eab17fc59134815f8d197681b1bcf65108cba63ac5c58ee632b1e5ed6bba5d474 -8b955f1d894b3aefd883fb4b65f14cd37fc2b9db77db79273f1700bef9973bf3fd123897ea2b7989f50003733f8f7f21 -ac79c00ddac47f5daf8d9418d798d8af89fc6f1682e7e451f71ea3a405b0d36af35388dd2a332af790bc83ca7b819328 -a0d44dd2a4438b809522b130d0938c3fe7c5c46379365dbd1810a170a9aa5818e1c783470dd5d0b6d4ac7edbb7330910 -a30b69e39ad43dd540a43c521f05b51b5f1b9c4eed54b8162374ae11eac25da4f5756e7b70ce9f3c92c2eeceee7431ed -ac43220b762c299c7951222ea19761ab938bf38e4972deef58ed84f4f9c68c230647cf7506d7cbfc08562fcca55f0485 -b28233b46a8fb424cfa386a845a3b5399d8489ceb83c8f3e05c22c934798d639c93718b7b68ab3ce24c5358339e41cbb -ac30d50ee8ce59a10d4b37a3a35e62cdb2273e5e52232e202ca7d7b8d09d28958ee667fae41a7bb6cdc6fe8f6e6c9c85 -b199842d9141ad169f35cc7ff782b274cbaa645fdb727761e0a89edbf0d781a15f8218b4bf4eead326f2903dd88a9cc1 -85e018c7ddcad34bb8285a737c578bf741ccd547e68c734bdb3808380e12c5d4ef60fc896b497a87d443ff9abd063b38 -8c856e6ba4a815bdb891e1276f93545b7072f6cb1a9aa6aa5cf240976f29f4dee01878638500a6bf1daf677b96b54343 -b8a47555fa8710534150e1a3f13eab33666017be6b41005397afa647ea49708565f2b86b77ad4964d140d9ced6b4d585 -8cd1f1db1b2f4c85a3f46211599caf512d5439e2d8e184663d7d50166fd3008f0e9253272f898d81007988435f715881 -b1f34b14612c973a3eceb716dc102b82ab18afef9de7630172c2780776679a7706a4874e1df3eaadf541fb009731807f -b25464af9cff883b55be2ff8daf610052c02df9a5e147a2cf4df6ce63edcdee6dc535c533590084cc177da85c5dc0baa -91c3c4b658b42d8d3448ae1415d4541d02379a40dc51e36a59bd6e7b9ba3ea51533f480c7c6e8405250ee9b96a466c29 -86dc027b95deb74c36a58a1333a03e63cb5ae22d3b29d114cfd2271badb05268c9d0c819a977f5e0c6014b00c1512e3a -ae0e6ff58eb5fa35da5107ebeacf222ab8f52a22bb1e13504247c1dfa65320f40d97b0e6b201cb6613476687cb2f0681 -8f13415d960b9d7a1d93ef28afc2223e926639b63bdefce0f85e945dfc81670a55df288893a0d8b3abe13c5708f82f91 -956f67ca49ad27c1e3a68c1faad5e7baf0160c459094bf6b7baf36b112de935fdfd79fa4a9ea87ea8de0ac07272969f4 -835e45e4a67df9fb51b645d37840b3a15c171d571a10b03a406dd69d3c2f22df3aa9c5cbe1e73f8d767ce01c4914ea9a -919b938e56d4b32e2667469d0bdccb95d9dda3341aa907683ee70a14bbbe623035014511c261f4f59b318b610ac90aa3 -96b48182121ccd9d689bf1dfdc228175564cd68dc904a99c808a7f0053a6f636c9d953e12198bdf2ea49ea92772f2e18 -ac5e5a941d567fa38fdbcfa8cf7f85bb304e3401c52d88752bcd516d1fa9bac4572534ea2205e38423c1df065990790f -ac0bd594fb85a8d4fc26d6df0fa81f11919401f1ecf9168b891ec7f061a2d9368af99f7fd8d9b43b2ce361e7b8482159 -83d92c69ca540d298fe80d8162a1c7af3fa9b49dfb69e85c1d136a3ec39fe419c9fa78e0bb6d96878771fbd37fe92e40 -b35443ae8aa66c763c2db9273f908552fe458e96696b90e41dd509c17a5c04ee178e3490d9c6ba2dc0b8f793c433c134 -923b2d25aa45b2e580ffd94cbb37dc8110f340f0f011217ee1bd81afb0714c0b1d5fb4db86006cdd2457563276f59c59 -96c9125d38fca1a61ac21257b696f8ac3dae78def50285e44d90ea293d591d1c58f703540a7e4e99e070afe4646bbe15 -b57946b2332077fbcdcb406b811779aefd54473b5559a163cd65cb8310679b7e2028aa55c12a1401fdcfcac0e6fae29a -845daedc5cf972883835d7e13c937b63753c2200324a3b8082a6c4abb4be06c5f7c629d4abe4bfaf1d80a1f073eb6ce6 -91a55dfd0efefcd03dc6dacc64ec93b8d296cb83c0ee72400a36f27246e7f2a60e73b7b70ba65819e9cfb73edb7bd297 -8874606b93266455fe8fdd25df9f8d2994e927460af06f2e97dd4d2d90db1e6b06d441b72c2e76504d753badca87fb37 -8ee99e6d231274ff9252c0f4e84549da173041299ad1230929c3e3d32399731c4f20a502b4a307642cac9306ccd49d3c -8836497714a525118e20849d6933bb8535fb6f72b96337d49e3133d936999c90a398a740f42e772353b5f1c63581df6d -a6916945e10628f7497a6cdc5e2de113d25f7ade3e41e74d3de48ccd4fce9f2fa9ab69645275002e6f49399b798c40af -9597706983107eb23883e0812e1a2c58af7f3499d50c6e29b455946cb9812fde1aa323d9ed30d1c0ffd455abe32303cd -a24ee89f7f515cc33bdbdb822e7d5c1877d337f3b2162303cfc2dae028011c3a267c5cb4194afa63a4856a6e1c213448 -8cd25315e4318801c2776824ae6e7d543cb85ed3bc2498ba5752df2e8142b37653cf9e60104d674be3aeb0a66912e97a -b5085ecbe793180b40dbeb879f4c976eaaccaca3a5246807dced5890e0ed24d35f3f86955e2460e14fb44ff5081c07ba -960188cc0b4f908633a6840963a6fa2205fc42c511c6c309685234911c5304ef4c304e3ae9c9c69daa2fb6a73560c256 -a32d0a70bf15d569b4cda5aebe3e41e03c28bf99cdd34ffa6c5d58a097f322772acca904b3a47addb6c7492a7126ebac -977f72d06ad72d4aa4765e0f1f9f4a3231d9f030501f320fe7714cc5d329d08112789fa918c60dd7fdb5837d56bb7fc6 -99fa038bb0470d45852bb871620d8d88520adb701712fcb1f278fed2882722b9e729e6cdce44c82caafad95e37d0e6f7 -b855e8f4fc7634ada07e83b6c719a1e37acb06394bc8c7dcab7747a8c54e5df3943915f021364bd019fdea103864e55f -88bc2cd7458532e98c596ef59ea2cf640d7cc31b4c33cef9ed065c078d1d4eb49677a67de8e6229cc17ea48bace8ee5a -aaa78a3feaa836d944d987d813f9b9741afb076e6aca1ffa42682ab06d46d66e0c07b8f40b9dbd63e75e81efa1ef7b08 -b7b080420cc4d808723b98b2a5b7b59c81e624ab568ecdfdeb8bf3aa151a581b6f56e983ef1b6f909661e25db40b0c69 -abee85c462ac9a2c58e54f06c91b3e5cd8c5f9ab5b5deb602b53763c54826ed6deb0d6db315a8d7ad88733407e8d35e2 -994d075c1527407547590df53e9d72dd31f037c763848d1662eebd4cefec93a24328c986802efa80e038cb760a5300f5 -ab8777640116dfb6678e8c7d5b36d01265dfb16321abbfc277da71556a34bb3be04bc4ae90124ed9c55386d2bfb3bda0 -967e3a828bc59409144463bcf883a3a276b5f24bf3cbfdd7a42343348cba91e00b46ac285835a9b91eef171202974204 -875a9f0c4ffe5bb1d8da5e3c8e41d0397aa6248422a628bd60bfae536a651417d4e8a7d2fb98e13f2dad3680f7bd86d3 -acaa330c3e8f95d46b1880126572b238dbb6d04484d2cd4f257ab9642d8c9fc7b212188b9c7ac9e0fd135c520d46b1bf -aceb762edbb0f0c43dfcdb01ea7a1ac5918ca3882b1e7ebc4373521742f1ed5250d8966b498c00b2b0f4d13212e6dd0b -81d072b4ad258b3646f52f399bced97c613b22e7ad76373453d80b1650c0ca87edb291a041f8253b649b6e5429bb4cff -980a47d27416ac39c7c3a0ebe50c492f8c776ea1de44d5159ac7d889b6d554357f0a77f0e5d9d0ff41aae4369eba1fc2 -8b4dfd5ef5573db1476d5e43aacfb5941e45d6297794508f29c454fe50ea622e6f068b28b3debe8635cf6036007de2e3 -a60831559d6305839515b68f8c3bc7abbd8212cc4083502e19dd682d56ca37c9780fc3ce4ec2eae81ab23b221452dc57 -951f6b2c1848ced9e8a2339c65918e00d3d22d3e59a0a660b1eca667d18f8430d737884e9805865ef3ed0fe1638a22d9 -b02e38fe790b492aa5e89257c4986c9033a8b67010fa2add9787de857d53759170fdd67715ca658220b4e14b0ca48124 -a51007e4346060746e6b0e4797fc08ef17f04a34fe24f307f6b6817edbb8ce2b176f40771d4ae8a60d6152cbebe62653 -a510005b05c0b305075b27b243c9d64bcdce85146b6ed0e75a3178b5ff9608213f08c8c9246f2ca6035a0c3e31619860 -aaff4ef27a7a23be3419d22197e13676d6e3810ceb06a9e920d38125745dc68a930f1741c9c2d9d5c875968e30f34ab5 -864522a9af9857de9814e61383bebad1ba9a881696925a0ea6bfc6eff520d42c506bbe5685a9946ed710e889765be4a0 -b63258c080d13f3b7d5b9f3ca9929f8982a6960bdb1b0f8676f4dca823971601672f15e653917bf5d3746bb220504913 -b51ce0cb10869121ae310c7159ee1f3e3a9f8ad498827f72c3d56864808c1f21fa2881788f19ece884d3f705cd7bd0c5 -95d9cecfc018c6ed510e441cf84c712d9909c778c16734706c93222257f64dcd2a9f1bd0b400ca271e22c9c487014274 -8beff4d7d0140b86380ff4842a9bda94c2d2be638e20ac68a4912cb47dbe01a261857536375208040c0554929ced1ddc -891ff49258749e2b57c1e9b8e04b12c77d79c3308b1fb615a081f2aacdfb4b39e32d53e069ed136fdbd43c53b87418fa -9625cad224e163d387738825982d1e40eeff35fe816d10d7541d15fdc4d3eee48009090f3faef4024b249205b0b28f72 -8f3947433d9bd01aa335895484b540a9025a19481a1c40b4f72dd676bfcf332713714fd4010bde936eaf9470fd239ed0 -a00ec2d67789a7054b53f0e858a8a232706ccc29a9f3e389df7455f1a51a2e75801fd78469a13dbc25d28399ae4c6182 -a3f65884506d4a62b8775a0ea0e3d78f5f46bc07910a93cd604022154eabdf1d73591e304d61edc869e91462951975e1 -a14eef4fd5dfac311713f0faa9a60415e3d30b95a4590cbf95f2033dffb4d16c02e7ceff3dcd42148a4e3bc49cce2dd4 -8afa11c0eef3c540e1e3460bc759bb2b6ea90743623f88e62950c94e370fe4fd01c22b6729beba4dcd4d581198d9358f -afb05548a69f0845ffcc5f5dc63e3cdb93cd270f5655173b9a950394b0583663f2b7164ba6df8d60c2e775c1d9f120af -97f179e01a947a906e1cbeafa083960bc9f1bade45742a3afee488dfb6011c1c6e2db09a355d77f5228a42ccaa7bdf8e -8447fca4d35f74b3efcbd96774f41874ca376bf85b79b6e66c92fa3f14bdd6e743a051f12a7fbfd87f319d1c6a5ce217 -a57ca39c23617cd2cf32ff93b02161bd7baf52c4effb4679d9d5166406e103bc8f3c6b5209e17c37dbb02deb8bc72ddd -9667c7300ff80f0140be002b0e36caab07aaee7cce72679197c64d355e20d96196acaf54e06e1382167d081fe6f739c1 -828126bb0559ce748809b622677267ca896fa2ee76360fd2c02990e6477e06a667241379ca7e65d61a5b64b96d7867de -8b8835dea6ba8cf61c91f01a4b3d2f8150b687a4ee09b45f2e5fc8f80f208ae5d142d8e3a18153f0722b90214e60c5a7 -a98e8ff02049b4da386e3ee93db23bbb13dfeb72f1cfde72587c7e6d962780b7671c63e8ac3fbaeb1a6605e8d79e2f29 -87a4892a0026d7e39ef3af632172b88337cb03669dea564bcdb70653b52d744730ebb5d642e20cb627acc9dbb547a26b -877352a22fc8052878a57effc159dac4d75fe08c84d3d5324c0bab6d564cdf868f33ceee515eee747e5856b62cfa0cc7 -8b801ba8e2ff019ee62f64b8cb8a5f601fc35423eb0f9494b401050103e1307dc584e4e4b21249cd2c686e32475e96c3 -a9e7338d6d4d9bfec91b2af28a8ed13b09415f57a3a00e5e777c93d768fdb3f8e4456ae48a2c6626b264226e911a0e28 -99c05fedf40ac4726ed585d7c1544c6e79619a0d3fb6bda75a08c7f3c0008e8d5e19ed4da48de3216135f34a15eba17c -a61cce8a1a8b13a4a650fdbec0eeea8297c352a8238fb7cac95a0df18ed16ee02a3daa2de108fa122aca733bd8ad7855 -b97f37da9005b440b4cb05870dd881bf8491fe735844f2d5c8281818583b38e02286e653d9f2e7fa5e74c3c3eb616540 -a72164a8554da8e103f692ac5ebb4aece55d5194302b9f74b6f2a05335b6e39beede0bf7bf8c5bfd4d324a784c5fb08c -b87e8221c5341cd9cc8bb99c10fe730bc105550f25ed4b96c0d45e6142193a1b2e72f1b3857373a659b8c09be17b3d91 -a41fb1f327ef91dcb7ac0787918376584890dd9a9675c297c45796e32d6e5985b12f9b80be47fc3a8596c245f419d395 -90dafa3592bdbb3465c92e2a54c2531822ba0459d45d3e7a7092fa6b823f55af28357cb51896d4ec2d66029c82f08e26 -a0a9adc872ebc396557f484f1dd21954d4f4a21c4aa5eec543f5fa386fe590839735c01f236574f7ff95407cd12de103 -b8c5c940d58be7538acf8672852b5da3af34f82405ef2ce8e4c923f1362f97fc50921568d0fd2fe846edfb0823e62979 -85aaf06a8b2d0dac89dafd00c28533f35dbd074978c2aaa5bef75db44a7b12aeb222e724f395513b9a535809a275e30b -81f3cbe82fbc7028c26a6c1808c604c63ba023a30c9f78a4c581340008dbda5ec07497ee849a2183fcd9124f7936af32 -a11ac738de75fd60f15a34209d3825d5e23385796a4c7fc5931822f3f380af977dd0f7b59fbd58eed7777a071e21b680 -85a279c493de03db6fa6c3e3c1b1b29adc9a8c4effc12400ae1128da8421954fa8b75ad19e5388fe4543b76fb0812813 -83a217b395d59ab20db6c4adb1e9713fc9267f5f31a6c936042fe051ce8b541f579442f3dcf0fa16b9e6de9fd3518191 -83a0b86e7d4ed8f9ccdc6dfc8ff1484509a6378fa6f09ed908e6ab9d1073f03011dc497e14304e4e3d181b57de06a5ab -a63ad69c9d25704ce1cc8e74f67818e5ed985f8f851afa8412248b2df5f833f83b95b27180e9e7273833ed0d07113d3b -99b1bc2021e63b561fe44ddd0af81fcc8627a91bfeecbbc989b642bc859abc0c8d636399701aad7bbaf6a385d5f27d61 -b53434adb66f4a807a6ad917c6e856321753e559b1add70824e5c1e88191bf6993fccb9b8b911fc0f473fb11743acacd -97ed3b9e6fb99bf5f945d4a41f198161294866aa23f2327818cdd55cb5dc4c1a8eff29dd8b8d04902d6cd43a71835c82 -b1e808260e368a18d9d10bdea5d60223ba1713b948c782285a27a99ae50cc5fc2c53d407de07155ecc16fb8a36d744a0 -a3eb4665f18f71833fec43802730e56b3ee5a357ea30a888ad482725b169d6f1f6ade6e208ee081b2e2633079b82ba7d -ab8beb2c8353fc9f571c18fdd02bdb977fc883313469e1277b0372fbbb33b80dcff354ca41de436d98d2ed710faa467e -aa9071cfa971e4a335a91ad634c98f2be51544cb21f040f2471d01bb97e1df2277ae1646e1ea8f55b7ba9f5c8c599b39 -80b7dbfdcaf40f0678012acc634eba44ea51181475180d9deb2050dc4f2de395289edd0223018c81057ec79b04b04c49 -89623d7f6cb17aa877af14de842c2d4ab7fd576d61ddd7518b5878620a01ded40b6010de0da3cdf31d837eecf30e9847 -a773bb024ae74dd24761f266d4fb27d6fd366a8634febe8235376b1ae9065c2fe12c769f1d0407867dfbe9f5272c352f -8455a561c3aaa6ba64c881a5e13921c592b3a02e968f4fb24a2243c36202795d0366d9cc1a24e916f84d6e158b7aeac7 -81d8bfc4b283cf702a40b87a2b96b275bdbf0def17e67d04842598610b67ea08c804d400c3e69fa09ea001eaf345b276 -b8f8f82cb11fea1c99467013d7e167ff03deb0c65a677fab76ded58826d1ba29aa7cf9fcd7763615735ea3ad38e28719 -89a6a04baf9cccc1db55179e1650b1a195dd91fb0aebc197a25143f0f393524d2589975e3fbfc2547126f0bced7fd6f2 -b81b2162df045390f04df07cbd0962e6b6ca94275a63edded58001a2f28b2ae2af2c7a6cba4ecd753869684e77e7e799 -a3757f722776e50de45c62d9c4a2ee0f5655a512344c4cbec542d8045332806568dd626a719ef21a4eb06792ca70f204 -8c5590df96ec22179a4e8786de41beb44f987a1dcc508eb341eecbc0b39236fdfad47f108f852e87179ccf4e10091e59 -87502f026ed4e10167419130b88c3737635c5b9074c364e1dd247cef5ef0fc064b4ae99b187e33301e438bbd2fe7d032 -af925a2165e980ced620ff12289129fe17670a90ae0f4db9d4b39bd887ccb1f5d2514ac9ecf910f6390a8fc66bd5be17 -857fca899828cf5c65d26e3e8a6e658542782fc72762b3b9c73514919f83259e0f849a9d4838b40dc905fe43024d0d23 -87ffebdbfb69a9e1007ebac4ffcb4090ff13705967b73937063719aa97908986effcb7262fdadc1ae0f95c3690e3245d -a9ff6c347ac6f4c6ab993b748802e96982eaf489dc69032269568412fc9a79e7c2850dfc991b28211b3522ee4454344b -a65b3159df4ec48bebb67cb3663cd744027ad98d970d620e05bf6c48f230fa45bf17527fe726fdf705419bb7a1bb913e -84b97b1e6408b6791831997b03cd91f027e7660fd492a93d95daafe61f02427371c0e237c75706412f442991dfdff989 -ab761c26527439b209af0ae6afccd9340bbed5fbe098734c3145b76c5d2cd7115d9227b2eb523882b7317fbb09180498 -a0479a8da06d7a69c0b0fee60df4e691c19c551f5e7da286dab430bfbcabf31726508e20d26ea48c53365a7f00a3ad34 -a732dfc9baa0f4f40b5756d2e8d8937742999623477458e0bc81431a7b633eefc6f53b3b7939fe0a020018549c954054 -901502436a1169ba51dc479a5abe7c8d84e0943b16bc3c6a627b49b92cd46263c0005bc324c67509edd693f28e612af1 -b627aee83474e7f84d1bab9b7f6b605e33b26297ac6bbf52d110d38ba10749032bd551641e73a383a303882367af429b -95108866745760baef4a46ef56f82da6de7e81c58b10126ebd2ba2cd13d339f91303bf2fb4dd104a6956aa3b13739503 -899ed2ade37236cec90056f3569bc50f984f2247792defafcceb49ad0ca5f6f8a2f06573705300e07f0de0c759289ff5 -a9f5eee196d608efe4bcef9bf71c646d27feb615e21252cf839a44a49fd89da8d26a758419e0085a05b1d59600e2dc42 -b36c6f68fed6e6c85f1f4a162485f24817f2843ec5cbee45a1ebfa367d44892e464949c6669f7972dc7167af08d55d25 -aaaede243a9a1b6162afbc8f571a52671a5a4519b4062e3f26777664e245ba873ed13b0492c5dbf0258c788c397a0e9e -972b4fb39c31cbe127bf9a32a5cc10d621ebdd9411df5e5da3d457f03b2ab2cd1f6372d8284a4a9400f0b06ecdbfd38e -8f6ca1e110e959a4b1d9a5ce5f212893cec21db40d64d5ac4d524f352d72198f923416a850bf845bc5a22a79c0ea2619 -a0f3c93b22134f66f04b2553a53b738644d1665ceb196b8494b315a4c28236fb492017e4a0de4224827c78e42f9908b7 -807fb5ee74f6c8735b0b5ca07e28506214fe4047dbeb00045d7c24f7849e98706aea79771241224939cb749cf1366c7d -915eb1ff034224c0b645442cdb7d669303fdc00ca464f91aaf0b6fde0b220a3a74ff0cb043c26c9f3a5667b3fdaa9420 -8fda6cef56ed33fefffa9e6ac8e6f76b1af379f89761945c63dd448801f7bb8ca970504a7105fac2f74f652ccff32327 -87380cffdcffb1d0820fa36b63cc081e72187f86d487315177d4d04da4533eb19a0e2ff6115ceab528887819c44a5164 -8cd89e03411a18e7f16f968b89fb500c36d47d229f6487b99e62403a980058db5925ce249206743333538adfad168330 -974451b1df33522ce7056de9f03e10c70bf302c44b0741a59df3d6877d53d61a7394dcee1dd46e013d7cb9d73419c092 -98c35ddf645940260c490f384a49496a7352bb8e3f686feed815b1d38f59ded17b1ad6e84a209e773ed08f7b8ff1e4c2 -963f386cf944bb9b2ddebb97171b64253ea0a2894ac40049bdd86cda392292315f3a3d490ca5d9628c890cfb669f0acb -8d507712152babd6d142ee682638da8495a6f3838136088df9424ef50d5ec28d815a198c9a4963610b22e49b4cdf95e9 -83d4bc6b0be87c8a4f1e9c53f257719de0c73d85b490a41f7420e777311640937320557ff2f1d9bafd1daaa54f932356 -82f5381c965b7a0718441131c4d13999f4cdce637698989a17ed97c8ea2e5bdb5d07719c5f7be8688edb081b23ede0f4 -a6ebecab0b72a49dfd01d69fa37a7f74d34fb1d4fef0aa10e3d6fceb9eccd671225c230af89f6eb514250e41a5f91f52 -846d185bdad6e11e604df7f753b7a08a28b643674221f0e750ebdb6b86ec584a29c869e131bca868972a507e61403f6a -85a98332292acb744bd1c0fd6fdcf1f889a78a2c9624d79413ffa194cc8dfa7821a4b60cde8081d4b5f71f51168dd67f -8f7d97c3b4597880d73200d074eb813d95432306e82dafc70b580b8e08cb8098b70f2d07b4b3ac6a4d77e92d57035031 -8185439c8751e595825d7053518cbe121f191846a38d4dbcb558c3f9d7a3104f3153401adaaaf27843bbe2edb504bfe3 -b3c00d8ece1518fca6b1215a139b0a0e26d9cba1b3a424f7ee59f30ce800a5db967279ed60958dd1f3ee69cf4dd1b204 -a2e6cb6978e883f9719c3c0d44cfe8de0cc6f644b98f98858433bea8bbe7b612c8aca5952fccce4f195f9d54f9722dc2 -99663087e3d5000abbec0fbda4e7342ec38846cc6a1505191fb3f1a337cb369455b7f8531a6eb8b0f7b2c4baf83cbe2b -ab0836c6377a4dbc7ca6a4d6cf021d4cd60013877314dd05f351706b128d4af6337711ed3443cb6ca976f40d74070a9a -87abfd5126152fd3bac3c56230579b489436755ea89e0566aa349490b36a5d7b85028e9fb0710907042bcde6a6f5d7e3 -974ba1033f75f60e0cf7c718a57ae1da3721cf9d0fb925714c46f027632bdd84cd9e6de4cf4d00bc55465b1c5ebb7384 -a607b49d73689ac64f25cec71221d30d53e781e1100d19a2114a21da6507a60166166369d860bd314acb226596525670 -a7c2b0b915d7beba94954f2aa7dd08ec075813661e2a3ecca5d28a0733e59583247fed9528eb28aba55b972cdbaf06eb -b8b3123e44128cc8efbe3270f2f94e50ca214a4294c71c3b851f8cbb70cb67fe9536cf07d04bf7fe380e5e3a29dd3c15 -a59a07e343b62ad6445a0859a32b58c21a593f9ddbfe52049650f59628c93715aa1f4e1f45b109321756d0eeec8a5429 -94f51f8a4ed18a6030d0aaa8899056744bd0e9dc9ac68f62b00355cddab11da5da16798db75f0bfbce0e5bdfe750c0b6 -97460a97ca1e1fa5ce243b81425edc0ec19b7448e93f0b55bc9785eedeeafe194a3c8b33a61a5c72990edf375f122777 -8fa859a089bc17d698a7ee381f37ce9beadf4e5b44fce5f6f29762bc04f96faff5d58c48c73631290325f05e9a1ecf49 -abdf38f3b20fc95eff31de5aa9ef1031abfa48f1305ee57e4d507594570401503476d3bcc493838fc24d6967a3082c7f -b8914bfb82815abb86da35c64d39ab838581bc0bf08967192697d9663877825f2b9d6fbdcf9b410463482b3731361aef -a8187f9d22b193a5f578999954d6ec9aa9b32338ccadb8a3e1ce5bad5ea361d69016e1cdfac44e9d6c54e49dd88561b9 -aac262cb7cba7fd62c14daa7b39677cabc1ef0947dd06dd89cac8570006a200f90d5f0353e84f5ff03179e3bebe14231 -a630ef5ece9733b8c46c0a2df14a0f37647a85e69c63148e79ffdcc145707053f9f9d305c3f1cf3c7915cb46d33abd07 -b102c237cb2e254588b6d53350dfda6901bd99493a3fbddb4121d45e0b475cf2663a40d7b9a75325eda83e4ba1e68cb3 -86a930dd1ddcc16d1dfa00aa292cb6c2607d42c367e470aa920964b7c17ab6232a7108d1c2c11fc40fb7496547d0bbf8 -a832fdc4500683e72a96cce61e62ac9ee812c37fe03527ad4cf893915ca1962cee80e72d4f82b20c8fc0b764376635a1 -88ad985f448dabb04f8808efd90f273f11f5e6d0468b5489a1a6a3d77de342992a73eb842d419034968d733f101ff683 -98a8538145f0d86f7fbf9a81c9140f6095c5bdd8960b1c6f3a1716428cd9cca1bf8322e6d0af24e6169abcf7df2b0ff6 -9048c6eba5e062519011e177e955a200b2c00b3a0b8615bdecdebc217559d41058d3315f6d05617be531ef0f6aef0e51 -833bf225ab6fc68cdcacf1ec1b50f9d05f5410e6cdcd8d56a3081dc2be8a8d07b81534d1ec93a25c2e270313dfb99e3b -a84bcd24c3da5e537e64a811b93c91bfc84d7729b9ead7f79078989a6eb76717d620c1fad17466a0519208651e92f5ff -b7cdd0a3fbd79aed93e1b5a44ca44a94e7af5ed911e4492f332e3a5ed146c7286bde01b52276a2fcc02780d2109874dd -8a19a09854e627cb95750d83c20c67442b66b35896a476358f993ba9ac114d32c59c1b3d0b8787ee3224cf3888b56c64 -a9abd5afb8659ee52ada8fa5d57e7dd355f0a7350276f6160bec5fbf70d5f99234dd179eb221c913e22a49ec6d267846 -8c13c4274c0d30d184e73eaf812200094bbbd57293780bdadbceb262e34dee5b453991e7f37c7333a654fc71c69d6445 -a4320d73296ff8176ce0127ca1921c450e2a9c06eff936681ebaffb5a0b05b17fded24e548454de89aca2dcf6d7a9de4 -b2b8b3e15c1f645f07783e5628aba614e60157889db41d8161d977606788842b67f83f361eae91815dc0abd84e09abd5 -ad26c3aa35ddfddc15719b8bb6c264aaec7065e88ac29ba820eb61f220fef451609a7bb037f3722d022e6c86e4f1dc88 -b8615bf43e13ae5d7b8dd903ce37190800cd490f441c09b22aa29d7a29ed2c0417b7a08ead417868f1de2589deaadd80 -8d3425e1482cd1e76750a76239d33c06b3554c3c3c87c15cb7ab58b1cee86a4c5c4178b44e23f36928365a1b484bde02 -806893a62e38c941a7dd6f249c83af16596f69877cc737d8f73f6b8cd93cbc01177a7a276b2b8c6b0e5f2ad864db5994 -86618f17fa4b0d65496b661bbb5ba3bc3a87129d30a4b7d4f515b904f4206ca5253a41f49fd52095861e5e065ec54f21 -9551915da1304051e55717f4c31db761dcdcf3a1366c89a4af800a9e99aca93a357bf928307f098e62b44a02cb689a46 -8f79c4ec0ec1146cb2a523b52fe33def90d7b5652a0cb9c2d1c8808a32293e00aec6969f5b1538e3a94cd1efa3937f86 -a0c03e329a707300081780f1e310671315b4c6a4cedcb29697aedfabb07a9d5df83f27b20e9c44cf6b16e39d9ded5b98 -86a7cfa7c8e7ce2c01dd0baec2139e97e8e090ad4e7b5f51518f83d564765003c65968f85481bbb97cb18f005ccc7d9f -a33811770c6dfda3f7f74e6ad0107a187fe622d61b444bbd84fd7ef6e03302e693b093df76f6ab39bb4e02afd84a575a -85480f5c10d4162a8e6702b5e04f801874d572a62a130be94b0c02b58c3c59bdcd48cd05f0a1c2839f88f06b6e3cd337 -8e181011564b17f7d787fe0e7f3c87f6b62da9083c54c74fd6c357a1f464c123c1d3d8ade3cf72475000b464b14e2be3 -8ee178937294b8c991337e0621ab37e9ffa4ca2bdb3284065c5e9c08aad6785d50cf156270ff9daf9a9127289710f55b -8bd1e8e2d37379d4b172f1aec96f2e41a6e1393158d7a3dbd9a95c8dd4f8e0b05336a42efc11a732e5f22b47fc5c271d -8f3da353cd487c13136a85677de8cedf306faae0edec733cf4f0046f82fa4639db4745b0095ff33a9766aba50de0cbcf -8d187c1e97638df0e4792b78e8c23967dac43d98ea268ca4aabea4e0fa06cb93183fd92d4c9df74118d7cc27bf54415e -a4c992f08c2f8bac0b74b3702fb0c75c9838d2ce90b28812019553d47613c14d8ce514d15443159d700b218c5a312c49 -a6fd1874034a34c3ea962a316c018d9493d2b3719bb0ec4edbc7c56b240802b2228ab49bee6f04c8a3e9f6f24a48c1c2 -b2efed8e799f8a15999020900dc2c58ece5a3641c90811b86a5198e593d7318b9d53b167818ccdfbe7df2414c9c34011 -995ff7de6181ddf95e3ead746089c6148da3508e4e7a2323c81785718b754d356789b902e7e78e2edc6b0cbd4ff22c78 -944073d24750a9068cbd020b834afc72d2dde87efac04482b3287b40678ad07588519a4176b10f2172a2c463d063a5cd -99db4b1bb76475a6fd75289986ef40367960279524378cc917525fb6ba02a145a218c1e9caeb99332332ab486a125ac0 -89fce4ecd420f8e477af4353b16faabb39e063f3f3c98fde2858b1f2d1ef6eed46f0975a7c08f233b97899bf60ccd60a -8c09a4f07a02b80654798bc63aada39fd638d3e3c4236ccd8a5ca280350c31e4a89e5f4c9aafb34116e71da18c1226b8 -85325cfa7ded346cc51a2894257eab56e7488dbff504f10f99f4cd2b630d913003761a50f175ed167e8073f1b6b63fb0 -b678b4fbec09a8cc794dcbca185f133578f29e354e99c05f6d07ac323be20aecb11f781d12898168e86f2e0f09aca15e -a249cfcbca4d9ba0a13b5f6aac72bf9b899adf582f9746bb2ad043742b28915607467eb794fca3704278f9136f7642be -9438e036c836a990c5e17af3d78367a75b23c37f807228362b4d13e3ddcb9e431348a7b552d09d11a2e9680704a4514f -925ab70450af28c21a488bfb5d38ac994f784cf249d7fd9ad251bb7fd897a23e23d2528308c03415074d43330dc37ef4 -a290563904d5a8c0058fc8330120365bdd2ba1fdbaef7a14bc65d4961bb4217acfaed11ab82669e359531f8bf589b8db -a7e07a7801b871fc9b981a71e195a3b4ba6b6313bc132b04796a125157e78fe5c11a3a46cf731a255ac2d78a4ae78cd0 -b26cd2501ee72718b0eebab6fb24d955a71f363f36e0f6dff0ab1d2d7836dab88474c0cef43a2cc32701fca7e82f7df3 -a1dc3b6c968f3de00f11275092290afab65b2200afbcfa8ddc70e751fa19dbbc300445d6d479a81bda3880729007e496 -a9bc213e28b630889476a095947d323b9ac6461dea726f2dc9084473ae8e196d66fb792a21905ad4ec52a6d757863e7d -b25d178df8c2df8051e7c888e9fa677fde5922e602a95e966db9e4a3d6b23ce043d7dc48a5b375c6b7c78e966893e8c3 -a1c8d88d72303692eaa7adf68ea41de4febec40cc14ae551bb4012afd786d7b6444a3196b5d9d5040655a3366d96b7cd -b22bd44f9235a47118a9bbe2ba5a2ba9ec62476061be2e8e57806c1a17a02f9a51403e849e2e589520b759abd0117683 -b8add766050c0d69fe81d8d9ea73e1ed05f0135d093ff01debd7247e42dbb86ad950aceb3b50b9af6cdc14ab443b238f -af2cf95f30ef478f018cf81d70d47d742120b09193d8bb77f0d41a5d2e1a80bfb467793d9e2471b4e0ad0cb2c3b42271 -8af5ef2107ad284e246bb56e20fef2a255954f72de791cbdfd3be09f825298d8466064f3c98a50496c7277af32b5c0bc -85dc19558572844c2849e729395a0c125096476388bd1b14fa7f54a7c38008fc93e578da3aac6a52ff1504d6ca82db05 -ae8c9b43c49572e2e166d704caf5b4b621a3b47827bb2a3bcd71cdc599bba90396fd9a405261b13e831bb5d44c0827d7 -a7ba7efede25f02e88f6f4cbf70643e76784a03d97e0fbd5d9437c2485283ad7ca3abb638a5f826cd9f6193e5dec0b6c -94a9d122f2f06ef709fd8016fd4b712d88052245a65a301f5f177ce22992f74ad05552b1f1af4e70d1eac62cef309752 -82d999b3e7cf563833b8bc028ff63a6b26eb357dfdb3fd5f10e33a1f80a9b2cfa7814d871b32a7ebfbaa09e753e37c02 -aec6edcde234df502a3268dd2c26f4a36a2e0db730afa83173f9c78fcb2b2f75510a02b80194327b792811caefda2725 -94c0bfa66c9f91d462e9194144fdd12d96f9bbe745737e73bab8130607ee6ea9d740e2cfcbbd00a195746edb6369ee61 -ab7573dab8c9d46d339e3f491cb2826cabe8b49f85f1ede78d845fc3995537d1b4ab85140b7d0238d9c24daf0e5e2a7e -87e8b16832843251fe952dadfd01d41890ed4bb4b8fa0254550d92c8cced44368225eca83a6c3ad47a7f81ff8a80c984 -9189d2d9a7c64791b19c0773ad4f0564ce6bea94aa275a917f78ad987f150fdb3e5e26e7fef9982ac184897ecc04683f -b3661bf19e2da41415396ae4dd051a9272e8a2580b06f1a1118f57b901fa237616a9f8075af1129af4eabfefedbe2f1c -af43c86661fb15daf5d910a4e06837225e100fb5680bd3e4b10f79a2144c6ec48b1f8d6e6b98e067d36609a5d038889a -82ac0c7acaa83ddc86c5b4249aae12f28155989c7c6b91e5137a4ce05113c6cbc16f6c44948b0efd8665362d3162f16a -8f268d1195ab465beeeb112cd7ffd5d5548559a8bc01261106d3555533fc1971081b25558d884d552df0db1cddda89d8 -8ef7caa5521f3e037586ce8ac872a4182ee20c7921c0065ed9986c047e3dda08294da1165f385d008b40d500f07d895f -8c2f98f6880550573fad46075d3eba26634b5b025ce25a0b4d6e0193352c8a1f0661064027a70fe8190b522405f9f4e3 -b7653f353564feb164f0f89ec7949da475b8dad4a4d396d252fc2a884f6932d027b7eb2dc4d280702c74569319ed701a -a026904f4066333befd9b87a8fad791d014096af60cdd668ef919c24dbe295ff31f7a790e1e721ba40cf5105abca67f4 -988f982004ada07a22dd345f2412a228d7a96b9cae2c487de42e392afe1e35c2655f829ce07a14629148ce7079a1f142 -9616add009067ed135295fb74d5b223b006b312bf14663e547a0d306694ff3a8a7bb9cfc466986707192a26c0bce599f -ad4c425de9855f6968a17ee9ae5b15e0a5b596411388cf976df62ecc6c847a6e2ddb2cea792a5f6e9113c2445dba3e5c -b698ac9d86afa3dc69ff8375061f88e3b0cff92ff6dfe747cebaf142e813c011851e7a2830c10993b715e7fd594604a9 -a386fa189847bb3b798efca917461e38ead61a08b101948def0f82cd258b945ed4d45b53774b400af500670149e601b7 -905c95abda2c68a6559d8a39b6db081c68cef1e1b4be63498004e1b2f408409be9350b5b5d86a30fd443e2b3e445640a -9116dade969e7ce8954afcdd43e5cab64dc15f6c1b8da9d2d69de3f02ba79e6c4f6c7f54d6bf586d30256ae405cd1e41 -a3084d173eacd08c9b5084a196719b57e47a0179826fda73466758235d7ecdb87cbcf097bd6b510517d163a85a7c7edd -85bb00415ad3c9be99ff9ba83672cc59fdd24356b661ab93713a3c8eab34e125d8867f628a3c3891b8dc056e69cd0e83 -8d58541f9f39ed2ee4478acce5d58d124031338ec11b0d55551f00a5a9a6351faa903a5d7c132dc5e4bb026e9cbd18e4 -a622adf72dc250e54f672e14e128c700166168dbe0474cecb340da175346e89917c400677b1bc1c11fcc4cc26591d9db -b3f865014754b688ca8372e8448114fff87bf3ca99856ab9168894d0c4679782c1ced703f5b74e851b370630f5e6ee86 -a7e490b2c40c2446fcd91861c020da9742c326a81180e38110558bb5d9f2341f1c1885e79b364e6419023d1cbdc47380 -b3748d472b1062e54572badbb8e87ac36534407f74932e7fc5b8392d008e8e89758f1671d1e4d30ab0fa40551b13bb5e -89898a5c5ec4313aabc607b0049fd1ebad0e0c074920cf503c9275b564d91916c2c446d3096491c950b7af3ac5e4b0ed -8eb8c83fef2c9dd30ea44e286e9599ec5c20aba983f702e5438afe2e5b921884327ad8d1566c72395587efac79ca7d56 -b92479599e806516ce21fb0bd422a1d1d925335ebe2b4a0a7e044dd275f30985a72b97292477053ac5f00e081430da80 -a34ae450a324fe8a3c25a4d653a654f9580ed56bbea213b8096987bbad0f5701d809a17076435e18017fea4d69f414bc -81381afe6433d62faf62ea488f39675e0091835892ecc238e02acf1662669c6d3962a71a3db652f6fe3bc5f42a0e5dc5 -a430d475bf8580c59111103316fe1aa79c523ea12f1d47a976bbfae76894717c20220e31cf259f08e84a693da6688d70 -b842814c359754ece614deb7d184d679d05d16f18a14b288a401cef5dad2cf0d5ee90bad487b80923fc5573779d4e4e8 -971d9a2627ff2a6d0dcf2af3d895dfbafca28b1c09610c466e4e2bff2746f8369de7f40d65b70aed135fe1d72564aa88 -8f4ce1c59e22b1ce7a0664caaa7e53735b154cfba8d2c5cc4159f2385843de82ab58ed901be876c6f7fce69cb4130950 -86cc9dc321b6264297987000d344fa297ef45bcc2a4df04e458fe2d907ad304c0ea2318e32c3179af639a9a56f3263cf -8229e0876dfe8f665c3fb19b250bd89d40f039bbf1b331468b403655be7be2e104c2fd07b9983580c742d5462ca39a43 -99299d73066e8eb128f698e56a9f8506dfe4bd014931e86b6b487d6195d2198c6c5bf15cccb40ccf1f8ddb57e9da44a2 -a3a3be37ac554c574b393b2f33d0a32a116c1a7cfeaf88c54299a4da2267149a5ecca71f94e6c0ef6e2f472b802f5189 -a91700d1a00387502cdba98c90f75fbc4066fefe7cc221c8f0e660994c936badd7d2695893fde2260c8c11d5bdcdd951 -8e03cae725b7f9562c5c5ab6361644b976a68bada3d7ca508abca8dfc80a469975689af1fba1abcf21bc2a190dab397d -b01461ad23b2a8fa8a6d241e1675855d23bc977dbf4714add8c4b4b7469ccf2375cec20e80cedfe49361d1a30414ac5b -a2673bf9bc621e3892c3d7dd4f1a9497f369add8cbaa3472409f4f86bd21ac67cfac357604828adfee6ada1835365029 -a042dff4bf0dfc33c178ba1b335e798e6308915128de91b12e5dbbab7c4ac8d60a01f6aea028c3a6d87b9b01e4e74c01 -86339e8a75293e4b3ae66b5630d375736b6e6b6b05c5cda5e73fbf7b2f2bd34c18a1d6cefede08625ce3046e77905cb8 -af2ebe1b7d073d03e3d98bc61af83bf26f7a8c130fd607aa92b75db22d14d016481b8aa231e2c9757695f55b7224a27f -a00ee882c9685e978041fd74a2c465f06e2a42ffd3db659053519925be5b454d6f401e3c12c746e49d910e4c5c9c5e8c -978a781c0e4e264e0dad57e438f1097d447d891a1e2aa0d5928f79a9d5c3faae6f258bc94fdc530b7b2fa6a9932bb193 -aa4b7ce2e0c2c9e9655bf21e3e5651c8503bce27483017b0bf476be743ba06db10228b3a4c721219c0779747f11ca282 -b003d1c459dacbcf1a715551311e45d7dbca83a185a65748ac74d1800bbeaba37765d9f5a1a221805c571910b34ebca8 -95b6e531b38648049f0d19de09b881baa1f7ea3b2130816b006ad5703901a05da57467d1a3d9d2e7c73fb3f2e409363c -a6cf9c06593432d8eba23a4f131bb7f72b9bd51ab6b4b772a749fe03ed72b5ced835a349c6d9920dba2a39669cb7c684 -aa3d59f6e2e96fbb66195bc58c8704e139fa76cd15e4d61035470bd6e305db9f98bcbf61ac1b95e95b69ba330454c1b3 -b57f97959c208361de6d7e86dff2b873068adb0f158066e646f42ae90e650079798f165b5cd713141cd3a2a90a961d9a -a76ee8ed9052f6a7a8c69774bb2597be182942f08115baba03bf8faaeaee526feba86120039fe8ca7b9354c3b6e0a8e6 -95689d78c867724823f564627d22d25010f278674c6d2d0cdb10329169a47580818995d1d727ce46c38a1e47943ebb89 -ab676d2256c6288a88e044b3d9ffd43eb9d5aaee00e8fc60ac921395fb835044c71a26ca948e557fed770f52d711e057 -96351c72785c32e5d004b6f4a1259fb8153d631f0c93fed172f18e8ba438fbc5585c1618deeabd0d6d0b82173c2e6170 -93dd8d3db576418e22536eba45ab7f56967c6c97c64260d6cddf38fb19c88f2ec5cd0e0156f50e70855eee8a2b879ffd -ad6ff16f40f6de3d7a737f8e6cebd8416920c4ff89dbdcd75eabab414af9a6087f83ceb9aff7680aa86bff98bd09c8cc -84de53b11671abc9c38710e19540c5c403817562aeb22a88404cdaff792c1180f717dbdfe8f54940c062c4d032897429 -872231b9efa1cdd447b312099a5c164c560440a9441d904e70f5abfc3b2a0d16be9a01aca5e0a2599a61e19407587e3d -88f44ac27094a2aa14e9dc40b099ee6d68f97385950f303969d889ee93d4635e34dff9239103bdf66a4b7cbba3e7eb7a -a59afebadf0260e832f6f44468443562f53fbaf7bcb5e46e1462d3f328ac437ce56edbca617659ac9883f9e13261fad7 -b1990e42743a88de4deeacfd55fafeab3bc380cb95de43ed623d021a4f2353530bcab9594389c1844b1c5ea6634c4555 -85051e841149a10e83f56764e042182208591396d0ce78c762c4a413e6836906df67f38c69793e158d64fef111407ba3 -9778172bbd9b1f2ec6bbdd61829d7b39a7df494a818e31c654bf7f6a30139899c4822c1bf418dd4f923243067759ce63 -9355005b4878c87804fc966e7d24f3e4b02bed35b4a77369d01f25a3dcbff7621b08306b1ac85b76fe7b4a3eb5f839b1 -8f9dc6a54fac052e236f8f0e1f571ac4b5308a43acbe4cc8183bce26262ddaf7994e41cf3034a4cbeca2c505a151e3b1 -8cc59c17307111723fe313046a09e0e32ea0cce62c13814ab7c6408c142d6a0311d801be4af53fc9240523f12045f9ef -8e6057975ed40a1932e47dd3ac778f72ee2a868d8540271301b1aa6858de1a5450f596466494a3e0488be4fbeb41c840 -812145efbd6559ae13325d56a15940ca4253b17e72a9728986b563bb5acc13ec86453796506ac1a8f12bd6f9e4a288c3 -911da0a6d6489eb3dab2ec4a16e36127e8a291ae68a6c2c9de33e97f3a9b1f00da57a94e270a0de79ecc5ecb45d19e83 -b72ea85973f4b2a7e6e71962b0502024e979a73c18a9111130e158541fa47bbaaf53940c8f846913a517dc69982ba9e1 -a7a56ad1dbdc55f177a7ad1d0af78447dc2673291e34e8ab74b26e2e2e7d8c5fe5dc89e7ef60f04a9508847b5b3a8188 -b52503f6e5411db5d1e70f5fb72ccd6463fa0f197b3e51ca79c7b5a8ab2e894f0030476ada72534fa4eb4e06c3880f90 -b51c7957a3d18c4e38f6358f2237b3904618d58b1de5dec53387d25a63772e675a5b714ad35a38185409931157d4b529 -b86b4266e719d29c043d7ec091547aa6f65bbf2d8d831d1515957c5c06513b72aa82113e9645ad38a7bc3f5383504fa6 -b95b547357e6601667b0f5f61f261800a44c2879cf94e879def6a105b1ad2bbf1795c3b98a90d588388e81789bd02681 -a58fd4c5ae4673fa350da6777e13313d5d37ed1dafeeb8f4f171549765b84c895875d9d3ae6a9741f3d51006ef81d962 -9398dc348d078a604aadc154e6eef2c0be1a93bb93ba7fe8976edc2840a3a318941338cc4d5f743310e539d9b46613d2 -902c9f0095014c4a2f0dccaaab543debba6f4cc82c345a10aaf4e72511725dbed7a34cd393a5f4e48a3e5142b7be84ed -a7c0447849bb44d04a0393a680f6cd390093484a79a147dd238f5d878030d1c26646d88211108e59fe08b58ad20c6fbd -80db045535d6e67a422519f5c89699e37098449d249698a7cc173a26ccd06f60238ae6cc7242eb780a340705c906790c -8e52b451a299f30124505de2e74d5341e1b5597bdd13301cc39b05536c96e4380e7f1b5c7ef076f5b3005a868657f17c -824499e89701036037571761e977654d2760b8ce21f184f2879fda55d3cda1e7a95306b8abacf1caa79d3cc075b9d27f -9049b956b77f8453d2070607610b79db795588c0cec12943a0f5fe76f358dea81e4f57a4692112afda0e2c05c142b26f -81911647d818a4b5f4990bfd4bc13bf7be7b0059afcf1b6839333e8569cdb0172fd2945410d88879349f677abaed5eb3 -ad4048f19b8194ed45b6317d9492b71a89a66928353072659f5ce6c816d8f21e69b9d1817d793effe49ca1874daa1096 -8d22f7b2ddb31458661abd34b65819a374a1f68c01fc6c9887edeba8b80c65bceadb8f57a3eb686374004b836261ef67 -92637280c259bc6842884db3d6e32602a62252811ae9b019b3c1df664e8809ffe86db88cfdeb8af9f46435c9ee790267 -a2f416379e52e3f5edc21641ea73dc76c99f7e29ea75b487e18bd233856f4c0183429f378d2bfc6cd736d29d6cadfa49 -882cb6b76dbdc188615dcf1a8439eba05ffca637dd25197508156e03c930b17b9fed2938506fdd7b77567cb488f96222 -b68b621bb198a763fb0634eddb93ed4b5156e59b96c88ca2246fd1aea3e6b77ed651e112ac41b30cd361fadc011d385e -a3cb22f6b675a29b2d1f827cacd30df14d463c93c3502ef965166f20d046af7f9ab7b2586a9c64f4eae4fad2d808a164 -8302d9ce4403f48ca217079762ce42cee8bc30168686bb8d3a945fbd5acd53b39f028dce757b825eb63af2d5ae41169d -b2eef1fbd1a176f1f4cd10f2988c7329abe4eb16c7405099fb92baa724ab397bc98734ef7d4b24c0f53dd90f57520d04 -a1bbef0bd684a3f0364a66bde9b29326bac7aa3dde4caed67f14fb84fed3de45c55e406702f1495a3e2864d4ee975030 -976acdb0efb73e3a3b65633197692dedc2adaed674291ae3df76b827fc866d214e9cac9ca46baefc4405ff13f953d936 -b9fbf71cc7b6690f601f0b1c74a19b7d14254183a2daaafec7dc3830cba5ae173d854bbfebeca985d1d908abe5ef0cda -90591d7b483598c94e38969c4dbb92710a1a894bcf147807f1bcbd8aa3ac210b9f2be65519aa829f8e1ccdc83ad9b8cf -a30568577c91866b9c40f0719d46b7b3b2e0b4a95e56196ac80898a2d89cc67880e1229933f2cd28ee3286f8d03414d7 -97589a88c3850556b359ec5e891f0937f922a751ac7c95949d3bbc7058c172c387611c0f4cb06351ef02e5178b3dd9e4 -98e7bbe27a1711f4545df742f17e3233fbcc63659d7419e1ca633f104cb02a32c84f2fac23ca2b84145c2672f68077ab -a7ddb91636e4506d8b7e92aa9f4720491bb71a72dadc47c7f4410e15f93e43d07d2b371951a0e6a18d1bd087aa96a5c4 -a7c006692227a06db40bceac3d5b1daae60b5692dd9b54772bedb5fea0bcc91cbcdb530cac31900ffc70c5b3ffadc969 -8d3ec6032778420dfa8be52066ba0e623467df33e4e1901dbadd586c5d750f4ccde499b5197e26b9ea43931214060f69 -8d9a8410518ea64f89df319bfd1fc97a0971cdb9ad9b11d1f8fe834042ea7f8dce4db56eeaf179ff8dda93b6db93e5ce -a3c533e9b3aa04df20b9ff635cb1154ce303e045278fcf3f10f609064a5445552a1f93989c52ce852fd0bbd6e2b6c22e -81934f3a7f8c1ae60ec6e4f212986bcc316118c760a74155d06ce0a8c00a9b9669ec4e143ca214e1b995e41271774fd9 -ab8e2d01a71192093ef8fafa7485e795567cc9db95a93fb7cc4cf63a391ef89af5e2bfad4b827fffe02b89271300407f -83064a1eaa937a84e392226f1a60b7cfad4efaa802f66de5df7498962f7b2649924f63cd9962d47906380b97b9fe80e1 -b4f5e64a15c6672e4b55417ee5dc292dcf93d7ea99965a888b1cc4f5474a11e5b6520eacbcf066840b343f4ceeb6bf33 -a63d278b842456ef15c278b37a6ea0f27c7b3ffffefca77c7a66d2ea06c33c4631eb242bbb064d730e70a8262a7b848a -83a41a83dbcdf0d22dc049de082296204e848c453c5ab1ba75aa4067984e053acf6f8b6909a2e1f0009ed051a828a73b -819485b036b7958508f15f3c19436da069cbe635b0318ebe8c014cf1ef9ab2df038c81161b7027475bcfa6fff8dd9faf -aa40e38172806e1e045e167f3d1677ef12d5dcdc89b43639a170f68054bd196c4fae34c675c1644d198907a03f76ba57 -969bae484883a9ed1fbed53b26b3d4ee4b0e39a6c93ece5b3a49daa01444a1c25727dabe62518546f36b047b311b177c -80a9e73a65da99664988b238096a090d313a0ee8e4235bc102fa79bb337b51bb08c4507814eb5baec22103ec512eaab0 -86604379aec5bddda6cbe3ef99c0ac3a3c285b0b1a15b50451c7242cd42ae6b6c8acb717dcca7917838432df93a28502 -a23407ee02a495bed06aa7e15f94cfb05c83e6d6fba64456a9bbabfa76b2b68c5c47de00ba169e710681f6a29bb41a22 -98cff5ecc73b366c6a01b34ac9066cb34f7eeaf4f38a5429bad2d07e84a237047e2a065c7e8a0a6581017dadb4695deb -8de9f68a938f441f3b7ab84bb1f473c5f9e5c9e139e42b7ccee1d254bd57d0e99c2ccda0f3198f1fc5737f6023dd204e -b0ce48d815c2768fb472a315cad86aa033d0e9ca506f146656e2941829e0acb735590b4fbc713c2d18d3676db0a954ac -82f485cdefd5642a6af58ac6817991c49fac9c10ace60f90b27f1788cc026c2fe8afc83cf499b3444118f9f0103598a8 -82c24550ed512a0d53fc56f64cc36b553823ae8766d75d772dacf038c460f16f108f87a39ceef7c66389790f799dbab3 -859ffcf1fe9166388316149b9acc35694c0ea534d43f09dae9b86f4aa00a23b27144dda6a352e74b9516e8c8d6fc809c -b8f7f353eec45da77fb27742405e5ad08d95ec0f5b6842025be9def3d9892f85eb5dd0921b41e6eff373618dba215bca -8ccca4436f9017e426229290f5cd05eac3f16571a4713141a7461acfe8ae99cd5a95bf5b6df129148693c533966145da -a2c67ecc19c0178b2994846fea4c34c327a5d786ac4b09d1d13549d5be5996d8a89021d63d65cb814923388f47cc3a03 -aa0ff87d676b418ec08f5cbf577ac7e744d1d0e9ebd14615b550eb86931eafd2a36d4732cc5d6fab1713fd7ab2f6f7c0 -8aef4730bb65e44efd6bb9441c0ae897363a2f3054867590a2c2ecf4f0224e578c7a67f10b40f8453d9f492ac15a9b2d -86a187e13d8fba5addcfdd5b0410cedd352016c930f913addd769ee09faa6be5ca3e4b1bdb417a965c643a99bd92be42 -a0a4e9632a7a094b14b29b78cd9c894218cdf6783e61671e0203865dc2a835350f465fbaf86168f28af7c478ca17bc89 -a8c7b02d8deff2cd657d8447689a9c5e2cd74ef57c1314ac4d69084ac24a7471954d9ff43fe0907d875dcb65fd0d3ce5 -97ded38760aa7be6b6960b5b50e83b618fe413cbf2bcc1da64c05140bcc32f5e0e709cd05bf8007949953fac5716bad9 -b0d293835a24d64c2ae48ce26e550b71a8c94a0883103757fb6b07e30747f1a871707d23389ba2b2065fa6bafe220095 -8f9e291bf849feaa575592e28e3c8d4b7283f733d41827262367ea1c40f298c7bcc16505255a906b62bf15d9f1ba85fb -998f4e2d12708b4fd85a61597ca2eddd750f73c9e0c9b3cf0825d8f8e01f1628fd19797dcaed3b16dc50331fc6b8b821 -b30d1f8c115d0e63bf48f595dd10908416774c78b3bbb3194192995154d80ea042d2e94d858de5f8aa0261b093c401fd -b5d9c75bb41f964cbff3f00e96d9f1480c91df8913f139f0d385d27a19f57a820f838eb728e46823cbff00e21c660996 -a6edec90b5d25350e2f5f0518777634f9e661ec9d30674cf5b156c4801746d62517751d90074830ac0f4b09911c262f1 -82f98da1264b6b75b8fbeb6a4d96d6a05b25c24db0d57ba3a38efe3a82d0d4e331b9fc4237d6494ccfe4727206457519 -b89511843453cf4ecd24669572d6371b1e529c8e284300c43e0d5bb6b3aaf35aeb634b3cb5c0a2868f0d5e959c1d0772 -a82bf065676583e5c1d3b81987aaae5542f522ba39538263a944bb33ea5b514c649344a96c0205a3b197a3f930fcda6c -a37b47ea527b7e06c460776aa662d9a49ff4149d3993f1a974b0dd165f7171770d189b0e2ea54fd5fccb6a14b116e68a -a1017677f97dda818274d47556d09d0e4ccacb23a252f82a6cfe78c630ad46fb9806307445a59fb61262182de3a2b29c -b01e9fcac239ba270e6877b79273ddd768bf8a51d2ed8a051b1c11e18eff3de5920e2fcbfbd26f06d381eddd3b1f1e1b -82fcd53d803b1c8e4ed76adc339b7f3a5962d37042b9683aabac7513ac68775d4a566a9460183926a6a95dbe7d551a1f -a763e78995d55cd21cdb7ef75d9642d6e1c72453945e346ab6690c20a4e1eeec61bb848ef830ae4b56182535e3c71d8f -b769f4db602251d4b0a1186782799bdcef66de33c110999a5775c50b349666ffd83d4c89714c4e376f2efe021a5cfdb2 -a59cbd1b785efcfa6e83fc3b1d8cf638820bc0c119726b5368f3fba9dce8e3414204fb1f1a88f6c1ff52e87961252f97 -95c8c458fd01aa23ecf120481a9c6332ebec2e8bb70a308d0576926a858457021c277958cf79017ddd86a56cacc2d7db -82eb41390800287ae56e77f2e87709de5b871c8bdb67c10a80fc65f3acb9f7c29e8fa43047436e8933f27449ea61d94d -b3ec25e3545eb83aed2a1f3558d1a31c7edde4be145ecc13b33802654b77dc049b4f0065069dd9047b051e52ab11dcdd -b78a0c715738f56f0dc459ab99e252e3b579b208142836b3c416b704ca1de640ca082f29ebbcee648c8c127df06f6b1e -a4083149432eaaf9520188ebf4607d09cf664acd1f471d4fb654476e77a9eaae2251424ffda78d09b6cb880df35c1219 -8c52857d68d6e9672df3db2df2dbf46b516a21a0e8a18eec09a6ae13c1ef8f369d03233320dd1c2c0bbe00abfc1ea18b -8c856089488803066bff3f8d8e09afb9baf20cecc33c8823c1c0836c3d45498c3de37e87c016b705207f60d2b00f8609 -831a3df39be959047b2aead06b4dcd3012d7b29417f642b83c9e8ce8de24a3dbbd29c6fdf55e2db3f7ea04636c94e403 -aed84d009f66544addabe404bf6d65af7779ce140dc561ff0c86a4078557b96b2053b7b8a43432ffb18cd814f143b9da -93282e4d72b0aa85212a77b336007d8ba071eea17492da19860f1ad16c1ea8867ccc27ef5c37c74b052465cc11ea4f52 -a7b78b8c8d057194e8d68767f1488363f77c77bddd56c3da2bc70b6354c7aa76247c86d51f7371aa38a4aa7f7e3c0bb7 -b1c77283d01dcd1bde649b5b044eac26befc98ff57cbee379fb5b8e420134a88f2fc7f0bf04d15e1fbd45d29e7590fe6 -a4aa8de70330a73b2c6458f20a1067eed4b3474829b36970a8df125d53bbdda4f4a2c60063b7cccb0c80fc155527652f -948a6c79ba1b8ad7e0bed2fae2f0481c4e41b4d9bbdd9b58164e28e9065700e83f210c8d5351d0212e0b0b68b345b3a5 -86a48c31dcbbf7b082c92d28e1f613a2378a910677d7db3a349dc089e4a1e24b12eee8e8206777a3a8c64748840b7387 -976adb1af21e0fc34148917cf43d933d7bfd3fd12ed6c37039dcd5a4520e3c6cf5868539ba5bf082326430deb8a4458d -b93e1a4476f2c51864bb4037e7145f0635eb2827ab91732b98d49b6c07f6ac443111aa1f1da76d1888665cb897c3834e -8afd46fb23bf869999fa19784b18a432a1f252d09506b8dbb756af900518d3f5f244989b3d7c823d9029218c655d3dc6 -83f1e59e3abeed18cdc632921672673f1cb6e330326e11c4e600e13e0d5bc11bdc970ae12952e15103a706fe720bf4d6 -90ce4cc660714b0b673d48010641c09c00fc92a2c596208f65c46073d7f349dd8e6e077ba7dcef9403084971c3295b76 -8b09b0f431a7c796561ecf1549b85048564de428dac0474522e9558b6065fede231886bc108539c104ce88ebd9b5d1b0 -85d6e742e2fb16a7b0ba0df64bc2c0dbff9549be691f46a6669bca05e89c884af16822b85faefefb604ec48c8705a309 -a87989ee231e468a712c66513746fcf03c14f103aadca0eac28e9732487deb56d7532e407953ab87a4bf8961588ef7b0 -b00da10efe1c29ee03c9d37d5918e391ae30e48304e294696b81b434f65cf8c8b95b9d1758c64c25e534d045ba28696f -91c0e1fb49afe46c7056400baa06dbb5f6e479db78ee37e2d76c1f4e88994357e257b83b78624c4ef6091a6c0eb8254d -883fb797c498297ccbf9411a3e727c3614af4eccde41619b773dc7f3259950835ee79453debf178e11dec4d3ada687a0 -a14703347e44eb5059070b2759297fcfcfc60e6893c0373eea069388eba3950aa06f1c57cd2c30984a2d6f9e9c92c79e -afebc7585b304ceba9a769634adff35940e89cd32682c78002822aab25eec3edc29342b7f5a42a56a1fec67821172ad5 -aea3ff3822d09dba1425084ca95fd359718d856f6c133c5fabe2b2eed8303b6e0ba0d8698b48b93136a673baac174fd9 -af2456a09aa777d9e67aa6c7c49a1845ea5cdda2e39f4c935c34a5f8280d69d4eec570446998cbbe31ede69a91e90b06 -82cada19fed16b891ef3442bafd49e1f07c00c2f57b2492dd4ee36af2bd6fd877d6cb41188a4d6ce9ec8d48e8133d697 -82a21034c832287f616619a37c122cee265cc34ae75e881fcaea4ea7f689f3c2bc8150bbf7dbcfd123522bfb7f7b1d68 -86877217105f5d0ec3eeff0289fc2a70d505c9fdf7862e8159553ef60908fb1a27bdaf899381356a4ef4649072a9796c -82b196e49c6e861089a427c0b4671d464e9d15555ffb90954cd0d630d7ae02eb3d98ceb529d00719c2526cd96481355a -a29b41d0d43d26ce76d4358e0db2b77df11f56e389f3b084d8af70a636218bd3ac86b36a9fe46ec9058c26a490f887f7 -a4311c4c20c4d7dd943765099c50f2fd423e203ccfe98ff00087d205467a7873762510cac5fdce7a308913ed07991ed7 -b1f040fc5cc51550cb2c25cf1fd418ecdd961635a11f365515f0cb4ffb31da71f48128c233e9cc7c0cf3978d757ec84e -a9ebae46f86d3bd543c5f207ed0d1aed94b8375dc991161d7a271f01592912072e083e2daf30c146430894e37325a1b9 -826418c8e17ad902b5fe88736323a47e0ca7a44bce4cbe27846ec8fe81de1e8942455dda6d30e192cdcc73e11df31256 -85199db563427c5edcbac21f3d39fec2357be91fb571982ddcdc4646b446ad5ced84410de008cb47b3477ee0d532daf8 -b7eed9cd400b2ca12bf1d9ae008214b8561fb09c8ad9ff959e626ffde00fee5ff2f5b6612e231f2a1a9b1646fcc575e3 -8b40bf12501dcbac78f5a314941326bfcddf7907c83d8d887d0bb149207f85d80cd4dfbd7935439ea7b14ea39a3fded7 -83e3041af302485399ba6cd5120e17af61043977083887e8d26b15feec4a6b11171ac5c06e6ad0971d4b58a81ff12af3 -8f5b9a0eecc589dbf8c35a65d5e996a659277ef6ea509739c0cb7b3e2da9895e8c8012de662e5b23c5fa85d4a8f48904 -835d71ed5e919d89d8e6455f234f3ff215462c4e3720c371ac8c75e83b19dfe3ae15a81547e4dc1138e5f5997f413cc9 -8b7d2e4614716b1db18e9370176ea483e6abe8acdcc3dcdf5fb1f4d22ca55d652feebdccc171c6de38398d9f7bfdec7a -93eace72036fe57d019676a02acf3d224cf376f166658c1bf705db4f24295881d477d6fdd7916efcfceff8c7a063deda -b1ac460b3d516879a84bc886c54f020a9d799e7c49af3e4d7de5bf0d2793c852254c5d8fe5616147e6659512e5ccb012 -acd0947a35cb167a48bcd9667620464b54ac0e78f9316b4aa92dcaab5422d7a732087e52e1c827faa847c6b2fe6e7766 -94ac33d21c3d12ff762d32557860e911cd94d666609ddcc42161b9c16f28d24a526e8b10bb03137257a92cec25ae637d -832e02058b6b994eadd8702921486241f9a19e68ed1406dad545e000a491ae510f525ccf9d10a4bba91c68f2c53a0f58 -9471035d14f78ff8f463b9901dd476b587bb07225c351161915c2e9c6114c3c78a501379ab6fb4eb03194c457cbd22bf -ab64593e034c6241d357fcbc32d8ea5593445a5e7c24cac81ad12bd2ef01843d477a36dc1ba21dbe63b440750d72096a -9850f3b30045e927ad3ec4123a32ed2eb4c911f572b6abb79121873f91016f0d80268de8b12e2093a4904f6e6cab7642 -987212c36b4722fe2e54fa30c52b1e54474439f9f35ca6ad33c5130cd305b8b54b532dd80ffd2c274105f20ce6d79f6e -8b4d0c6abcb239b5ed47bef63bc17efe558a27462c8208fa652b056e9eae9665787cd1aee34fbb55beb045c8bfdb882b -a9f3483c6fee2fe41312d89dd4355d5b2193ac413258993805c5cbbf0a59221f879386d3e7a28e73014f10e65dd503d9 -a2225da3119b9b7c83d514b9f3aeb9a6d9e32d9cbf9309cbb971fd53c4b2c001d10d880a8ad8a7c281b21d85ceca0b7c -a050be52e54e676c151f7a54453bbb707232f849beab4f3bf504b4d620f59ed214409d7c2bd3000f3ff13184ccda1c35 -adbccf681e15b3edb6455a68d292b0a1d0f5a4cb135613f5e6db9943f02181341d5755875db6ee474e19ace1c0634a28 -8b6eff675632a6fad0111ec72aacc61c7387380eb87933fd1d098856387d418bd38e77d897e65d6fe35951d0627c550b -aabe2328ddf90989b15e409b91ef055cb02757d34987849ae6d60bef2c902bf8251ed21ab30acf39e500d1d511e90845 -92ba4eb1f796bc3d8b03515f65c045b66e2734c2da3fc507fdd9d6b5d1e19ab3893726816a32141db7a31099ca817d96 -8a98b3cf353138a1810beb60e946183803ef1d39ac4ea92f5a1e03060d35a4774a6e52b14ead54f6794d5f4022b8685c -909f8a5c13ec4a59b649ed3bee9f5d13b21d7f3e2636fd2bb3413c0646573fdf9243d63083356f12f5147545339fcd55 -9359d914d1267633141328ed0790d81c695fea3ddd2d406c0df3d81d0c64931cf316fe4d92f4353c99ff63e2aefc4e34 -b88302031681b54415fe8fbfa161c032ea345c6af63d2fb8ad97615103fd4d4281c5a9cae5b0794c4657b97571a81d3b -992c80192a519038082446b1fb947323005b275e25f2c14c33cc7269e0ec038581cc43705894f94bad62ae33a8b7f965 -a78253e3e3eece124bef84a0a8807ce76573509f6861d0b6f70d0aa35a30a123a9da5e01e84969708c40b0669eb70aa6 -8d5724de45270ca91c94792e8584e676547d7ac1ac816a6bb9982ee854eb5df071d20545cdfd3771cd40f90e5ba04c8e -825a6f586726c68d45f00ad0f5a4436523317939a47713f78fd4fe81cd74236fdac1b04ecd97c2d0267d6f4981d7beb1 -93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8 -b5bfd7dd8cdeb128843bc287230af38926187075cbfbefa81009a2ce615ac53d2914e5870cb452d2afaaab24f3499f72185cbfee53492714734429b7b38608e23926c911cceceac9a36851477ba4c60b087041de621000edc98edada20c1def2 -b5337ba0ce5d37224290916e268e2060e5c14f3f9fc9e1ec3af5a958e7a0303122500ce18f1a4640bf66525bd10e763501fe986d86649d8d45143c08c3209db3411802c226e9fe9a55716ac4a0c14f9dcef9e70b2bb309553880dc5025eab3cc -b3c1dcdc1f62046c786f0b82242ef283e7ed8f5626f72542aa2c7a40f14d9094dd1ebdbd7457ffdcdac45fd7da7e16c51200b06d791e5e43e257e45efdf0bd5b06cd2333beca2a3a84354eb48662d83aef5ecf4e67658c851c10b13d8d87c874 -954d91c7688983382609fca9e211e461f488a5971fd4e40d7e2892037268eacdfd495cfa0a7ed6eb0eb11ac3ae6f651716757e7526abe1e06c64649d80996fd3105c20c4c94bc2b22d97045356fe9d791f21ea6428ac48db6f9e68e30d875280 -88a6b6bb26c51cf9812260795523973bb90ce80f6820b6c9048ab366f0fb96e48437a7f7cb62aedf64b11eb4dfefebb0147608793133d32003cb1f2dc47b13b5ff45f1bb1b2408ea45770a08dbfaec60961acb8119c47b139a13b8641e2c9487 -85cd7be9728bd925d12f47fb04b32d9fad7cab88788b559f053e69ca18e463113ecc8bbb6dbfb024835f901b3a957d3108d6770fb26d4c8be0a9a619f6e3a4bf15cbfd48e61593490885f6cee30e4300c5f9cf5e1c08e60a2d5b023ee94fcad0 -80477dba360f04399821a48ca388c0fa81102dd15687fea792ee8c1114e00d1bc4839ad37ac58900a118d863723acfbe08126ea883be87f50e4eabe3b5e72f5d9e041db8d9b186409fd4df4a7dde38c0e0a3b1ae29b098e5697e7f110b6b27e4 -b7a6aec08715a9f8672a2b8c367e407be37e59514ac19dd4f0942a68007bba3923df22da48702c63c0d6b3efd3c2d04e0fe042d8b5a54d562f9f33afc4865dcbcc16e99029e25925580e87920c399e710d438ac1ce3a6dc9b0d76c064a01f6f7 -ac1b001edcea02c8258aeffbf9203114c1c874ad88dae1184fadd7d94cd09053649efd0ca413400e6e9b5fa4eac33261000af88b6bd0d2abf877a4f0355d2fb4d6007adb181695201c5432e50b850b51b3969f893bddf82126c5a71b042b7686 -90043fda4de53fb364fab2c04be5296c215599105ecff0c12e4917c549257125775c29f2507124d15f56e30447f367db0596c33237242c02d83dfd058735f1e3c1ff99069af55773b6d51d32a68bf75763f59ec4ee7267932ae426522b8aaab6 -a8660ce853e9dc08271bf882e29cd53397d63b739584dda5263da4c7cc1878d0cf6f3e403557885f557e184700575fee016ee8542dec22c97befe1d10f414d22e84560741cdb3e74c30dda9b42eeaaf53e27822de2ee06e24e912bf764a9a533 -8fe3921a96d0d065e8aa8fce9aa42c8e1461ca0470688c137be89396dd05103606dab6cdd2a4591efd6addf72026c12e065da7be276dee27a7e30afa2bd81c18f1516e7f068f324d0bad9570b95f6bd02c727cd2343e26db0887c3e4e26dceda -8ae1ad97dcb9c192c9a3933541b40447d1dc4eebf380151440bbaae1e120cc5cdf1bcea55180b128d8e180e3af623815191d063cc0d7a47d55fb7687b9d87040bf7bc1a7546b07c61db5ccf1841372d7c2fe4a5431ffff829f3c2eb590b0b710 -8c2fa96870a88150f7876c931e2d3cc2adeaaaf5c73ef5fa1cf9dfa0991ae4819f9321af7e916e5057d87338e630a2f21242c29d76963cf26035b548d2a63d8ad7bd6efefa01c1df502cbdfdfe0334fb21ceb9f686887440f713bf17a89b8081 -b9aa98e2f02bb616e22ee5dd74c7d1049321ac9214d093a738159850a1dbcc7138cb8d26ce09d8296368fd5b291d74fa17ac7cc1b80840fdd4ee35e111501e3fa8485b508baecda7c1ab7bd703872b7d64a2a40b3210b6a70e8a6ffe0e5127e3 -9292db67f8771cdc86854a3f614a73805bf3012b48f1541e704ea4015d2b6b9c9aaed36419769c87c49f9e3165f03edb159c23b3a49c4390951f78e1d9b0ad997129b17cdb57ea1a6638794c0cca7d239f229e589c5ae4f9fe6979f7f8cba1d7 -91cd9e86550f230d128664f7312591fee6a84c34f5fc7aed557bcf986a409a6de722c4330453a305f06911d2728626e611acfdf81284f77f60a3a1595053a9479964fd713117e27c0222cc679674b03bc8001501aaf9b506196c56de29429b46 -a9516b73f605cc31b89c68b7675dc451e6364595243d235339437f556cf22d745d4250c1376182273be2d99e02c10eee047410a43eff634d051aeb784e76cb3605d8e079b9eb6ad1957dfdf77e1cd32ce4a573c9dfcc207ca65af6eb187f6c3d -a9667271f7d191935cc8ad59ef3ec50229945faea85bfdfb0d582090f524436b348aaa0183b16a6231c00332fdac2826125b8c857a2ed9ec66821cfe02b3a2279be2412441bc2e369b255eb98614e4be8490799c4df22f18d47d24ec70bba5f7 -a4371144d2aa44d70d3cb9789096d3aa411149a6f800cb46f506461ee8363c8724667974252f28aea61b6030c05930ac039c1ee64bb4bd56532a685cae182bf2ab935eee34718cffcb46cae214c77aaca11dbb1320faf23c47247db1da04d8dc -89a7eb441892260b7e81168c386899cd84ffc4a2c5cad2eae0d1ab9e8b5524662e6f660fe3f8bfe4c92f60b060811bc605b14c5631d16709266886d7885a5eb5930097127ec6fb2ebbaf2df65909cf48f253b3d5e22ae48d3e9a2fd2b01f447e -9648c42ca97665b5eccb49580d8532df05eb5a68db07f391a2340769b55119eaf4c52fe4f650c09250fa78a76c3a1e271799b8333cc2628e3d4b4a6a3e03da1f771ecf6516dd63236574a7864ff07e319a6f11f153406280d63af9e2b5713283 -9663bf6dd446ea7a90658ee458578d4196dc0b175ef7fcfa75f44d41670850774c2e46c5a6be132a2c072a3c0180a24f0305d1acac49d2d79878e5cda80c57feda3d01a6af12e78b5874e2a4b3717f11c97503b41a4474e2e95b179113726199 -b212aeb4814e0915b432711b317923ed2b09e076aaf558c3ae8ef83f9e15a83f9ea3f47805b2750ab9e8106cb4dc6ad003522c84b03dc02829978a097899c773f6fb31f7fe6b8f2d836d96580f216fec20158f1590c3e0d7850622e15194db05 -925f005059bf07e9ceccbe66c711b048e236ade775720d0fe479aebe6e23e8af281225ad18e62458dc1b03b42ad4ca290d4aa176260604a7aad0d9791337006fbdebe23746f8060d42876f45e4c83c3643931392fde1cd13ff8bddf8111ef974 -9553edb22b4330c568e156a59ef03b26f5c326424f830fe3e8c0b602f08c124730ffc40bc745bec1a22417adb22a1a960243a10565c2be3066bfdb841d1cd14c624cd06e0008f4beb83f972ce6182a303bee3fcbcabc6cfe48ec5ae4b7941bfc -935f5a404f0a78bdcce709899eda0631169b366a669e9b58eacbbd86d7b5016d044b8dfc59ce7ed8de743ae16c2343b50e2f925e88ba6319e33c3fc76b314043abad7813677b4615c8a97eb83cc79de4fedf6ccbcfa4d4cbf759a5a84e4d9742 -a5b014ab936eb4be113204490e8b61cd38d71da0dec7215125bcd131bf3ab22d0a32ce645bca93e7b3637cf0c2db3d6601a0ddd330dc46f9fae82abe864ffc12d656c88eb50c20782e5bb6f75d18760666f43943abb644b881639083e122f557 -935b7298ae52862fa22bf03bfc1795b34c70b181679ae27de08a9f5b4b884f824ef1b276b7600efa0d2f1d79e4a470d51692fd565c5cf8343dd80e5d3336968fc21c09ba9348590f6206d4424eb229e767547daefa98bc3aa9f421158dee3f2a -9830f92446e708a8f6b091cc3c38b653505414f8b6507504010a96ffda3bcf763d5331eb749301e2a1437f00e2415efb01b799ad4c03f4b02de077569626255ac1165f96ea408915d4cf7955047620da573e5c439671d1fa5c833fb11de7afe6 -840dcc44f673fff3e387af2bb41e89640f2a70bcd2b92544876daa92143f67c7512faf5f90a04b7191de01f3e2b1bde00622a20dc62ca23bbbfaa6ad220613deff43908382642d4d6a86999f662efd64b1df448b68c847cfa87630a3ffd2ec76 -92950c895ed54f7f876b2fda17ecc9c41b7accfbdd42c210cc5b475e0737a7279f558148531b5c916e310604a1de25a80940c94fe5389ae5d6a5e9c371be67bceea1877f5401725a6595bcf77ece60905151b6dfcb68b75ed2e708c73632f4fd -8010246bf8e94c25fd029b346b5fbadb404ef6f44a58fd9dd75acf62433d8cc6db66974f139a76e0c26dddc1f329a88214dbb63276516cf325c7869e855d07e0852d622c332ac55609ba1ec9258c45746a2aeb1af0800141ee011da80af175d4 -b0f1bad257ebd187bdc3f37b23f33c6a5d6a8e1f2de586080d6ada19087b0e2bf23b79c1b6da1ee82271323f5bdf3e1b018586b54a5b92ab6a1a16bb3315190a3584a05e6c37d5ca1e05d702b9869e27f513472bcdd00f4d0502a107773097da -9636d24f1ede773ce919f309448dd7ce023f424afd6b4b69cb98c2a988d849a283646dc3e469879daa1b1edae91ae41f009887518e7eb5578f88469321117303cd3ac2d7aee4d9cb5f82ab9ae3458e796dfe7c24284b05815acfcaa270ff22e2 -b373feb5d7012fd60578d7d00834c5c81df2a23d42794fed91aa9535a4771fde0341c4da882261785e0caca40bf83405143085e7f17e55b64f6c5c809680c20b050409bf3702c574769127c854d27388b144b05624a0e24a1cbcc4d08467005b -b15680648949ce69f82526e9b67d9b55ce5c537dc6ab7f3089091a9a19a6b90df7656794f6edc87fb387d21573ffc847062623685931c2790a508cbc8c6b231dd2c34f4d37d4706237b1407673605a604bcf6a50cc0b1a2db20485e22b02c17e -8817e46672d40c8f748081567b038a3165f87994788ec77ee8daea8587f5540df3422f9e120e94339be67f186f50952504cb44f61e30a5241f1827e501b2de53c4c64473bcc79ab887dd277f282fbfe47997a930dd140ac08b03efac88d81075 -a6e4ef6c1d1098f95aae119905f87eb49b909d17f9c41bcfe51127aa25fee20782ea884a7fdf7d5e9c245b5a5b32230b07e0dbf7c6743bf52ee20e2acc0b269422bd6cf3c07115df4aa85b11b2c16630a07c974492d9cdd0ec325a3fabd95044 -8634aa7c3d00e7f17150009698ce440d8e1b0f13042b624a722ace68ead870c3d2212fbee549a2c190e384d7d6ac37ce14ab962c299ea1218ef1b1489c98906c91323b94c587f1d205a6edd5e9d05b42d591c26494a6f6a029a2aadb5f8b6f67 -821a58092900bdb73decf48e13e7a5012a3f88b06288a97b855ef51306406e7d867d613d9ec738ebacfa6db344b677d21509d93f3b55c2ebf3a2f2a6356f875150554c6fff52e62e3e46f7859be971bf7dd9d5b3e1d799749c8a97c2e04325df -8dba356577a3a388f782e90edb1a7f3619759f4de314ad5d95c7cc6e197211446819c4955f99c5fc67f79450d2934e3c09adefc91b724887e005c5190362245eec48ce117d0a94d6fa6db12eda4ba8dde608fbbd0051f54dcf3bb057adfb2493 -a32a690dc95c23ed9fb46443d9b7d4c2e27053a7fcc216d2b0020a8cf279729c46114d2cda5772fd60a97016a07d6c5a0a7eb085a18307d34194596f5b541cdf01b2ceb31d62d6b55515acfd2b9eec92b27d082fbc4dc59fc63b551eccdb8468 -a040f7f4be67eaf0a1d658a3175d65df21a7dbde99bfa893469b9b43b9d150fc2e333148b1cb88cfd0447d88fa1a501d126987e9fdccb2852ecf1ba907c2ca3d6f97b055e354a9789854a64ecc8c2e928382cf09dda9abde42bbdf92280cdd96 -864baff97fa60164f91f334e0c9be00a152a416556b462f96d7c43b59fe1ebaff42f0471d0bf264976f8aa6431176eb905bd875024cf4f76c13a70bede51dc3e47e10b9d5652d30d2663b3af3f08d5d11b9709a0321aba371d2ef13174dcfcaf -95a46f32c994133ecc22db49bad2c36a281d6b574c83cfee6680b8c8100466ca034b815cfaedfbf54f4e75188e661df901abd089524e1e0eb0bf48d48caa9dd97482d2e8c1253e7e8ac250a32fd066d5b5cb08a8641bdd64ecfa48289dca83a3 -a2cce2be4d12144138cb91066e0cd0542c80b478bf467867ebef9ddaf3bd64e918294043500bf5a9f45ee089a8d6ace917108d9ce9e4f41e7e860cbce19ac52e791db3b6dde1c4b0367377b581f999f340e1d6814d724edc94cb07f9c4730774 -b145f203eee1ac0a1a1731113ffa7a8b0b694ef2312dabc4d431660f5e0645ef5838e3e624cfe1228cfa248d48b5760501f93e6ab13d3159fc241427116c4b90359599a4cb0a86d0bb9190aa7fabff482c812db966fd2ce0a1b48cb8ac8b3bca -adabe5d215c608696e03861cbd5f7401869c756b3a5aadc55f41745ad9478145d44393fec8bb6dfc4ad9236dc62b9ada0f7ca57fe2bae1b71565dbf9536d33a68b8e2090b233422313cc96afc7f1f7e0907dc7787806671541d6de8ce47c4cd0 -ae7845fa6b06db53201c1080e01e629781817f421f28956589c6df3091ec33754f8a4bd4647a6bb1c141ac22731e3c1014865d13f3ed538dcb0f7b7576435133d9d03be655f8fbb4c9f7d83e06d1210aedd45128c2b0c9bab45a9ddde1c862a5 -9159eaa826a24adfa7adf6e8d2832120ebb6eccbeb3d0459ffdc338548813a2d239d22b26451fda98cc0c204d8e1ac69150b5498e0be3045300e789bcb4e210d5cd431da4bdd915a21f407ea296c20c96608ded0b70d07188e96e6c1a7b9b86b -a9fc6281e2d54b46458ef564ffaed6944bff71e389d0acc11fa35d3fcd8e10c1066e0dde5b9b6516f691bb478e81c6b20865281104dcb640e29dc116daae2e884f1fe6730d639dbe0e19a532be4fb337bf52ae8408446deb393d224eee7cfa50 -84291a42f991bfb36358eedead3699d9176a38f6f63757742fdbb7f631f2c70178b1aedef4912fed7b6cf27e88ddc7eb0e2a6aa4b999f3eb4b662b93f386c8d78e9ac9929e21f4c5e63b12991fcde93aa64a735b75b535e730ff8dd2abb16e04 -a1b7fcacae181495d91765dfddf26581e8e39421579c9cbd0dd27a40ea4c54af3444a36bf85a11dda2114246eaddbdd619397424bb1eb41b5a15004b902a590ede5742cd850cf312555be24d2df8becf48f5afba5a8cd087cb7be0a521728386 -92feaaf540dbd84719a4889a87cdd125b7e995a6782911931fef26da9afcfbe6f86aaf5328fe1f77631491ce6239c5470f44c7791506c6ef1626803a5794e76d2be0af92f7052c29ac6264b7b9b51f267ad820afc6f881460521428496c6a5f1 -a525c925bfae1b89320a5054acc1fa11820f73d0cf28d273092b305467b2831fab53b6daf75fb926f332782d50e2522a19edcd85be5eb72f1497193c952d8cd0bcc5d43b39363b206eae4cb1e61668bde28a3fb2fc1e0d3d113f6dfadb799717 -98752bb6f5a44213f40eda6aa4ff124057c1b13b6529ab42fe575b9afa66e59b9c0ed563fb20dff62130c436c3e905ee17dd8433ba02c445b1d67182ab6504a90bbe12c26a754bbf734665c622f76c62fe2e11dd43ce04fd2b91a8463679058b -a9aa9a84729f7c44219ff9e00e651e50ddea3735ef2a73fdf8ed8cd271961d8ed7af5cd724b713a89a097a3fe65a3c0202f69458a8b4c157c62a85668b12fc0d3957774bc9b35f86c184dd03bfefd5c325da717d74192cc9751c2073fe9d170e -b221c1fd335a4362eff504cd95145f122bf93ea02ae162a3fb39c75583fc13a932d26050e164da97cff3e91f9a7f6ff80302c19dd1916f24acf6b93b62f36e9665a8785413b0c7d930c7f1668549910f849bca319b00e59dd01e5dec8d2edacc -a71e2b1e0b16d754b848f05eda90f67bedab37709550171551050c94efba0bfc282f72aeaaa1f0330041461f5e6aa4d11537237e955e1609a469d38ed17f5c2a35a1752f546db89bfeff9eab78ec944266f1cb94c1db3334ab48df716ce408ef -b990ae72768779ba0b2e66df4dd29b3dbd00f901c23b2b4a53419226ef9232acedeb498b0d0687c463e3f1eead58b20b09efcefa566fbfdfe1c6e48d32367936142d0a734143e5e63cdf86be7457723535b787a9cfcfa32fe1d61ad5a2617220 -8d27e7fbff77d5b9b9bbc864d5231fecf817238a6433db668d5a62a2c1ee1e5694fdd90c3293c06cc0cb15f7cbeab44d0d42be632cb9ff41fc3f6628b4b62897797d7b56126d65b694dcf3e298e3561ac8813fbd7296593ced33850426df42db -a92039a08b5502d5b211a7744099c9f93fa8c90cedcb1d05e92f01886219dd464eb5fb0337496ad96ed09c987da4e5f019035c5b01cc09b2a18b8a8dd419bc5895388a07e26958f6bd26751929c25f89b8eb4a299d822e2d26fec9ef350e0d3c -92dcc5a1c8c3e1b28b1524e3dd6dbecd63017c9201da9dbe077f1b82adc08c50169f56fc7b5a3b28ec6b89254de3e2fd12838a761053437883c3e01ba616670cea843754548ef84bcc397de2369adcca2ab54cd73c55dc68d87aec3fc2fe4f10 diff --git a/crates/primitives/src/kzg/trusted_setup_points.rs b/crates/primitives/src/kzg/trusted_setup_points.rs deleted file mode 100644 index dc90b64bed..0000000000 --- a/crates/primitives/src/kzg/trusted_setup_points.rs +++ /dev/null @@ -1,133 +0,0 @@ -use core::fmt; -use derive_more::{AsMut, AsRef, Deref, DerefMut}; -use std::boxed::Box; - -pub use c_kzg::{BYTES_PER_G1_POINT, BYTES_PER_G2_POINT}; - -/// Number of G1 Points. -pub const NUM_G1_POINTS: usize = 4096; - -/// Number of G2 Points. -pub const NUM_G2_POINTS: usize = 65; - -/// A newtype over list of G1 point from kzg trusted setup. -#[derive(Debug, Clone, PartialEq, AsRef, AsMut, Deref, DerefMut)] -#[repr(transparent)] -pub struct G1Points(pub [[u8; BYTES_PER_G1_POINT]; NUM_G1_POINTS]); - -impl Default for G1Points { - fn default() -> Self { - Self([[0; BYTES_PER_G1_POINT]; NUM_G1_POINTS]) - } -} - -/// A newtype over list of G2 point from kzg trusted setup. -#[derive(Debug, Clone, Eq, PartialEq, AsRef, AsMut, Deref, DerefMut)] -#[repr(transparent)] -pub struct G2Points(pub [[u8; BYTES_PER_G2_POINT]; NUM_G2_POINTS]); - -impl Default for G2Points { - fn default() -> Self { - Self([[0; BYTES_PER_G2_POINT]; NUM_G2_POINTS]) - } -} - -/// Default G1 points. -pub const G1_POINTS: &G1Points = { - const BYTES: &[u8] = include_bytes!("./g1_points.bin"); - assert!(BYTES.len() == core::mem::size_of::()); - unsafe { &*BYTES.as_ptr().cast::() } -}; - -/// Default G2 points. -pub const G2_POINTS: &G2Points = { - const BYTES: &[u8] = include_bytes!("./g2_points.bin"); - assert!(BYTES.len() == core::mem::size_of::()); - unsafe { &*BYTES.as_ptr().cast::() } -}; - -/// Parses the contents of a KZG trusted setup file into a list of G1 and G2 points. -/// -/// These can then be used to create a KZG settings object with -/// [`KzgSettings::load_trusted_setup`](c_kzg::KzgSettings::load_trusted_setup). -pub fn parse_kzg_trusted_setup( - trusted_setup: &str, -) -> Result<(Box, Box), KzgErrors> { - let mut lines = trusted_setup.lines(); - - // load number of points - let n_g1 = lines - .next() - .ok_or(KzgErrors::FileFormatError)? - .parse::() - .map_err(|_| KzgErrors::ParseError)?; - let n_g2 = lines - .next() - .ok_or(KzgErrors::FileFormatError)? - .parse::() - .map_err(|_| KzgErrors::ParseError)?; - - if n_g1 != NUM_G1_POINTS { - return Err(KzgErrors::MismatchedNumberOfPoints); - } - - if n_g2 != NUM_G2_POINTS { - return Err(KzgErrors::MismatchedNumberOfPoints); - } - - // load g1 points - let mut g1_points = Box::::default(); - for bytes in &mut g1_points.0 { - let line = lines.next().ok_or(KzgErrors::FileFormatError)?; - crate::hex::decode_to_slice(line, bytes).map_err(|_| KzgErrors::ParseError)?; - } - - // load g2 points - let mut g2_points = Box::::default(); - for bytes in &mut g2_points.0 { - let line = lines.next().ok_or(KzgErrors::FileFormatError)?; - crate::hex::decode_to_slice(line, bytes).map_err(|_| KzgErrors::ParseError)?; - } - - if lines.next().is_some() { - return Err(KzgErrors::FileFormatError); - } - - Ok((g1_points, g2_points)) -} - -#[derive(Debug)] -pub enum KzgErrors { - /// Failed to get current directory. - FailedCurrentDirectory, - /// The specified path does not exist. - PathNotExists, - /// Problems related to I/O. - IOError, - /// Not a valid file. - NotValidFile, - /// File is not properly formatted. - FileFormatError, - /// Not able to parse to usize. - ParseError, - /// Number of points does not match what is expected. - MismatchedNumberOfPoints, -} - -impl fmt::Display for KzgErrors { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let s = match self { - Self::FailedCurrentDirectory => "failed to get current directory", - Self::PathNotExists => "the specified path does not exist", - Self::IOError => "IO error", - Self::NotValidFile => "not a valid file", - Self::FileFormatError => "file is not properly formatted", - Self::ParseError => "could not parse as usize", - Self::MismatchedNumberOfPoints => "number of points does not match what is expected", - }; - f.write_str(s) - } -} - -#[cfg(feature = "std")] -impl std::error::Error for KzgErrors {} diff --git a/crates/primitives/src/lib.rs b/crates/primitives/src/lib.rs index c57f900b90..8fb8bceeb2 100644 --- a/crates/primitives/src/lib.rs +++ b/crates/primitives/src/lib.rs @@ -1,46 +1,65 @@ //! # revm-primitives //! -//! EVM primitive types. +//! Core primitive types and constants for the Ethereum Virtual Machine (EVM) implementation. +//! +//! This crate provides: +//! - EVM constants and limits (gas, stack, code size) +//! - Ethereum hard fork management and version control +//! - EIP-specific constants and configuration values +//! - Cross-platform synchronization primitives +//! - Type aliases for common EVM concepts (storage keys/values) +//! - Re-exports of alloy primitive types for convenience #![cfg_attr(not(test), warn(unused_crate_dependencies))] #![cfg_attr(not(feature = "std"), no_std)] #[cfg(not(feature = "std"))] extern crate alloc as std; -mod bytecode; -mod constants; -pub mod db; -pub mod env; - -#[cfg(feature = "c-kzg")] -pub mod kzg; -pub mod precompile; -pub mod result; -pub mod specification; -pub mod state; -pub mod utilities; +pub mod constants; +pub mod eip170; +pub mod eip3860; +pub mod eip4844; +pub mod eip7702; +pub mod eip7823; +pub mod eip7825; +pub mod eip7907; +pub mod eip7918; +pub mod hardfork; +mod once_lock; + +pub use constants::*; +pub use once_lock::OnceLock; + +// Reexport alloy primitives. + +pub use alloy_primitives::map::{self, hash_map, hash_set, HashMap, HashSet}; pub use alloy_primitives::{ - self, address, b256, bytes, fixed_bytes, hex, hex_literal, ruint, uint, Address, Bytes, - FixedBytes, Log, LogData, B256, I256, U256, + self, address, b256, bytes, fixed_bytes, hex, hex_literal, keccak256, ruint, uint, Address, + Bytes, FixedBytes, Log, LogData, TxKind, B256, I128, I256, U128, U256, }; -pub use bitvec; -pub use bytecode::*; -pub use constants::*; -pub use env::*; - -cfg_if::cfg_if! { - if #[cfg(all(not(feature = "hashbrown"), feature = "std"))] { - pub use std::collections::{hash_map, hash_set, HashMap, HashSet}; - use hashbrown as _; - } else { - pub use hashbrown::{hash_map, hash_set, HashMap, HashSet}; + +/// Type alias for EVM storage keys (256-bit unsigned integers). +/// Used to identify storage slots within smart contract storage. +pub type StorageKey = U256; + +/// Type alias for EVM storage values (256-bit unsigned integers). +/// Used to store data values in smart contract storage slots. +pub type StorageValue = U256; + +/// Optimize short address access. +pub const SHORT_ADDRESS_CAP: usize = 300; + +/// Returns the short address from Address. +/// +/// Short address is considered address that has 18 leading zeros +/// and last two bytes are less than [`SHORT_ADDRESS_CAP`]. +#[inline] +pub fn short_address(address: &Address) -> Option { + if address.0[..18].iter().all(|b| *b == 0) { + let short_address = u16::from_be_bytes([address.0[18], address.0[19]]) as usize; + if short_address < SHORT_ADDRESS_CAP { + return Some(short_address); + } } + None } - -#[cfg(feature = "c-kzg")] -pub use kzg::{EnvKzgSettings, KzgSettings}; -pub use precompile::*; -pub use result::*; -pub use specification::*; -pub use state::*; -pub use utilities::*; diff --git a/crates/primitives/src/once_lock.rs b/crates/primitives/src/once_lock.rs new file mode 100644 index 0000000000..90d129ea6a --- /dev/null +++ b/crates/primitives/src/once_lock.rs @@ -0,0 +1,53 @@ +//! `OnceLock` abstraction that uses [`std::sync::OnceLock`] when available, once_cell otherwise. + +#[cfg(not(feature = "std"))] +mod no_std_impl { + use once_cell::race::OnceBox; + use std::boxed::Box; + + /// A thread-safe cell which can be written to only once. + #[derive(Debug)] + pub struct OnceLock { + inner: OnceBox, + } + + impl Default for OnceLock { + fn default() -> Self { + Self::new() + } + } + + impl OnceLock { + /// Creates a new empty OnceLock. + #[inline] + pub const fn new() -> Self { + Self { + inner: OnceBox::new(), + } + } + + /// Gets the contents of the OnceLock, initializing it if necessary. + #[inline] + pub fn get_or_init(&self, f: F) -> &T + where + F: FnOnce() -> T, + T: Into>, + { + self.inner.get_or_init(|| f().into()) + } + + /// Gets the contents of the OnceLock, returning None if it is not initialized. + #[inline] + pub fn get(&self) -> Option<&T> { + self.inner.get() + } + } +} + +#[cfg(feature = "std")] +use once_cell as _; +#[cfg(feature = "std")] +pub use std::sync::OnceLock; + +#[cfg(not(feature = "std"))] +pub use no_std_impl::OnceLock; diff --git a/crates/primitives/src/precompile.rs b/crates/primitives/src/precompile.rs deleted file mode 100644 index e585377537..0000000000 --- a/crates/primitives/src/precompile.rs +++ /dev/null @@ -1,190 +0,0 @@ -use crate::{Bytes, Env}; -use core::fmt; -use dyn_clone::DynClone; -use std::{boxed::Box, string::String, sync::Arc}; - -/// A precompile operation result. -/// -/// Returns either `Ok((gas_used, return_bytes))` or `Err(error)`. -pub type PrecompileResult = Result<(u64, Bytes), PrecompileError>; - -pub type StandardPrecompileFn = fn(&Bytes, u64) -> PrecompileResult; -pub type EnvPrecompileFn = fn(&Bytes, u64, env: &Env) -> PrecompileResult; - -/// Stateful precompile trait. It is used to create -/// a arc precompile Precompile::Stateful. -pub trait StatefulPrecompile: Sync + Send { - fn call(&self, bytes: &Bytes, gas_price: u64, env: &Env) -> PrecompileResult; -} - -/// Mutable stateful precompile trait. It is used to create -/// a boxed precompile in Precompile::StatefulMut. -pub trait StatefulPrecompileMut: DynClone + Send + Sync { - fn call_mut(&mut self, bytes: &Bytes, gas_price: u64, env: &Env) -> PrecompileResult; -} - -dyn_clone::clone_trait_object!(StatefulPrecompileMut); - -/// Arc over stateful precompile. -pub type StatefulPrecompileArc = Arc; - -/// Box over mutable stateful precompile -pub type StatefulPrecompileBox = Box; - -/// Precompile and its handlers. -#[derive(Clone)] -pub enum Precompile { - /// Standard simple precompile that takes input and gas limit. - Standard(StandardPrecompileFn), - /// Similar to Standard but takes reference to environment. - Env(EnvPrecompileFn), - /// Stateful precompile that is Arc over [`StatefulPrecompile`] trait. - /// It takes a reference to input, gas limit and environment. - Stateful(StatefulPrecompileArc), - /// Mutable stateful precompile that is Box over [`StatefulPrecompileMut`] trait. - /// It takes a reference to input, gas limit and environment. - StatefulMut(StatefulPrecompileBox), -} - -impl From for Precompile { - fn from(p: StandardPrecompileFn) -> Self { - Precompile::Standard(p) - } -} - -impl From for Precompile { - fn from(p: EnvPrecompileFn) -> Self { - Precompile::Env(p) - } -} - -impl From for Precompile { - fn from(p: StatefulPrecompileArc) -> Self { - Precompile::Stateful(p) - } -} - -impl From for Precompile { - fn from(p: StatefulPrecompileBox) -> Self { - Precompile::StatefulMut(p) - } -} - -impl fmt::Debug for Precompile { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Precompile::Standard(_) => f.write_str("Standard"), - Precompile::Env(_) => f.write_str("Env"), - Precompile::Stateful(_) => f.write_str("Stateful"), - Precompile::StatefulMut(_) => f.write_str("StatefulMut"), - } - } -} - -impl Precompile { - /// Create a new stateful precompile. - pub fn new_stateful(p: P) -> Self { - Self::Stateful(Arc::new(p)) - } - - /// Create a new mutable stateful precompile. - pub fn new_stateful_mut(p: P) -> Self { - Self::StatefulMut(Box::new(p)) - } - - /// Call the precompile with the given input and gas limit and return the result. - pub fn call(&mut self, bytes: &Bytes, gas_price: u64, env: &Env) -> PrecompileResult { - match self { - Precompile::Standard(p) => p(bytes, gas_price), - Precompile::Env(p) => p(bytes, gas_price, env), - Precompile::Stateful(p) => p.call(bytes, gas_price, env), - Precompile::StatefulMut(p) => p.call_mut(bytes, gas_price, env), - } - } -} - -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub enum PrecompileError { - /// out of gas is the main error. Others are here just for completeness - OutOfGas, - // Blake2 errors - Blake2WrongLength, - Blake2WrongFinalIndicatorFlag, - // Modexp errors - ModexpExpOverflow, - ModexpBaseOverflow, - ModexpModOverflow, - // Bn128 errors - Bn128FieldPointNotAMember, - Bn128AffineGFailedToCreate, - Bn128PairLength, - // Blob errors - /// The input length is not exactly 192 bytes. - BlobInvalidInputLength, - /// The commitment does not match the versioned hash. - BlobMismatchedVersion, - /// The proof verification failed. - BlobVerifyKzgProofFailed, - /// Catch-all variant for other errors. - Other(String), -} - -impl PrecompileError { - pub fn other(err: impl Into) -> Self { - Self::Other(err.into()) - } -} - -#[cfg(feature = "std")] -impl std::error::Error for PrecompileError {} - -impl fmt::Display for PrecompileError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let s = match self { - Self::OutOfGas => "out of gas", - Self::Blake2WrongLength => "wrong input length for blake2", - Self::Blake2WrongFinalIndicatorFlag => "wrong final indicator flag for blake2", - Self::ModexpExpOverflow => "modexp exp overflow", - Self::ModexpBaseOverflow => "modexp base overflow", - Self::ModexpModOverflow => "modexp mod overflow", - Self::Bn128FieldPointNotAMember => "field point not a member of bn128 curve", - Self::Bn128AffineGFailedToCreate => "failed to create affine g point for bn128 curve", - Self::Bn128PairLength => "bn128 invalid pair length", - Self::BlobInvalidInputLength => "invalid blob input length", - Self::BlobMismatchedVersion => "mismatched blob version", - Self::BlobVerifyKzgProofFailed => "verifying blob kzg proof failed", - Self::Other(s) => s, - }; - f.write_str(s) - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn stateful_precompile_mut() { - #[derive(Default, Clone)] - struct MyPrecompile {} - - impl StatefulPrecompileMut for MyPrecompile { - fn call_mut( - &mut self, - _bytes: &Bytes, - _gas_price: u64, - _env: &Env, - ) -> PrecompileResult { - PrecompileResult::Err(PrecompileError::OutOfGas) - } - } - - let mut p = Precompile::new_stateful_mut(MyPrecompile::default()); - match &mut p { - Precompile::StatefulMut(p) => { - let _ = p.call_mut(&Bytes::new(), 0, &Env::default()); - } - _ => panic!("not a state"), - } - } -} diff --git a/crates/primitives/src/result.rs b/crates/primitives/src/result.rs deleted file mode 100644 index 438451e2a9..0000000000 --- a/crates/primitives/src/result.rs +++ /dev/null @@ -1,442 +0,0 @@ -use crate::{Address, Bytes, EvmState, Log, U256}; -use core::fmt; -use std::{boxed::Box, string::String, vec::Vec}; - -/// Result of EVM execution. -pub type EVMResult = EVMResultGeneric; - -/// Generic result of EVM execution. Used to represent error and generic output. -pub type EVMResultGeneric = core::result::Result>; - -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct ResultAndState { - /// Status of execution - pub result: ExecutionResult, - /// State that got updated - pub state: EvmState, -} - -/// Result of a transaction execution. -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum ExecutionResult { - /// Returned successfully - Success { - reason: SuccessReason, - gas_used: u64, - gas_refunded: u64, - logs: Vec, - output: Output, - }, - /// Reverted by `REVERT` opcode that doesn't spend all gas. - Revert { gas_used: u64, output: Bytes }, - /// Reverted for various reasons and spend all gas. - Halt { - reason: HaltReason, - /// Halting will spend all the gas, and will be equal to gas_limit. - gas_used: u64, - }, -} - -impl ExecutionResult { - /// Returns if transaction execution is successful. - /// 1 indicates success, 0 indicates revert. - /// - pub fn is_success(&self) -> bool { - matches!(self, Self::Success { .. }) - } - - /// Returns true if execution result is a Halt. - pub fn is_halt(&self) -> bool { - matches!(self, Self::Halt { .. }) - } - - /// Returns the output data of the execution. - /// - /// Returns `None` if the execution was halted. - pub fn output(&self) -> Option<&Bytes> { - match self { - Self::Success { output, .. } => Some(output.data()), - Self::Revert { output, .. } => Some(output), - _ => None, - } - } - - /// Consumes the type and returns the output data of the execution. - /// - /// Returns `None` if the execution was halted. - pub fn into_output(self) -> Option { - match self { - Self::Success { output, .. } => Some(output.into_data()), - Self::Revert { output, .. } => Some(output), - _ => None, - } - } - - /// Returns the logs if execution is successful, or an empty list otherwise. - pub fn logs(&self) -> &[Log] { - match self { - Self::Success { logs, .. } => logs, - _ => &[], - } - } - - /// Consumes `self` and returns the logs if execution is successful, or an empty list otherwise. - pub fn into_logs(self) -> Vec { - match self { - Self::Success { logs, .. } => logs, - _ => Vec::new(), - } - } - - /// Returns the gas used. - pub fn gas_used(&self) -> u64 { - match *self { - Self::Success { gas_used, .. } - | Self::Revert { gas_used, .. } - | Self::Halt { gas_used, .. } => gas_used, - } - } -} - -/// Output of a transaction execution. -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum Output { - Call(Bytes), - Create(Bytes, Option
), -} - -impl Output { - /// Returns the output data of the execution output. - pub fn into_data(self) -> Bytes { - match self { - Output::Call(data) => data, - Output::Create(data, _) => data, - } - } - - /// Returns the output data of the execution output. - pub fn data(&self) -> &Bytes { - match self { - Output::Call(data) => data, - Output::Create(data, _) => data, - } - } - - /// Returns the created address, if any. - pub fn address(&self) -> Option<&Address> { - match self { - Output::Call(_) => None, - Output::Create(_, address) => address.as_ref(), - } - } -} - -/// Main EVM error. -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum EVMError { - /// Transaction validation error. - Transaction(InvalidTransaction), - /// Header validation error. - Header(InvalidHeader), - /// Database error. - Database(DBError), - /// Custom error. - /// - /// Useful for handler registers where custom logic would want to return their own custom error. - Custom(String), -} - -#[cfg(feature = "std")] -impl std::error::Error for EVMError { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - match self { - Self::Transaction(e) => Some(e), - Self::Header(e) => Some(e), - Self::Database(e) => Some(e), - Self::Custom(_) => None, - } - } -} - -impl fmt::Display for EVMError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::Transaction(e) => write!(f, "transaction validation error: {e}"), - Self::Header(e) => write!(f, "header validation error: {e}"), - Self::Database(e) => write!(f, "database error: {e}"), - Self::Custom(e) => f.write_str(e), - } - } -} - -impl From for EVMError { - fn from(value: InvalidTransaction) -> Self { - Self::Transaction(value) - } -} - -impl From for EVMError { - fn from(value: InvalidHeader) -> Self { - Self::Header(value) - } -} - -/// Transaction validation error. -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum InvalidTransaction { - /// When using the EIP-1559 fee model introduced in the London upgrade, transactions specify two primary fee fields: - /// - `gas_max_fee`: The maximum total fee a user is willing to pay, inclusive of both base fee and priority fee. - /// - `gas_priority_fee`: The extra amount a user is willing to give directly to the miner, often referred to as the "tip". - /// - /// Provided `gas_priority_fee` exceeds the total `gas_max_fee`. - PriorityFeeGreaterThanMaxFee, - /// EIP-1559: `gas_price` is less than `basefee`. - GasPriceLessThanBasefee, - /// `gas_limit` in the tx is bigger than `block_gas_limit`. - CallerGasLimitMoreThanBlock, - /// Initial gas for a Call is bigger than `gas_limit`. - /// - /// Initial gas for a Call contains: - /// - initial stipend gas - /// - gas for access list and input data - CallGasCostMoreThanGasLimit, - /// EIP-3607 Reject transactions from senders with deployed code - RejectCallerWithCode, - /// Transaction account does not have enough amount of ether to cover transferred value and gas_limit*gas_price. - LackOfFundForMaxFee { - fee: Box, - balance: Box, - }, - /// Overflow payment in transaction. - OverflowPaymentInTransaction, - /// Nonce overflows in transaction. - NonceOverflowInTransaction, - NonceTooHigh { - tx: u64, - state: u64, - }, - NonceTooLow { - tx: u64, - state: u64, - }, - /// EIP-3860: Limit and meter initcode - CreateInitCodeSizeLimit, - /// Transaction chain id does not match the config chain id. - InvalidChainId, - /// Access list is not supported for blocks before the Berlin hardfork. - AccessListNotSupported, - /// `max_fee_per_blob_gas` is not supported for blocks before the Cancun hardfork. - MaxFeePerBlobGasNotSupported, - /// `blob_hashes`/`blob_versioned_hashes` is not supported for blocks before the Cancun hardfork. - BlobVersionedHashesNotSupported, - /// Block `blob_gas_price` is greater than tx-specified `max_fee_per_blob_gas` after Cancun. - BlobGasPriceGreaterThanMax, - /// There should be at least one blob in Blob transaction. - EmptyBlobs, - /// Blob transaction can't be a create transaction. - /// `to` must be present - BlobCreateTransaction, - /// Transaction has more then [`crate::MAX_BLOB_NUMBER_PER_BLOCK`] blobs - TooManyBlobs { - max: usize, - have: usize, - }, - /// Blob transaction contains a versioned hash with an incorrect version - BlobVersionNotSupported, - /// EOF crate should have `to` address - EofCrateShouldHaveToAddress, - /// System transactions are not supported post-regolith hardfork. - /// - /// Before the Regolith hardfork, there was a special field in the `Deposit` transaction - /// type that differentiated between `system` and `user` deposit transactions. This field - /// was deprecated in the Regolith hardfork, and this error is thrown if a `Deposit` transaction - /// is found with this field set to `true` after the hardfork activation. - /// - /// In addition, this error is internal, and bubbles up into a [HaltReason::FailedDeposit] error - /// in the `revm` handler for the consumer to easily handle. This is due to a state transition - /// rule on OP Stack chains where, if for any reason a deposit transaction fails, the transaction - /// must still be included in the block, the sender nonce is bumped, the `mint` value persists, and - /// special gas accounting rules are applied. Normally on L1, [EVMError::Transaction] errors - /// are cause for non-inclusion, so a special [HaltReason] variant was introduced to handle this - /// case for failed deposit transactions. - #[cfg(feature = "optimism")] - DepositSystemTxPostRegolith, - /// Deposit transaction haults bubble up to the global main return handler, wiping state and - /// only increasing the nonce + persisting the mint value. - /// - /// This is a catch-all error for any deposit transaction that is results in a [HaltReason] error - /// post-regolith hardfork. This allows for a consumer to easily handle special cases where - /// a deposit transaction fails during validation, but must still be included in the block. - /// - /// In addition, this error is internal, and bubbles up into a [HaltReason::FailedDeposit] error - /// in the `revm` handler for the consumer to easily handle. This is due to a state transition - /// rule on OP Stack chains where, if for any reason a deposit transaction fails, the transaction - /// must still be included in the block, the sender nonce is bumped, the `mint` value persists, and - /// special gas accounting rules are applied. Normally on L1, [EVMError::Transaction] errors - /// are cause for non-inclusion, so a special [HaltReason] variant was introduced to handle this - /// case for failed deposit transactions. - #[cfg(feature = "optimism")] - HaltedDepositPostRegolith, -} - -#[cfg(feature = "std")] -impl std::error::Error for InvalidTransaction {} - -impl fmt::Display for InvalidTransaction { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::PriorityFeeGreaterThanMaxFee => { - write!(f, "priority fee is greater than max fee") - } - Self::GasPriceLessThanBasefee => { - write!(f, "gas price is less than basefee") - } - Self::CallerGasLimitMoreThanBlock => { - write!(f, "caller gas limit exceeds the block gas limit") - } - Self::CallGasCostMoreThanGasLimit => { - write!(f, "call gas cost exceeds the gas limit") - } - Self::RejectCallerWithCode => { - write!(f, "reject transactions from senders with deployed code") - } - Self::LackOfFundForMaxFee { fee, balance } => { - write!(f, "lack of funds ({balance}) for max fee ({fee})") - } - Self::OverflowPaymentInTransaction => { - write!(f, "overflow payment in transaction") - } - Self::NonceOverflowInTransaction => { - write!(f, "nonce overflow in transaction") - } - Self::NonceTooHigh { tx, state } => { - write!(f, "nonce {tx} too high, expected {state}") - } - Self::NonceTooLow { tx, state } => { - write!(f, "nonce {tx} too low, expected {state}") - } - Self::CreateInitCodeSizeLimit => { - write!(f, "create initcode size limit") - } - Self::InvalidChainId => write!(f, "invalid chain ID"), - Self::AccessListNotSupported => write!(f, "access list not supported"), - Self::MaxFeePerBlobGasNotSupported => { - write!(f, "max fee per blob gas not supported") - } - Self::BlobVersionedHashesNotSupported => { - write!(f, "blob versioned hashes not supported") - } - Self::BlobGasPriceGreaterThanMax => { - write!(f, "blob gas price is greater than max fee per blob gas") - } - Self::EmptyBlobs => write!(f, "empty blobs"), - Self::BlobCreateTransaction => write!(f, "blob create transaction"), - Self::TooManyBlobs { max, have } => { - write!(f, "too many blobs, have {have}, max {max}") - } - Self::BlobVersionNotSupported => write!(f, "blob version not supported"), - Self::EofCrateShouldHaveToAddress => write!(f, "EOF crate should have `to` address"), - #[cfg(feature = "optimism")] - Self::DepositSystemTxPostRegolith => { - write!( - f, - "deposit system transactions post regolith hardfork are not supported" - ) - } - #[cfg(feature = "optimism")] - Self::HaltedDepositPostRegolith => { - write!( - f, - "deposit transaction halted post-regolith; error will be bubbled up to main return handler" - ) - } - } - } -} - -/// Errors related to misconfiguration of a [`crate::env::BlockEnv`]. -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum InvalidHeader { - /// `prevrandao` is not set for Merge and above. - PrevrandaoNotSet, - /// `excess_blob_gas` is not set for Cancun and above. - ExcessBlobGasNotSet, -} - -#[cfg(feature = "std")] -impl std::error::Error for InvalidHeader {} - -impl fmt::Display for InvalidHeader { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::PrevrandaoNotSet => write!(f, "`prevrandao` not set"), - Self::ExcessBlobGasNotSet => write!(f, "`excess_blob_gas` not set"), - } - } -} - -/// Reason a transaction successfully completed. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum SuccessReason { - Stop, - Return, - SelfDestruct, -} - -/// Indicates that the EVM has experienced an exceptional halt. This causes execution to -/// immediately end with all gas being consumed. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum HaltReason { - OutOfGas(OutOfGasError), - OpcodeNotFound, - InvalidFEOpcode, - InvalidJump, - NotActivated, - StackUnderflow, - StackOverflow, - OutOfOffset, - CreateCollision, - PrecompileError, - NonceOverflow, - /// Create init code size exceeds limit (runtime). - CreateContractSizeLimit, - /// Error on created contract that begins with EF - CreateContractStartingWithEF, - /// EIP-3860: Limit and meter initcode. Initcode size limit exceeded. - CreateInitCodeSizeLimit, - - /* Internal Halts that can be only found inside Inspector */ - OverflowPayment, - StateChangeDuringStaticCall, - CallNotAllowedInsideStatic, - OutOfFunds, - CallTooDeep, - - /* Optimism errors */ - #[cfg(feature = "optimism")] - FailedDeposit, -} - -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum OutOfGasError { - // Basic OOG error - Basic, - // Tried to expand past REVM limit - MemoryLimit, - // Basic OOG error from memory expansion - Memory, - // Precompile threw OOG error - Precompile, - // When performing something that takes a U256 and casts down to a u64, if its too large this would fire - // i.e. in `as_usize_or_fail` - InvalidOperand, -} diff --git a/crates/primitives/src/specification.rs b/crates/primitives/src/specification.rs deleted file mode 100644 index d7c1d3e6cf..0000000000 --- a/crates/primitives/src/specification.rs +++ /dev/null @@ -1,529 +0,0 @@ -#![allow(non_camel_case_types)] - -pub use SpecId::*; - -/// Specification IDs and their activation block. -/// -/// Information was obtained from the [Ethereum Execution Specifications](https://github.com/ethereum/execution-specs) -#[cfg(not(feature = "optimism"))] -#[repr(u8)] -#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, enumn::N)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum SpecId { - FRONTIER = 0, // Frontier 0 - FRONTIER_THAWING = 1, // Frontier Thawing 200000 - HOMESTEAD = 2, // Homestead 1150000 - DAO_FORK = 3, // DAO Fork 1920000 - TANGERINE = 4, // Tangerine Whistle 2463000 - SPURIOUS_DRAGON = 5, // Spurious Dragon 2675000 - BYZANTIUM = 6, // Byzantium 4370000 - CONSTANTINOPLE = 7, // Constantinople 7280000 is overwritten with PETERSBURG - PETERSBURG = 8, // Petersburg 7280000 - ISTANBUL = 9, // Istanbul 9069000 - MUIR_GLACIER = 10, // Muir Glacier 9200000 - BERLIN = 11, // Berlin 12244000 - LONDON = 12, // London 12965000 - ARROW_GLACIER = 13, // Arrow Glacier 13773000 - GRAY_GLACIER = 14, // Gray Glacier 15050000 - MERGE = 15, // Paris/Merge 15537394 (TTD: 58750000000000000000000) - SHANGHAI = 16, // Shanghai 17034870 (Timestamp: 1681338455) - CANCUN = 17, // Cancun 19426587 (Timestamp: 1710338135) - PRAGUE = 18, // Praque TBD - #[default] - LATEST = u8::MAX, -} - -/// Specification IDs and their activation block. -/// -/// Information was obtained from the [Ethereum Execution Specifications](https://github.com/ethereum/execution-specs) -#[cfg(feature = "optimism")] -#[repr(u8)] -#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, enumn::N)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum SpecId { - FRONTIER = 0, - FRONTIER_THAWING = 1, - HOMESTEAD = 2, - DAO_FORK = 3, - TANGERINE = 4, - SPURIOUS_DRAGON = 5, - BYZANTIUM = 6, - CONSTANTINOPLE = 7, - PETERSBURG = 8, - ISTANBUL = 9, - MUIR_GLACIER = 10, - BERLIN = 11, - LONDON = 12, - ARROW_GLACIER = 13, - GRAY_GLACIER = 14, - MERGE = 15, - BEDROCK = 16, - REGOLITH = 17, - SHANGHAI = 18, - CANYON = 19, - CANCUN = 20, - ECOTONE = 21, - FJORD = 22, - PRAGUE = 23, - #[default] - LATEST = u8::MAX, -} - -impl SpecId { - /// Returns the `SpecId` for the given `u8`. - #[inline] - pub fn try_from_u8(spec_id: u8) -> Option { - Self::n(spec_id) - } - - /// Returns `true` if the given specification ID is enabled in this spec. - #[inline] - pub const fn is_enabled_in(self, other: Self) -> bool { - Self::enabled(self, other) - } - - /// Returns `true` if the given specification ID is enabled in this spec. - #[inline] - pub const fn enabled(our: SpecId, other: SpecId) -> bool { - our as u8 >= other as u8 - } -} - -impl From<&str> for SpecId { - fn from(name: &str) -> Self { - match name { - "Frontier" => Self::FRONTIER, - "Homestead" => Self::HOMESTEAD, - "Tangerine" => Self::TANGERINE, - "Spurious" => Self::SPURIOUS_DRAGON, - "Byzantium" => Self::BYZANTIUM, - "Constantinople" => Self::CONSTANTINOPLE, - "Petersburg" => Self::PETERSBURG, - "Istanbul" => Self::ISTANBUL, - "MuirGlacier" => Self::MUIR_GLACIER, - "Berlin" => Self::BERLIN, - "London" => Self::LONDON, - "Merge" => Self::MERGE, - "Shanghai" => Self::SHANGHAI, - "Cancun" => Self::CANCUN, - "Prague" => Self::PRAGUE, - #[cfg(feature = "optimism")] - "Bedrock" => SpecId::BEDROCK, - #[cfg(feature = "optimism")] - "Regolith" => SpecId::REGOLITH, - #[cfg(feature = "optimism")] - "Canyon" => SpecId::CANYON, - #[cfg(feature = "optimism")] - "Ecotone" => SpecId::ECOTONE, - #[cfg(feature = "optimism")] - "Fjord" => SpecId::FJORD, - _ => Self::LATEST, - } - } -} - -impl From for &'static str { - fn from(spec_id: SpecId) -> Self { - match spec_id { - SpecId::FRONTIER => "Frontier", - SpecId::FRONTIER_THAWING => "Frontier Thawing", - SpecId::HOMESTEAD => "Homestead", - SpecId::DAO_FORK => "DAO Fork", - SpecId::TANGERINE => "Tangerine", - SpecId::SPURIOUS_DRAGON => "Spurious", - SpecId::BYZANTIUM => "Byzantium", - SpecId::CONSTANTINOPLE => "Constantinople", - SpecId::PETERSBURG => "Petersburg", - SpecId::ISTANBUL => "Istanbul", - SpecId::MUIR_GLACIER => "MuirGlacier", - SpecId::BERLIN => "Berlin", - SpecId::LONDON => "London", - SpecId::ARROW_GLACIER => "Arrow Glacier", - SpecId::GRAY_GLACIER => "Gray Glacier", - SpecId::MERGE => "Merge", - SpecId::SHANGHAI => "Shanghai", - SpecId::CANCUN => "Cancun", - SpecId::PRAGUE => "Prague", - #[cfg(feature = "optimism")] - SpecId::BEDROCK => "Bedrock", - #[cfg(feature = "optimism")] - SpecId::REGOLITH => "Regolith", - #[cfg(feature = "optimism")] - SpecId::CANYON => "Canyon", - #[cfg(feature = "optimism")] - SpecId::ECOTONE => "Ecotone", - #[cfg(feature = "optimism")] - SpecId::FJORD => "Fjord", - SpecId::LATEST => "Latest", - } - } -} - -pub trait Spec: Sized + 'static { - /// The specification ID. - const SPEC_ID: SpecId; - - /// Returns `true` if the given specification ID is enabled in this spec. - #[inline] - fn enabled(spec_id: SpecId) -> bool { - SpecId::enabled(Self::SPEC_ID, spec_id) - } -} - -macro_rules! spec { - ($spec_id:ident, $spec_name:ident) => { - #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] - pub struct $spec_name; - - impl Spec for $spec_name { - const SPEC_ID: SpecId = $spec_id; - } - }; -} - -spec!(FRONTIER, FrontierSpec); -// FRONTIER_THAWING no EVM spec change -spec!(HOMESTEAD, HomesteadSpec); -// DAO_FORK no EVM spec change -spec!(TANGERINE, TangerineSpec); -spec!(SPURIOUS_DRAGON, SpuriousDragonSpec); -spec!(BYZANTIUM, ByzantiumSpec); -// CONSTANTINOPLE was overridden with PETERSBURG -spec!(PETERSBURG, PetersburgSpec); -spec!(ISTANBUL, IstanbulSpec); -// MUIR_GLACIER no EVM spec change -spec!(BERLIN, BerlinSpec); -spec!(LONDON, LondonSpec); -// ARROW_GLACIER no EVM spec change -// GRAY_GLACIER no EVM spec change -spec!(MERGE, MergeSpec); -spec!(SHANGHAI, ShanghaiSpec); -spec!(CANCUN, CancunSpec); -spec!(PRAGUE, PragueSpec); - -spec!(LATEST, LatestSpec); - -// Optimism Hardforks -#[cfg(feature = "optimism")] -spec!(BEDROCK, BedrockSpec); -#[cfg(feature = "optimism")] -spec!(REGOLITH, RegolithSpec); -#[cfg(feature = "optimism")] -spec!(CANYON, CanyonSpec); -#[cfg(feature = "optimism")] -spec!(ECOTONE, EcotoneSpec); -#[cfg(feature = "optimism")] -spec!(FJORD, FjordSpec); - -#[cfg(not(feature = "optimism"))] -#[macro_export] -macro_rules! spec_to_generic { - ($spec_id:expr, $e:expr) => {{ - match $spec_id { - $crate::SpecId::FRONTIER | SpecId::FRONTIER_THAWING => { - use $crate::FrontierSpec as SPEC; - $e - } - $crate::SpecId::HOMESTEAD | SpecId::DAO_FORK => { - use $crate::HomesteadSpec as SPEC; - $e - } - $crate::SpecId::TANGERINE => { - use $crate::TangerineSpec as SPEC; - $e - } - $crate::SpecId::SPURIOUS_DRAGON => { - use $crate::SpuriousDragonSpec as SPEC; - $e - } - $crate::SpecId::BYZANTIUM => { - use $crate::ByzantiumSpec as SPEC; - $e - } - $crate::SpecId::PETERSBURG | $crate::SpecId::CONSTANTINOPLE => { - use $crate::PetersburgSpec as SPEC; - $e - } - $crate::SpecId::ISTANBUL | $crate::SpecId::MUIR_GLACIER => { - use $crate::IstanbulSpec as SPEC; - $e - } - $crate::SpecId::BERLIN => { - use $crate::BerlinSpec as SPEC; - $e - } - $crate::SpecId::LONDON - | $crate::SpecId::ARROW_GLACIER - | $crate::SpecId::GRAY_GLACIER => { - use $crate::LondonSpec as SPEC; - $e - } - $crate::SpecId::MERGE => { - use $crate::MergeSpec as SPEC; - $e - } - $crate::SpecId::SHANGHAI => { - use $crate::ShanghaiSpec as SPEC; - $e - } - $crate::SpecId::CANCUN => { - use $crate::CancunSpec as SPEC; - $e - } - $crate::SpecId::LATEST => { - use $crate::LatestSpec as SPEC; - $e - } - $crate::SpecId::PRAGUE => { - use $crate::PragueSpec as SPEC; - $e - } - } - }}; -} - -#[cfg(feature = "optimism")] -#[macro_export] -macro_rules! spec_to_generic { - ($spec_id:expr, $e:expr) => {{ - match $spec_id { - $crate::SpecId::FRONTIER | SpecId::FRONTIER_THAWING => { - use $crate::FrontierSpec as SPEC; - $e - } - $crate::SpecId::HOMESTEAD | SpecId::DAO_FORK => { - use $crate::HomesteadSpec as SPEC; - $e - } - $crate::SpecId::TANGERINE => { - use $crate::TangerineSpec as SPEC; - $e - } - $crate::SpecId::SPURIOUS_DRAGON => { - use $crate::SpuriousDragonSpec as SPEC; - $e - } - $crate::SpecId::BYZANTIUM => { - use $crate::ByzantiumSpec as SPEC; - $e - } - $crate::SpecId::PETERSBURG | $crate::SpecId::CONSTANTINOPLE => { - use $crate::PetersburgSpec as SPEC; - $e - } - $crate::SpecId::ISTANBUL | $crate::SpecId::MUIR_GLACIER => { - use $crate::IstanbulSpec as SPEC; - $e - } - $crate::SpecId::BERLIN => { - use $crate::BerlinSpec as SPEC; - $e - } - $crate::SpecId::LONDON - | $crate::SpecId::ARROW_GLACIER - | $crate::SpecId::GRAY_GLACIER => { - use $crate::LondonSpec as SPEC; - $e - } - $crate::SpecId::MERGE => { - use $crate::MergeSpec as SPEC; - $e - } - $crate::SpecId::SHANGHAI => { - use $crate::ShanghaiSpec as SPEC; - $e - } - $crate::SpecId::CANCUN => { - use $crate::CancunSpec as SPEC; - $e - } - $crate::SpecId::LATEST => { - use $crate::LatestSpec as SPEC; - $e - } - $crate::SpecId::PRAGUE => { - use $crate::PragueSpec as SPEC; - $e - } - $crate::SpecId::BEDROCK => { - use $crate::BedrockSpec as SPEC; - $e - } - $crate::SpecId::REGOLITH => { - use $crate::RegolithSpec as SPEC; - $e - } - $crate::SpecId::CANYON => { - use $crate::CanyonSpec as SPEC; - $e - } - $crate::SpecId::ECOTONE => { - use $crate::EcotoneSpec as SPEC; - $e - } - $crate::SpecId::FJORD => { - use $crate::FjordSpec as SPEC; - $e - } - } - }}; -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn spec_to_generic() { - use SpecId::*; - - spec_to_generic!(FRONTIER, assert_eq!(SPEC::SPEC_ID, FRONTIER)); - spec_to_generic!(FRONTIER_THAWING, assert_eq!(SPEC::SPEC_ID, FRONTIER)); - spec_to_generic!(HOMESTEAD, assert_eq!(SPEC::SPEC_ID, HOMESTEAD)); - spec_to_generic!(DAO_FORK, assert_eq!(SPEC::SPEC_ID, HOMESTEAD)); - spec_to_generic!(TANGERINE, assert_eq!(SPEC::SPEC_ID, TANGERINE)); - spec_to_generic!(SPURIOUS_DRAGON, assert_eq!(SPEC::SPEC_ID, SPURIOUS_DRAGON)); - spec_to_generic!(BYZANTIUM, assert_eq!(SPEC::SPEC_ID, BYZANTIUM)); - spec_to_generic!(CONSTANTINOPLE, assert_eq!(SPEC::SPEC_ID, PETERSBURG)); - spec_to_generic!(PETERSBURG, assert_eq!(SPEC::SPEC_ID, PETERSBURG)); - spec_to_generic!(ISTANBUL, assert_eq!(SPEC::SPEC_ID, ISTANBUL)); - spec_to_generic!(MUIR_GLACIER, assert_eq!(SPEC::SPEC_ID, ISTANBUL)); - spec_to_generic!(BERLIN, assert_eq!(SPEC::SPEC_ID, BERLIN)); - spec_to_generic!(LONDON, assert_eq!(SPEC::SPEC_ID, LONDON)); - spec_to_generic!(ARROW_GLACIER, assert_eq!(SPEC::SPEC_ID, LONDON)); - spec_to_generic!(GRAY_GLACIER, assert_eq!(SPEC::SPEC_ID, LONDON)); - spec_to_generic!(MERGE, assert_eq!(SPEC::SPEC_ID, MERGE)); - #[cfg(feature = "optimism")] - spec_to_generic!(BEDROCK, assert_eq!(SPEC::SPEC_ID, BEDROCK)); - #[cfg(feature = "optimism")] - spec_to_generic!(REGOLITH, assert_eq!(SPEC::SPEC_ID, REGOLITH)); - spec_to_generic!(SHANGHAI, assert_eq!(SPEC::SPEC_ID, SHANGHAI)); - #[cfg(feature = "optimism")] - spec_to_generic!(CANYON, assert_eq!(SPEC::SPEC_ID, CANYON)); - spec_to_generic!(CANCUN, assert_eq!(SPEC::SPEC_ID, CANCUN)); - #[cfg(feature = "optimism")] - spec_to_generic!(ECOTONE, assert_eq!(SPEC::SPEC_ID, ECOTONE)); - #[cfg(feature = "optimism")] - spec_to_generic!(FJORD, assert_eq!(SPEC::SPEC_ID, FJORD)); - spec_to_generic!(PRAGUE, assert_eq!(SPEC::SPEC_ID, PRAGUE)); - spec_to_generic!(LATEST, assert_eq!(SPEC::SPEC_ID, LATEST)); - } -} - -#[cfg(feature = "optimism")] -#[cfg(test)] -mod optimism_tests { - use super::*; - - #[test] - fn test_bedrock_post_merge_hardforks() { - assert!(BedrockSpec::enabled(SpecId::MERGE)); - assert!(!BedrockSpec::enabled(SpecId::SHANGHAI)); - assert!(!BedrockSpec::enabled(SpecId::CANCUN)); - assert!(!BedrockSpec::enabled(SpecId::LATEST)); - assert!(BedrockSpec::enabled(SpecId::BEDROCK)); - assert!(!BedrockSpec::enabled(SpecId::REGOLITH)); - } - - #[test] - fn test_regolith_post_merge_hardforks() { - assert!(RegolithSpec::enabled(SpecId::MERGE)); - assert!(!RegolithSpec::enabled(SpecId::SHANGHAI)); - assert!(!RegolithSpec::enabled(SpecId::CANCUN)); - assert!(!RegolithSpec::enabled(SpecId::LATEST)); - assert!(RegolithSpec::enabled(SpecId::BEDROCK)); - assert!(RegolithSpec::enabled(SpecId::REGOLITH)); - } - - #[test] - fn test_bedrock_post_merge_hardforks_spec_id() { - assert!(SpecId::enabled(SpecId::BEDROCK, SpecId::MERGE)); - assert!(!SpecId::enabled(SpecId::BEDROCK, SpecId::SHANGHAI)); - assert!(!SpecId::enabled(SpecId::BEDROCK, SpecId::CANCUN)); - assert!(!SpecId::enabled(SpecId::BEDROCK, SpecId::LATEST)); - assert!(SpecId::enabled(SpecId::BEDROCK, SpecId::BEDROCK)); - assert!(!SpecId::enabled(SpecId::BEDROCK, SpecId::REGOLITH)); - } - - #[test] - fn test_regolith_post_merge_hardforks_spec_id() { - assert!(SpecId::enabled(SpecId::REGOLITH, SpecId::MERGE)); - assert!(!SpecId::enabled(SpecId::REGOLITH, SpecId::SHANGHAI)); - assert!(!SpecId::enabled(SpecId::REGOLITH, SpecId::CANCUN)); - assert!(!SpecId::enabled(SpecId::REGOLITH, SpecId::LATEST)); - assert!(SpecId::enabled(SpecId::REGOLITH, SpecId::BEDROCK)); - assert!(SpecId::enabled(SpecId::REGOLITH, SpecId::REGOLITH)); - } - - #[test] - fn test_canyon_post_merge_hardforks() { - assert!(CanyonSpec::enabled(SpecId::MERGE)); - assert!(CanyonSpec::enabled(SpecId::SHANGHAI)); - assert!(!CanyonSpec::enabled(SpecId::CANCUN)); - assert!(!CanyonSpec::enabled(SpecId::LATEST)); - assert!(CanyonSpec::enabled(SpecId::BEDROCK)); - assert!(CanyonSpec::enabled(SpecId::REGOLITH)); - assert!(CanyonSpec::enabled(SpecId::CANYON)); - } - - #[test] - fn test_canyon_post_merge_hardforks_spec_id() { - assert!(SpecId::enabled(SpecId::CANYON, SpecId::MERGE)); - assert!(SpecId::enabled(SpecId::CANYON, SpecId::SHANGHAI)); - assert!(!SpecId::enabled(SpecId::CANYON, SpecId::CANCUN)); - assert!(!SpecId::enabled(SpecId::CANYON, SpecId::LATEST)); - assert!(SpecId::enabled(SpecId::CANYON, SpecId::BEDROCK)); - assert!(SpecId::enabled(SpecId::CANYON, SpecId::REGOLITH)); - assert!(SpecId::enabled(SpecId::CANYON, SpecId::CANYON)); - } - - #[test] - fn test_ecotone_post_merge_hardforks() { - assert!(EcotoneSpec::enabled(SpecId::MERGE)); - assert!(EcotoneSpec::enabled(SpecId::SHANGHAI)); - assert!(EcotoneSpec::enabled(SpecId::CANCUN)); - assert!(!EcotoneSpec::enabled(SpecId::LATEST)); - assert!(EcotoneSpec::enabled(SpecId::BEDROCK)); - assert!(EcotoneSpec::enabled(SpecId::REGOLITH)); - assert!(EcotoneSpec::enabled(SpecId::CANYON)); - assert!(EcotoneSpec::enabled(SpecId::ECOTONE)); - } - - #[test] - fn test_ecotone_post_merge_hardforks_spec_id() { - assert!(SpecId::enabled(SpecId::ECOTONE, SpecId::MERGE)); - assert!(SpecId::enabled(SpecId::ECOTONE, SpecId::SHANGHAI)); - assert!(SpecId::enabled(SpecId::ECOTONE, SpecId::CANCUN)); - assert!(!SpecId::enabled(SpecId::ECOTONE, SpecId::LATEST)); - assert!(SpecId::enabled(SpecId::ECOTONE, SpecId::BEDROCK)); - assert!(SpecId::enabled(SpecId::ECOTONE, SpecId::REGOLITH)); - assert!(SpecId::enabled(SpecId::ECOTONE, SpecId::CANYON)); - assert!(SpecId::enabled(SpecId::ECOTONE, SpecId::ECOTONE)); - } - - #[test] - fn test_fjord_post_merge_hardforks() { - assert!(FjordSpec::enabled(SpecId::MERGE)); - assert!(FjordSpec::enabled(SpecId::SHANGHAI)); - assert!(FjordSpec::enabled(SpecId::CANCUN)); - assert!(!FjordSpec::enabled(SpecId::LATEST)); - assert!(FjordSpec::enabled(SpecId::BEDROCK)); - assert!(FjordSpec::enabled(SpecId::REGOLITH)); - assert!(FjordSpec::enabled(SpecId::CANYON)); - assert!(FjordSpec::enabled(SpecId::ECOTONE)); - assert!(FjordSpec::enabled(SpecId::FJORD)); - } - - #[test] - fn test_fjord_post_merge_hardforks_spec_id() { - assert!(SpecId::enabled(SpecId::FJORD, SpecId::MERGE)); - assert!(SpecId::enabled(SpecId::FJORD, SpecId::SHANGHAI)); - assert!(SpecId::enabled(SpecId::FJORD, SpecId::CANCUN)); - assert!(!SpecId::enabled(SpecId::FJORD, SpecId::LATEST)); - assert!(SpecId::enabled(SpecId::FJORD, SpecId::BEDROCK)); - assert!(SpecId::enabled(SpecId::FJORD, SpecId::REGOLITH)); - assert!(SpecId::enabled(SpecId::FJORD, SpecId::CANYON)); - assert!(SpecId::enabled(SpecId::FJORD, SpecId::ECOTONE)); - assert!(SpecId::enabled(SpecId::FJORD, SpecId::FJORD)); - } -} diff --git a/crates/primitives/src/state.rs b/crates/primitives/src/state.rs deleted file mode 100644 index 37315d3b68..0000000000 --- a/crates/primitives/src/state.rs +++ /dev/null @@ -1,346 +0,0 @@ -use crate::{Address, Bytecode, HashMap, B256, KECCAK_EMPTY, U256}; -use bitflags::bitflags; -use core::hash::{Hash, Hasher}; - -/// EVM State is a mapping from addresses to accounts. -pub type EvmState = HashMap; - -/// Structure used for EIP-1153 transient storage. -pub type TransientStorage = HashMap<(Address, U256), U256>; - -/// An account's Storage is a mapping from 256-bit integer keys to [EvmStorageSlot]s. -pub type EvmStorage = HashMap; - -#[derive(Debug, Clone, PartialEq, Eq, Default)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Account { - /// Balance, nonce, and code. - pub info: AccountInfo, - /// Storage cache - pub storage: EvmStorage, - /// Account status flags. - pub status: AccountStatus, -} - -// The `bitflags!` macro generates `struct`s that manage a set of flags. -bitflags! { - #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] - #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] - #[cfg_attr(feature = "serde", serde(transparent))] - pub struct AccountStatus: u8 { - /// When account is loaded but not touched or interacted with. - /// This is the default state. - const Loaded = 0b00000000; - /// When account is newly created we will not access database - /// to fetch storage values - const Created = 0b00000001; - /// If account is marked for self destruction. - const SelfDestructed = 0b00000010; - /// Only when account is marked as touched we will save it to database. - const Touched = 0b00000100; - /// used only for pre spurious dragon hardforks where existing and empty were two separate states. - /// it became same state after EIP-161: State trie clearing - const LoadedAsNotExisting = 0b0001000; - } -} - -impl Default for AccountStatus { - fn default() -> Self { - Self::Loaded - } -} - -impl Account { - /// Create new account and mark it as non existing. - pub fn new_not_existing() -> Self { - Self { - info: AccountInfo::default(), - storage: HashMap::new(), - status: AccountStatus::LoadedAsNotExisting, - } - } - - /// Mark account as self destructed. - pub fn mark_selfdestruct(&mut self) { - self.status |= AccountStatus::SelfDestructed; - } - - /// Unmark account as self destructed. - pub fn unmark_selfdestruct(&mut self) { - self.status -= AccountStatus::SelfDestructed; - } - - /// Is account marked for self destruct. - pub fn is_selfdestructed(&self) -> bool { - self.status.contains(AccountStatus::SelfDestructed) - } - - /// Mark account as touched - pub fn mark_touch(&mut self) { - self.status |= AccountStatus::Touched; - } - - /// Unmark the touch flag. - pub fn unmark_touch(&mut self) { - self.status -= AccountStatus::Touched; - } - - /// If account status is marked as touched. - pub fn is_touched(&self) -> bool { - self.status.contains(AccountStatus::Touched) - } - - /// Mark account as newly created. - pub fn mark_created(&mut self) { - self.status |= AccountStatus::Created; - } - - /// Unmark created flag. - pub fn unmark_created(&mut self) { - self.status -= AccountStatus::Created; - } - - /// Is account loaded as not existing from database - /// This is needed for pre spurious dragon hardforks where - /// existing and empty were two separate states. - pub fn is_loaded_as_not_existing(&self) -> bool { - self.status.contains(AccountStatus::LoadedAsNotExisting) - } - - /// Is account newly created in this transaction. - pub fn is_created(&self) -> bool { - self.status.contains(AccountStatus::Created) - } - - /// Is account empty, check if nonce and balance are zero and code is empty. - pub fn is_empty(&self) -> bool { - self.info.is_empty() - } - - /// Returns an iterator over the storage slots that have been changed. - /// - /// See also [EvmStorageSlot::is_changed] - pub fn changed_storage_slots(&self) -> impl Iterator { - self.storage.iter().filter(|(_, slot)| slot.is_changed()) - } -} - -impl From for Account { - fn from(info: AccountInfo) -> Self { - Self { - info, - storage: HashMap::new(), - status: AccountStatus::Loaded, - } - } -} - -/// This type keeps track of the current value of a storage slot. -#[derive(Debug, Clone, Default, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct EvmStorageSlot { - /// Original value of the storage slot. - pub original_value: U256, - /// Present value of the storage slot. - pub present_value: U256, -} - -impl EvmStorageSlot { - /// Creates a new _unchanged_ `EvmStorageSlot` for the given value. - pub fn new(original: U256) -> Self { - Self { - original_value: original, - present_value: original, - } - } - - /// Creates a new _changed_ `EvmStorageSlot`. - pub fn new_changed(original_value: U256, present_value: U256) -> Self { - Self { - original_value, - present_value, - } - } - /// Returns true if the present value differs from the original value - pub fn is_changed(&self) -> bool { - self.original_value != self.present_value - } - - /// Returns the original value of the storage slot. - pub fn original_value(&self) -> U256 { - self.original_value - } - - /// Returns the current value of the storage slot. - pub fn present_value(&self) -> U256 { - self.present_value - } -} - -/// AccountInfo account information. -#[derive(Clone, Debug, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct AccountInfo { - /// Account balance. - pub balance: U256, - /// Account nonce. - pub nonce: u64, - /// code hash, - pub code_hash: B256, - /// code: if None, `code_by_hash` will be used to fetch it if code needs to be loaded from - /// inside of `revm`. - pub code: Option, -} - -impl Default for AccountInfo { - fn default() -> Self { - Self { - balance: U256::ZERO, - code_hash: KECCAK_EMPTY, - code: Some(Bytecode::default()), - nonce: 0, - } - } -} - -impl PartialEq for AccountInfo { - fn eq(&self, other: &Self) -> bool { - self.balance == other.balance - && self.nonce == other.nonce - && self.code_hash == other.code_hash - } -} - -impl Hash for AccountInfo { - fn hash(&self, state: &mut H) { - self.balance.hash(state); - self.nonce.hash(state); - self.code_hash.hash(state); - } -} - -impl AccountInfo { - pub fn new(balance: U256, nonce: u64, code_hash: B256, code: Bytecode) -> Self { - Self { - balance, - nonce, - code: Some(code), - code_hash, - } - } - - /// Returns account info without the code. - pub fn without_code(mut self) -> Self { - self.take_bytecode(); - self - } - - /// Returns if an account is empty. - /// - /// An account is empty if the following conditions are met. - /// - code hash is zero or set to the Keccak256 hash of the empty string `""` - /// - balance is zero - /// - nonce is zero - pub fn is_empty(&self) -> bool { - let code_empty = self.is_empty_code_hash() || self.code_hash == B256::ZERO; - code_empty && self.balance == U256::ZERO && self.nonce == 0 - } - - /// Returns `true` if the account is not empty. - pub fn exists(&self) -> bool { - !self.is_empty() - } - - /// Returns `true` if account has no nonce and code. - pub fn has_no_code_and_nonce(&self) -> bool { - self.is_empty_code_hash() && self.nonce == 0 - } - - /// Return bytecode hash associated with this account. - /// If account does not have code, it return's `KECCAK_EMPTY` hash. - pub fn code_hash(&self) -> B256 { - self.code_hash - } - - /// Returns true if the code hash is the Keccak256 hash of the empty string `""`. - #[inline] - pub fn is_empty_code_hash(&self) -> bool { - self.code_hash == KECCAK_EMPTY - } - - /// Take bytecode from account. Code will be set to None. - pub fn take_bytecode(&mut self) -> Option { - self.code.take() - } - - pub fn from_balance(balance: U256) -> Self { - AccountInfo { - balance, - ..Default::default() - } - } -} - -#[cfg(test)] -mod tests { - use crate::{Account, KECCAK_EMPTY, U256}; - - #[test] - fn account_is_empty_balance() { - let mut account = Account::default(); - assert!(account.is_empty()); - - account.info.balance = U256::from(1); - assert!(!account.is_empty()); - - account.info.balance = U256::ZERO; - assert!(account.is_empty()); - } - - #[test] - fn account_is_empty_nonce() { - let mut account = Account::default(); - assert!(account.is_empty()); - - account.info.nonce = 1; - assert!(!account.is_empty()); - - account.info.nonce = 0; - assert!(account.is_empty()); - } - - #[test] - fn account_is_empty_code_hash() { - let mut account = Account::default(); - assert!(account.is_empty()); - - account.info.code_hash = [1; 32].into(); - assert!(!account.is_empty()); - - account.info.code_hash = [0; 32].into(); - assert!(account.is_empty()); - - account.info.code_hash = KECCAK_EMPTY; - assert!(account.is_empty()); - } - - #[test] - fn account_state() { - let mut account = Account::default(); - - assert!(!account.is_touched()); - assert!(!account.is_selfdestructed()); - - account.mark_touch(); - assert!(account.is_touched()); - assert!(!account.is_selfdestructed()); - - account.mark_selfdestruct(); - assert!(account.is_touched()); - assert!(account.is_selfdestructed()); - - account.unmark_selfdestruct(); - assert!(account.is_touched()); - assert!(!account.is_selfdestructed()); - } -} diff --git a/crates/primitives/src/utilities.rs b/crates/primitives/src/utilities.rs deleted file mode 100644 index 07aa0457a3..0000000000 --- a/crates/primitives/src/utilities.rs +++ /dev/null @@ -1,170 +0,0 @@ -use crate::{ - b256, B256, BLOB_GASPRICE_UPDATE_FRACTION, MIN_BLOB_GASPRICE, TARGET_BLOB_GAS_PER_BLOCK, -}; -pub use alloy_primitives::keccak256; - -/// The Keccak-256 hash of the empty string `""`. -pub const KECCAK_EMPTY: B256 = - b256!("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"); - -/// Calculates the `excess_blob_gas` from the parent header's `blob_gas_used` and `excess_blob_gas`. -/// -/// See also [the EIP-4844 helpers] -/// (`calc_excess_blob_gas`). -#[inline] -pub fn calc_excess_blob_gas(parent_excess_blob_gas: u64, parent_blob_gas_used: u64) -> u64 { - (parent_excess_blob_gas + parent_blob_gas_used).saturating_sub(TARGET_BLOB_GAS_PER_BLOCK) -} - -/// Calculates the blob gas price from the header's excess blob gas field. -/// -/// See also [the EIP-4844 helpers](https://eips.ethereum.org/EIPS/eip-4844#helpers) -/// (`get_blob_gasprice`). -#[inline] -pub fn calc_blob_gasprice(excess_blob_gas: u64) -> u128 { - fake_exponential( - MIN_BLOB_GASPRICE, - excess_blob_gas, - BLOB_GASPRICE_UPDATE_FRACTION, - ) -} - -/// Approximates `factor * e ** (numerator / denominator)` using Taylor expansion. -/// -/// This is used to calculate the blob price. -/// -/// See also [the EIP-4844 helpers](https://eips.ethereum.org/EIPS/eip-4844#helpers) -/// (`fake_exponential`). -/// -/// # Panics -/// -/// This function panics if `denominator` is zero. -#[inline] -pub fn fake_exponential(factor: u64, numerator: u64, denominator: u64) -> u128 { - assert_ne!(denominator, 0, "attempt to divide by zero"); - let factor = factor as u128; - let numerator = numerator as u128; - let denominator = denominator as u128; - - let mut i = 1; - let mut output = 0; - let mut numerator_accum = factor * denominator; - while numerator_accum > 0 { - output += numerator_accum; - - // Denominator is asserted as not zero at the start of the function. - numerator_accum = (numerator_accum * numerator) / (denominator * i); - i += 1; - } - output / denominator -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::GAS_PER_BLOB; - - // https://github.com/ethereum/go-ethereum/blob/28857080d732857030eda80c69b9ba2c8926f221/consensus/misc/eip4844/eip4844_test.go#L27 - #[test] - fn test_calc_excess_blob_gas() { - for t @ &(excess, blobs, expected) in &[ - // The excess blob gas should not increase from zero if the used blob - // slots are below - or equal - to the target. - (0, 0, 0), - (0, 1, 0), - (0, TARGET_BLOB_GAS_PER_BLOCK / GAS_PER_BLOB, 0), - // If the target blob gas is exceeded, the excessBlobGas should increase - // by however much it was overshot - ( - 0, - (TARGET_BLOB_GAS_PER_BLOCK / GAS_PER_BLOB) + 1, - GAS_PER_BLOB, - ), - ( - 1, - (TARGET_BLOB_GAS_PER_BLOCK / GAS_PER_BLOB) + 1, - GAS_PER_BLOB + 1, - ), - ( - 1, - (TARGET_BLOB_GAS_PER_BLOCK / GAS_PER_BLOB) + 2, - 2 * GAS_PER_BLOB + 1, - ), - // The excess blob gas should decrease by however much the target was - // under-shot, capped at zero. - ( - TARGET_BLOB_GAS_PER_BLOCK, - TARGET_BLOB_GAS_PER_BLOCK / GAS_PER_BLOB, - TARGET_BLOB_GAS_PER_BLOCK, - ), - ( - TARGET_BLOB_GAS_PER_BLOCK, - (TARGET_BLOB_GAS_PER_BLOCK / GAS_PER_BLOB) - 1, - TARGET_BLOB_GAS_PER_BLOCK - GAS_PER_BLOB, - ), - ( - TARGET_BLOB_GAS_PER_BLOCK, - (TARGET_BLOB_GAS_PER_BLOCK / GAS_PER_BLOB) - 2, - TARGET_BLOB_GAS_PER_BLOCK - (2 * GAS_PER_BLOB), - ), - ( - GAS_PER_BLOB - 1, - (TARGET_BLOB_GAS_PER_BLOCK / GAS_PER_BLOB) - 1, - 0, - ), - ] { - let actual = calc_excess_blob_gas(excess, blobs * GAS_PER_BLOB); - assert_eq!(actual, expected, "test: {t:?}"); - } - } - - // https://github.com/ethereum/go-ethereum/blob/28857080d732857030eda80c69b9ba2c8926f221/consensus/misc/eip4844/eip4844_test.go#L60 - #[test] - fn test_calc_blob_fee() { - let blob_fee_vectors = &[ - (0, 1), - (2314057, 1), - (2314058, 2), - (10 * 1024 * 1024, 23), - // calc_blob_gasprice approximates `e ** (excess_blob_gas / BLOB_GASPRICE_UPDATE_FRACTION)` using Taylor expansion - // - // to roughly find where boundaries will be hit: - // 2 ** bits = e ** (excess_blob_gas / BLOB_GASPRICE_UPDATE_FRACTION) - // excess_blob_gas = ln(2 ** bits) * BLOB_GASPRICE_UPDATE_FRACTION - (148099578, 18446739238971471609), // output is just below the overflow - (148099579, 18446744762204311910), // output is just after the overflow - (161087488, 902580055246494526580), - ]; - - for &(excess, expected) in blob_fee_vectors { - let actual = calc_blob_gasprice(excess); - assert_eq!(actual, expected, "test: {excess}"); - } - } - - // https://github.com/ethereum/go-ethereum/blob/28857080d732857030eda80c69b9ba2c8926f221/consensus/misc/eip4844/eip4844_test.go#L78 - #[test] - fn fake_exp() { - for t @ &(factor, numerator, denominator, expected) in &[ - (1u64, 0u64, 1u64, 1u128), - (38493, 0, 1000, 38493), - (0, 1234, 2345, 0), - (1, 2, 1, 6), // approximate 7.389 - (1, 4, 2, 6), - (1, 3, 1, 16), // approximate 20.09 - (1, 6, 2, 18), - (1, 4, 1, 49), // approximate 54.60 - (1, 8, 2, 50), - (10, 8, 2, 542), // approximate 540.598 - (11, 8, 2, 596), // approximate 600.58 - (1, 5, 1, 136), // approximate 148.4 - (1, 5, 2, 11), // approximate 12.18 - (2, 5, 2, 23), // approximate 24.36 - (1, 50000000, 2225652, 5709098764), - (1, 380928, BLOB_GASPRICE_UPDATE_FRACTION, 1), - ] { - let actual = fake_exponential(factor, numerator, denominator); - assert_eq!(actual, expected, "test: {t:?}"); - } - } -} diff --git a/crates/revm/CHANGELOG.md b/crates/revm/CHANGELOG.md index fc2408cb5c..f380d29a73 100644 --- a/crates/revm/CHANGELOG.md +++ b/crates/revm/CHANGELOG.md @@ -6,6 +6,461 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [27.1.0](https://github.com/bluealloy/revm/compare/revm-v27.0.3...revm-v27.1.0) - 2025-07-23 + +### Added + +- expose sha3-keccak in revm and revm-primitives ([#2713](https://github.com/bluealloy/revm/pull/2713)) + +### Fixed + +- features and check in ci ([#2766](https://github.com/bluealloy/revm/pull/2766)) +- gas deduction with `disable_balance_check` ([#2699](https://github.com/bluealloy/revm/pull/2699)) + +### Other + +- add asm-sha2 feature for sha2 precompile ([#2712](https://github.com/bluealloy/revm/pull/2712)) + +## [27.0.3](https://github.com/bluealloy/revm/compare/revm-v27.0.2...revm-v27.0.3) - 2025-07-14 + +### Other + +- updated the following local packages: revm-context, revm-interpreter, revm-precompile, revm-handler, revm-inspector + +## [27.0.2](https://github.com/bluealloy/revm/compare/revm-v27.0.1...revm-v27.0.2) - 2025-07-03 + +### Other + +- updated the following local packages: revm-bytecode, revm-handler, revm-inspector, revm-state, revm-database-interface, revm-context-interface, revm-context, revm-database, revm-interpreter + +## [27.0.1](https://github.com/bluealloy/revm/compare/revm-v26.0.1...revm-v27.0.1) - 2025-06-30 + +### Added + +- optional_eip3541 ([#2661](https://github.com/bluealloy/revm/pull/2661)) + +### Other + +- cargo clippy --fix --all ([#2671](https://github.com/bluealloy/revm/pull/2671)) +- inline documentation of revm top modules ([#2666](https://github.com/bluealloy/revm/pull/2666)) +- use TxEnv::builder ([#2652](https://github.com/bluealloy/revm/pull/2652)) + +## [26.0.1](https://github.com/bluealloy/revm/compare/revm-v26.0.0...revm-v26.0.1) - 2025-06-20 + +### Fixed + +- call stack_frame.clear() at end ([#2656](https://github.com/bluealloy/revm/pull/2656)) + +## [26.0.0](https://github.com/bluealloy/revm/compare/revm-v25.0.0...revm-v26.0.0) - 2025-06-19 + +### Added + +- *(precompile)* rug/gmp-based modexp ([#2596](https://github.com/bluealloy/revm/pull/2596)) +- enable P256 in Osaka ([#2601](https://github.com/bluealloy/revm/pull/2601)) + +### Fixed + +- compare_or_save_testdata sig ([#2637](https://github.com/bluealloy/revm/pull/2637)) + +### Other + +- lints for examples ([#2650](https://github.com/bluealloy/revm/pull/2650)) +- rename `transact` methods ([#2616](https://github.com/bluealloy/revm/pull/2616)) + +## [25.0.0](https://github.com/bluealloy/revm/compare/revm-v24.0.1...revm-v25.0.0) - 2025-06-06 + +### Added + +- transact multi tx ([#2517](https://github.com/bluealloy/revm/pull/2517)) + +### Fixed + +- *(multitx)* Add local flags for create and selfdestruct ([#2581](https://github.com/bluealloy/revm/pull/2581)) + +### Other + +- tag v75 revm v24.0.1 ([#2563](https://github.com/bluealloy/revm/pull/2563)) ([#2589](https://github.com/bluealloy/revm/pull/2589)) + +## [24.0.1](https://github.com/bluealloy/revm/compare/revm-v24.0.0...revm-v24.0.1) - 2025-05-31 + +### Other + +- updated the following local packages: revm-context, revm-handler, revm-inspector + +## [24.0.0](https://github.com/bluealloy/revm/compare/revm-v23.1.0...revm-v24.0.0) - 2025-05-22 + +### Other + +- make crates.io version badge clickable ([#2526](https://github.com/bluealloy/revm/pull/2526)) + +## [23.1.0](https://github.com/bluealloy/revm/compare/revm-v23.0.0...revm-v23.1.0) - 2025-05-07 + +Dependency bump + +## [23.0.0](https://github.com/bluealloy/revm/compare/revm-v22.0.1...revm-v23.0.0) - 2025-05-07 + +### Other + +- typos ([#2474](https://github.com/bluealloy/revm/pull/2474)) +- copy edit The Book ([#2463](https://github.com/bluealloy/revm/pull/2463)) +- bump dependency version ([#2431](https://github.com/bluealloy/revm/pull/2431)) +- fixed broken link ([#2421](https://github.com/bluealloy/revm/pull/2421)) + +## [22.0.1](https://github.com/bluealloy/revm/compare/revm-v22.0.0..revm-v22.0.1) - 2025-04-15 + +### Other + +## [22.0.0](https://github.com/bluealloy/revm/compare/revm-v21.0.0...revm-v22.0.0) - 2025-04-09 + +### Added + +- support for system calls ([#2350](https://github.com/bluealloy/revm/pull/2350)) +- Reorder revm deps in Cargo.toml ([#2331](https://github.com/bluealloy/revm/pull/2331)) + +## [21.0.0](https://github.com/bluealloy/revm/compare/revm-v20.0.0...revm-v21.0.0) - 2025-03-28 + +### Added + +- Add JournalInner ([#2311](https://github.com/bluealloy/revm/pull/2311)) +- Add a wrapper for arkworks for EIP196 ([#2305](https://github.com/bluealloy/revm/pull/2305)) + +### Other + +- Propagate asyncdb feature flag from database-interface to revm ([#2310](https://github.com/bluealloy/revm/pull/2310)) + +## [20.0.0](https://github.com/bluealloy/revm/compare/revm-v20.0.0-alpha.7...revm-v20.0.0) - 2025-03-24 + +### Other + +- updated the following local packages: revm-database, revm-precompile + +## [20.0.0-alpha.7](https://github.com/bluealloy/revm/compare/revm-v20.0.0-alpha.6...revm-v20.0.0-alpha.7) - 2025-03-21 + +### Other + +- updated the following local packages: revm-primitives, revm-context-interface, revm-context, revm-database, revm-interpreter, revm-precompile, revm-handler, revm-inspector + +## [20.0.0-alpha.6](https://github.com/bluealloy/revm/compare/revm-v20.0.0-alpha.5...revm-v20.0.0-alpha.6) - 2025-03-16 + +### Other + +- updated the following local packages: revm-primitives, revm-bytecode, revm-context-interface, revm-context, revm-precompile, revm-handler, revm-inspector + +## [20.0.0-alpha.5](https://github.com/bluealloy/revm/compare/revm-v20.0.0-alpha.4...revm-v20.0.0-alpha.5) - 2025-03-12 + +### Other + +- updated the following local packages: revm-context-interface, revm-context, revm-interpreter, revm-handler, revm-inspector + +## [20.0.0-alpha.4](https://github.com/bluealloy/revm/compare/revm-v20.0.0-alpha.3...revm-v20.0.0-alpha.4) - 2025-03-11 + +### Fixed + +- correct propagate features ([#2177](https://github.com/bluealloy/revm/pull/2177)) + +## [20.0.0-alpha.3](https://github.com/bluealloy/revm/compare/revm-v20.0.0-alpha.2...revm-v20.0.0-alpha.3) - 2025-03-10 + +### Fixed + +- *(precompiles)* add portable flag for bls ([#2174](https://github.com/bluealloy/revm/pull/2174)) + +## [20.0.0-alpha.2](https://github.com/bluealloy/revm/compare/revm-v20.0.0-alpha.1...revm-v20.0.0-alpha.2) - 2025-03-10 + +### Added + +- remove specification crate ([#2165](https://github.com/bluealloy/revm/pull/2165)) + +### Other + +- JournalTr, JournalOutput, op only using revm crate ([#2155](https://github.com/bluealloy/revm/pull/2155)) +- examples to use main revm crate ([#2152](https://github.com/bluealloy/revm/pull/2152)) +- move mainnet builder to handler crate ([#2138](https://github.com/bluealloy/revm/pull/2138)) +- remove `optional_gas_refund` as unused ([#2132](https://github.com/bluealloy/revm/pull/2132)) +- export eip2930 eip7702 types from one place ([#2097](https://github.com/bluealloy/revm/pull/2097)) +- move all dependencies to workspace ([#2092](https://github.com/bluealloy/revm/pull/2092)) +- re-export all crates from `revm` ([#2088](https://github.com/bluealloy/revm/pull/2088)) + +## [20.0.0-alpha.1](https://github.com/bluealloy/revm/compare/revm-v19.5.0...revm-v20.0.0-alpha.1) - 2025-02-16 + +### Added + +- Split Inspector trait from EthHandler into standalone crate (#2075) +- integrate alloy-eips (#2078) +- Evm structure (Cached Instructions and Precompiles) (#2049) +- Context execution (#2013) +- EthHandler trait (#2001) +- *(EIP-7623)* adjuct floor gas check order (main) (#1991) +- *(EIP-7623)* Increase calldata cost. backport from rel/v51 (#1965) +- simplify Transaction trait (#1959) +- expose precompile address in Journal, DB::Error: StdError (#1956) +- integrate codspeed (#1935) +- Make Ctx journal generic (#1933) +- Restucturing Part7 Handler and Context rework (#1865) +- restructuring Part6 transaction crate (#1814) +- push NonceChange to Journal in deduct_caller (#1804) +- Merge validation/analyzis with Bytecode (#1793) +- Restructuring Part3 inspector crate (#1788) +- restructure Part2 database crate (#1784) +- project restructuring Part1 (#1776) +- to_plain_state (#1778) +- *(example)* deploy bytecode from scratch (#1767) +- introducing EvmWiring, a chain-specific configuration (#1672) + +### Fixed + +- make macro crate-agnostic (#1802) + +### Other + +- backport op l1 fetch perf (#2076) +- API cleanup (#2067) +- Add helpers with_inspector with_precompile (#2063) +- Bump licence year to 2025 (#2058) +- bump alloy versions to match latest (#2007) +- align crates versions (#1983) +- Make inspector use generics, rm associated types (#1934) +- fix comments and docs into more sensible (#1920) +- EVM transact, make output generic for POSTEXEC (#1931) +- Move CfgEnv from context-interface to context crate (#1910) +- bumps select alloy crates to 0.6 (#1854) +- some no_std cleanup (#1834) +- bump alloy to 0.4.2 (#1817) +- *(primitives)* replace HashMap re-exports with alloy_primitives::map (#1805) +- *(deps)* bump anyhow from 1.0.88 to 1.0.89 (#1772) +- simplify SuccessOrHalt trait bound (#1768) + + +## [19.5.0](https://github.com/bluealloy/revm/compare/revm-v19.4.0...revm-v19.5.0) - 2025-02-11 + +### Fixed + +- *(op-isthmus)* missing granite precompiles and disable eof (#2065) +- *(op)* add operator fee scalar scaling factor on refund (#2050) +- fix ethersdb.rs forking ([#2047](https://github.com/bluealloy/revm/pull/2047)) + +## [19.4.0](https://github.com/bluealloy/revm/compare/revm-v19.3.0...revm-v19.4.0) - 2025-01-28 + +### Added + +- Include EIP7702 address for extcodecopy ([#2016](https://github.com/bluealloy/revm/pull/2016)) +- add precompiles for BLS12-381 to isthmus ([#2000](https://github.com/bluealloy/revm/pull/2000)) + +### Fixed + +- *(op)* isthmus compilation ([#2022](https://github.com/bluealloy/revm/pull/2022)) + +## [19.3.0](https://github.com/bluealloy/revm/compare/revm-v19.2.0...revm-v19.3.0) - 2025-01-13 + +### Added + +- *(EIP-7623)* adjuct floor gas check order ([#1990](https://github.com/bluealloy/revm/pull/1990)) + +## [19.2.0](https://github.com/bluealloy/revm/compare/revm-v19.1.0...revm-v19.2.0) - 2025-01-06 + +### Fixed + +- *(op)* move l1block loading to verification ([#1970](https://github.com/bluealloy/revm/pull/1970)) + +## [19.1.0](https://github.com/bluealloy/revm/compare/revm-v19.0.0...revm-v19.1.0) - 2025-01-06 + +### Added + +- handle isthmus operator fee ([#1960](https://github.com/bluealloy/revm/pull/1960)) + +### Other + +- optimize tx l1 fetches ([#1967](https://github.com/bluealloy/revm/pull/1967)) + +## [19.0.0](https://github.com/bluealloy/revm/compare/revm-v18.0.0...revm-v19.0.0) - 2024-12-26 + +### Added + +- apply latest EIP-7702 changes ([#1850](https://github.com/bluealloy/revm/pull/1850)) +- *(Prague)* EIP-7623 Increase Calldata Cost ([#1744](https://github.com/bluealloy/revm/pull/1744)) + +### Other + +- eip7702 chainid u256 change ([#1950](https://github.com/bluealloy/revm/pull/1950)) +- refactor L1BlockInfo::tx_estimated_size_fjord ([#1862](https://github.com/bluealloy/revm/pull/1862)) +- [v50] perf: remove unneeded clones ([#1863](https://github.com/bluealloy/revm/pull/1863)) +- Add static Optimism precompiles for Fjord & Granite ([#1864](https://github.com/bluealloy/revm/pull/1864)) + +## [18.0.0](https://github.com/bluealloy/revm/compare/revm-v17.1.0...revm-v18.0.0) - 2024-11-06 + +### Added + +- to_plain_state ([#1778](https://github.com/bluealloy/revm/pull/1778)) ([#1841](https://github.com/bluealloy/revm/pull/1841)) + +### Other + +- bump alloy-eip7702 and remove `Parity` re-export ([#1842](https://github.com/bluealloy/revm/pull/1842)) +- Osaka Activation (release_49 branch) ([#1835](https://github.com/bluealloy/revm/pull/1835)) + +## [17.1.0](https://github.com/bluealloy/revm/compare/revm-v17.0.0...revm-v17.1.0) - 2024-10-23 + +### Other + +- chore: bump alloydb deps ([#1832](https://github.com/bluealloy/revm/pull/1832)) + +## [17.0.0](https://github.com/bluealloy/revm/compare/revm-v16.0.0...revm-v17.0.0) - 2024-10-23 + +### Other + +- bump alloy-eip7702 ([#1829](https://github.com/bluealloy/revm/pull/1829)) + +## [16.0.0](https://github.com/bluealloy/revm/compare/revm-v15.0.0...revm-v16.0.0) - 2024-10-17 + +### Other + +- update Cargo.toml dependencies + +## [15.0.0](https://github.com/bluealloy/revm/compare/revm-v14.0.3...revm-v15.0.0) - 2024-10-17 + +### Added + +- Rename PRAGUE_EOF to OSAKA ([#1822](https://github.com/bluealloy/revm/pull/1822)) +- *(EIP-7702)* devnet-4 changes ([#1821](https://github.com/bluealloy/revm/pull/1821)) + +## [14.0.3](https://github.com/bluealloy/revm/compare/revm-v14.0.2...revm-v14.0.3) - 2024-09-26 + +### Other + +- update Cargo.lock dependencies + +## [14.0.2](https://github.com/bluealloy/revm/compare/revm-v14.0.1...revm-v14.0.2) - 2024-09-18 + +### Fixed + +- *(inspector)* always call selfdestruct if entry is made ([#1746](https://github.com/bluealloy/revm/pull/1746)) + +### Other + +- *(deps)* bump alloy-sol-types from 0.8.0 to 0.8.2 ([#1762](https://github.com/bluealloy/revm/pull/1762)) +- *(deps)* bump anyhow from 1.0.86 to 1.0.87 ([#1760](https://github.com/bluealloy/revm/pull/1760)) +- make clippy happy ([#1755](https://github.com/bluealloy/revm/pull/1755)) +- Test l1 gas used fjord ([#1749](https://github.com/bluealloy/revm/pull/1749)) +- Add test for `revm::optimism::L1BlockInfo::calculate_tx_l1_cost_fjord` ([#1743](https://github.com/bluealloy/revm/pull/1743)) +- *(deps)* bump tokio from 1.39.2 to 1.40.0 ([#1739](https://github.com/bluealloy/revm/pull/1739)) + +## [14.0.1](https://github.com/bluealloy/revm/compare/revm-v14.0.0...revm-v14.0.1) - 2024-08-30 + +### Other +- Bump new logo ([#1735](https://github.com/bluealloy/revm/pull/1735)) + +## [14.0.0](https://github.com/bluealloy/revm/compare/revm-v13.0.0...revm-v14.0.0) - 2024-08-29 + +### Added +- *(eip7702)* Impl newest version of EIP ([#1695](https://github.com/bluealloy/revm/pull/1695)) + +### Other +- *(deps)* bump alloy and primitives ([#1725](https://github.com/bluealloy/revm/pull/1725)) +- cast block number to u64 and not usize ([#1727](https://github.com/bluealloy/revm/pull/1727)) +- clean up some journalstate docs ([#1712](https://github.com/bluealloy/revm/pull/1712)) +- update some docs related to state ([#1711](https://github.com/bluealloy/revm/pull/1711)) + +## [12.2.0](https://github.com/bluealloy/revm/compare/revm-v12.1.0...revm-v12.2.0) - 2024-08-08 + +### Added +- check for typos in CI ([#1686](https://github.com/bluealloy/revm/pull/1686)) +- *(EOF)* EOF Validation add code type and sub container tracker ([#1648](https://github.com/bluealloy/revm/pull/1648)) + +### Other +- Add OP-Granite hardfork, limiting bn256Pairing input size ([#1685](https://github.com/bluealloy/revm/pull/1685)) +- *(deps)* bump rstest from 0.21.0 to 0.22.0 ([#1681](https://github.com/bluealloy/revm/pull/1681)) +- *(deps)* bump tokio from 1.38.1 to 1.39.2 ([#1668](https://github.com/bluealloy/revm/pull/1668)) +- *(clippy)* 1.80 rust clippy list paragraph ident ([#1661](https://github.com/bluealloy/revm/pull/1661)) +- avoid cloning original_bytes ([#1646](https://github.com/bluealloy/revm/pull/1646)) +- use `is_zero` for `U256` and `B256` ([#1638](https://github.com/bluealloy/revm/pull/1638)) +- fix some typos & remove useless Arc::clone ([#1621](https://github.com/bluealloy/revm/pull/1621)) +- *(eof)* simplify magic checks ([#1633](https://github.com/bluealloy/revm/pull/1633)) + +## [12.0.0](https://github.com/bluealloy/revm/compare/revm-v11.0.0...revm-v12.0.0) - 2024-07-16 + +### Added +- pass interpreter into Inspector::log ([#1610](https://github.com/bluealloy/revm/pull/1610)) +- *(EOF)* Bytecode::new_raw supports EOF, new_raw_checked added ([#1607](https://github.com/bluealloy/revm/pull/1607)) +- use `kzg-rs` for kzg point evaluation ([#1558](https://github.com/bluealloy/revm/pull/1558)) + +### Fixed +- *(eip7702)* Add tests and fix some bugs ([#1605](https://github.com/bluealloy/revm/pull/1605)) +- correctly calculate eofcreate address ([#1619](https://github.com/bluealloy/revm/pull/1619)) +- allow non-static lifetime in HandleRegisterBox ([#1608](https://github.com/bluealloy/revm/pull/1608)) +- *(EOF)* Use cfg code size limit for eofcreate ([#1606](https://github.com/bluealloy/revm/pull/1606)) + +### Other +- bump alloy deps ([#1623](https://github.com/bluealloy/revm/pull/1623)) +- *(deps)* bump alloy-sol-types from 0.7.6 to 0.7.7 ([#1614](https://github.com/bluealloy/revm/pull/1614)) +- group optimism invalid txn errors ([#1604](https://github.com/bluealloy/revm/pull/1604)) +- load_account -> warm_preloaded_addresses ([#1584](https://github.com/bluealloy/revm/pull/1584)) +- Refactor code, and check if precompile for create collision ([#1600](https://github.com/bluealloy/revm/pull/1600)) +- *(revm)* defer bytecode load ([#1588](https://github.com/bluealloy/revm/pull/1588)) +- Rename gas_price to gas_limit for precompile args ([#1593](https://github.com/bluealloy/revm/pull/1593)) + +## [11.0.0](https://github.com/bluealloy/revm/compare/revm-v10.0.0...revm-v11.0.0) - 2024-07-08 + +### Added +- add bytecode_address from CallInputs to Contract during construction. ([#1568](https://github.com/bluealloy/revm/pull/1568)) +- *(Prague)* Add EIP-7702 ([#1565](https://github.com/bluealloy/revm/pull/1565)) +- *(EOF)* disallow ExtDelegateCall to legacy bytecode ([#1572](https://github.com/bluealloy/revm/pull/1572)) +- *(EOF)* Add target address expansion checks ([#1570](https://github.com/bluealloy/revm/pull/1570)) + +### Other +- bump precompile to v9.0.0 ([#1590](https://github.com/bluealloy/revm/pull/1590)) +- *(README)* add rbuilder to used-by ([#1585](https://github.com/bluealloy/revm/pull/1585)) +- Use HandleOrRuntime to allow alloydb/ethersdb to hold a custom runtime ([#1576](https://github.com/bluealloy/revm/pull/1576)) +- store tokio::runtime::Handle in ethers/alloyDB ([#1557](https://github.com/bluealloy/revm/pull/1557)) +- use const blocks ([#1522](https://github.com/bluealloy/revm/pull/1522)) +- fix compile for alloydb ([#1559](https://github.com/bluealloy/revm/pull/1559)) +- replace AccessList with alloy version ([#1552](https://github.com/bluealloy/revm/pull/1552)) +- replace U256 with u64 in BLOCKHASH ([#1505](https://github.com/bluealloy/revm/pull/1505)) + +## [10.0.0](https://github.com/bluealloy/revm/compare/revm-v9.0.0...revm-v10.0.0) - 2024-06-20 + +### Added +- *(revm)* derive serde for `BundleState` ([#1539](https://github.com/bluealloy/revm/pull/1539)) +- bump alloy, re-enable alloydb ([#1533](https://github.com/bluealloy/revm/pull/1533)) +- mutable access for all fields in BundleBuilder ([#1524](https://github.com/bluealloy/revm/pull/1524)) +- *(EOF)* Put EOF bytecode behind an Arc ([#1517](https://github.com/bluealloy/revm/pull/1517)) +- *(EOF)* EXTCODECOPY,EXTCODESIZE,EXTCODEHASH eof support ([#1504](https://github.com/bluealloy/revm/pull/1504)) +- add helpers for working with instruction tables ([#1493](https://github.com/bluealloy/revm/pull/1493)) +- *(precompiles)* fatal error for precompiles ([#1499](https://github.com/bluealloy/revm/pull/1499)) +- Persist reverted account and storage slot lookups in `JournaledState` ([#1437](https://github.com/bluealloy/revm/pull/1437)) +- *(EOF)* EIP-7698 eof creation transaction ([#1467](https://github.com/bluealloy/revm/pull/1467)) +- *(EOF)* Add EOF to inspector handle register ([#1469](https://github.com/bluealloy/revm/pull/1469)) +- *(optimism)* Implement new L1 cost function for Fjord ([#1420](https://github.com/bluealloy/revm/pull/1420)) +- *(optimism)* Add secp256r1 precompile for Fjord ([#1436](https://github.com/bluealloy/revm/pull/1436)) +- *(revm)* revert EIP-2935 BLOCKHASH opcode changes ([#1450](https://github.com/bluealloy/revm/pull/1450)) +- load account should return db error ([#1447](https://github.com/bluealloy/revm/pull/1447)) +- *(EOF)* remove TXCREATE ([#1415](https://github.com/bluealloy/revm/pull/1415)) + +### Fixed +- *(eof)* fixture 2 tests ([#1550](https://github.com/bluealloy/revm/pull/1550)) +- *(eof)* output gas for eofcreate ([#1540](https://github.com/bluealloy/revm/pull/1540)) +- *(revm)* remove storage reset that clears is_cold flag ([#1518](https://github.com/bluealloy/revm/pull/1518)) +- *(op)* Remove `U256::from()` ([#1498](https://github.com/bluealloy/revm/pull/1498)) +- *(EOF)* panic on empty input range, and continue exec after eofcreate ([#1477](https://github.com/bluealloy/revm/pull/1477)) +- *(Interpreter)* wrong block number used ([#1458](https://github.com/bluealloy/revm/pull/1458)) +- blockchash for devnet-0 ([#1427](https://github.com/bluealloy/revm/pull/1427)) + +### Other +- Add CI build target for no-std + optimism, use matrix builds ([#1551](https://github.com/bluealloy/revm/pull/1551)) +- replace TransactTo with TxKind ([#1542](https://github.com/bluealloy/revm/pull/1542)) +- avoid cloning precompiles ([#1486](https://github.com/bluealloy/revm/pull/1486)) +- add setters to `BundleBuilder` with `&mut self` ([#1527](https://github.com/bluealloy/revm/pull/1527)) +- pluralize EOFCreateInput ([#1523](https://github.com/bluealloy/revm/pull/1523)) +- added simular to used-by ([#1521](https://github.com/bluealloy/revm/pull/1521)) +- Removed .clone() in ExecutionHandler::call, and reusing output buffer in Interpreter ([#1512](https://github.com/bluealloy/revm/pull/1512)) +- remove old deprecated items ([#1489](https://github.com/bluealloy/revm/pull/1489)) +- *(deps)* bump rstest from 0.19.0 to 0.21.0 ([#1482](https://github.com/bluealloy/revm/pull/1482)) +- *(deps)* bump tokio from 1.37.0 to 1.38.0 ([#1480](https://github.com/bluealloy/revm/pull/1480)) +- *(primitives)* rename State/Storage to EvmState/EvmStorage ([#1459](https://github.com/bluealloy/revm/pull/1459)) +- remove 'checked' bytecode bench causing benchmarks to crash due to name ([#1461](https://github.com/bluealloy/revm/pull/1461)) +- cargo update ([#1451](https://github.com/bluealloy/revm/pull/1451)) +- cleanup host blockhash fn ([#1430](https://github.com/bluealloy/revm/pull/1430)) +- Revert "Revert "feat: implement EIP-2935 ([#1354](https://github.com/bluealloy/revm/pull/1354))" ([#1424](https://github.com/bluealloy/revm/pull/1424))" ([#1426](https://github.com/bluealloy/revm/pull/1426)) +- Revert "feat: implement EIP-2935 ([#1354](https://github.com/bluealloy/revm/pull/1354))" ([#1424](https://github.com/bluealloy/revm/pull/1424)) +- *(deps)* bump anyhow from 1.0.82 to 1.0.83 ([#1404](https://github.com/bluealloy/revm/pull/1404)) + ## [9.0.0](https://github.com/bluealloy/revm/compare/revm-v8.0.0...revm-v9.0.0) - 2024-05-12 ### Added @@ -15,7 +470,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add uniswap V2 WETH-USDC swap example ([#1353](https://github.com/bluealloy/revm/pull/1353)) - *(interpreter)* add helpers for spending all gas ([#1360](https://github.com/bluealloy/revm/pull/1360)) - add helper methods to CallInputs ([#1345](https://github.com/bluealloy/revm/pull/1345)) -- *(revm)* make `FrameOrResult` serializable ([#1282](https://github.com/bluealloy/revm/pull/1282)) +- *(revm)* make `ItemOrResult` serializable ([#1282](https://github.com/bluealloy/revm/pull/1282)) - add flag to force hashbrown usage ([#1284](https://github.com/bluealloy/revm/pull/1284)) - EOF (Ethereum Object Format) ([#1143](https://github.com/bluealloy/revm/pull/1143)) - *(`db`)* Introduce `alloydb` ([#1257](https://github.com/bluealloy/revm/pull/1257)) @@ -702,7 +1157,7 @@ Changes: # v1.0.0 date: 18.12.2021 -It feel's like that the lib is in the state that is okay to promote it to the v1 version. Other that that, a lot of optimizations are done and the inspector trait was rewritten. +It feel's like that the lib is in the state that is okay to promote it to the v1 version. Other than that, a lot of optimizations are done and the inspector trait was rewritten. Changes: * web3 db diff --git a/crates/revm/Cargo.toml b/crates/revm/Cargo.toml index 1a93a83d19..491c4ba9b7 100644 --- a/crates/revm/Cargo.toml +++ b/crates/revm/Cargo.toml @@ -1,164 +1,112 @@ [package] -authors = ["Dragan Rakita "] -description = "revm - Rust Ethereum Virtual Machine" -edition = "2021" -keywords = ["no_std", "ethereum", "evm", "revm"] -license = "MIT" name = "revm" -repository = "https://github.com/bluealloy/revm" -version = "9.0.0" -readme = "../../README.md" +description = "Revm - Rust Ethereum Virtual Machine" +version = "27.1.0" +authors.workspace = true +edition.workspace = true +keywords.workspace = true +license.workspace = true +repository.workspace = true +readme.workspace = true [package.metadata.docs.rs] all-features = true rustdoc-args = ["--cfg", "docsrs"] -[lints.rust] -unreachable_pub = "warn" -unused_must_use = "deny" -rust_2018_idioms = "deny" - -[lints.rustdoc] -all = "warn" +[lints] +workspace = true [dependencies] # revm -revm-interpreter = { path = "../interpreter", version = "5.0.0", default-features = false } -revm-precompile = { path = "../precompile", version = "7.0.0", default-features = false } - -# misc -auto_impl = { version = "1.2", default-features = false } -cfg-if = "1.0" -dyn-clone = "1.0" - -# Optional -serde = { version = "1.0", default-features = false, features = [ - "derive", - "rc", -], optional = true } -serde_json = { version = "1.0", default-features = false, features = [ - "alloc", -], optional = true } - -# ethersdb -tokio = { version = "1.37", features = [ - "rt-multi-thread", - "macros", -], optional = true } -ethers-providers = { version = "2.0", optional = true } -ethers-core = { version = "2.0", optional = true } - -# alloydb -# alloy-provider = { git = "https://github.com/alloy-rs/alloy.git", rev = "44b8a6d", optional = true, default-features = false } -# alloy-rpc-types = { git = "https://github.com/alloy-rs/alloy.git", rev = "44b8a6d", optional = true, default-features = false } -# alloy-transport = { git = "https://github.com/alloy-rs/alloy.git", rev = "44b8a6d", optional = true, default-features = false } +bytecode.workspace = true +context.workspace = true +context-interface.workspace = true +database.workspace = true +database-interface.workspace = true +handler.workspace = true +inspector.workspace = true +interpreter.workspace = true +precompile.workspace = true +primitives.workspace = true +state.workspace = true [dev-dependencies] -alloy-sol-types = { version = "0.7.0", default-features = false, features = [ - "std", -] } -ethers-contract = { version = "2.0.14", default-features = false } -anyhow = "1.0.83" -criterion = "0.5" -indicatif = "0.17" -reqwest = { version = "0.12" } -rstest = "0.19.0" - -alloy-provider = { git = "https://github.com/alloy-rs/alloy.git", rev = "44b8a6d", default-features = false, features = [ - "reqwest", -] } -# needed for enabling TLS to use HTTPS connections when testing alloy DB -alloy-transport-http = { git = "https://github.com/alloy-rs/alloy.git", rev = "44b8a6d" } +serde_json = { workspace = true, features = ["alloc", "preserve_order"] } +serde = { workspace = true, features = ["derive"] } [features] -default = ["std", "c-kzg", "secp256k1", "portable", "blst"] +default = ["std", "c-kzg", "secp256k1", "portable", "blst", "tracer"] std = [ - "serde?/std", - "serde_json?/std", - "serde_json?/preserve_order", - "revm-interpreter/std", - "revm-precompile/std", + "interpreter/std", + "precompile/std", + "handler/std", + "context/std", + "context-interface/std", + "bytecode/std", + "database/std", + "database-interface/std", + "inspector/std", + "primitives/std", + "state/std", + "serde/std", + "serde_json/std", ] -hashbrown = ["revm-interpreter/hashbrown", "revm-precompile/hashbrown"] -serde = ["dep:serde", "revm-interpreter/serde"] -serde-json = ["serde", "dep:serde_json"] -arbitrary = ["revm-interpreter/arbitrary"] -asm-keccak = ["revm-interpreter/asm-keccak", "revm-precompile/asm-keccak"] -portable = ["revm-precompile/portable", "revm-interpreter/portable"] - -test-utils = [] - -optimism = ["revm-interpreter/optimism", "revm-precompile/optimism"] -# Optimism default handler enabled Optimism handler register by default in EvmBuilder. -optimism-default-handler = [ - "optimism", - "revm-precompile/optimism-default-handler", - "revm-interpreter/optimism-default-handler", -] -negate-optimism-default-handler = [ - "revm-precompile/negate-optimism-default-handler", - "revm-interpreter/negate-optimism-default-handler", +hashbrown = ["interpreter/hashbrown", "precompile/hashbrown"] +map-foldhash = ["primitives/map-foldhash"] +serde = [ + "interpreter/serde", + "database-interface/serde", + "primitives/serde", + "handler/serde", + "context-interface/serde", + "bytecode/serde", + "context/serde", + "database/serde", + "inspector/serde", + "state/serde", ] +arbitrary = ["primitives/arbitrary"] +asm-keccak = ["primitives/asm-keccak"] +sha3-keccak = ["primitives/sha3-keccak"] +asyncdb = ["database-interface/asyncdb"] -ethersdb = [ - "std", - "tokio", - "ethers-providers", - "ethers-core", -] # Negate optimism default handler +# Enables alloydb inside database crate +alloydb = ["database/alloydb"] -# -# alloydb = [ -# "std", -# "tokio", -# "alloy-provider", -# "alloy-rpc-types", -# "alloy-transport", -# ] +# Enables serde-json inside inspector crate +serde-json = ["serde", "inspector/tracer"] +tracer = ["inspector/tracer"] dev = [ - "memory_limit", - "optional_balance_check", - "optional_block_gas_limit", - "optional_eip3607", - "optional_gas_refund", - "optional_no_base_fee", - "optional_beneficiary_reward", + "memory_limit", + "optional_balance_check", + "optional_block_gas_limit", + "optional_eip3541", + "optional_eip3607", + "optional_no_base_fee", ] -memory_limit = ["revm-interpreter/memory_limit"] -optional_balance_check = ["revm-interpreter/optional_balance_check"] -optional_block_gas_limit = ["revm-interpreter/optional_block_gas_limit"] -optional_eip3607 = ["revm-interpreter/optional_eip3607"] -optional_gas_refund = ["revm-interpreter/optional_gas_refund"] -optional_no_base_fee = ["revm-interpreter/optional_no_base_fee"] -optional_beneficiary_reward = ["revm-interpreter/optional_beneficiary_reward"] - -# See comments in `revm-precompile` -secp256k1 = ["revm-precompile/secp256k1"] -c-kzg = ["revm-precompile/c-kzg"] -blst = ["revm-precompile/blst"] - -[[example]] -name = "fork_ref_transact" -path = "../../examples/fork_ref_transact.rs" -required-features = ["ethersdb"] - -[[example]] -name = "generate_block_traces" -path = "../../examples/generate_block_traces.rs" -required-features = ["std", "serde-json", "ethersdb"] - -[[example]] -name = "db_by_ref" -path = "../../examples/db_by_ref.rs" -required-features = ["std", "serde-json"] - -#[[example]] -#name = "uniswap_v2_usdc_swap" -#path = "../../examples/uniswap_v2_usdc_swap.rs" -#required-features = ["alloydb"] - -[[bench]] -name = "bench" -path = "benches/bench.rs" -harness = false +memory_limit = ["context/memory_limit", "interpreter/memory_limit"] +optional_balance_check = ["context/optional_balance_check"] +optional_block_gas_limit = ["context/optional_block_gas_limit"] +optional_eip3541 = ["context/optional_eip3541"] +optional_eip3607 = ["context/optional_eip3607"] +optional_no_base_fee = ["context/optional_no_base_fee"] + +# Precompiles features + +secp256k1 = ["precompile/secp256k1"] # See comments in `precompile` +c-kzg = [ + "precompile/c-kzg", +] # `kzg-rs` is not audited but useful for `no_std` environment, use it with causing and default to `c-kzg` if possible. +kzg-rs = ["precompile/kzg-rs"] +blst = ["precompile/blst"] +bn = ["precompile/bn"] +asm-sha2 = ["precompile/asm-sha2"] + +# Compile in portable mode, without ISA extensions. +# Binary can be executed on all systems. +portable = ["precompile/portable"] + +# use gmp for modexp precompile. +# It is faster library but licences as GPL code, if enabled please make sure to follow the license. +gmp = ["precompile/gmp"] diff --git a/crates/revm/LICENSE b/crates/revm/LICENSE index ad98ff22cc..be6d350ebe 100644 --- a/crates/revm/LICENSE +++ b/crates/revm/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2021-2024 draganrakita +Copyright (c) 2021-2025 draganrakita Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/crates/revm/benches/bench.rs b/crates/revm/benches/bench.rs deleted file mode 100644 index b45beefd6f..0000000000 --- a/crates/revm/benches/bench.rs +++ /dev/null @@ -1,132 +0,0 @@ -use criterion::{ - criterion_group, criterion_main, measurement::WallTime, BenchmarkGroup, Criterion, -}; -use revm::{ - db::BenchmarkDB, - interpreter::{analysis::to_analysed, Contract, DummyHost, Interpreter}, - primitives::{address, bytes, hex, BerlinSpec, Bytecode, Bytes, TransactTo, U256}, - Evm, -}; -use revm_interpreter::{opcode::make_instruction_table, SharedMemory, EMPTY_SHARED_MEMORY}; -use std::time::Duration; - -fn analysis(c: &mut Criterion) { - let evm = Evm::builder() - .modify_tx_env(|tx| { - tx.caller = address!("0000000000000000000000000000000000000002"); - tx.transact_to = TransactTo::Call(address!("0000000000000000000000000000000000000000")); - // evm.env.tx.data = bytes!("30627b7c"); - tx.data = bytes!("8035F0CE"); - }) - .build(); - - let contract_data: Bytes = hex::decode(ANALYSIS).unwrap().into(); - - let mut g = c.benchmark_group("analysis"); - g.noise_threshold(0.03) - .warm_up_time(Duration::from_secs(3)) - .measurement_time(Duration::from_secs(10)) - .sample_size(10); - - let raw = Bytecode::new_raw(contract_data.clone()); - let mut evm = evm - .modify() - .reset_handler_with_db(BenchmarkDB::new_bytecode(raw)) - .build(); - bench_transact(&mut g, &mut evm); - - let analysed = to_analysed(Bytecode::new_raw(contract_data)); - let mut evm = evm - .modify() - .reset_handler_with_db(BenchmarkDB::new_bytecode(analysed)) - .build(); - bench_transact(&mut g, &mut evm); - - g.finish(); -} - -fn snailtracer(c: &mut Criterion) { - let mut evm = Evm::builder() - .with_db(BenchmarkDB::new_bytecode(bytecode(SNAILTRACER))) - .modify_tx_env(|tx| { - tx.caller = address!("1000000000000000000000000000000000000000"); - tx.transact_to = TransactTo::Call(address!("0000000000000000000000000000000000000000")); - tx.data = bytes!("30627b7c"); - }) - .build(); - - let mut g = c.benchmark_group("snailtracer"); - g.noise_threshold(0.03) - .warm_up_time(Duration::from_secs(3)) - .measurement_time(Duration::from_secs(10)) - .sample_size(10); - bench_transact(&mut g, &mut evm); - bench_eval(&mut g, &mut evm); - g.finish(); -} - -fn transfer(c: &mut Criterion) { - let mut evm = Evm::builder() - .with_db(BenchmarkDB::new_bytecode(Bytecode::new())) - .modify_tx_env(|tx| { - tx.caller = address!("0000000000000000000000000000000000000001"); - tx.transact_to = TransactTo::Call(address!("0000000000000000000000000000000000000000")); - tx.value = U256::from(10); - }) - .build(); - - let mut g = c.benchmark_group("transfer"); - g.noise_threshold(0.03).warm_up_time(Duration::from_secs(1)); - bench_transact(&mut g, &mut evm); - g.finish(); -} - -fn bench_transact(g: &mut BenchmarkGroup<'_, WallTime>, evm: &mut Evm<'_, EXT, BenchmarkDB>) { - let state = match evm.context.evm.db.0 { - Bytecode::LegacyRaw(_) => "raw", - Bytecode::LegacyAnalyzed(_) => "analysed", - Bytecode::Eof(_) => "eof", - }; - let id = format!("transact/{state}"); - g.bench_function(id, |b| b.iter(|| evm.transact().unwrap())); -} - -fn bench_eval(g: &mut BenchmarkGroup<'_, WallTime>, evm: &mut Evm<'static, (), BenchmarkDB>) { - g.bench_function("eval", |b| { - let contract = Contract { - input: evm.context.evm.env.tx.data.clone(), - bytecode: to_analysed(evm.context.evm.db.0.clone()), - ..Default::default() - }; - let mut shared_memory = SharedMemory::new(); - let mut host = DummyHost::new(*evm.context.evm.env.clone()); - let instruction_table = make_instruction_table::(); - b.iter(move || { - // replace memory with empty memory to use it inside interpreter. - // Later return memory back. - let temp = core::mem::replace(&mut shared_memory, EMPTY_SHARED_MEMORY); - let mut interpreter = Interpreter::new(contract.clone(), u64::MAX, false); - let res = interpreter.run(temp, &instruction_table, &mut host); - shared_memory = interpreter.take_memory(); - host.clear(); - res - }) - }); -} - -fn bytecode(s: &str) -> Bytecode { - to_analysed(Bytecode::new_raw(hex::decode(s).unwrap().into())) -} - -#[rustfmt::skip] -criterion_group!( - benches, - analysis, - snailtracer, - transfer, -); -criterion_main!(benches); - -const ANALYSIS: &str = "6060604052341561000f57600080fd5b604051610dd1380380610dd18339810160405280805190602001909190805182019190602001805190602001909190805182019190505083600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508360008190555082600390805190602001906100a79291906100e3565b5081600460006101000a81548160ff021916908360ff16021790555080600590805190602001906100d99291906100e3565b5050505050610188565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061012457805160ff1916838001178555610152565b82800160010185558215610152579182015b82811115610151578251825591602001919060010190610136565b5b50905061015f9190610163565b5090565b61018591905b80821115610181576000816000905550600101610169565b5090565b90565b610c3a806101976000396000f3006060604052600436106100af576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306fdde03146100b4578063095ea7b31461014257806318160ddd1461019c57806323b872dd146101c557806327e235e31461023e578063313ce5671461028b5780635c658165146102ba57806370a082311461032657806395d89b4114610373578063a9059cbb14610401578063dd62ed3e1461045b575b600080fd5b34156100bf57600080fd5b6100c76104c7565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156101075780820151818401526020810190506100ec565b50505050905090810190601f1680156101345780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561014d57600080fd5b610182600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035906020019091905050610565565b604051808215151515815260200191505060405180910390f35b34156101a757600080fd5b6101af610657565b6040518082815260200191505060405180910390f35b34156101d057600080fd5b610224600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061065d565b604051808215151515815260200191505060405180910390f35b341561024957600080fd5b610275600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919050506108f7565b6040518082815260200191505060405180910390f35b341561029657600080fd5b61029e61090f565b604051808260ff1660ff16815260200191505060405180910390f35b34156102c557600080fd5b610310600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610922565b6040518082815260200191505060405180910390f35b341561033157600080fd5b61035d600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610947565b6040518082815260200191505060405180910390f35b341561037e57600080fd5b610386610990565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156103c65780820151818401526020810190506103ab565b50505050905090810190601f1680156103f35780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561040c57600080fd5b610441600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035906020019091905050610a2e565b604051808215151515815260200191505060405180910390f35b341561046657600080fd5b6104b1600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610b87565b6040518082815260200191505060405180910390f35b60038054600181600116156101000203166002900480601f01602080910402602001604051908101604052809291908181526020018280546001816001161561010002031660029004801561055d5780601f106105325761010080835404028352916020019161055d565b820191906000526020600020905b81548152906001019060200180831161054057829003601f168201915b505050505081565b600081600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040518082815260200191505060405180910390a36001905092915050565b60005481565b600080600260008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905082600160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541015801561072e5750828110155b151561073957600080fd5b82600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254019250508190555082600160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8110156108865782600260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055505b8373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef856040518082815260200191505060405180910390a360019150509392505050565b60016020528060005260406000206000915090505481565b600460009054906101000a900460ff1681565b6002602052816000526040600020602052806000526040600020600091509150505481565b6000600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b60058054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610a265780601f106109fb57610100808354040283529160200191610a26565b820191906000526020600020905b815481529060010190602001808311610a0957829003601f168201915b505050505081565b600081600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410151515610a7e57600080fd5b81600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555081600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a36001905092915050565b6000600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050929150505600a165627a7a72305820df254047bc8f2904ad3e966b6db116d703bebd40efadadb5e738c836ffc8f58a0029"; - -const SNAILTRACER: &str = "608060405234801561001057600080fd5b506004361061004c5760003560e01c806330627b7c1461005157806375ac892a14610085578063784f13661461011d578063c294360114610146575b600080fd5b610059610163565b604080516001600160f81b03199485168152928416602084015292168183015290519081900360600190f35b6100a86004803603604081101561009b57600080fd5b50803590602001356102d1565b6040805160208082528351818301528351919283929083019185019080838360005b838110156100e25781810151838201526020016100ca565b50505050905090810190601f16801561010f5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6100596004803603606081101561013357600080fd5b508035906020810135906040013561055b565b6100a86004803603602081101561015c57600080fd5b5035610590565b6000806000610176610400610300610834565b60405180606001604052806001546000546207d5dc028161019357fe5b058152600060208083018290526040928301919091528251600b81905583820151600c81905593830151600d819055835160608082018652928152808401959095528484015282519081018352600654815260075491810191909152600854918101919091526102259161021c916102139161020e91612ef7565b612f64565b6207d5dc612feb565b620f424061301e565b8051600e556020810151600f55604001516010556102416142dd565b61025a816102556102006101806008613064565b613212565b90506102708161025561014561021c6008613064565b905061028481610255610258806008613064565b905061029a8161025561020a61020c6008613064565b90506102a781600461301e565b90506102b1613250565b8051602082015160409092015160f891821b9692821b9550901b92509050565b606060005b6000548112156104c95760006102ed828686613064565b90506002816000015160f81b90808054603f811680603e811461032a576002830184556001831661031c578192505b600160028404019350610342565b600084815260209081902060ff198516905560419094555b505050600190038154600116156103685790600052602060002090602091828204019190065b909190919091601f036101000a81548160ff02191690600160f81b840402179055506002816020015160f81b90808054603f811680603e81146103c557600283018455600183166103b7578192505b6001600284040193506103dd565b600084815260209081902060ff198516905560419094555b505050600190038154600116156104035790600052602060002090602091828204019190065b909190919091601f036101000a81548160ff02191690600160f81b840402179055506002816040015160f81b90808054603f811680603e81146104605760028301845560018316610452578192505b600160028404019350610478565b600084815260209081902060ff198516905560419094555b5050506001900381546001161561049e5790600052602060002090602091828204019190065b815460ff601f929092036101000a9182021916600160f81b90930402919091179055506001016102d6565b506002805460408051602060018416156101000260001901909316849004601f8101849004840282018401909252818152929183018282801561054d5780601f106105225761010080835404028352916020019161054d565b820191906000526020600020905b81548152906001019060200180831161053057829003601f168201915b505050505090505b92915050565b60008060008061056c878787613064565b8051602082015160409092015160f891821b9a92821b9950901b9650945050505050565b600154606090600019015b600081126107a35760005b6000548112156107995760006105bd828487613064565b90506002816000015160f81b90808054603f811680603e81146105fa57600283018455600183166105ec578192505b600160028404019350610612565b600084815260209081902060ff198516905560419094555b505050600190038154600116156106385790600052602060002090602091828204019190065b909190919091601f036101000a81548160ff02191690600160f81b840402179055506002816020015160f81b90808054603f811680603e81146106955760028301845560018316610687578192505b6001600284040193506106ad565b600084815260209081902060ff198516905560419094555b505050600190038154600116156106d35790600052602060002090602091828204019190065b909190919091601f036101000a81548160ff02191690600160f81b840402179055506002816040015160f81b90808054603f811680603e81146107305760028301845560018316610722578192505b600160028404019350610748565b600084815260209081902060ff198516905560419094555b5050506001900381546001161561076e5790600052602060002090602091828204019190065b815460ff601f929092036101000a9182021916600160f81b90930402919091179055506001016105a6565b506000190161059b565b506002805460408051602060018416156101000260001901909316849004601f810184900484028201840190925281815292918301828280156108275780601f106107fc57610100808354040283529160200191610827565b820191906000526020600020905b81548152906001019060200180831161080a57829003601f168201915b505050505090505b919050565b8160008190555080600181905550604051806080016040528060405180606001604052806302faf08081526020016303197500815260200163119e7f8081525081526020016108a460405180606001604052806000815260200161a673198152602001620f423f19815250612f64565b815260006020808301829052604092830182905283518051600355808201516004558301516005558381015180516006559081015160075582015160085582820151600955606092830151600a805460ff1916911515919091179055815192830190915260015490548291906207d5dc028161091c57fe5b058152600060208083018290526040928301919091528251600b81905583820151600c81905593830151600d819055835160608082018652928152808401959095528484015282519081018352600654815260075491810191909152600854918101919091526109979161021c916102139161020e91612ef7565b8051600e55602080820151600f55604091820151601055815160a08101835264174876e8008152825160608082018552641748862a40825263026e8f00828501526304dd1e008286015282840191825284518082018652600080825281860181905281870181905284870191825286518084018852620b71b081526203d09081880181905281890152928501928352608085018181526011805460018082018355919093528651600b9093027f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c688101938455955180517f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c69880155808901517f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c6a8801558901517f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c6b870155925180517f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c6c870155808801517f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c6d8701558801517f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c6e860155925180517f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c6f860155958601517f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c7085015594909501517f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c71830155517f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c72909101805492949192909160ff1990911690836002811115610c1057fe5b0217905550505060116040518060a0016040528064174876e8008152602001604051806060016040528064174290493f19815260200163026e8f0081526020016304dd1e008152508152602001604051806060016040528060008152602001600081526020016000815250815260200160405180606001604052806203d09081526020016203d0908152602001620b71b0815250815260200160006002811115610cb657fe5b905281546001818101845560009384526020938490208351600b90930201918255838301518051838301558085015160028085019190915560409182015160038501558185015180516004860155808701516005860155820151600685015560608501518051600786015595860151600885015594015160098301556080830151600a83018054949593949193909260ff1990921691908490811115610d5857fe5b0217905550505060116040518060a0016040528064174876e800815260200160405180606001604052806302faf080815260200163026e8f00815260200164174876e800815250815260200160405180606001604052806000815260200160008152602001600081525081526020016040518060600160405280620b71b08152602001620b71b08152602001620b71b0815250815260200160006002811115610dfd57fe5b905281546001818101845560009384526020938490208351600b90930201918255838301518051838301558085015160028085019190915560409182015160038501558185015180516004860155808701516005860155820151600685015560608501518051600786015595860151600885015594015160098301556080830151600a83018054949593949193909260ff1990921691908490811115610e9f57fe5b0217905550505060116040518060a0016040528064174876e800815260200160405180606001604052806302faf080815260200163026e8f00815260200164173e54e97f1981525081526020016040518060600160405280600081526020016000815260200160008152508152602001604051806060016040528060008152602001600081526020016000815250815260200160006002811115610f3f57fe5b905281546001818101845560009384526020938490208351600b90930201918255838301518051838301558085015160028085019190915560409182015160038501558185015180516004860155808701516005860155820151600685015560608501518051600786015595860151600885015594015160098301556080830151600a83018054949593949193909260ff1990921691908490811115610fe157fe5b0217905550505060116040518060a0016040528064174876e800815260200160405180606001604052806302faf080815260200164174876e80081526020016304dd1e00815250815260200160405180606001604052806000815260200160008152602001600081525081526020016040518060600160405280620b71b08152602001620b71b08152602001620b71b081525081526020016000600281111561108657fe5b905281546001818101845560009384526020938490208351600b90930201918255838301518051838301558085015160028085019190915560409182015160038501558185015180516004860155808701516005860155820151600685015560608501518051600786015595860151600885015594015160098301556080830151600a83018054949593949193909260ff199092169190849081111561112857fe5b0217905550505060116040518060a0016040528064174876e800815260200160405180606001604052806302faf080815260200164174399c9ff1981526020016304dd1e00815250815260200160405180606001604052806000815260200160008152602001600081525081526020016040518060600160405280620b71b08152602001620b71b08152602001620b71b08152508152602001600060028111156111ce57fe5b905281546001818101845560009384526020938490208351600b90930201918255838301518051838301558085015160028085019190915560409182015160038501558185015180516004860155808701516005860155820151600685015560608501518051600786015595860151600885015594015160098301556080830151600a83018054949593949193909260ff199092169190849081111561127057fe5b0217905550505060116040518060a0016040528062fbc5208152602001604051806060016040528063019bfcc0815260200162fbc52081526020016302cd29c0815250815260200160405180606001604052806000815260200160008152602001600081525081526020016040518060600160405280620f3e588152602001620f3e588152602001620f3e5881525081526020016001600281111561131157fe5b905281546001818101845560009384526020938490208351600b90930201918255838301518051838301558085015160028085019190915560409182015160038501558185015180516004860155808701516005860155820151600685015560608501518051600786015595860151600885015594015160098301556080830151600a83018054949593949193909260ff19909216919084908111156113b357fe5b0217905550505060116040518060a001604052806323c34600815260200160405180606001604052806302faf080815260200163289c455081526020016304dd1e008152508152602001604051806060016040528062b71b00815260200162b71b00815260200162b71b00815250815260200160405180606001604052806000815260200160008152602001600081525081526020016000600281111561145657fe5b905281546001818101845560009384526020938490208351600b90930201918255838301518051838301558085015160028085019190915560409182015160038501558185015180516004860155808701516005860155820151600685015560608501518051600786015595860151600885015594015160098301556080830151600a83018054949593949193909260ff19909216919084908111156114f857fe5b0217905550505060126040518060e00160405280604051806060016040528063035e1f208152602001630188c2e081526020016304a62f8081525081526020016040518060600160405280630459e4408152602001630188c2e081526020016305a1f4a081525081526020016040518060600160405280630459e44081526020016302f34f6081526020016304a62f808152508152602001604051806060016040528060008152602001600081526020016000815250815260200160405180606001604052806000815260200160008152602001600081525081526020016040518060600160405280620f3e588152602001620f3e588152602001620f3e5881525081526020016001600281111561160c57fe5b905281546001818101845560009384526020938490208351805160139094029091019283558085015183830155604090810151600280850191909155858501518051600386015580870151600486015582015160058501558185015180516006860155808701516007860155820151600885015560608501518051600986015580870151600a860155820151600b85015560808501518051600c86015580870151600d860155820151600e85015560a08501518051600f860155958601516010850155940151601183015560c0830151601283018054949593949193909260ff19909216919084908111156116fd57fe5b0217905550505060126040518060e00160405280604051806060016040528063035e1f20815260200163016a8c8081526020016304a62f8081525081526020016040518060600160405280630459e4408152602001600081526020016304a62f8081525081526020016040518060600160405280630459e440815260200163016a8c8081526020016305a1f4a08152508152602001604051806060016040528060008152602001600081526020016000815250815260200160405180606001604052806000815260200160008152602001600081525081526020016040518060600160405280620f3e588152602001620f3e588152602001620f3e5881525081526020016001600281111561180e57fe5b905281546001818101845560009384526020938490208351805160139094029091019283558085015183830155604090810151600280850191909155858501518051600386015580870151600486015582015160058501558185015180516006860155808701516007860155820151600885015560608501518051600986015580870151600a860155820151600b85015560808501518051600c86015580870151600d860155820151600e85015560a08501518051600f860155958601516010850155940151601183015560c0830151601283018054949593949193909260ff19909216919084908111156118ff57fe5b0217905550505060126040518060e001604052806040518060600160405280630555a9608152602001630188c2e081526020016304a62f8081525081526020016040518060600160405280630459e44081526020016302f34f6081526020016304a62f8081525081526020016040518060600160405280630459e4408152602001630188c2e081526020016305a1f4a08152508152602001604051806060016040528060008152602001600081526020016000815250815260200160405180606001604052806000815260200160008152602001600081525081526020016040518060600160405280620f3e588152602001620f3e588152602001620f3e58815250815260200160016002811115611a1357fe5b905281546001818101845560009384526020938490208351805160139094029091019283558085015183830155604090810151600280850191909155858501518051600386015580870151600486015582015160058501558185015180516006860155808701516007860155820151600885015560608501518051600986015580870151600a860155820151600b85015560808501518051600c86015580870151600d860155820151600e85015560a08501518051600f860155958601516010850155940151601183015560c0830151601283018054949593949193909260ff1990921691908490811115611b0457fe5b0217905550505060126040518060e001604052806040518060600160405280630555a960815260200163016a8c8081526020016304a62f8081525081526020016040518060600160405280630459e440815260200163016a8c8081526020016305a1f4a081525081526020016040518060600160405280630459e4408152602001600081526020016304a62f808152508152602001604051806060016040528060008152602001600081526020016000815250815260200160405180606001604052806000815260200160008152602001600081525081526020016040518060600160405280620f3e588152602001620f3e588152602001620f3e58815250815260200160016002811115611c1557fe5b905281546001818101845560009384526020938490208351805160139094029091019283558085015183830155604090810151600280850191909155858501518051600386015580870151600486015582015160058501558185015180516006860155808701516007860155820151600885015560608501518051600986015580870151600a860155820151600b85015560808501518051600c86015580870151600d860155820151600e85015560a08501518051600f860155958601516010850155940151601183015560c0830151601283018054949593949193909260ff1990921691908490811115611d0657fe5b0217905550505060126040518060e00160405280604051806060016040528063035e1f208152602001630188c2e081526020016304a62f8081525081526020016040518060600160405280630459e44081526020016302f34f6081526020016304a62f8081525081526020016040518060600160405280630459e4408152602001630188c2e081526020016303aa6a608152508152602001604051806060016040528060008152602001600081526020016000815250815260200160405180606001604052806000815260200160008152602001600081525081526020016040518060600160405280620f3e588152602001620f3e588152602001620f3e58815250815260200160016002811115611e1a57fe5b905281546001818101845560009384526020938490208351805160139094029091019283558085015183830155604090810151600280850191909155858501518051600386015580870151600486015582015160058501558185015180516006860155808701516007860155820151600885015560608501518051600986015580870151600a860155820151600b85015560808501518051600c86015580870151600d860155820151600e85015560a08501518051600f860155958601516010850155940151601183015560c0830151601283018054949593949193909260ff1990921691908490811115611f0b57fe5b0217905550505060126040518060e00160405280604051806060016040528063035e1f20815260200163016a8c8081526020016304a62f8081525081526020016040518060600160405280630459e440815260200163016a8c8081526020016303aa6a6081525081526020016040518060600160405280630459e4408152602001600081526020016304a62f808152508152602001604051806060016040528060008152602001600081526020016000815250815260200160405180606001604052806000815260200160008152602001600081525081526020016040518060600160405280620f3e588152602001620f3e588152602001620f3e5881525081526020016001600281111561201c57fe5b905281546001818101845560009384526020938490208351805160139094029091019283558085015183830155604090810151600280850191909155858501518051600386015580870151600486015582015160058501558185015180516006860155808701516007860155820151600885015560608501518051600986015580870151600a860155820151600b85015560808501518051600c86015580870151600d860155820151600e85015560a08501518051600f860155958601516010850155940151601183015560c0830151601283018054949593949193909260ff199092169190849081111561210d57fe5b0217905550505060126040518060e001604052806040518060600160405280630555a9608152602001630188c2e081526020016304a62f8081525081526020016040518060600160405280630459e4408152602001630188c2e081526020016303aa6a6081525081526020016040518060600160405280630459e44081526020016302f34f6081526020016304a62f808152508152602001604051806060016040528060008152602001600081526020016000815250815260200160405180606001604052806000815260200160008152602001600081525081526020016040518060600160405280620f3e588152602001620f3e588152602001620f3e5881525081526020016001600281111561222157fe5b905281546001818101845560009384526020938490208351805160139094029091019283558085015183830155604090810151600280850191909155858501518051600386015580870151600486015582015160058501558185015180516006860155808701516007860155820151600885015560608501518051600986015580870151600a860155820151600b85015560808501518051600c86015580870151600d860155820151600e85015560a08501518051600f860155958601516010850155940151601183015560c0830151601283018054949593949193909260ff199092169190849081111561231257fe5b0217905550505060126040518060e001604052806040518060600160405280630555a960815260200163016a8c8081526020016304a62f8081525081526020016040518060600160405280630459e4408152602001600081526020016304a62f8081525081526020016040518060600160405280630459e440815260200163016a8c8081526020016303aa6a608152508152602001604051806060016040528060008152602001600081526020016000815250815260200160405180606001604052806000815260200160008152602001600081525081526020016040518060600160405280620f3e588152602001620f3e588152602001620f3e5881525081526020016001600281111561242357fe5b905281546001818101845560009384526020938490208351805160139094029091019283558085015183830155604090810151600280850191909155858501518051600386015580870151600486015582015160058501558185015180516006860155808701516007860155820151600885015560608501518051600986015580870151600a860155820151600b85015560808501518051600c86015580870151600d860155820151600e85015560a08501518051600f860155958601516010850155940151601183015560c0830151601283018054949593949193909260ff199092169190849081111561251457fe5b0217905550505060126040518060e00160405280604051806060016040528063035e1f208152602001630188c2e081526020016304a62f8081525081526020016040518060600160405280630459e4408152602001630188c2e081526020016303aa6a6081525081526020016040518060600160405280630555a9608152602001630188c2e081526020016304a62f808152508152602001604051806060016040528060008152602001600081526020016000815250815260200160405180606001604052806000815260200160008152602001600081525081526020016040518060600160405280620f3e588152602001620f3e588152602001620f3e5881525081526020016001600281111561262857fe5b905281546001818101845560009384526020938490208351805160139094029091019283558085015183830155604090810151600280850191909155858501518051600386015580870151600486015582015160058501558185015180516006860155808701516007860155820151600885015560608501518051600986015580870151600a860155820151600b85015560808501518051600c86015580870151600d860155820151600e85015560a08501518051600f860155958601516010850155940151601183015560c0830151601283018054949593949193909260ff199092169190849081111561271957fe5b0217905550505060126040518060e00160405280604051806060016040528063035e1f208152602001630188c2e081526020016304a62f8081525081526020016040518060600160405280630555a9608152602001630188c2e081526020016304a62f8081525081526020016040518060600160405280630459e4408152602001630188c2e081526020016305a1f4a08152508152602001604051806060016040528060008152602001600081526020016000815250815260200160405180606001604052806000815260200160008152602001600081525081526020016040518060600160405280620f3e588152602001620f3e588152602001620f3e5881525081526020016001600281111561282d57fe5b905281546001818101845560009384526020938490208351805160139094029091019283558085015183830155604090810151600280850191909155858501518051600386015580870151600486015582015160058501558185015180516006860155808701516007860155820151600885015560608501518051600986015580870151600a860155820151600b85015560808501518051600c86015580870151600d860155820151600e85015560a08501518051600f860155958601516010850155940151601183015560c0830151601283018054949593949193909260ff199092169190849081111561291e57fe5b0217905550505060126040518060e00160405280604051806060016040528063035e1f20815260200163016a8c8081526020016304a62f8081525081526020016040518060600160405280630555a960815260200163016a8c8081526020016304a62f8081525081526020016040518060600160405280630459e440815260200163016a8c8081526020016303aa6a608152508152602001604051806060016040528060008152602001600081526020016000815250815260200160405180606001604052806000815260200160008152602001600081525081526020016040518060600160405280620f3e588152602001620f3e588152602001620f3e58815250815260200160016002811115612a3257fe5b905281546001818101845560009384526020938490208351805160139094029091019283558085015183830155604090810151600280850191909155858501518051600386015580870151600486015582015160058501558185015180516006860155808701516007860155820151600885015560608501518051600986015580870151600a860155820151600b85015560808501518051600c86015580870151600d860155820151600e85015560a08501518051600f860155958601516010850155940151601183015560c0830151601283018054949593949193909260ff1990921691908490811115612b2357fe5b0217905550505060126040518060e00160405280604051806060016040528063035e1f20815260200163016a8c8081526020016304a62f8081525081526020016040518060600160405280630459e440815260200163016a8c8081526020016305a1f4a081525081526020016040518060600160405280630555a960815260200163016a8c8081526020016304a62f808152508152602001604051806060016040528060008152602001600081526020016000815250815260200160405180606001604052806000815260200160008152602001600081525081526020016040518060600160405280620f3e588152602001620f3e588152602001620f3e58815250815260200160016002811115612c3757fe5b905281546001818101845560009384526020938490208351805160139094029091019283558085015183830155604090810151600280850191909155858501518051600386015580870151600486015582015160058501558185015180516006860155808701516007860155820151600885015560608501518051600986015580870151600a860155820151600b85015560808501518051600c86015580870151600d860155820151600e85015560a08501518051600f860155958601516010850155940151601183015560c0830151601283018054949593949193909260ff1990921691908490811115612d2857fe5b0217905550505060005b601254811015612ef257600060128281548110612d4b57fe5b600091825260209182902060408051610140810182526013909302909101805460e08401908152600182015461010085015260028083015461012086015290845282516060818101855260038401548252600484015482880152600584015482860152858701919091528351808201855260068401548152600784015481880152600884015481860152858501528351808201855260098401548152600a84015481880152600b840154818601528186015283518082018552600c8401548152600d84015481880152600e84015481860152608086015283519081018452600f830154815260108301549581019590955260118201549285019290925260a0830193909352601283015491929160c084019160ff90911690811115612e6c57fe5b6002811115612e7757fe5b815250509050612eac61020e612e95836020015184600001516132cd565b612ea7846040015185600001516132cd565b612ef7565b60128381548110612eb957fe5b60009182526020918290208351600960139093029091019182015590820151600a820155604090910151600b9091015550600101612d32565b505050565b612eff6142dd565b604051806060016040528083602001518560400151028460400151866020015102038152602001836040015185600001510284600001518660400151020381526020018360000151856020015102846020015186600001510203815250905092915050565b612f6c6142dd565b604082015160208301518351600092612f9292918002918002919091019080020161330c565b90506040518060600160405280828560000151620f42400281612fb157fe5b058152602001828560200151620f42400281612fc957fe5b058152602001828560400151620f42400281612fe157fe5b0590529392505050565b612ff36142dd565b5060408051606081018252835183028152602080850151840290820152928101519091029082015290565b6130266142dd565b60405180606001604052808385600001518161303e57fe5b0581526020018385602001518161305157fe5b05815260200183856040015181612fe157fe5b61306c6142dd565b6000546013805463ffffffff1916918502860163ffffffff169190911790556130936142dd565b905060005b828112156131f157600061317261314c61021c613115600b60405180606001604052908160008201548152602001600182015481526020016002820154815250506207a1206000546207a1206130ec613343565b63ffffffff16816130f957fe5b0663ffffffff168d620f424002018161310e57fe5b0503612feb565b60408051606081018252600e548152600f5460208201526010549181019190915260015461025591906207a12090816130ec613343565b604080516060810182526006548152600754602082015260085491810191909152613212565b6040805160e081019091526003546080820190815260045460a083015260055460c083015291925060009181906131ae9061025586608c612feb565b81526020016131bc84612f64565b815260006020820181905260409091015290506131e5846102556131df8461336c565b8861301e565b93505050600101613098565b5061320861021c61320183613753565b60ff612feb565b90505b9392505050565b61321a6142dd565b50604080516060810182528251845101815260208084015181860151019082015291810151928101519092019181019190915290565b60008080556001819055613266906002906142fe565b60006003819055600481905560058190556006819055600781905560088190556009819055600a805460ff19169055600b819055600c819055600d819055600e819055600f81905560108190556132bf90601190614345565b6132cb60126000614366565b565b6132d56142dd565b5060408051606081018252825184510381526020808401518186015103908201528282015184830151039181019190915292915050565b80600260018201055b8181121561333d5780915060028182858161332c57fe5b05018161333557fe5b059050613315565b50919050565b6013805463ffffffff19811663ffffffff9182166341c64e6d0261303901821617918290551690565b6133746142dd565b600a826040015113156133a657604051806060016040528060008152602001600081526020016000815250905061082f565b60008060006133b48561379f565b91945092509050826133e857604051806060016040528060008152602001600081526020016000815250935050505061082f565b6133f0614387565b6133f86143c7565b6134006142dd565b6134086142dd565b600086600181111561341657fe5b1415613505576011858154811061342957fe5b60009182526020918290206040805160a081018252600b90930290910180548352815160608082018452600183015482526002808401548388015260038401548386015285870192909252835180820185526004840154815260058401548188015260068401548186015285850152835180820185526007840154815260088401549681019690965260098301549386019390935291830193909352600a830154919291608084019160ff909116908111156134e157fe5b60028111156134ec57fe5b8152505093508360600151915083604001519050613653565b6012858154811061351257fe5b600091825260209182902060408051610140810182526013909302909101805460e08401908152600182015461010085015260028083015461012086015290845282516060818101855260038401548252600484015482880152600584015482860152858701919091528351808201855260068401548152600784015481880152600884015481860152858501528351808201855260098401548152600a84015481880152600b840154818601528186015283518082018552600c8401548152600d84015481880152600e84015481860152608086015283519081018452600f830154815260108301549581019590955260118201549285019290925260a0830193909352601283015491929160c084019160ff9091169081111561363357fe5b600281111561363e57fe5b8152505092508260a001519150826080015190505b6040820151600190811215613669575060408201515b808360200151131561367c575060208201515b808360400151131561368f575060408201515b60408a01805160010190819052600512156136f75780620f42406136b1613343565b63ffffffff16816136be57fe5b0663ffffffff1612156136e8576136e16136db84620f4240612feb565b8261301e565b92506136f7565b50965061082f95505050505050565b6136ff6142dd565b600088600181111561370d57fe5b14156137255761371e8b878b613a57565b9050613733565b6137308b868b613aec565b90505b6137448361025561021c8785613baa565b9b9a5050505050505050505050565b61375b6142dd565b60405180606001604052806137738460000151613be8565b81526020016137858460200151613be8565b81526020016137978460400151613be8565b905292915050565b60008080808080805b6011548110156138c2576000613890601183815481106137c457fe5b60009182526020918290206040805160a081018252600b90930290910180548352815160608082018452600183015482526002808401548388015260038401548386015285870192909252835180820185526004840154815260058401548188015260068401548186015285850152835180820185526007840154815260088401549681019690965260098301549386019390935291830193909352600a830154919291608084019160ff9091169081111561387c57fe5b600281111561388757fe5b9052508a613c13565b90506000811380156138a957508415806138a957508481125b156138b957809450600093508192505b506001016137a8565b5060005b601254811015613a49576000613a17601283815481106138e257fe5b600091825260209182902060408051610140810182526013909302909101805460e08401908152600182015461010085015260028083015461012086015290845282516060818101855260038401548252600484015482880152600584015482860152858701919091528351808201855260068401548152600784015481880152600884015481860152858501528351808201855260098401548152600a84015481880152600b840154818601528186015283518082018552600c8401548152600d84015481880152600e84015481860152608086015283519081018452600f830154815260108301549581019590955260118201549285019290925260a0830193909352601283015491929160c084019160ff90911690811115613a0357fe5b6002811115613a0e57fe5b9052508a613cbb565b9050600081138015613a305750841580613a3057508481125b15613a4057809450600193508192505b506001016138c6565b509196909550909350915050565b613a5f6142dd565b6000613a7a856000015161025561021c886020015187612feb565b90506000613a8f61020e8387602001516132cd565b9050600085608001516002811115613aa357fe5b1415613ae1576000613ab9828860200151613e0c565b12613acd57613aca81600019612feb565b90505b613ad8868383613e31565b9250505061320b565b613ad8868383613fc1565b613af46142dd565b6000613b0f856000015161025561021c886020015187612feb565b6060860151909150620a2c2a9015613b2757506216e3605b6000620f4240613b3f87606001518960200151613e0c565b81613b4657fe5b05905060008112613b55576000035b64e8d4a5100081800281038380020281900590036000811215613b8c57613b8188858960600151613fc1565b94505050505061320b565b613b9e88858960600151868686614039565b98975050505050505050565b613bb26142dd565b50604080516060810182528251845102815260208084015181860151029082015291810151928101519092029181019190915290565b600080821215613bfa5750600061082f565b620f4240821315613c0f5750620f424061082f565b5090565b600080613c28846020015184600001516132cd565b90506000620f4240613c3e838660200151613e0c565b81613c4557fe5b865191900591506000908002613c5b8480613e0c565b838402030190506000811215613c775760009350505050610555565b613c808161330c565b90506103e88183031315613c9957900391506105559050565b6103e88183011315613caf570191506105559050565b50600095945050505050565b600080613cd0846020015185600001516132cd565b90506000613ce6856040015186600001516132cd565b90506000613cf8856020015183612ef7565b90506000620f4240613d0a8584613e0c565b81613d1157fe5b0590506103e71981138015613d2757506103e881125b15613d39576000945050505050610555565b85518751600091613d49916132cd565b9050600082613d588386613e0c565b81613d5f57fe5b0590506000811280613d735750620f424081135b15613d875760009650505050505050610555565b6000613d938388612ef7565b9050600084613da68b6020015184613e0c565b81613dad57fe5b0590506000811280613dc35750620f4240818401135b15613dd957600098505050505050505050610555565b600085613de68985613e0c565b81613ded57fe5b0590506103e88112156137445760009950505050505050505050610555565b6040808201519083015160208084015190850151845186510291020191020192915050565b613e396142dd565b6000620f424080613e48613343565b63ffffffff1681613e5557fe5b0663ffffffff16625fdfb00281613e6857fe5b0590506000620f4240613e79613343565b63ffffffff1681613e8657fe5b0663ffffffff1690506000613e9a8261330c565b6103e8029050613ea86142dd565b620186a0613eb98760000151614216565b1315613ee657604051806060016040528060008152602001620f4240815260200160008152509050613f09565b6040518060600160405280620f4240815260200160008152602001600081525090505b613f1661020e8288612ef7565b90506000613f2761020e8884612ef7565b9050613f7f61020e613f64613f5285620f424088613f448c61422e565b0281613f4c57fe5b05612feb565b61025585620f424089613f448d61424e565b6102558a613f7689620f42400361330c565b6103e802612feb565b9150613fb460405180608001604052808a81526020018481526020018b6040015181526020018b60600151151581525061336c565b9998505050505050505050565b613fc96142dd565b6000613ffb61020e8660200151613ff686620f4240613fec898c60200151613e0c565b60020281613f4c57fe5b6132cd565b90506140306040518060800160405280868152602001838152602001876040015181526020018760600151151581525061336c565b95945050505050565b6140416142dd565b60608701516000199015614053575060015b600061408961020e61021c61406c8c602001518a612feb565b613ff68b6140798a61330c565b620f42408c8e0205018802612feb565b60608a0151909150620f42408601906140ba57620f42406140aa838a613e0c565b816140b157fe5b05620f42400390505b60408a0151619c406c0c9f2c9cd04674edea40000000620ea6008480028502850285020205019060021261415e5761412a61411f60405180608001604052808d81526020018681526020018e6040015181526020018e6060015115151581525061336c565b82620f424003612feb565b92506141448361025561413e8e8e8e613fc1565b84612feb565b925061415383620f424061301e565b94505050505061420c565b600281056203d09001620f4240614173613343565b63ffffffff168161418057fe5b0663ffffffff1612156141b2576141536141a461419e8d8d8d613fc1565b83612feb565b600283056203d0900161301e565b6142056141f76141ec60405180608001604052808e81526020018781526020018f6040015181526020018f6060015115151581525061336c565b83620f424003612feb565b60028305620b71b00361301e565b9450505050505b9695505050505050565b60008082131561422757508061082f565b5060000390565b60008061423a8361424e565b905061320b81820264e8d4a510000361330c565b60005b600082121561426757625fdfb082019150614251565b5b625fdfb0821261427f57625fdfb082039150614268565b6001828160025b818313156142d457818385028161429957fe5b0585019450620f4240808788860202816142af57fe5b05816142b757fe5b600095909503940592506001810181029190910290600201614286565b50505050919050565b60405180606001604052806000815260200160008152602001600081525090565b50805460018160011615610100020316600290046000825580601f106143245750614342565b601f0160209004906000526020600020908101906143429190614401565b50565b50805460008255600b02906000526020600020908101906143429190614416565b50805460008255601302906000526020600020908101906143429190614475565b6040518060a00160405280600081526020016143a16142dd565b81526020016143ae6142dd565b81526020016143bb6142dd565b81526020016000905290565b6040518060e001604052806143da6142dd565b81526020016143e76142dd565b81526020016143f46142dd565b81526020016143a16142dd565b5b80821115613c0f5760008155600101614402565b5b80821115613c0f57600080825560018201819055600282018190556003820181905560048201819055600582018190556006820181905560078201819055600882018190556009820155600a8101805460ff19169055600b01614417565b5b80821115613c0f576000808255600182018190556002820181905560038201819055600482018190556005820181905560068201819055600782018190556008820181905560098201819055600a8201819055600b8201819055600c8201819055600d8201819055600e8201819055600f820181905560108201819055601182015560128101805460ff1916905560130161447656fea2646970667358221220037024f5647853879c58fbcc61ac3616455f6f731cc6e84f91eb5a3b4e06c00464736f6c63430007060033"; diff --git a/crates/revm/src/builder.rs b/crates/revm/src/builder.rs deleted file mode 100644 index 4b2a81ec4f..0000000000 --- a/crates/revm/src/builder.rs +++ /dev/null @@ -1,639 +0,0 @@ -use crate::{ - db::{Database, DatabaseRef, EmptyDB, WrapDatabaseRef}, - handler::register, - primitives::{ - BlockEnv, CfgEnv, CfgEnvWithHandlerCfg, Env, EnvWithHandlerCfg, HandlerCfg, SpecId, TxEnv, - }, - Context, ContextWithHandlerCfg, Evm, Handler, -}; -use core::marker::PhantomData; -use std::boxed::Box; - -/// Evm Builder allows building or modifying EVM. -/// Note that some of the methods that changes underlying structures -/// will reset the registered handler to default mainnet. -pub struct EvmBuilder<'a, BuilderStage, EXT, DB: Database> { - context: Context, - /// Handler that will be used by EVM. It contains handle registers - handler: Handler<'a, Context, EXT, DB>, - /// Phantom data to mark the stage of the builder. - phantom: PhantomData, -} - -/// First stage of the builder allows setting generic variables. -/// Generic variables are database and external context. -pub struct SetGenericStage; - -/// Second stage of the builder allows appending handler registers. -/// Requires the database and external context to be set. -pub struct HandlerStage; - -impl<'a> Default for EvmBuilder<'a, SetGenericStage, (), EmptyDB> { - fn default() -> Self { - cfg_if::cfg_if! { - if #[cfg(all(feature = "optimism-default-handler", - not(feature = "negate-optimism-default-handler")))] { - let mut handler_cfg = HandlerCfg::new(SpecId::LATEST); - // set is_optimism to true by default. - handler_cfg.is_optimism = true; - - } else { - let handler_cfg = HandlerCfg::new(SpecId::LATEST); - } - } - - Self { - context: Context::default(), - handler: EvmBuilder::<'a, SetGenericStage, (), EmptyDB>::handler(handler_cfg), - phantom: PhantomData, - } - } -} - -impl<'a, EXT, DB: Database> EvmBuilder<'a, SetGenericStage, EXT, DB> { - /// Sets the [`EmptyDB`] as the [`Database`] that will be used by [`Evm`]. - pub fn with_empty_db(self) -> EvmBuilder<'a, SetGenericStage, EXT, EmptyDB> { - EvmBuilder { - context: Context::new( - self.context.evm.with_db(EmptyDB::default()), - self.context.external, - ), - handler: EvmBuilder::<'a, SetGenericStage, EXT, EmptyDB>::handler(self.handler.cfg()), - phantom: PhantomData, - } - } - /// Sets the [`Database`] that will be used by [`Evm`]. - pub fn with_db(self, db: ODB) -> EvmBuilder<'a, SetGenericStage, EXT, ODB> { - EvmBuilder { - context: Context::new(self.context.evm.with_db(db), self.context.external), - handler: EvmBuilder::<'a, SetGenericStage, EXT, ODB>::handler(self.handler.cfg()), - phantom: PhantomData, - } - } - /// Sets the [`DatabaseRef`] that will be used by [`Evm`]. - pub fn with_ref_db( - self, - db: ODB, - ) -> EvmBuilder<'a, SetGenericStage, EXT, WrapDatabaseRef> { - EvmBuilder { - context: Context::new( - self.context.evm.with_db(WrapDatabaseRef(db)), - self.context.external, - ), - handler: EvmBuilder::<'a, SetGenericStage, EXT, WrapDatabaseRef>::handler( - self.handler.cfg(), - ), - phantom: PhantomData, - } - } - - /// Sets the external context that will be used by [`Evm`]. - pub fn with_external_context( - self, - external: OEXT, - ) -> EvmBuilder<'a, SetGenericStage, OEXT, DB> { - EvmBuilder { - context: Context::new(self.context.evm, external), - handler: EvmBuilder::<'a, SetGenericStage, OEXT, DB>::handler(self.handler.cfg()), - phantom: PhantomData, - } - } - - /// Sets Builder with [`EnvWithHandlerCfg`]. - pub fn with_env_with_handler_cfg( - mut self, - env_with_handler_cfg: EnvWithHandlerCfg, - ) -> EvmBuilder<'a, HandlerStage, EXT, DB> { - let EnvWithHandlerCfg { env, handler_cfg } = env_with_handler_cfg; - self.context.evm.env = env; - EvmBuilder { - context: self.context, - handler: EvmBuilder::<'a, HandlerStage, EXT, DB>::handler(handler_cfg), - phantom: PhantomData, - } - } - - /// Sets Builder with [`ContextWithHandlerCfg`]. - pub fn with_context_with_handler_cfg( - self, - context_with_handler_cfg: ContextWithHandlerCfg, - ) -> EvmBuilder<'a, HandlerStage, OEXT, ODB> { - EvmBuilder { - context: context_with_handler_cfg.context, - handler: EvmBuilder::<'a, HandlerStage, OEXT, ODB>::handler( - context_with_handler_cfg.cfg, - ), - phantom: PhantomData, - } - } - - /// Sets Builder with [`CfgEnvWithHandlerCfg`]. - pub fn with_cfg_env_with_handler_cfg( - mut self, - cfg_env_and_spec_id: CfgEnvWithHandlerCfg, - ) -> EvmBuilder<'a, HandlerStage, EXT, DB> { - self.context.evm.env.cfg = cfg_env_and_spec_id.cfg_env; - - EvmBuilder { - context: self.context, - handler: EvmBuilder::<'a, HandlerStage, EXT, DB>::handler( - cfg_env_and_spec_id.handler_cfg, - ), - phantom: PhantomData, - } - } - - /// Sets Builder with [`HandlerCfg`] - pub fn with_handler_cfg( - self, - handler_cfg: HandlerCfg, - ) -> EvmBuilder<'a, HandlerStage, EXT, DB> { - EvmBuilder { - context: self.context, - handler: EvmBuilder::<'a, HandlerStage, EXT, DB>::handler(handler_cfg), - phantom: PhantomData, - } - } - - /// Sets the Optimism handler with latest spec. - /// - /// If `optimism-default-handler` feature is enabled this is not needed. - #[cfg(feature = "optimism")] - pub fn optimism(mut self) -> EvmBuilder<'a, HandlerStage, EXT, DB> { - self.handler = Handler::optimism_with_spec(self.handler.cfg.spec_id); - EvmBuilder { - context: self.context, - handler: self.handler, - phantom: PhantomData, - } - } - - /// Sets the mainnet handler with latest spec. - /// - /// Enabled only with `optimism-default-handler` feature. - #[cfg(feature = "optimism-default-handler")] - pub fn mainnet(mut self) -> EvmBuilder<'a, HandlerStage, EXT, DB> { - self.handler = Handler::mainnet_with_spec(self.handler.cfg.spec_id); - EvmBuilder { - context: self.context, - handler: self.handler, - phantom: PhantomData, - } - } -} - -impl<'a, EXT, DB: Database> EvmBuilder<'a, HandlerStage, EXT, DB> { - /// Creates new builder from Evm, Evm is consumed and all field are moved to Builder. - /// It will preserve set handler and context. - /// - /// Builder is in HandlerStage and both database and external are set. - pub fn new(evm: Evm<'a, EXT, DB>) -> Self { - Self { - context: evm.context, - handler: evm.handler, - phantom: PhantomData, - } - } - - /// Sets the [`EmptyDB`] and resets the [`Handler`] to default mainnet. - pub fn reset_handler_with_empty_db(self) -> EvmBuilder<'a, HandlerStage, EXT, EmptyDB> { - EvmBuilder { - context: Context::new( - self.context.evm.with_db(EmptyDB::default()), - self.context.external, - ), - handler: EvmBuilder::<'a, HandlerStage, EXT, EmptyDB>::handler(self.handler.cfg()), - phantom: PhantomData, - } - } - - /// Resets the [`Handler`] and sets base mainnet handler. - /// - /// Enabled only with `optimism-default-handler` feature. - #[cfg(feature = "optimism-default-handler")] - pub fn reset_handler_with_mainnet(mut self) -> EvmBuilder<'a, HandlerStage, EXT, DB> { - self.handler = Handler::mainnet_with_spec(self.handler.cfg.spec_id); - EvmBuilder { - context: self.context, - handler: self.handler, - phantom: PhantomData, - } - } - - /// Sets the [`Database`] that will be used by [`Evm`] - /// and resets the [`Handler`] to default mainnet. - pub fn reset_handler_with_db( - self, - db: ODB, - ) -> EvmBuilder<'a, SetGenericStage, EXT, ODB> { - EvmBuilder { - context: Context::new(self.context.evm.with_db(db), self.context.external), - handler: EvmBuilder::<'a, SetGenericStage, EXT, ODB>::handler(self.handler.cfg()), - phantom: PhantomData, - } - } - - /// Resets [`Handler`] and sets the [`DatabaseRef`] that will be used by [`Evm`] - /// and resets the [`Handler`] to default mainnet. - pub fn reset_handler_with_ref_db( - self, - db: ODB, - ) -> EvmBuilder<'a, SetGenericStage, EXT, WrapDatabaseRef> { - EvmBuilder { - context: Context::new( - self.context.evm.with_db(WrapDatabaseRef(db)), - self.context.external, - ), - handler: EvmBuilder::<'a, SetGenericStage, EXT, WrapDatabaseRef>::handler( - self.handler.cfg(), - ), - phantom: PhantomData, - } - } - - /// Resets [`Handler`] and sets new `ExternalContext` type. - /// and resets the [`Handler`] to default mainnet. - pub fn reset_handler_with_external_context( - self, - external: OEXT, - ) -> EvmBuilder<'a, SetGenericStage, OEXT, DB> { - EvmBuilder { - context: Context::new(self.context.evm, external), - handler: EvmBuilder::<'a, SetGenericStage, OEXT, DB>::handler(self.handler.cfg()), - phantom: PhantomData, - } - } -} - -impl<'a, BuilderStage, EXT, DB: Database> EvmBuilder<'a, BuilderStage, EXT, DB> { - /// Creates the default handler. - /// - /// This is useful for adding optimism handle register. - fn handler(handler_cfg: HandlerCfg) -> Handler<'a, Context, EXT, DB> { - Handler::new(handler_cfg) - } - - /// This modifies the [EvmBuilder] to make it easy to construct an [`Evm`] with a _specific_ - /// handler. - /// - /// # Example - /// ```rust - /// use revm::{EvmBuilder, Handler, primitives::{SpecId, HandlerCfg}}; - /// use revm_interpreter::primitives::CancunSpec; - /// let builder = EvmBuilder::default(); - /// - /// // get the desired handler - /// let mainnet = Handler::mainnet::(); - /// let builder = builder.with_handler(mainnet); - /// - /// // build the EVM - /// let evm = builder.build(); - /// ``` - pub fn with_handler( - self, - handler: Handler<'a, Context, EXT, DB>, - ) -> EvmBuilder<'a, BuilderStage, EXT, DB> { - EvmBuilder { - context: self.context, - handler, - phantom: PhantomData, - } - } - - /// Builds the [`Evm`]. - pub fn build(self) -> Evm<'a, EXT, DB> { - Evm::new(self.context, self.handler) - } - - /// Register Handler that modifies the behavior of EVM. - /// Check [`Handler`] for more information. - /// - /// When called, EvmBuilder will transition from SetGenericStage to HandlerStage. - pub fn append_handler_register( - mut self, - handle_register: register::HandleRegister, - ) -> EvmBuilder<'a, HandlerStage, EXT, DB> { - self.handler - .append_handler_register(register::HandleRegisters::Plain(handle_register)); - EvmBuilder { - context: self.context, - handler: self.handler, - - phantom: PhantomData, - } - } - - /// Register Handler that modifies the behavior of EVM. - /// Check [`Handler`] for more information. - /// - /// When called, EvmBuilder will transition from SetGenericStage to HandlerStage. - pub fn append_handler_register_box( - mut self, - handle_register: register::HandleRegisterBox, - ) -> EvmBuilder<'a, HandlerStage, EXT, DB> { - self.handler - .append_handler_register(register::HandleRegisters::Box(handle_register)); - EvmBuilder { - context: self.context, - handler: self.handler, - - phantom: PhantomData, - } - } - - /// Sets specification Id , that will mark the version of EVM. - /// It represent the hard fork of ethereum. - /// - /// # Note - /// - /// When changed it will reapply all handle registers, this can be - /// expensive operation depending on registers. - pub fn with_spec_id(mut self, spec_id: SpecId) -> Self { - self.handler.modify_spec_id(spec_id); - EvmBuilder { - context: self.context, - handler: self.handler, - - phantom: PhantomData, - } - } - - /// Allows modification of Evm Database. - pub fn modify_db(mut self, f: impl FnOnce(&mut DB)) -> Self { - f(&mut self.context.evm.db); - self - } - - /// Allows modification of external context. - pub fn modify_external_context(mut self, f: impl FnOnce(&mut EXT)) -> Self { - f(&mut self.context.external); - self - } - - /// Allows modification of Evm Environment. - pub fn modify_env(mut self, f: impl FnOnce(&mut Box)) -> Self { - f(&mut self.context.evm.env); - self - } - - /// Sets Evm Environment. - pub fn with_env(mut self, env: Box) -> Self { - self.context.evm.env = env; - self - } - - /// Allows modification of Evm's Transaction Environment. - pub fn modify_tx_env(mut self, f: impl FnOnce(&mut TxEnv)) -> Self { - f(&mut self.context.evm.env.tx); - self - } - - /// Sets Evm's Transaction Environment. - pub fn with_tx_env(mut self, tx_env: TxEnv) -> Self { - self.context.evm.env.tx = tx_env; - self - } - - /// Allows modification of Evm's Block Environment. - pub fn modify_block_env(mut self, f: impl FnOnce(&mut BlockEnv)) -> Self { - f(&mut self.context.evm.env.block); - self - } - - /// Sets Evm's Block Environment. - pub fn with_block_env(mut self, block_env: BlockEnv) -> Self { - self.context.evm.env.block = block_env; - self - } - - /// Allows modification of Evm's Config Environment. - pub fn modify_cfg_env(mut self, f: impl FnOnce(&mut CfgEnv)) -> Self { - f(&mut self.context.evm.env.cfg); - self - } - - /// Clears Environment of EVM. - pub fn with_clear_env(mut self) -> Self { - self.context.evm.env.clear(); - self - } - - /// Clears Transaction environment of EVM. - pub fn with_clear_tx_env(mut self) -> Self { - self.context.evm.env.tx.clear(); - self - } - /// Clears Block environment of EVM. - pub fn with_clear_block_env(mut self) -> Self { - self.context.evm.env.block.clear(); - self - } - - /// Resets [`Handler`] to default mainnet. - pub fn reset_handler(mut self) -> Self { - self.handler = Self::handler(self.handler.cfg()); - self - } -} - -#[cfg(test)] -mod test { - use super::SpecId; - use crate::{ - db::EmptyDB, - inspector::inspector_handle_register, - inspectors::NoOpInspector, - primitives::{ - address, AccountInfo, Address, Bytecode, Bytes, PrecompileResult, TransactTo, U256, - }, - Context, ContextPrecompile, ContextStatefulPrecompile, Evm, InMemoryDB, InnerEvmContext, - }; - use revm_interpreter::{gas, Host, Interpreter}; - use std::{cell::RefCell, rc::Rc, sync::Arc}; - - /// Custom evm context - #[derive(Default, Clone, Debug)] - pub(crate) struct CustomContext { - pub(crate) inner: Rc>, - } - - #[test] - fn simple_add_stateful_instruction() { - let code = Bytecode::new_raw([0xEF, 0x00].into()); - let code_hash = code.hash_slow(); - let to_addr = address!("ffffffffffffffffffffffffffffffffffffffff"); - - // initialize the custom context and make sure it's zero - let custom_context = CustomContext::default(); - assert_eq!(*custom_context.inner.borrow(), 0); - - let to_capture = custom_context.clone(); - let mut evm = Evm::builder() - .with_db(InMemoryDB::default()) - .modify_db(|db| { - db.insert_account_info(to_addr, AccountInfo::new(U256::ZERO, 0, code_hash, code)) - }) - .modify_tx_env(|tx| tx.transact_to = TransactTo::Call(to_addr)) - // we need to use handle register box to capture the custom context in the handle - // register - .append_handler_register_box(Box::new(move |handler| { - let custom_context = to_capture.clone(); - - // we need to use a box to capture the custom context in the instruction - let custom_instruction = Box::new( - move |_interp: &mut Interpreter, _host: &mut Context<(), InMemoryDB>| { - // modify the value - let mut inner = custom_context.inner.borrow_mut(); - *inner += 1; - }, - ); - - // need to ensure the instruction table is a boxed instruction table so that we - // can insert the custom instruction as a boxed instruction - handler - .instruction_table - .insert_boxed(0xEF, custom_instruction); - })) - .build(); - - let _result_and_state = evm.transact().unwrap(); - - // ensure the custom context was modified - assert_eq!(*custom_context.inner.borrow(), 1); - } - - #[test] - fn simple_add_instruction() { - const CUSTOM_INSTRUCTION_COST: u64 = 133; - const INITIAL_TX_GAS: u64 = 21000; - const EXPECTED_RESULT_GAS: u64 = INITIAL_TX_GAS + CUSTOM_INSTRUCTION_COST; - - fn custom_instruction(interp: &mut Interpreter, _host: &mut impl Host) { - // just spend some gas - gas!(interp, CUSTOM_INSTRUCTION_COST); - } - - let code = Bytecode::new_raw([0xEF, 0x00].into()); - let code_hash = code.hash_slow(); - let to_addr = address!("ffffffffffffffffffffffffffffffffffffffff"); - - let mut evm = Evm::builder() - .with_db(InMemoryDB::default()) - .modify_db(|db| { - db.insert_account_info(to_addr, AccountInfo::new(U256::ZERO, 0, code_hash, code)) - }) - .modify_tx_env(|tx| tx.transact_to = TransactTo::Call(to_addr)) - .append_handler_register(|handler| { - handler.instruction_table.insert(0xEF, custom_instruction) - }) - .build(); - - let result_and_state = evm.transact().unwrap(); - assert_eq!(result_and_state.result.gas_used(), EXPECTED_RESULT_GAS); - } - - #[test] - fn simple_build() { - // build without external with latest spec - Evm::builder().build(); - // build with empty db - Evm::builder().with_empty_db().build(); - // build with_db - Evm::builder().with_db(EmptyDB::default()).build(); - // build with empty external - Evm::builder().with_empty_db().build(); - // build with some external - Evm::builder() - .with_empty_db() - .with_external_context(()) - .build(); - // build with spec - Evm::builder() - .with_empty_db() - .with_spec_id(SpecId::HOMESTEAD) - .build(); - - // with with Env change in multiple places - Evm::builder() - .with_empty_db() - .modify_tx_env(|tx| tx.gas_limit = 10) - .build(); - Evm::builder().modify_tx_env(|tx| tx.gas_limit = 10).build(); - Evm::builder() - .with_empty_db() - .modify_tx_env(|tx| tx.gas_limit = 10) - .build(); - Evm::builder() - .with_empty_db() - .modify_tx_env(|tx| tx.gas_limit = 10) - .build(); - - // with inspector handle - Evm::builder() - .with_empty_db() - .with_external_context(NoOpInspector) - .append_handler_register(inspector_handle_register) - .build(); - - // create the builder - let evm = Evm::builder() - .with_db(EmptyDB::default()) - .with_external_context(NoOpInspector) - .append_handler_register(inspector_handle_register) - // this would not compile - // .with_db(..) - .build(); - - let Context { external: _, .. } = evm.into_context(); - } - - #[test] - fn build_modify_build() { - // build evm - let evm = Evm::builder() - .with_empty_db() - .with_spec_id(SpecId::HOMESTEAD) - .build(); - - // modify evm - let evm = evm.modify().with_spec_id(SpecId::FRONTIER).build(); - let _ = evm - .modify() - .modify_tx_env(|tx| tx.chain_id = Some(2)) - .build(); - } - - #[test] - fn build_custom_precompile() { - struct CustomPrecompile; - - impl ContextStatefulPrecompile for CustomPrecompile { - fn call( - &self, - _input: &Bytes, - _gas_price: u64, - _context: &mut InnerEvmContext, - ) -> PrecompileResult { - Ok((10, Bytes::new())) - } - } - - let mut evm = Evm::builder() - .with_empty_db() - .with_spec_id(SpecId::HOMESTEAD) - .append_handler_register(|handler| { - let precompiles = handler.pre_execution.load_precompiles(); - handler.pre_execution.load_precompiles = Arc::new(move || { - let mut precompiles = precompiles.clone(); - precompiles.extend([( - Address::ZERO, - ContextPrecompile::ContextStateful(Arc::new(CustomPrecompile)), - )]); - precompiles - }); - }) - .build(); - - evm.transact().unwrap(); - } -} diff --git a/crates/revm/src/context.rs b/crates/revm/src/context.rs deleted file mode 100644 index 6cdbdfe6fa..0000000000 --- a/crates/revm/src/context.rs +++ /dev/null @@ -1,195 +0,0 @@ -mod context_precompiles; -pub(crate) mod evm_context; -mod inner_evm_context; - -pub use context_precompiles::{ - ContextPrecompile, ContextPrecompiles, ContextStatefulPrecompile, ContextStatefulPrecompileArc, - ContextStatefulPrecompileBox, ContextStatefulPrecompileMut, -}; -pub use evm_context::EvmContext; -pub use inner_evm_context::InnerEvmContext; -use revm_interpreter::as_usize_saturated; - -use crate::{ - db::{Database, EmptyDB}, - interpreter::{Host, LoadAccountResult, SStoreResult, SelfDestructResult}, - primitives::{Address, Bytecode, Env, HandlerCfg, Log, B256, BLOCK_HASH_HISTORY, U256}, -}; -use std::boxed::Box; - -/// Main Context structure that contains both EvmContext and External context. -pub struct Context { - /// Evm Context (internal context). - pub evm: EvmContext, - /// External contexts. - pub external: EXT, -} - -impl Clone for Context -where - DB::Error: Clone, -{ - fn clone(&self) -> Self { - Self { - evm: self.evm.clone(), - external: self.external.clone(), - } - } -} - -impl Default for Context<(), EmptyDB> { - fn default() -> Self { - Self::new_empty() - } -} - -impl Context<(), EmptyDB> { - /// Creates empty context. This is useful for testing. - pub fn new_empty() -> Context<(), EmptyDB> { - Context { - evm: EvmContext::new(EmptyDB::new()), - external: (), - } - } -} - -impl Context<(), DB> { - /// Creates new context with database. - pub fn new_with_db(db: DB) -> Context<(), DB> { - Context { - evm: EvmContext::new_with_env(db, Box::default()), - external: (), - } - } -} - -impl Context { - /// Creates new context with external and database. - pub fn new(evm: EvmContext, external: EXT) -> Context { - Context { evm, external } - } -} - -/// Context with handler configuration. -pub struct ContextWithHandlerCfg { - /// Context of execution. - pub context: Context, - /// Handler configuration. - pub cfg: HandlerCfg, -} - -impl ContextWithHandlerCfg { - /// Creates new context with handler configuration. - pub fn new(context: Context, cfg: HandlerCfg) -> Self { - Self { cfg, context } - } -} - -impl Clone for ContextWithHandlerCfg -where - DB::Error: Clone, -{ - fn clone(&self) -> Self { - Self { - context: self.context.clone(), - cfg: self.cfg, - } - } -} - -impl Host for Context { - fn env(&self) -> &Env { - &self.evm.env - } - - fn env_mut(&mut self) -> &mut Env { - &mut self.evm.env - } - - fn block_hash(&mut self, number: U256) -> Option { - let block_number = as_usize_saturated!(self.env().block.number); - let requested_number = as_usize_saturated!(number); - - let Some(diff) = block_number.checked_sub(requested_number) else { - return Some(B256::ZERO); - }; - - // blockhash should push zero if number is same as current block number. - if diff == 0 { - return Some(B256::ZERO); - } - - if diff <= BLOCK_HASH_HISTORY { - return self - .evm - .block_hash(number) - .map_err(|e| self.evm.error = Err(e)) - .ok(); - } - - Some(B256::ZERO) - } - - fn load_account(&mut self, address: Address) -> Option { - self.evm - .load_account_exist(address) - .map_err(|e| self.evm.error = Err(e)) - .ok() - } - - fn balance(&mut self, address: Address) -> Option<(U256, bool)> { - self.evm - .balance(address) - .map_err(|e| self.evm.error = Err(e)) - .ok() - } - - fn code(&mut self, address: Address) -> Option<(Bytecode, bool)> { - self.evm - .code(address) - .map_err(|e| self.evm.error = Err(e)) - .ok() - } - - fn code_hash(&mut self, address: Address) -> Option<(B256, bool)> { - self.evm - .code_hash(address) - .map_err(|e| self.evm.error = Err(e)) - .ok() - } - - fn sload(&mut self, address: Address, index: U256) -> Option<(U256, bool)> { - self.evm - .sload(address, index) - .map_err(|e| self.evm.error = Err(e)) - .ok() - } - - fn sstore(&mut self, address: Address, index: U256, value: U256) -> Option { - self.evm - .sstore(address, index, value) - .map_err(|e| self.evm.error = Err(e)) - .ok() - } - - fn tload(&mut self, address: Address, index: U256) -> U256 { - self.evm.tload(address, index) - } - - fn tstore(&mut self, address: Address, index: U256, value: U256) { - self.evm.tstore(address, index, value) - } - - fn log(&mut self, log: Log) { - self.evm.journaled_state.log(log); - } - - fn selfdestruct(&mut self, address: Address, target: Address) -> Option { - self.evm - .inner - .journaled_state - .selfdestruct(address, target, &mut self.evm.inner.db) - .map_err(|e| self.evm.error = Err(e)) - .ok() - } -} diff --git a/crates/revm/src/context/context_precompiles.rs b/crates/revm/src/context/context_precompiles.rs deleted file mode 100644 index a6fdc5e67e..0000000000 --- a/crates/revm/src/context/context_precompiles.rs +++ /dev/null @@ -1,153 +0,0 @@ -use crate::{ - precompile::{Precompile, PrecompileResult}, - primitives::{db::Database, Address, Bytes, HashMap}, -}; -use core::ops::{Deref, DerefMut}; -use dyn_clone::DynClone; -use revm_precompile::Precompiles; -use std::{boxed::Box, sync::Arc}; - -use super::InnerEvmContext; - -/// Precompile and its handlers. -pub enum ContextPrecompile { - /// Ordinary precompiles - Ordinary(Precompile), - /// Stateful precompile that is Arc over [`ContextStatefulPrecompile`] trait. - /// It takes a reference to input, gas limit and Context. - ContextStateful(ContextStatefulPrecompileArc), - /// Mutable stateful precompile that is Box over [`ContextStatefulPrecompileMut`] trait. - /// It takes a reference to input, gas limit and context. - ContextStatefulMut(ContextStatefulPrecompileBox), -} - -impl Clone for ContextPrecompile { - fn clone(&self) -> Self { - match self { - Self::Ordinary(arg0) => Self::Ordinary(arg0.clone()), - Self::ContextStateful(arg0) => Self::ContextStateful(arg0.clone()), - Self::ContextStatefulMut(arg0) => Self::ContextStatefulMut(arg0.clone()), - } - } -} - -#[derive(Clone)] -pub struct ContextPrecompiles { - inner: HashMap>, -} - -impl ContextPrecompiles { - /// Returns precompiles addresses. - #[inline] - pub fn addresses(&self) -> impl Iterator { - self.inner.keys() - } - - /// Extends the precompiles with the given precompiles. - /// - /// Other precompiles with overwrite existing precompiles. - #[inline] - pub fn extend( - &mut self, - other: impl IntoIterator)>>, - ) { - self.inner.extend(other.into_iter().map(Into::into)); - } - - /// Call precompile and executes it. Returns the result of the precompile execution. - /// None if the precompile does not exist. - #[inline] - pub fn call( - &mut self, - addess: Address, - bytes: &Bytes, - gas_price: u64, - evmctx: &mut InnerEvmContext, - ) -> Option { - let precompile = self.inner.get_mut(&addess)?; - - match precompile { - ContextPrecompile::Ordinary(p) => Some(p.call(bytes, gas_price, &evmctx.env)), - ContextPrecompile::ContextStatefulMut(p) => Some(p.call_mut(bytes, gas_price, evmctx)), - ContextPrecompile::ContextStateful(p) => Some(p.call(bytes, gas_price, evmctx)), - } - } -} - -impl Default for ContextPrecompiles { - fn default() -> Self { - Self { - inner: Default::default(), - } - } -} - -impl Deref for ContextPrecompiles { - type Target = HashMap>; - - fn deref(&self) -> &Self::Target { - &self.inner - } -} - -impl DerefMut for ContextPrecompiles { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.inner - } -} - -/// Context aware stateful precompile trait. It is used to create -/// a arc precompile in [`ContextPrecompile`]. -pub trait ContextStatefulPrecompile: Sync + Send { - fn call( - &self, - bytes: &Bytes, - gas_price: u64, - evmctx: &mut InnerEvmContext, - ) -> PrecompileResult; -} - -/// Context aware mutable stateful precompile trait. It is used to create -/// a boxed precompile in [`ContextPrecompile`]. -pub trait ContextStatefulPrecompileMut: DynClone + Send + Sync { - fn call_mut( - &mut self, - bytes: &Bytes, - gas_price: u64, - evmctx: &mut InnerEvmContext, - ) -> PrecompileResult; -} - -dyn_clone::clone_trait_object!( ContextStatefulPrecompileMut); - -/// Arc over context stateful precompile. -pub type ContextStatefulPrecompileArc = Arc>; - -/// Box over context mutable stateful precompile -pub type ContextStatefulPrecompileBox = Box>; - -impl From for ContextPrecompile { - fn from(p: Precompile) -> Self { - ContextPrecompile::Ordinary(p) - } -} - -impl From for ContextPrecompiles { - fn from(p: Precompiles) -> Self { - ContextPrecompiles { - inner: p.inner.into_iter().map(|(k, v)| (k, v.into())).collect(), - } - } -} - -impl From<&Precompiles> for ContextPrecompiles { - fn from(p: &Precompiles) -> Self { - ContextPrecompiles { - inner: p - .inner - .iter() - .map(|(&k, v)| (k, v.clone().into())) - .collect(), - } - } -} diff --git a/crates/revm/src/context/evm_context.rs b/crates/revm/src/context/evm_context.rs deleted file mode 100644 index b92d711da8..0000000000 --- a/crates/revm/src/context/evm_context.rs +++ /dev/null @@ -1,400 +0,0 @@ -use revm_interpreter::CallValue; - -use super::inner_evm_context::InnerEvmContext; -use crate::{ - db::Database, - interpreter::{ - return_ok, CallInputs, Contract, Gas, InstructionResult, Interpreter, InterpreterResult, - }, - primitives::{Address, Bytes, EVMError, Env, HashSet, U256}, - ContextPrecompiles, FrameOrResult, CALL_STACK_LIMIT, -}; -use core::{ - fmt, - ops::{Deref, DerefMut}, -}; -use std::boxed::Box; - -/// EVM context that contains the inner EVM context and precompiles. -pub struct EvmContext { - /// Inner EVM context. - pub inner: InnerEvmContext, - /// Precompiles that are available for evm. - pub precompiles: ContextPrecompiles, -} - -impl Clone for EvmContext -where - DB::Error: Clone, -{ - fn clone(&self) -> Self { - Self { - inner: self.inner.clone(), - precompiles: ContextPrecompiles::default(), - } - } -} - -impl fmt::Debug for EvmContext -where - DB: Database + fmt::Debug, - DB::Error: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("EvmContext") - .field("inner", &self.inner) - .field("precompiles", &self.inner) - .finish_non_exhaustive() - } -} - -impl Deref for EvmContext { - type Target = InnerEvmContext; - - fn deref(&self) -> &Self::Target { - &self.inner - } -} - -impl DerefMut for EvmContext { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.inner - } -} - -impl EvmContext { - /// Create new context with database. - pub fn new(db: DB) -> Self { - Self { - inner: InnerEvmContext::new(db), - precompiles: ContextPrecompiles::default(), - } - } - - /// Creates a new context with the given environment and database. - #[inline] - pub fn new_with_env(db: DB, env: Box) -> Self { - Self { - inner: InnerEvmContext::new_with_env(db, env), - precompiles: ContextPrecompiles::default(), - } - } - - /// Sets the database. - /// - /// Note that this will ignore the previous `error` if set. - #[inline] - pub fn with_db(self, db: ODB) -> EvmContext { - EvmContext { - inner: self.inner.with_db(db), - precompiles: ContextPrecompiles::default(), - } - } - - /// Sets precompiles - #[inline] - pub fn set_precompiles(&mut self, precompiles: ContextPrecompiles) { - // set warm loaded addresses. - self.journaled_state.warm_preloaded_addresses = - precompiles.addresses().copied().collect::>(); - self.precompiles = precompiles; - } - - /// Call precompile contract - #[inline] - fn call_precompile( - &mut self, - address: Address, - input_data: &Bytes, - gas: Gas, - ) -> Option { - let out = self - .precompiles - .call(address, input_data, gas.limit(), &mut self.inner)?; - - let mut result = InterpreterResult { - result: InstructionResult::Return, - gas, - output: Bytes::new(), - }; - - match out { - Ok((gas_used, data)) => { - if result.gas.record_cost(gas_used) { - result.result = InstructionResult::Return; - result.output = data; - } else { - result.result = InstructionResult::PrecompileOOG; - } - } - Err(e) => { - result.result = if e == crate::precompile::Error::OutOfGas { - InstructionResult::PrecompileOOG - } else { - InstructionResult::PrecompileError - }; - } - } - Some(result) - } - - /// Make call frame - #[inline] - pub fn make_call_frame( - &mut self, - inputs: &CallInputs, - ) -> Result> { - let gas = Gas::new(inputs.gas_limit); - - let return_result = |instruction_result: InstructionResult| { - Ok(FrameOrResult::new_call_result( - InterpreterResult { - result: instruction_result, - gas, - output: Bytes::new(), - }, - inputs.return_memory_offset.clone(), - )) - }; - - // Check depth - if self.journaled_state.depth() > CALL_STACK_LIMIT { - return return_result(InstructionResult::CallTooDeep); - } - - let (account, _) = self - .inner - .journaled_state - .load_code(inputs.bytecode_address, &mut self.inner.db)?; - let code_hash = account.info.code_hash(); - let bytecode = account.info.code.clone().unwrap_or_default(); - - // Create subroutine checkpoint - let checkpoint = self.journaled_state.checkpoint(); - - // Touch address. For "EIP-158 State Clear", this will erase empty accounts. - match inputs.value { - // if transfer value is zero, do the touch. - CallValue::Transfer(value) if value == U256::ZERO => { - self.load_account(inputs.target_address)?; - self.journaled_state.touch(&inputs.target_address); - } - CallValue::Transfer(value) => { - // Transfer value from caller to called account - if let Some(result) = self.inner.journaled_state.transfer( - &inputs.caller, - &inputs.target_address, - value, - &mut self.inner.db, - )? { - self.journaled_state.checkpoint_revert(checkpoint); - return return_result(result); - } - } - _ => {} - }; - - if let Some(result) = self.call_precompile(inputs.bytecode_address, &inputs.input, gas) { - if matches!(result.result, return_ok!()) { - self.journaled_state.checkpoint_commit(); - } else { - self.journaled_state.checkpoint_revert(checkpoint); - } - Ok(FrameOrResult::new_call_result( - result, - inputs.return_memory_offset.clone(), - )) - } else if !bytecode.is_empty() { - let contract = - Contract::new_with_context(inputs.input.clone(), bytecode, Some(code_hash), inputs); - // Create interpreter and executes call and push new CallStackFrame. - Ok(FrameOrResult::new_call_frame( - inputs.return_memory_offset.clone(), - checkpoint, - Interpreter::new(contract, gas.limit(), inputs.is_static), - )) - } else { - self.journaled_state.checkpoint_commit(); - return_result(InstructionResult::Stop) - } - } -} - -/// Test utilities for the [`EvmContext`]. -#[cfg(any(test, feature = "test-utils"))] -pub(crate) mod test_utils { - use super::*; - use crate::{ - db::{CacheDB, EmptyDB}, - journaled_state::JournaledState, - primitives::{address, SpecId, B256}, - }; - - /// Mock caller address. - pub const MOCK_CALLER: Address = address!("0000000000000000000000000000000000000000"); - - /// Creates `CallInputs` that calls a provided contract address from the mock caller. - pub fn create_mock_call_inputs(to: Address) -> CallInputs { - CallInputs { - input: Bytes::new(), - gas_limit: 0, - bytecode_address: to, - target_address: to, - caller: MOCK_CALLER, - value: CallValue::Transfer(U256::ZERO), - scheme: revm_interpreter::CallScheme::Call, - is_eof: false, - is_static: false, - return_memory_offset: 0..0, - } - } - - /// Creates an evm context with a cache db backend. - /// Additionally loads the mock caller account into the db, - /// and sets the balance to the provided U256 value. - pub fn create_cache_db_evm_context_with_balance( - env: Box, - mut db: CacheDB, - balance: U256, - ) -> EvmContext> { - db.insert_account_info( - test_utils::MOCK_CALLER, - crate::primitives::AccountInfo { - nonce: 0, - balance, - code_hash: B256::default(), - code: None, - }, - ); - create_cache_db_evm_context(env, db) - } - - /// Creates a cached db evm context. - pub fn create_cache_db_evm_context( - env: Box, - db: CacheDB, - ) -> EvmContext> { - EvmContext { - inner: InnerEvmContext { - env, - journaled_state: JournaledState::new(SpecId::CANCUN, HashSet::new()), - db, - error: Ok(()), - #[cfg(feature = "optimism")] - l1_block_info: None, - }, - precompiles: ContextPrecompiles::default(), - } - } - - /// Returns a new `EvmContext` with an empty journaled state. - pub fn create_empty_evm_context(env: Box, db: EmptyDB) -> EvmContext { - EvmContext { - inner: InnerEvmContext { - env, - journaled_state: JournaledState::new(SpecId::CANCUN, HashSet::new()), - db, - error: Ok(()), - #[cfg(feature = "optimism")] - l1_block_info: None, - }, - precompiles: ContextPrecompiles::default(), - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::{ - db::{CacheDB, EmptyDB}, - primitives::{address, Bytecode}, - Frame, JournalEntry, - }; - use std::boxed::Box; - use test_utils::*; - - // Tests that the `EVMContext::make_call_frame` function returns an error if the - // call stack is too deep. - #[test] - fn test_make_call_frame_stack_too_deep() { - let env = Env::default(); - let db = EmptyDB::default(); - let mut context = test_utils::create_empty_evm_context(Box::new(env), db); - context.journaled_state.depth = CALL_STACK_LIMIT as usize + 1; - let contract = address!("dead10000000000000000000000000000001dead"); - let call_inputs = test_utils::create_mock_call_inputs(contract); - let res = context.make_call_frame(&call_inputs); - let Ok(FrameOrResult::Result(err)) = res else { - panic!("Expected FrameOrResult::Result"); - }; - assert_eq!( - err.interpreter_result().result, - InstructionResult::CallTooDeep - ); - } - - // Tests that the `EVMContext::make_call_frame` function returns an error if the - // transfer fails on the journaled state. It also verifies that the revert was - // checkpointed on the journaled state correctly. - #[test] - fn test_make_call_frame_transfer_revert() { - let env = Env::default(); - let db = EmptyDB::default(); - let mut evm_context = test_utils::create_empty_evm_context(Box::new(env), db); - let contract = address!("dead10000000000000000000000000000001dead"); - let mut call_inputs = test_utils::create_mock_call_inputs(contract); - call_inputs.value = CallValue::Transfer(U256::from(1)); - let res = evm_context.make_call_frame(&call_inputs); - let Ok(FrameOrResult::Result(result)) = res else { - panic!("Expected FrameOrResult::Result"); - }; - assert_eq!( - result.interpreter_result().result, - InstructionResult::OutOfFunds - ); - let checkpointed = vec![vec![JournalEntry::AccountLoaded { address: contract }]]; - assert_eq!(evm_context.journaled_state.journal, checkpointed); - assert_eq!(evm_context.journaled_state.depth, 0); - } - - #[test] - fn test_make_call_frame_missing_code_context() { - let env = Env::default(); - let cdb = CacheDB::new(EmptyDB::default()); - let bal = U256::from(3_000_000_000_u128); - let mut context = create_cache_db_evm_context_with_balance(Box::new(env), cdb, bal); - let contract = address!("dead10000000000000000000000000000001dead"); - let call_inputs = test_utils::create_mock_call_inputs(contract); - let res = context.make_call_frame(&call_inputs); - let Ok(FrameOrResult::Result(result)) = res else { - panic!("Expected FrameOrResult::Result"); - }; - assert_eq!(result.interpreter_result().result, InstructionResult::Stop); - } - - #[test] - fn test_make_call_frame_succeeds() { - let env = Env::default(); - let mut cdb = CacheDB::new(EmptyDB::default()); - let bal = U256::from(3_000_000_000_u128); - let by = Bytecode::new_raw(Bytes::from(vec![0x60, 0x00, 0x60, 0x00])); - let contract = address!("dead10000000000000000000000000000001dead"); - cdb.insert_account_info( - contract, - crate::primitives::AccountInfo { - nonce: 0, - balance: bal, - code_hash: by.clone().hash_slow(), - code: Some(by), - }, - ); - let mut evm_context = create_cache_db_evm_context_with_balance(Box::new(env), cdb, bal); - let call_inputs = test_utils::create_mock_call_inputs(contract); - let res = evm_context.make_call_frame(&call_inputs); - let Ok(FrameOrResult::Frame(Frame::Call(call_frame))) = res else { - panic!("Expected FrameOrResult::Frame(Frame::Call(..))"); - }; - assert_eq!(call_frame.return_memory_range, 0..0,); - } -} diff --git a/crates/revm/src/context/inner_evm_context.rs b/crates/revm/src/context/inner_evm_context.rs deleted file mode 100644 index 109b16a7a6..0000000000 --- a/crates/revm/src/context/inner_evm_context.rs +++ /dev/null @@ -1,507 +0,0 @@ -use crate::{ - db::Database, - interpreter::{ - analysis::to_analysed, gas, return_ok, Contract, CreateInputs, EOFCreateInput, Gas, - InstructionResult, Interpreter, InterpreterResult, LoadAccountResult, SStoreResult, - SelfDestructResult, MAX_CODE_SIZE, - }, - journaled_state::JournaledState, - primitives::{ - keccak256, Account, Address, AnalysisKind, Bytecode, Bytes, CreateScheme, EVMError, Env, - Eof, HashSet, Spec, - SpecId::{self, *}, - B256, U256, - }, - FrameOrResult, JournalCheckpoint, CALL_STACK_LIMIT, -}; -use std::boxed::Box; - -/// EVM contexts contains data that EVM needs for execution. -#[derive(Debug)] -pub struct InnerEvmContext { - /// EVM Environment contains all the information about config, block and transaction that - /// evm needs. - pub env: Box, - /// EVM State with journaling support. - pub journaled_state: JournaledState, - /// Database to load data from. - pub db: DB, - /// Error that happened during execution. - pub error: Result<(), EVMError>, - /// Used as temporary value holder to store L1 block info. - #[cfg(feature = "optimism")] - pub l1_block_info: Option, -} - -impl Clone for InnerEvmContext -where - DB::Error: Clone, -{ - fn clone(&self) -> Self { - Self { - env: self.env.clone(), - journaled_state: self.journaled_state.clone(), - db: self.db.clone(), - error: self.error.clone(), - #[cfg(feature = "optimism")] - l1_block_info: self.l1_block_info.clone(), - } - } -} - -impl InnerEvmContext { - pub fn new(db: DB) -> Self { - Self { - env: Box::default(), - journaled_state: JournaledState::new(SpecId::LATEST, HashSet::new()), - db, - error: Ok(()), - #[cfg(feature = "optimism")] - l1_block_info: None, - } - } - - /// Creates a new context with the given environment and database. - #[inline] - pub fn new_with_env(db: DB, env: Box) -> Self { - Self { - env, - journaled_state: JournaledState::new(SpecId::LATEST, HashSet::new()), - db, - error: Ok(()), - #[cfg(feature = "optimism")] - l1_block_info: None, - } - } - - /// Sets the database. - /// - /// Note that this will ignore the previous `error` if set. - #[inline] - pub fn with_db(self, db: ODB) -> InnerEvmContext { - InnerEvmContext { - env: self.env, - journaled_state: self.journaled_state, - db, - error: Ok(()), - #[cfg(feature = "optimism")] - l1_block_info: self.l1_block_info, - } - } - - /// Returns the configured EVM spec ID. - #[inline] - pub const fn spec_id(&self) -> SpecId { - self.journaled_state.spec - } - - /// Load access list for berlin hard fork. - /// - /// Loading of accounts/storages is needed to make them warm. - #[inline] - pub fn load_access_list(&mut self) -> Result<(), EVMError> { - for (address, slots) in self.env.tx.access_list.iter() { - self.journaled_state - .initial_account_load(*address, slots, &mut self.db)?; - } - Ok(()) - } - - /// Return environment. - #[inline] - pub fn env(&mut self) -> &mut Env { - &mut self.env - } - - /// Returns the error by replacing it with `Ok(())`, if any. - #[inline] - pub fn take_error(&mut self) -> Result<(), EVMError> { - core::mem::replace(&mut self.error, Ok(())) - } - - /// Fetch block hash from database. - #[inline] - pub fn block_hash(&mut self, number: U256) -> Result> { - self.db.block_hash(number).map_err(EVMError::Database) - } - - /// Mark account as touched as only touched accounts will be added to state. - #[inline] - pub fn touch(&mut self, address: &Address) { - self.journaled_state.touch(address); - } - - /// Loads an account into memory. Returns `true` if it is cold accessed. - #[inline] - pub fn load_account( - &mut self, - address: Address, - ) -> Result<(&mut Account, bool), EVMError> { - self.journaled_state.load_account(address, &mut self.db) - } - - /// Load account from database to JournaledState. - /// - /// Return boolean pair where first is `is_cold` second bool `exists`. - #[inline] - pub fn load_account_exist( - &mut self, - address: Address, - ) -> Result> { - self.journaled_state - .load_account_exist(address, &mut self.db) - } - - /// Return account balance and is_cold flag. - #[inline] - pub fn balance(&mut self, address: Address) -> Result<(U256, bool), EVMError> { - self.journaled_state - .load_account(address, &mut self.db) - .map(|(acc, is_cold)| (acc.info.balance, is_cold)) - } - - /// Return account code and if address is cold loaded. - #[inline] - pub fn code(&mut self, address: Address) -> Result<(Bytecode, bool), EVMError> { - self.journaled_state - .load_code(address, &mut self.db) - .map(|(a, is_cold)| (a.info.code.clone().unwrap(), is_cold)) - } - - /// Get code hash of address. - #[inline] - pub fn code_hash(&mut self, address: Address) -> Result<(B256, bool), EVMError> { - let (acc, is_cold) = self.journaled_state.load_code(address, &mut self.db)?; - if acc.is_empty() { - return Ok((B256::ZERO, is_cold)); - } - Ok((acc.info.code_hash, is_cold)) - } - - /// Load storage slot, if storage is not present inside the account then it will be loaded from database. - #[inline] - pub fn sload( - &mut self, - address: Address, - index: U256, - ) -> Result<(U256, bool), EVMError> { - // account is always warm. reference on that statement https://eips.ethereum.org/EIPS/eip-2929 see `Note 2:` - self.journaled_state.sload(address, index, &mut self.db) - } - - /// Storage change of storage slot, before storing `sload` will be called for that slot. - #[inline] - pub fn sstore( - &mut self, - address: Address, - index: U256, - value: U256, - ) -> Result> { - self.journaled_state - .sstore(address, index, value, &mut self.db) - } - - /// Returns transient storage value. - #[inline] - pub fn tload(&mut self, address: Address, index: U256) -> U256 { - self.journaled_state.tload(address, index) - } - - /// Stores transient storage value. - #[inline] - pub fn tstore(&mut self, address: Address, index: U256, value: U256) { - self.journaled_state.tstore(address, index, value) - } - - /// Selfdestructs the account. - #[inline] - pub fn selfdestruct( - &mut self, - address: Address, - target: Address, - ) -> Result> { - self.journaled_state - .selfdestruct(address, target, &mut self.db) - } - - /// Make create frame. - #[inline] - pub fn make_eofcreate_frame( - &mut self, - spec_id: SpecId, - inputs: &EOFCreateInput, - ) -> Result> { - let return_error = |e| { - Ok(FrameOrResult::new_eofcreate_result( - InterpreterResult { - result: e, - gas: Gas::new(inputs.gas_limit), - output: Bytes::new(), - }, - inputs.created_address, - inputs.return_memory_range.clone(), - )) - }; - - // Check depth - if self.journaled_state.depth() > CALL_STACK_LIMIT { - return return_error(InstructionResult::CallTooDeep); - } - - // Fetch balance of caller. - let (caller_balance, _) = self.balance(inputs.caller)?; - - // Check if caller has enough balance to send to the created contract. - if caller_balance < inputs.value { - return return_error(InstructionResult::OutOfFunds); - } - - // Increase nonce of caller and check if it overflows - if self.journaled_state.inc_nonce(inputs.caller).is_none() { - // can't happen on mainnet. - return return_error(InstructionResult::Return); - } - - // Load account so it needs to be marked as warm for access list. - self.journaled_state - .load_account(inputs.created_address, &mut self.db)?; - - // create account, transfer funds and make the journal checkpoint. - let checkpoint = match self.journaled_state.create_account_checkpoint( - inputs.caller, - inputs.created_address, - inputs.value, - spec_id, - ) { - Ok(checkpoint) => checkpoint, - Err(e) => { - return return_error(e); - } - }; - - let contract = Contract::new( - Bytes::new(), - // fine to clone as it is Bytes. - Bytecode::Eof(inputs.eof_init_code.clone()), - None, - inputs.created_address, - inputs.caller, - inputs.value, - ); - - let mut interpreter = Interpreter::new(contract, inputs.gas_limit, false); - // EOF init will enable RETURNCONTRACT opcode. - interpreter.set_is_eof_init(); - - Ok(FrameOrResult::new_eofcreate_frame( - inputs.created_address, - inputs.return_memory_range.clone(), - checkpoint, - interpreter, - )) - } - - /// If error is present revert changes, otherwise save EOF bytecode. - pub fn eofcreate_return( - &mut self, - interpreter_result: &mut InterpreterResult, - address: Address, - journal_checkpoint: JournalCheckpoint, - ) { - // Note we still execute RETURN opcode and return the bytes. - // In EOF those opcodes should abort execution. - // - // In RETURN gas is still protecting us from ddos and in oog, - // behaviour will be same as if it failed on return. - // - // Bytes of RETURN will drained in `insert_eofcreate_outcome`. - if interpreter_result.result != InstructionResult::ReturnContract { - self.journaled_state.checkpoint_revert(journal_checkpoint); - return; - } - - // commit changes reduces depth by -1. - self.journaled_state.checkpoint_commit(); - - // decode bytecode has a performance hit, but it has reasonable restrains. - let bytecode = - Eof::decode(interpreter_result.output.clone()).expect("Eof is already verified"); - - // eof bytecode is going to be hashed. - self.journaled_state - .set_code(address, Bytecode::Eof(bytecode)); - } - - /// Make create frame. - #[inline] - pub fn make_create_frame( - &mut self, - spec_id: SpecId, - inputs: &CreateInputs, - ) -> Result> { - // Prepare crate. - let gas = Gas::new(inputs.gas_limit); - - let return_error = |e| { - Ok(FrameOrResult::new_create_result( - InterpreterResult { - result: e, - gas, - output: Bytes::new(), - }, - None, - )) - }; - - // Check depth - if self.journaled_state.depth() > CALL_STACK_LIMIT { - return return_error(InstructionResult::CallTooDeep); - } - - // Fetch balance of caller. - let (caller_balance, _) = self.balance(inputs.caller)?; - - // Check if caller has enough balance to send to the created contract. - if caller_balance < inputs.value { - return return_error(InstructionResult::OutOfFunds); - } - - // Increase nonce of caller and check if it overflows - let old_nonce; - if let Some(nonce) = self.journaled_state.inc_nonce(inputs.caller) { - old_nonce = nonce - 1; - } else { - return return_error(InstructionResult::Return); - } - - // Create address - let mut init_code_hash = B256::ZERO; - let created_address = match inputs.scheme { - CreateScheme::Create => inputs.caller.create(old_nonce), - CreateScheme::Create2 { salt } => { - init_code_hash = keccak256(&inputs.init_code); - inputs.caller.create2(salt.to_be_bytes(), init_code_hash) - } - }; - - // Load account so it needs to be marked as warm for access list. - self.journaled_state - .load_account(created_address, &mut self.db)?; - - // create account, transfer funds and make the journal checkpoint. - let checkpoint = match self.journaled_state.create_account_checkpoint( - inputs.caller, - created_address, - inputs.value, - spec_id, - ) { - Ok(checkpoint) => checkpoint, - Err(e) => { - return return_error(e); - } - }; - - let bytecode = Bytecode::new_raw(inputs.init_code.clone()); - - let contract = Contract::new( - Bytes::new(), - bytecode, - Some(init_code_hash), - created_address, - inputs.caller, - inputs.value, - ); - - Ok(FrameOrResult::new_create_frame( - created_address, - checkpoint, - Interpreter::new(contract, gas.limit(), false), - )) - } - - /// Handles call return. - #[inline] - pub fn call_return( - &mut self, - interpreter_result: &InterpreterResult, - journal_checkpoint: JournalCheckpoint, - ) { - // revert changes or not. - if matches!(interpreter_result.result, return_ok!()) { - self.journaled_state.checkpoint_commit(); - } else { - self.journaled_state.checkpoint_revert(journal_checkpoint); - } - } - - /// Handles create return. - #[inline] - pub fn create_return( - &mut self, - interpreter_result: &mut InterpreterResult, - address: Address, - journal_checkpoint: JournalCheckpoint, - ) { - // if return is not ok revert and return. - if !matches!(interpreter_result.result, return_ok!()) { - self.journaled_state.checkpoint_revert(journal_checkpoint); - return; - } - // Host error if present on execution - // if ok, check contract creation limit and calculate gas deduction on output len. - // - // EIP-3541: Reject new contract code starting with the 0xEF byte - if SPEC::enabled(LONDON) - && !interpreter_result.output.is_empty() - && interpreter_result.output.first() == Some(&0xEF) - { - self.journaled_state.checkpoint_revert(journal_checkpoint); - interpreter_result.result = InstructionResult::CreateContractStartingWithEF; - return; - } - - // EIP-170: Contract code size limit - // By default limit is 0x6000 (~25kb) - if SPEC::enabled(SPURIOUS_DRAGON) - && interpreter_result.output.len() - > self - .env - .cfg - .limit_contract_code_size - .unwrap_or(MAX_CODE_SIZE) - { - self.journaled_state.checkpoint_revert(journal_checkpoint); - interpreter_result.result = InstructionResult::CreateContractSizeLimit; - return; - } - let gas_for_code = interpreter_result.output.len() as u64 * gas::CODEDEPOSIT; - if !interpreter_result.gas.record_cost(gas_for_code) { - // record code deposit gas cost and check if we are out of gas. - // EIP-2 point 3: If contract creation does not have enough gas to pay for the - // final gas fee for adding the contract code to the state, the contract - // creation fails (i.e. goes out-of-gas) rather than leaving an empty contract. - if SPEC::enabled(HOMESTEAD) { - self.journaled_state.checkpoint_revert(journal_checkpoint); - interpreter_result.result = InstructionResult::OutOfGas; - return; - } else { - interpreter_result.output = Bytes::new(); - } - } - // if we have enough gas we can commit changes. - self.journaled_state.checkpoint_commit(); - - // Do analysis of bytecode straight away. - let bytecode = match self.env.cfg.perf_analyse_created_bytecodes { - AnalysisKind::Raw => Bytecode::new_raw(interpreter_result.output.clone()), - AnalysisKind::Analyse => { - to_analysed(Bytecode::new_raw(interpreter_result.output.clone())) - } - }; - - // set code - self.journaled_state.set_code(address, bytecode); - - interpreter_result.result = InstructionResult::Return; - } -} diff --git a/crates/revm/src/db.rs b/crates/revm/src/db.rs deleted file mode 100644 index 03dd5ac0a3..0000000000 --- a/crates/revm/src/db.rs +++ /dev/null @@ -1,22 +0,0 @@ -//! [Database] implementations. - -//#[cfg(feature = "alloydb")] -//pub mod alloydb; -pub mod emptydb; -#[cfg(feature = "ethersdb")] -pub mod ethersdb; -pub mod in_memory_db; -pub mod states; - -pub use crate::primitives::db::*; -//#[cfg(feature = "alloydb")] -//pub use alloydb::AlloyDB; -pub use emptydb::{EmptyDB, EmptyDBTyped}; -#[cfg(feature = "ethersdb")] -pub use ethersdb::EthersDB; -pub use in_memory_db::*; -pub use states::{ - AccountRevert, AccountStatus, BundleAccount, BundleState, CacheState, DBBox, - OriginalValuesKnown, PlainAccount, RevertToSlot, State, StateBuilder, StateDBBox, - StorageWithOriginalValues, TransitionAccount, TransitionState, -}; diff --git a/crates/revm/src/db/alloydb.rs b/crates/revm/src/db/alloydb.rs deleted file mode 100644 index 932fc32dbe..0000000000 --- a/crates/revm/src/db/alloydb.rs +++ /dev/null @@ -1,171 +0,0 @@ -use crate::{ - db::{Database, DatabaseRef}, - primitives::{AccountInfo, Address, Bytecode, B256, KECCAK_EMPTY, U256}, -}; -use alloy_provider::{Network, Provider}; -use alloy_rpc_types::BlockId; -use alloy_transport::{Transport, TransportError}; -use tokio::runtime::{Builder, Handle}; - -/// An alloy-powered REVM [Database]. -/// -/// When accessing the database, it'll use the given provider to fetch the corresponding account's data. -#[derive(Debug, Clone)] -pub struct AlloyDB> { - /// The provider to fetch the data from. - provider: P, - /// The block number on which the queries will be based on. - block_number: BlockId, - _marker: std::marker::PhantomData (T, N)>, -} - -impl> AlloyDB { - /// Create a new AlloyDB instance, with a [Provider] and a block (Use None for latest). - pub fn new(provider: P, block_number: BlockId) -> Self { - Self { - provider, - block_number, - _marker: std::marker::PhantomData, - } - } - - /// Internal utility function that allows us to block on a future regardless of the runtime flavor. - #[inline] - fn block_on(f: F) -> F::Output - where - F: std::future::Future + Send, - F::Output: Send, - { - match Handle::try_current() { - Ok(handle) => match handle.runtime_flavor() { - // This is essentially equal to tokio::task::spawn_blocking because tokio doesn't - // allow the current_thread runtime to block_in_place. - // See for more info. - tokio::runtime::RuntimeFlavor::CurrentThread => std::thread::scope(move |s| { - s.spawn(move || { - Builder::new_current_thread() - .enable_all() - .build() - .unwrap() - .block_on(f) - }) - .join() - .unwrap() - }), - _ => tokio::task::block_in_place(move || handle.block_on(f)), - }, - Err(_) => Builder::new_current_thread() - .enable_all() - .build() - .unwrap() - .block_on(f), - } - } - - /// Set the block number on which the queries will be based on. - pub fn set_block_number(&mut self, block_number: BlockId) { - self.block_number = block_number; - } -} - -impl> DatabaseRef for AlloyDB { - type Error = TransportError; - - fn basic_ref(&self, address: Address) -> Result, Self::Error> { - let f = async { - let nonce = self - .provider - .get_transaction_count(address, self.block_number); - let balance = self.provider.get_balance(address, self.block_number); - let code = self.provider.get_code_at(address, self.block_number); - tokio::join!(nonce, balance, code) - }; - - let (nonce, balance, code) = Self::block_on(f); - - let balance = balance?; - let code = Bytecode::new_raw(code?.0.into()); - let code_hash = code.hash_slow(); - let nonce = nonce?; - - Ok(Some(AccountInfo::new(balance, nonce, code_hash, code))) - } - - fn block_hash_ref(&self, number: U256) -> Result { - // Saturate usize - if number > U256::from(u64::MAX) { - return Ok(KECCAK_EMPTY); - } - - let block = Self::block_on( - self.provider - // SAFETY: We know number <= u64::MAX, so we can safely convert it to u64 - .get_block_by_number(number.to::().into(), false), - )?; - // SAFETY: If the number is given, the block is supposed to be finalized, so unwrapping is safe. - Ok(B256::new(*block.unwrap().header.hash.unwrap())) - } - - fn code_by_hash_ref(&self, _code_hash: B256) -> Result { - panic!("This should not be called, as the code is already loaded"); - // This is not needed, as the code is already loaded with basic_ref - } - - fn storage_ref(&self, address: Address, index: U256) -> Result { - let slot_val = Self::block_on(self.provider.get_storage_at( - address, - index, - self.block_number, - ))?; - Ok(slot_val) - } -} - -impl> Database for AlloyDB { - type Error = TransportError; - - #[inline] - fn basic(&mut self, address: Address) -> Result, Self::Error> { - ::basic_ref(self, address) - } - - #[inline] - fn code_by_hash(&mut self, code_hash: B256) -> Result { - ::code_by_hash_ref(self, code_hash) - } - - #[inline] - fn storage(&mut self, address: Address, index: U256) -> Result { - ::storage_ref(self, address, index) - } - - #[inline] - fn block_hash(&mut self, number: U256) -> Result { - ::block_hash_ref(self, number) - } -} - -#[cfg(test)] -mod tests { - use alloy_provider::ProviderBuilder; - - use super::*; - - #[test] - fn can_get_basic() { - let client = ProviderBuilder::new().on_http( - "https://mainnet.infura.io/v3/c60b0bb42f8a4c6481ecd229eddaca27" - .parse() - .unwrap(), - ); - let alloydb = AlloyDB::new(client, BlockId::from(16148323)); - - // ETH/USDT pair on Uniswap V2 - let address: Address = "0x0d4a11d5EEaaC28EC3F61d100daF4d40471f1852" - .parse() - .unwrap(); - - let acc_info = alloydb.basic_ref(address).unwrap().unwrap(); - assert!(acc_info.exists()); - } -} diff --git a/crates/revm/src/db/ethersdb.rs b/crates/revm/src/db/ethersdb.rs deleted file mode 100644 index d7863f100f..0000000000 --- a/crates/revm/src/db/ethersdb.rs +++ /dev/null @@ -1,175 +0,0 @@ -use std::sync::Arc; - -use ethers_core::types::{Block, BlockId, TxHash, H160 as eH160, H256, U64 as eU64}; -use ethers_providers::Middleware; -use tokio::runtime::{Builder, Handle, RuntimeFlavor}; - -use crate::primitives::{AccountInfo, Address, Bytecode, B256, KECCAK_EMPTY, U256}; -use crate::{Database, DatabaseRef}; - -#[derive(Debug, Clone)] -pub struct EthersDB { - client: Arc, - block_number: Option, -} - -impl EthersDB { - /// create ethers db connector inputs are url and block on what we are basing our database (None for latest) - pub fn new(client: Arc, block_number: Option) -> Option { - let block_number: Option = if block_number.is_some() { - block_number - } else { - Some(BlockId::from( - Self::block_on(client.get_block_number()).ok()?, - )) - }; - - Some(Self { - client, - block_number, - }) - } - - /// internal utility function to call tokio feature and wait for output - #[inline] - fn block_on(f: F) -> F::Output - where - F: core::future::Future + Send, - F::Output: Send, - { - match Handle::try_current() { - Ok(handle) => match handle.runtime_flavor() { - // This essentially equals to tokio::task::spawn_blocking because tokio doesn't - // allow current_thread runtime to block_in_place - RuntimeFlavor::CurrentThread => std::thread::scope(move |s| { - s.spawn(move || { - Builder::new_current_thread() - .enable_all() - .build() - .unwrap() - .block_on(f) - }) - .join() - .unwrap() - }), - _ => tokio::task::block_in_place(move || handle.block_on(f)), - }, - Err(_) => Builder::new_current_thread() - .enable_all() - .build() - .unwrap() - .block_on(f), - } - } - - /// set block number on which upcoming queries will be based - #[inline] - pub fn set_block_number(&mut self, block_number: BlockId) { - self.block_number = Some(block_number); - } -} - -impl DatabaseRef for EthersDB { - type Error = M::Error; - - fn basic_ref(&self, address: Address) -> Result, Self::Error> { - let add = eH160::from(address.0 .0); - - let f = async { - let nonce = self.client.get_transaction_count(add, self.block_number); - let balance = self.client.get_balance(add, self.block_number); - let code = self.client.get_code(add, self.block_number); - tokio::join!(nonce, balance, code) - }; - let (nonce, balance, code) = Self::block_on(f); - - let balance = U256::from_limbs(balance?.0); - let nonce = nonce?.as_u64(); - let bytecode = Bytecode::new_raw(code?.0.into()); - let code_hash = bytecode.hash_slow(); - Ok(Some(AccountInfo::new(balance, nonce, code_hash, bytecode))) - } - - fn code_by_hash_ref(&self, _code_hash: B256) -> Result { - panic!("Should not be called. Code is already loaded"); - // not needed because we already load code with basic info - } - - fn storage_ref(&self, address: Address, index: U256) -> Result { - let add = eH160::from(address.0 .0); - let index = H256::from(index.to_be_bytes()); - let slot_value: H256 = - Self::block_on(self.client.get_storage_at(add, index, self.block_number))?; - Ok(U256::from_be_bytes(slot_value.to_fixed_bytes())) - } - - fn block_hash_ref(&self, number: U256) -> Result { - // saturate usize - if number > U256::from(u64::MAX) { - return Ok(KECCAK_EMPTY); - } - // We know number <= u64::MAX so unwrap is safe - let number = eU64::from(u64::try_from(number).unwrap()); - let block: Option> = - Self::block_on(self.client.get_block(BlockId::from(number)))?; - // If number is given, the block is supposed to be finalized so unwrap is safe too. - Ok(B256::new(block.unwrap().hash.unwrap().0)) - } -} - -impl Database for EthersDB { - type Error = M::Error; - - #[inline] - fn basic(&mut self, address: Address) -> Result, Self::Error> { - ::basic_ref(self, address) - } - - #[inline] - fn code_by_hash(&mut self, code_hash: B256) -> Result { - ::code_by_hash_ref(self, code_hash) - } - - #[inline] - fn storage(&mut self, address: Address, index: U256) -> Result { - ::storage_ref(self, address, index) - } - - #[inline] - fn block_hash(&mut self, number: U256) -> Result { - ::block_hash_ref(self, number) - } -} - -// Run tests with `cargo test -- --nocapture` to see print statements -#[cfg(test)] -mod tests { - use super::*; - use ethers_providers::{Http, Provider}; - - //#[test] - fn _can_get_basic() { - let client = Provider::::try_from( - "https://mainnet.infura.io/v3/c60b0bb42f8a4c6481ecd229eddaca27", - ) - .unwrap(); - let client = Arc::new(client); - - let ethersdb = EthersDB::new( - Arc::clone(&client), // public infura mainnet - Some(BlockId::from(16148323)), - ) - .unwrap(); - - // ETH/USDT pair on Uniswap V2 - let address = "0x0d4a11d5EEaaC28EC3F61d100daF4d40471f1852" - .parse::() - .unwrap(); - let address = address.as_fixed_bytes().into(); - - let acc_info = ethersdb.basic_ref(address).unwrap().unwrap(); - - // check if not empty - assert!(acc_info.exists()); - } -} diff --git a/crates/revm/src/evm.rs b/crates/revm/src/evm.rs deleted file mode 100644 index 2fcf932452..0000000000 --- a/crates/revm/src/evm.rs +++ /dev/null @@ -1,376 +0,0 @@ -use crate::{ - builder::{EvmBuilder, HandlerStage, SetGenericStage}, - db::{Database, DatabaseCommit, EmptyDB}, - handler::Handler, - interpreter::{Host, InterpreterAction, SharedMemory}, - primitives::{ - specification::SpecId, BlockEnv, CfgEnv, EVMError, EVMResult, EnvWithHandlerCfg, - ExecutionResult, HandlerCfg, ResultAndState, TransactTo, TxEnv, - }, - Context, ContextWithHandlerCfg, Frame, FrameOrResult, FrameResult, -}; -use core::fmt; -use revm_interpreter::{CallInputs, CreateInputs}; -use std::vec::Vec; - -/// EVM call stack limit. -pub const CALL_STACK_LIMIT: u64 = 1024; - -/// EVM instance containing both internal EVM context and external context -/// and the handler that dictates the logic of EVM (or hardfork specification). -pub struct Evm<'a, EXT, DB: Database> { - /// Context of execution, containing both EVM and external context. - pub context: Context, - /// Handler is a component of the of EVM that contains all the logic. Handler contains specification id - /// and it different depending on the specified fork. - pub handler: Handler<'a, Context, EXT, DB>, -} - -impl fmt::Debug for Evm<'_, EXT, DB> -where - EXT: fmt::Debug, - DB: Database + fmt::Debug, - DB::Error: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Evm") - .field("evm context", &self.context.evm) - .finish_non_exhaustive() - } -} - -impl Evm<'_, EXT, DB> { - /// Commit the changes to the database. - pub fn transact_commit(&mut self) -> Result> { - let ResultAndState { result, state } = self.transact()?; - self.context.evm.db.commit(state); - Ok(result) - } -} - -impl<'a> Evm<'a, (), EmptyDB> { - /// Returns evm builder with empty database and empty external context. - pub fn builder() -> EvmBuilder<'a, SetGenericStage, (), EmptyDB> { - EvmBuilder::default() - } -} - -impl<'a, EXT, DB: Database> Evm<'a, EXT, DB> { - /// Create new EVM. - pub fn new( - mut context: Context, - handler: Handler<'a, Context, EXT, DB>, - ) -> Evm<'a, EXT, DB> { - context.evm.journaled_state.set_spec_id(handler.cfg.spec_id); - Evm { context, handler } - } - - /// Allow for evm setting to be modified by feeding current evm - /// into the builder for modifications. - pub fn modify(self) -> EvmBuilder<'a, HandlerStage, EXT, DB> { - EvmBuilder::new(self) - } - - /// Runs main call loop. - #[inline] - pub fn run_the_loop(&mut self, first_frame: Frame) -> Result> { - let mut call_stack: Vec = Vec::with_capacity(1025); - call_stack.push(first_frame); - - #[cfg(feature = "memory_limit")] - let mut shared_memory = - SharedMemory::new_with_memory_limit(self.context.evm.env.cfg.memory_limit); - #[cfg(not(feature = "memory_limit"))] - let mut shared_memory = SharedMemory::new(); - - shared_memory.new_context(); - - // Peek the last stack frame. - let mut stack_frame = call_stack.last_mut().unwrap(); - - loop { - // Execute the frame. - let next_action = - self.handler - .execute_frame(stack_frame, &mut shared_memory, &mut self.context)?; - - // Take error and break the loop, if any. - // This error can be set in the Interpreter when it interacts with the context. - self.context.evm.take_error()?; - - let exec = &mut self.handler.execution; - let frame_or_result = match next_action { - InterpreterAction::Call { inputs } => exec.call(&mut self.context, inputs)?, - InterpreterAction::Create { inputs } => exec.create(&mut self.context, inputs)?, - InterpreterAction::EOFCreate { inputs } => { - exec.eofcreate(&mut self.context, inputs)? - } - InterpreterAction::Return { result } => { - // free memory context. - shared_memory.free_context(); - - // pop last frame from the stack and consume it to create FrameResult. - let returned_frame = call_stack - .pop() - .expect("We just returned from Interpreter frame"); - - let ctx = &mut self.context; - FrameOrResult::Result(match returned_frame { - Frame::Call(frame) => { - // return_call - FrameResult::Call(exec.call_return(ctx, frame, result)?) - } - Frame::Create(frame) => { - // return_create - FrameResult::Create(exec.create_return(ctx, frame, result)?) - } - Frame::EOFCreate(frame) => { - // return_eofcreate - FrameResult::EOFCreate(exec.eofcreate_return(ctx, frame, result)?) - } - }) - } - InterpreterAction::None => unreachable!("InterpreterAction::None is not expected"), - }; - - // handle result - match frame_or_result { - FrameOrResult::Frame(frame) => { - shared_memory.new_context(); - call_stack.push(frame); - stack_frame = call_stack.last_mut().unwrap(); - } - FrameOrResult::Result(result) => { - let Some(top_frame) = call_stack.last_mut() else { - // Break the loop if there are no more frames. - return Ok(result); - }; - stack_frame = top_frame; - let ctx = &mut self.context; - // Insert result to the top frame. - match result { - FrameResult::Call(outcome) => { - // return_call - exec.insert_call_outcome(ctx, stack_frame, &mut shared_memory, outcome)? - } - FrameResult::Create(outcome) => { - // return_create - exec.insert_create_outcome(ctx, stack_frame, outcome)? - } - FrameResult::EOFCreate(outcome) => { - // return_eofcreate - exec.insert_eofcreate_outcome(ctx, stack_frame, outcome)? - } - } - } - } - } - } -} - -impl Evm<'_, EXT, DB> { - /// Returns specification (hardfork) that the EVM is instanced with. - /// - /// SpecId depends on the handler. - pub fn spec_id(&self) -> SpecId { - self.handler.cfg.spec_id - } - - /// Pre verify transaction by checking Environment, initial gas spend and if caller - /// has enough balance to pay for the gas. - #[inline] - pub fn preverify_transaction(&mut self) -> Result<(), EVMError> { - let output = self.preverify_transaction_inner().map(|_| ()); - self.clear(); - output - } - - /// Calls clear handle of post execution to clear the state for next execution. - fn clear(&mut self) { - self.handler.post_execution().clear(&mut self.context); - } - - /// Transact pre-verified transaction - /// - /// This function will not validate the transaction. - #[inline] - pub fn transact_preverified(&mut self) -> EVMResult { - let initial_gas_spend = self - .handler - .validation() - .initial_tx_gas(&self.context.evm.env) - .map_err(|e| { - self.clear(); - e - })?; - let output = self.transact_preverified_inner(initial_gas_spend); - let output = self.handler.post_execution().end(&mut self.context, output); - self.clear(); - output - } - - /// Pre verify transaction inner. - #[inline] - fn preverify_transaction_inner(&mut self) -> Result> { - self.handler.validation().env(&self.context.evm.env)?; - let initial_gas_spend = self - .handler - .validation() - .initial_tx_gas(&self.context.evm.env)?; - self.handler - .validation() - .tx_against_state(&mut self.context)?; - Ok(initial_gas_spend) - } - - /// Transact transaction - /// - /// This function will validate the transaction. - #[inline] - pub fn transact(&mut self) -> EVMResult { - let initial_gas_spend = self.preverify_transaction_inner().map_err(|e| { - self.clear(); - e - })?; - - let output = self.transact_preverified_inner(initial_gas_spend); - let output = self.handler.post_execution().end(&mut self.context, output); - self.clear(); - output - } - - /// Returns the reference of handler configuration - #[inline] - pub fn handler_cfg(&self) -> &HandlerCfg { - &self.handler.cfg - } - - /// Returns the reference of Env configuration - #[inline] - pub fn cfg(&self) -> &CfgEnv { - &self.context.env().cfg - } - - /// Returns the mutable reference of Env configuration - #[inline] - pub fn cfg_mut(&mut self) -> &mut CfgEnv { - &mut self.context.evm.env.cfg - } - - /// Returns the reference of transaction - #[inline] - pub fn tx(&self) -> &TxEnv { - &self.context.evm.env.tx - } - - /// Returns the mutable reference of transaction - #[inline] - pub fn tx_mut(&mut self) -> &mut TxEnv { - &mut self.context.evm.env.tx - } - - /// Returns the reference of database - #[inline] - pub fn db(&self) -> &DB { - &self.context.evm.db - } - - /// Returns the mutable reference of database - #[inline] - pub fn db_mut(&mut self) -> &mut DB { - &mut self.context.evm.db - } - - /// Returns the reference of block - #[inline] - pub fn block(&self) -> &BlockEnv { - &self.context.evm.env.block - } - - /// Returns the mutable reference of block - #[inline] - pub fn block_mut(&mut self) -> &mut BlockEnv { - &mut self.context.evm.env.block - } - - /// Modify spec id, this will create new EVM that matches this spec id. - pub fn modify_spec_id(&mut self, spec_id: SpecId) { - self.handler.modify_spec_id(spec_id); - } - - /// Returns internal database and external struct. - #[inline] - pub fn into_context(self) -> Context { - self.context - } - - /// Returns database and [`EnvWithHandlerCfg`]. - #[inline] - pub fn into_db_and_env_with_handler_cfg(self) -> (DB, EnvWithHandlerCfg) { - ( - self.context.evm.inner.db, - EnvWithHandlerCfg { - env: self.context.evm.inner.env, - handler_cfg: self.handler.cfg, - }, - ) - } - - /// Returns [Context] and [HandlerCfg]. - #[inline] - pub fn into_context_with_handler_cfg(self) -> ContextWithHandlerCfg { - ContextWithHandlerCfg::new(self.context, self.handler.cfg) - } - - /// Transact pre-verified transaction. - fn transact_preverified_inner(&mut self, initial_gas_spend: u64) -> EVMResult { - let ctx = &mut self.context; - let pre_exec = self.handler.pre_execution(); - - // load access list and beneficiary if needed. - pre_exec.load_accounts(ctx)?; - - // load precompiles - let precompiles = pre_exec.load_precompiles(); - ctx.evm.set_precompiles(precompiles); - - // deduce caller balance with its limit. - pre_exec.deduct_caller(ctx)?; - - let gas_limit = ctx.evm.env.tx.gas_limit - initial_gas_spend; - - let exec = self.handler.execution(); - // call inner handling of call/create - let first_frame_or_result = match ctx.evm.env.tx.transact_to { - TransactTo::Call(_) => exec.call( - ctx, - CallInputs::new_boxed(&ctx.evm.env.tx, gas_limit).unwrap(), - )?, - TransactTo::Create => exec.create( - ctx, - CreateInputs::new_boxed(&ctx.evm.env.tx, gas_limit).unwrap(), - )?, - }; - - // Starts the main running loop. - let mut result = match first_frame_or_result { - FrameOrResult::Frame(first_frame) => self.run_the_loop(first_frame)?, - FrameOrResult::Result(result) => result, - }; - - let ctx = &mut self.context; - - // handle output of call/create calls. - self.handler - .execution() - .last_frame_return(ctx, &mut result)?; - - let post_exec = self.handler.post_execution(); - // Reimburse the caller - post_exec.reimburse_caller(ctx, result.gas())?; - // Reward beneficiary - post_exec.reward_beneficiary(ctx, result.gas())?; - // Returns output of transaction. - post_exec.output(ctx, result) - } -} diff --git a/crates/revm/src/frame.rs b/crates/revm/src/frame.rs deleted file mode 100644 index 7257650581..0000000000 --- a/crates/revm/src/frame.rs +++ /dev/null @@ -1,302 +0,0 @@ -use crate::{ - interpreter::Interpreter, - primitives::{Address, Output}, - JournalCheckpoint, -}; -use core::ops::Range; -use revm_interpreter::{ - CallOutcome, CreateOutcome, EOFCreateOutcome, Gas, InstructionResult, InterpreterResult, -}; -use std::boxed::Box; - -/// Call CallStackFrame. -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct CallFrame { - /// Call frame has return memory range where output will be stored. - pub return_memory_range: Range, - /// Frame data. - pub frame_data: FrameData, -} - -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct CreateFrame { - /// Create frame has a created address. - pub created_address: Address, - /// Frame data. - pub frame_data: FrameData, -} - -/// Eof Create Frame. -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct EOFCreateFrame { - pub created_address: Address, - pub return_memory_range: Range, - pub frame_data: FrameData, -} - -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct FrameData { - /// Journal checkpoint. - pub checkpoint: JournalCheckpoint, - /// Interpreter. - pub interpreter: Interpreter, -} - -/// Call stack frame. -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum Frame { - Call(Box), - Create(Box), - EOFCreate(Box), -} - -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum FrameResult { - Call(CallOutcome), - Create(CreateOutcome), - EOFCreate(EOFCreateOutcome), -} - -impl FrameResult { - /// Casts frame result to interpreter result. - #[inline] - pub fn into_interpreter_result(self) -> InterpreterResult { - match self { - FrameResult::Call(outcome) => outcome.result, - FrameResult::Create(outcome) => outcome.result, - FrameResult::EOFCreate(outcome) => outcome.result, - } - } - - /// Returns execution output. - #[inline] - pub fn output(&self) -> Output { - match self { - FrameResult::Call(outcome) => Output::Call(outcome.result.output.clone()), - FrameResult::Create(outcome) => { - Output::Create(outcome.result.output.clone(), outcome.address) - } - FrameResult::EOFCreate(_) => { - panic!("EOFCreate can't be called from external world."); - } - } - } - - /// Returns reference to gas. - #[inline] - pub fn gas(&self) -> &Gas { - match self { - FrameResult::Call(outcome) => &outcome.result.gas, - FrameResult::Create(outcome) => &outcome.result.gas, - FrameResult::EOFCreate(outcome) => &outcome.result.gas, - } - } - - /// Returns mutable reference to interpreter result. - #[inline] - pub fn gas_mut(&mut self) -> &mut Gas { - match self { - FrameResult::Call(outcome) => &mut outcome.result.gas, - FrameResult::Create(outcome) => &mut outcome.result.gas, - FrameResult::EOFCreate(outcome) => &mut outcome.result.gas, - } - } - - /// Returns reference to interpreter result. - #[inline] - pub fn interpreter_result(&self) -> &InterpreterResult { - match self { - FrameResult::Call(outcome) => &outcome.result, - FrameResult::Create(outcome) => &outcome.result, - FrameResult::EOFCreate(outcome) => &outcome.result, - } - } - - /// Returns mutable reference to interpreter result. - #[inline] - pub fn interpreter_result_mut(&mut self) -> &InterpreterResult { - match self { - FrameResult::Call(outcome) => &mut outcome.result, - FrameResult::Create(outcome) => &mut outcome.result, - FrameResult::EOFCreate(outcome) => &mut outcome.result, - } - } - - /// Return Instruction result. - #[inline] - pub fn instruction_result(&self) -> InstructionResult { - self.interpreter_result().result - } -} - -/// Contains either a frame or a result. -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum FrameOrResult { - /// Boxed call or create frame. - Frame(Frame), - /// Call or create result. - Result(FrameResult), -} - -impl Frame { - pub fn new_create( - created_address: Address, - checkpoint: JournalCheckpoint, - interpreter: Interpreter, - ) -> Self { - Frame::Create(Box::new(CreateFrame { - created_address, - frame_data: FrameData { - checkpoint, - interpreter, - }, - })) - } - - pub fn new_call( - return_memory_range: Range, - checkpoint: JournalCheckpoint, - interpreter: Interpreter, - ) -> Self { - Frame::Call(Box::new(CallFrame { - return_memory_range, - frame_data: FrameData { - checkpoint, - interpreter, - }, - })) - } - - /// Returns true if frame is call frame. - pub fn is_call(&self) -> bool { - matches!(self, Frame::Call { .. }) - } - - /// Returns true if frame is create frame. - pub fn is_create(&self) -> bool { - matches!(self, Frame::Create { .. }) - } - - /// Returns created address if frame is create otherwise returns None. - pub fn created_address(&self) -> Option
{ - match self { - Frame::Create(create_frame) => Some(create_frame.created_address), - _ => None, - } - } - - /// Takes frame and returns frame data. - pub fn into_frame_data(self) -> FrameData { - match self { - Frame::Call(call_frame) => call_frame.frame_data, - Frame::Create(create_frame) => create_frame.frame_data, - Frame::EOFCreate(eof_create_frame) => eof_create_frame.frame_data, - } - } - - /// Returns reference to frame data. - pub fn frame_data(&self) -> &FrameData { - match self { - Self::Call(call_frame) => &call_frame.frame_data, - Self::Create(create_frame) => &create_frame.frame_data, - Self::EOFCreate(eof_create_frame) => &eof_create_frame.frame_data, - } - } - - /// Returns mutable reference to frame data. - pub fn frame_data_mut(&mut self) -> &mut FrameData { - match self { - Self::Call(call_frame) => &mut call_frame.frame_data, - Self::Create(create_frame) => &mut create_frame.frame_data, - Self::EOFCreate(eof_create_frame) => &mut eof_create_frame.frame_data, - } - } - - /// Returns a reference to the interpreter. - pub fn interpreter(&self) -> &Interpreter { - &self.frame_data().interpreter - } - - /// Returns a mutable reference to the interpreter. - pub fn interpreter_mut(&mut self) -> &mut Interpreter { - &mut self.frame_data_mut().interpreter - } -} - -impl FrameOrResult { - /// Creates new create frame. - pub fn new_create_frame( - created_address: Address, - checkpoint: JournalCheckpoint, - interpreter: Interpreter, - ) -> Self { - Self::Frame(Frame::new_create(created_address, checkpoint, interpreter)) - } - - pub fn new_eofcreate_frame( - created_address: Address, - return_memory_range: Range, - checkpoint: JournalCheckpoint, - interpreter: Interpreter, - ) -> Self { - Self::Frame(Frame::EOFCreate(Box::new(EOFCreateFrame { - created_address, - return_memory_range, - frame_data: FrameData { - checkpoint, - interpreter, - }, - }))) - } - - /// Creates new call frame. - pub fn new_call_frame( - return_memory_range: Range, - checkpoint: JournalCheckpoint, - interpreter: Interpreter, - ) -> Self { - Self::Frame(Frame::new_call( - return_memory_range, - checkpoint, - interpreter, - )) - } - - /// Creates new create result. - pub fn new_create_result( - interpreter_result: InterpreterResult, - address: Option
, - ) -> Self { - FrameOrResult::Result(FrameResult::Create(CreateOutcome { - result: interpreter_result, - address, - })) - } - - pub fn new_eofcreate_result( - interpreter_result: InterpreterResult, - address: Address, - return_memory_range: Range, - ) -> Self { - FrameOrResult::Result(FrameResult::EOFCreate(EOFCreateOutcome { - result: interpreter_result, - address, - return_memory_range, - })) - } - - pub fn new_call_result( - interpreter_result: InterpreterResult, - memory_offset: Range, - ) -> Self { - FrameOrResult::Result(FrameResult::Call(CallOutcome { - result: interpreter_result, - memory_offset, - })) - } -} diff --git a/crates/revm/src/handler.rs b/crates/revm/src/handler.rs deleted file mode 100644 index fab20b1229..0000000000 --- a/crates/revm/src/handler.rs +++ /dev/null @@ -1,252 +0,0 @@ -// Modules. -mod handle_types; -pub mod mainnet; -pub mod register; - -// Exports. -pub use handle_types::*; - -// Includes. -use crate::{ - interpreter::{opcode::InstructionTables, Host, InterpreterAction, SharedMemory}, - primitives::{db::Database, spec_to_generic, EVMError, HandlerCfg, Spec, SpecId}, - Context, Frame, -}; -use core::mem; -use register::{EvmHandler, HandleRegisters}; -use std::vec::Vec; - -use self::register::{HandleRegister, HandleRegisterBox}; - -/// Handler acts as a proxy and allow to define different behavior for different -/// sections of the code. This allows nice integration of different chains or -/// to disable some mainnet behavior. -pub struct Handler<'a, H: Host + 'a, EXT, DB: Database> { - /// Handler configuration. - pub cfg: HandlerCfg, - /// Instruction table type. - pub instruction_table: InstructionTables<'a, H>, - /// Registers that will be called on initialization. - pub registers: Vec>, - /// Validity handles. - pub validation: ValidationHandler<'a, EXT, DB>, - /// Pre execution handle. - pub pre_execution: PreExecutionHandler<'a, EXT, DB>, - /// Post Execution handle. - pub post_execution: PostExecutionHandler<'a, EXT, DB>, - /// Execution loop that handles frames. - pub execution: ExecutionHandler<'a, EXT, DB>, -} - -impl<'a, EXT, DB: Database> EvmHandler<'a, EXT, DB> { - /// Created new Handler with given configuration. - /// - /// Internally it calls `mainnet_with_spec` with the given spec id. - /// Or `optimism_with_spec` if the optimism feature is enabled and `cfg.is_optimism` is set. - pub fn new(cfg: HandlerCfg) -> Self { - cfg_if::cfg_if! { - if #[cfg(feature = "optimism")] { - if cfg.is_optimism { - Handler::optimism_with_spec(cfg.spec_id) - } else { - Handler::mainnet_with_spec(cfg.spec_id) - } - } else { - Handler::mainnet_with_spec(cfg.spec_id) - } - } - } - - /// Default handler for Ethereum mainnet. - pub fn mainnet() -> Self { - Self { - cfg: HandlerCfg::new(SPEC::SPEC_ID), - instruction_table: InstructionTables::new_plain::(), - registers: Vec::new(), - validation: ValidationHandler::new::(), - pre_execution: PreExecutionHandler::new::(), - post_execution: PostExecutionHandler::new::(), - execution: ExecutionHandler::new::(), - } - } - - /// Returns `true` if the optimism feature is enabled and flag is set to `true`. - pub fn is_optimism(&self) -> bool { - self.cfg.is_optimism() - } - - /// Handler for optimism - #[cfg(feature = "optimism")] - pub fn optimism() -> Self { - let mut handler = Self::mainnet::(); - handler.cfg.is_optimism = true; - handler.append_handler_register(HandleRegisters::Plain( - crate::optimism::optimism_handle_register::, - )); - handler - } - - /// Optimism with spec. Similar to [`Self::mainnet_with_spec`]. - #[cfg(feature = "optimism")] - pub fn optimism_with_spec(spec_id: SpecId) -> Self { - spec_to_generic!(spec_id, Self::optimism::()) - } - - /// Creates handler with variable spec id, inside it will call `mainnet::` for - /// appropriate spec. - pub fn mainnet_with_spec(spec_id: SpecId) -> Self { - spec_to_generic!(spec_id, Self::mainnet::()) - } - - /// Specification ID. - pub fn cfg(&self) -> HandlerCfg { - self.cfg - } - - /// Returns specification ID. - pub fn spec_id(&self) -> SpecId { - self.cfg.spec_id - } - - /// Executes call frame. - pub fn execute_frame( - &self, - frame: &mut Frame, - shared_memory: &mut SharedMemory, - context: &mut Context, - ) -> Result> { - self.execution - .execute_frame(frame, shared_memory, &self.instruction_table, context) - } - - /// Take instruction table. - pub fn take_instruction_table(&mut self) -> InstructionTables<'a, Context> { - let spec_id = self.spec_id(); - mem::replace( - &mut self.instruction_table, - spec_to_generic!(spec_id, InstructionTables::new_plain::()), - ) - } - - /// Set instruction table. - pub fn set_instruction_table(&mut self, table: InstructionTables<'a, Context>) { - self.instruction_table = table; - } - - /// Returns reference to pre execution handler. - pub fn pre_execution(&self) -> &PreExecutionHandler<'a, EXT, DB> { - &self.pre_execution - } - - /// Returns reference to pre execution handler. - pub fn post_execution(&self) -> &PostExecutionHandler<'a, EXT, DB> { - &self.post_execution - } - - /// Returns reference to frame handler. - pub fn execution(&self) -> &ExecutionHandler<'a, EXT, DB> { - &self.execution - } - - /// Returns reference to validation handler. - pub fn validation(&self) -> &ValidationHandler<'a, EXT, DB> { - &self.validation - } - - /// Append handle register. - pub fn append_handler_register(&mut self, register: HandleRegisters) { - register.register(self); - self.registers.push(register); - } - - /// Append plain handle register. - pub fn append_handler_register_plain(&mut self, register: HandleRegister) { - register(self); - self.registers.push(HandleRegisters::Plain(register)); - } - - /// Append boxed handle register. - pub fn append_handler_register_box(&mut self, register: HandleRegisterBox) { - register(self); - self.registers.push(HandleRegisters::Box(register)); - } - - /// Pop last handle register and reapply all registers that are left. - pub fn pop_handle_register(&mut self) -> Option> { - let out = self.registers.pop(); - if out.is_some() { - let registers = core::mem::take(&mut self.registers); - let mut base_handler = Handler::mainnet_with_spec(self.cfg.spec_id); - // apply all registers to default handeler and raw mainnet instruction table. - for register in registers { - base_handler.append_handler_register(register) - } - *self = base_handler; - } - out - } - - /// Creates the Handler with Generic Spec. - pub fn create_handle_generic(&mut self) -> EvmHandler<'a, EXT, DB> { - let registers = core::mem::take(&mut self.registers); - let mut base_handler = Handler::mainnet::(); - // apply all registers to default handeler and raw mainnet instruction table. - for register in registers { - base_handler.append_handler_register(register) - } - base_handler - } - - /// Creates the Handler with variable SpecId, inside it will call function with Generic Spec. - pub fn modify_spec_id(&mut self, spec_id: SpecId) { - if self.cfg.spec_id == spec_id { - return; - } - - let registers = core::mem::take(&mut self.registers); - // register for optimism is added as a register, so we need to create mainnet handler here. - let mut handler = Handler::mainnet_with_spec(spec_id); - // apply all registers to default handler and raw mainnet instruction table. - for register in registers { - handler.append_handler_register(register) - } - handler.cfg = self.cfg(); - handler.cfg.spec_id = spec_id; - *self = handler; - } -} - -#[cfg(test)] -mod test { - use core::cell::RefCell; - - use crate::{db::EmptyDB, primitives::EVMError}; - use std::{rc::Rc, sync::Arc}; - - use super::*; - - #[test] - fn test_handler_register_pop() { - let register = |inner: &Rc>| -> HandleRegisterBox<(), EmptyDB> { - let inner = inner.clone(); - Box::new(move |h| { - *inner.borrow_mut() += 1; - h.post_execution.output = Arc::new(|_, _| Err(EVMError::Custom("test".to_string()))) - }) - }; - - let mut handler = EvmHandler::<(), EmptyDB>::new(HandlerCfg::new(SpecId::LATEST)); - let test = Rc::new(RefCell::new(0)); - - handler.append_handler_register_box(register(&test)); - assert_eq!(*test.borrow(), 1); - - handler.append_handler_register_box(register(&test)); - assert_eq!(*test.borrow(), 2); - - assert!(handler.pop_handle_register().is_some()); - - // first handler is reapplied - assert_eq!(*test.borrow(), 3); - } -} diff --git a/crates/revm/src/handler/handle_types.rs b/crates/revm/src/handler/handle_types.rs deleted file mode 100644 index 4bdc119831..0000000000 --- a/crates/revm/src/handler/handle_types.rs +++ /dev/null @@ -1,25 +0,0 @@ -// Modules - -pub mod execution; -pub mod post_execution; -pub mod pre_execution; -pub mod validation; - -// Exports - -pub use validation::{ - ValidateEnvHandle, ValidateInitialTxGasHandle, ValidateTxEnvAgainstState, ValidationHandler, -}; - -pub use execution::{ - ExecutionHandler, FrameCallHandle, FrameCallReturnHandle, FrameCreateHandle, - FrameCreateReturnHandle, InsertCallOutcomeHandle, InsertCreateOutcomeHandle, -}; - -pub use pre_execution::{ - DeductCallerHandle, LoadAccountsHandle, LoadPrecompilesHandle, PreExecutionHandler, -}; - -pub use post_execution::{ - EndHandle, OutputHandle, PostExecutionHandler, ReimburseCallerHandle, RewardBeneficiaryHandle, -}; diff --git a/crates/revm/src/handler/handle_types/execution.rs b/crates/revm/src/handler/handle_types/execution.rs deleted file mode 100644 index b69354a591..0000000000 --- a/crates/revm/src/handler/handle_types/execution.rs +++ /dev/null @@ -1,284 +0,0 @@ -use crate::{ - frame::EOFCreateFrame, - handler::mainnet, - interpreter::{CallInputs, CreateInputs, SharedMemory}, - primitives::{db::Database, EVMError, Spec}, - CallFrame, Context, CreateFrame, Frame, FrameOrResult, FrameResult, -}; -use revm_interpreter::{ - opcode::InstructionTables, CallOutcome, CreateOutcome, EOFCreateInput, EOFCreateOutcome, - InterpreterAction, InterpreterResult, -}; -use std::{boxed::Box, sync::Arc}; - -/// Handles first frame return handle. -pub type LastFrameReturnHandle<'a, EXT, DB> = Arc< - dyn Fn(&mut Context, &mut FrameResult) -> Result<(), EVMError<::Error>> - + 'a, ->; - -/// Executes a single frame. Errors can be returned in the EVM context. -pub type ExecuteFrameHandle<'a, EXT, DB> = Arc< - dyn Fn( - &mut Frame, - &mut SharedMemory, - &InstructionTables<'_, Context>, - &mut Context, - ) -> Result::Error>> - + 'a, ->; - -/// Handle sub call. -pub type FrameCallHandle<'a, EXT, DB> = Arc< - dyn Fn( - &mut Context, - Box, - ) -> Result::Error>> - + 'a, ->; - -/// Handle call return -pub type FrameCallReturnHandle<'a, EXT, DB> = Arc< - dyn Fn( - &mut Context, - Box, - InterpreterResult, - ) -> Result::Error>> - + 'a, ->; - -/// Insert call outcome to the parent -pub type InsertCallOutcomeHandle<'a, EXT, DB> = Arc< - dyn Fn( - &mut Context, - &mut Frame, - &mut SharedMemory, - CallOutcome, - ) -> Result<(), EVMError<::Error>> - + 'a, ->; - -/// Handle sub create. -pub type FrameCreateHandle<'a, EXT, DB> = Arc< - dyn Fn( - &mut Context, - Box, - ) -> Result::Error>> - + 'a, ->; - -/// Handle create return -pub type FrameCreateReturnHandle<'a, EXT, DB> = Arc< - dyn Fn( - &mut Context, - Box, - InterpreterResult, - ) -> Result::Error>> - + 'a, ->; - -/// Insert call outcome to the parent -pub type InsertCreateOutcomeHandle<'a, EXT, DB> = Arc< - dyn Fn( - &mut Context, - &mut Frame, - CreateOutcome, - ) -> Result<(), EVMError<::Error>> - + 'a, ->; - -/// Handle EOF sub create. -pub type FrameEOFCreateHandle<'a, EXT, DB> = Arc< - dyn Fn( - &mut Context, - Box, - ) -> Result::Error>> - + 'a, ->; - -/// Handle EOF create return -pub type FrameEOFCreateReturnHandle<'a, EXT, DB> = Arc< - dyn Fn( - &mut Context, - Box, - InterpreterResult, - ) -> Result::Error>> - + 'a, ->; - -/// Insert EOF crate outcome to the parent -pub type InsertEOFCreateOutcomeHandle<'a, EXT, DB> = Arc< - dyn Fn( - &mut Context, - &mut Frame, - EOFCreateOutcome, - ) -> Result<(), EVMError<::Error>> - + 'a, ->; - -/// Handles related to stack frames. -pub struct ExecutionHandler<'a, EXT, DB: Database> { - /// Handles last frame return, modified gas for refund and - /// sets tx gas limit. - pub last_frame_return: LastFrameReturnHandle<'a, EXT, DB>, - /// Executes a single frame. - pub execute_frame: ExecuteFrameHandle<'a, EXT, DB>, - /// Frame call - pub call: FrameCallHandle<'a, EXT, DB>, - /// Call return - pub call_return: FrameCallReturnHandle<'a, EXT, DB>, - /// Insert call outcome - pub insert_call_outcome: InsertCallOutcomeHandle<'a, EXT, DB>, - /// Frame crate - pub create: FrameCreateHandle<'a, EXT, DB>, - /// Crate return - pub create_return: FrameCreateReturnHandle<'a, EXT, DB>, - /// Insert create outcome. - pub insert_create_outcome: InsertCreateOutcomeHandle<'a, EXT, DB>, - /// Frame EOFCreate - pub eofcreate: FrameEOFCreateHandle<'a, EXT, DB>, - /// EOFCreate return - pub eofcreate_return: FrameEOFCreateReturnHandle<'a, EXT, DB>, - /// Insert EOFCreate outcome. - pub insert_eofcreate_outcome: InsertEOFCreateOutcomeHandle<'a, EXT, DB>, -} - -impl<'a, EXT: 'a, DB: Database + 'a> ExecutionHandler<'a, EXT, DB> { - /// Creates mainnet ExecutionHandler. - pub fn new() -> Self { - Self { - last_frame_return: Arc::new(mainnet::last_frame_return::), - execute_frame: Arc::new(mainnet::execute_frame::), - call: Arc::new(mainnet::call::), - call_return: Arc::new(mainnet::call_return::), - insert_call_outcome: Arc::new(mainnet::insert_call_outcome), - create: Arc::new(mainnet::create::), - create_return: Arc::new(mainnet::create_return::), - insert_create_outcome: Arc::new(mainnet::insert_create_outcome), - eofcreate: Arc::new(mainnet::eofcreate::), - eofcreate_return: Arc::new(mainnet::eofcreate_return::), - insert_eofcreate_outcome: Arc::new(mainnet::insert_eofcreate_outcome), - } - } -} - -impl<'a, EXT, DB: Database> ExecutionHandler<'a, EXT, DB> { - /// Executes single frame. - #[inline] - pub fn execute_frame( - &self, - frame: &mut Frame, - shared_memory: &mut SharedMemory, - instruction_tables: &InstructionTables<'_, Context>, - context: &mut Context, - ) -> Result> { - (self.execute_frame)(frame, shared_memory, instruction_tables, context) - } - - /// Handle call return, depending on instruction result gas will be reimbursed or not. - #[inline] - pub fn last_frame_return( - &self, - context: &mut Context, - frame_result: &mut FrameResult, - ) -> Result<(), EVMError> { - (self.last_frame_return)(context, frame_result) - } - - /// Call frame call handler. - #[inline] - pub fn call( - &self, - context: &mut Context, - inputs: Box, - ) -> Result> { - (self.call)(context, inputs.clone()) - } - - /// Call registered handler for call return. - #[inline] - pub fn call_return( - &self, - context: &mut Context, - frame: Box, - interpreter_result: InterpreterResult, - ) -> Result> { - (self.call_return)(context, frame, interpreter_result) - } - - /// Call registered handler for inserting call outcome. - #[inline] - pub fn insert_call_outcome( - &self, - context: &mut Context, - frame: &mut Frame, - shared_memory: &mut SharedMemory, - outcome: CallOutcome, - ) -> Result<(), EVMError> { - (self.insert_call_outcome)(context, frame, shared_memory, outcome) - } - - /// Call Create frame - #[inline] - pub fn create( - &self, - context: &mut Context, - inputs: Box, - ) -> Result> { - (self.create)(context, inputs) - } - - /// Call handler for create return. - #[inline] - pub fn create_return( - &self, - context: &mut Context, - frame: Box, - interpreter_result: InterpreterResult, - ) -> Result> { - (self.create_return)(context, frame, interpreter_result) - } - - /// Call handler for inserting create outcome. - #[inline] - pub fn insert_create_outcome( - &self, - context: &mut Context, - frame: &mut Frame, - outcome: CreateOutcome, - ) -> Result<(), EVMError> { - (self.insert_create_outcome)(context, frame, outcome) - } - - /// Call Create frame - #[inline] - pub fn eofcreate( - &self, - context: &mut Context, - inputs: Box, - ) -> Result> { - (self.eofcreate)(context, inputs) - } - - /// Call handler for create return. - #[inline] - pub fn eofcreate_return( - &self, - context: &mut Context, - frame: Box, - interpreter_result: InterpreterResult, - ) -> Result> { - (self.eofcreate_return)(context, frame, interpreter_result) - } - - /// Call handler for inserting create outcome. - #[inline] - pub fn insert_eofcreate_outcome( - &self, - context: &mut Context, - frame: &mut Frame, - outcome: EOFCreateOutcome, - ) -> Result<(), EVMError> { - (self.insert_eofcreate_outcome)(context, frame, outcome) - } -} diff --git a/crates/revm/src/handler/handle_types/post_execution.rs b/crates/revm/src/handler/handle_types/post_execution.rs deleted file mode 100644 index f2149e8903..0000000000 --- a/crates/revm/src/handler/handle_types/post_execution.rs +++ /dev/null @@ -1,112 +0,0 @@ -// Includes. -use crate::{ - handler::mainnet, - interpreter::Gas, - primitives::{db::Database, EVMError, EVMResultGeneric, ResultAndState, Spec}, - Context, FrameResult, -}; -use std::sync::Arc; - -/// Reimburse the caller with ethereum it didn't spent. -pub type ReimburseCallerHandle<'a, EXT, DB> = - Arc, &Gas) -> EVMResultGeneric<(), ::Error> + 'a>; - -/// Reward beneficiary with transaction rewards. -pub type RewardBeneficiaryHandle<'a, EXT, DB> = ReimburseCallerHandle<'a, EXT, DB>; - -/// Main return handle, takes state from journal and transforms internal result to external. -pub type OutputHandle<'a, EXT, DB> = Arc< - dyn Fn( - &mut Context, - FrameResult, - ) -> Result::Error>> - + 'a, ->; - -/// End handle, takes result and state and returns final result. -/// This will be called after all the other handlers. -/// -/// It is useful for catching errors and returning them in a different way. -pub type EndHandle<'a, EXT, DB> = Arc< - dyn Fn( - &mut Context, - Result::Error>>, - ) -> Result::Error>> - + 'a, ->; - -/// Clear handle, doesn't have output, its purpose is to clear the -/// context. It will be always called even on failed validation. -pub type ClearHandle<'a, EXT, DB> = Arc) + 'a>; - -/// Handles related to post execution after the stack loop is finished. -pub struct PostExecutionHandler<'a, EXT, DB: Database> { - /// Reimburse the caller with ethereum it didn't spent. - pub reimburse_caller: ReimburseCallerHandle<'a, EXT, DB>, - /// Reward the beneficiary with caller fee. - pub reward_beneficiary: RewardBeneficiaryHandle<'a, EXT, DB>, - /// Main return handle, returns the output of the transact. - pub output: OutputHandle<'a, EXT, DB>, - /// Called when execution ends. - /// End handle in comparison to output handle will be called every time after execution. - /// Output in case of error will not be called. - pub end: EndHandle<'a, EXT, DB>, - /// Clear handle will be called always. In comparison to end that - /// is called only on execution end, clear handle is called even if validation fails. - pub clear: ClearHandle<'a, EXT, DB>, -} - -impl<'a, EXT: 'a, DB: Database + 'a> PostExecutionHandler<'a, EXT, DB> { - /// Creates mainnet MainHandles. - pub fn new() -> Self { - Self { - reimburse_caller: Arc::new(mainnet::reimburse_caller::), - reward_beneficiary: Arc::new(mainnet::reward_beneficiary::), - output: Arc::new(mainnet::output::), - end: Arc::new(mainnet::end::), - clear: Arc::new(mainnet::clear::), - } - } -} - -impl<'a, EXT, DB: Database> PostExecutionHandler<'a, EXT, DB> { - /// Reimburse the caller with gas that were not spend. - pub fn reimburse_caller( - &self, - context: &mut Context, - gas: &Gas, - ) -> Result<(), EVMError> { - (self.reimburse_caller)(context, gas) - } - /// Reward beneficiary - pub fn reward_beneficiary( - &self, - context: &mut Context, - gas: &Gas, - ) -> Result<(), EVMError> { - (self.reward_beneficiary)(context, gas) - } - - /// Returns the output of transaction. - pub fn output( - &self, - context: &mut Context, - result: FrameResult, - ) -> Result> { - (self.output)(context, result) - } - - /// End handler. - pub fn end( - &self, - context: &mut Context, - end_output: Result>, - ) -> Result> { - (self.end)(context, end_output) - } - - /// Clean handler. - pub fn clear(&self, context: &mut Context) { - (self.clear)(context) - } -} diff --git a/crates/revm/src/handler/handle_types/pre_execution.rs b/crates/revm/src/handler/handle_types/pre_execution.rs deleted file mode 100644 index 1956d67f13..0000000000 --- a/crates/revm/src/handler/handle_types/pre_execution.rs +++ /dev/null @@ -1,58 +0,0 @@ -// Includes. -use crate::{ - handler::mainnet, - primitives::{db::Database, EVMError, EVMResultGeneric, Spec}, - Context, ContextPrecompiles, -}; -use std::sync::Arc; - -/// Loads precompiles into Evm -pub type LoadPrecompilesHandle<'a, DB> = Arc ContextPrecompiles + 'a>; - -/// Load access list accounts and beneficiary. -/// There is no need to load Caller as it is assumed that -/// it will be loaded in DeductCallerHandle. -pub type LoadAccountsHandle<'a, EXT, DB> = - Arc) -> Result<(), EVMError<::Error>> + 'a>; - -/// Deduct the caller to its limit. -pub type DeductCallerHandle<'a, EXT, DB> = - Arc) -> EVMResultGeneric<(), ::Error> + 'a>; - -/// Handles related to pre execution before the stack loop is started. -pub struct PreExecutionHandler<'a, EXT, DB: Database> { - /// Load precompiles - pub load_precompiles: LoadPrecompilesHandle<'a, DB>, - /// Main load handle - pub load_accounts: LoadAccountsHandle<'a, EXT, DB>, - /// Deduct max value from the caller. - pub deduct_caller: DeductCallerHandle<'a, EXT, DB>, -} - -impl<'a, EXT: 'a, DB: Database + 'a> PreExecutionHandler<'a, EXT, DB> { - /// Creates mainnet MainHandles. - pub fn new() -> Self { - Self { - load_precompiles: Arc::new(mainnet::load_precompiles::), - load_accounts: Arc::new(mainnet::load_accounts::), - deduct_caller: Arc::new(mainnet::deduct_caller::), - } - } -} - -impl<'a, EXT, DB: Database> PreExecutionHandler<'a, EXT, DB> { - /// Deduct caller to its limit. - pub fn deduct_caller(&self, context: &mut Context) -> Result<(), EVMError> { - (self.deduct_caller)(context) - } - - /// Main load - pub fn load_accounts(&self, context: &mut Context) -> Result<(), EVMError> { - (self.load_accounts)(context) - } - - /// Load precompiles - pub fn load_precompiles(&self) -> ContextPrecompiles { - (self.load_precompiles)() - } -} diff --git a/crates/revm/src/handler/handle_types/validation.rs b/crates/revm/src/handler/handle_types/validation.rs deleted file mode 100644 index 8aa55c28c2..0000000000 --- a/crates/revm/src/handler/handle_types/validation.rs +++ /dev/null @@ -1,60 +0,0 @@ -use crate::{ - handler::mainnet, - primitives::{db::Database, EVMError, Env, Spec}, - Context, -}; -use std::sync::Arc; - -/// Handle that validates env. -pub type ValidateEnvHandle<'a, DB> = - Arc Result<(), EVMError<::Error>> + 'a>; - -/// Handle that validates transaction environment against the state. -/// Second parametar is initial gas. -pub type ValidateTxEnvAgainstState<'a, EXT, DB> = - Arc) -> Result<(), EVMError<::Error>> + 'a>; - -/// Initial gas calculation handle -pub type ValidateInitialTxGasHandle<'a, DB> = - Arc Result::Error>> + 'a>; - -/// Handles related to validation. -pub struct ValidationHandler<'a, EXT, DB: Database> { - /// Validate and calculate initial transaction gas. - pub initial_tx_gas: ValidateInitialTxGasHandle<'a, DB>, - /// Validate transactions against state data. - pub tx_against_state: ValidateTxEnvAgainstState<'a, EXT, DB>, - /// Validate Env. - pub env: ValidateEnvHandle<'a, DB>, -} - -impl<'a, EXT: 'a, DB: Database + 'a> ValidationHandler<'a, EXT, DB> { - /// Create new ValidationHandles - pub fn new() -> Self { - Self { - initial_tx_gas: Arc::new(mainnet::validate_initial_tx_gas::), - env: Arc::new(mainnet::validate_env::), - tx_against_state: Arc::new(mainnet::validate_tx_against_state::), - } - } -} - -impl<'a, EXT, DB: Database> ValidationHandler<'a, EXT, DB> { - /// Validate env. - pub fn env(&self, env: &Env) -> Result<(), EVMError> { - (self.env)(env) - } - - /// Initial gas - pub fn initial_tx_gas(&self, env: &Env) -> Result> { - (self.initial_tx_gas)(env) - } - - /// Validate ttansaction against the state. - pub fn tx_against_state( - &self, - context: &mut Context, - ) -> Result<(), EVMError> { - (self.tx_against_state)(context) - } -} diff --git a/crates/revm/src/handler/mainnet.rs b/crates/revm/src/handler/mainnet.rs deleted file mode 100644 index b02e96bfdf..0000000000 --- a/crates/revm/src/handler/mainnet.rs +++ /dev/null @@ -1,15 +0,0 @@ -//! Mainnet related handlers. - -mod execution; -mod post_execution; -mod pre_execution; -mod validation; - -pub use execution::{ - call, call_return, create, create_return, eofcreate, eofcreate_return, execute_frame, - frame_return_with_refund_flag, insert_call_outcome, insert_create_outcome, - insert_eofcreate_outcome, last_frame_return, -}; -pub use post_execution::{clear, end, output, reimburse_caller, reward_beneficiary}; -pub use pre_execution::{deduct_caller, deduct_caller_inner, load_accounts, load_precompiles}; -pub use validation::{validate_env, validate_initial_tx_gas, validate_tx_against_state}; diff --git a/crates/revm/src/handler/mainnet/execution.rs b/crates/revm/src/handler/mainnet/execution.rs deleted file mode 100644 index 9e1ff3ef54..0000000000 --- a/crates/revm/src/handler/mainnet/execution.rs +++ /dev/null @@ -1,259 +0,0 @@ -use crate::{ - db::Database, - frame::EOFCreateFrame, - interpreter::{ - return_ok, return_revert, CallInputs, CreateInputs, CreateOutcome, Gas, InstructionResult, - SharedMemory, - }, - primitives::{EVMError, Env, Spec, SpecId}, - CallFrame, Context, CreateFrame, Frame, FrameOrResult, FrameResult, -}; -use core::mem; -use revm_interpreter::{ - opcode::InstructionTables, CallOutcome, EOFCreateInput, EOFCreateOutcome, InterpreterAction, - InterpreterResult, EMPTY_SHARED_MEMORY, -}; -use std::boxed::Box; - -/// Execute frame -#[inline] -pub fn execute_frame( - frame: &mut Frame, - shared_memory: &mut SharedMemory, - instruction_tables: &InstructionTables<'_, Context>, - context: &mut Context, -) -> Result> { - let interpreter = frame.interpreter_mut(); - let memory = mem::replace(shared_memory, EMPTY_SHARED_MEMORY); - let next_action = match instruction_tables { - InstructionTables::Plain(table) => interpreter.run(memory, table, context), - InstructionTables::Boxed(table) => interpreter.run(memory, table, context), - }; - // Take the shared memory back. - *shared_memory = interpreter.take_memory(); - - Ok(next_action) -} - -/// Helper function called inside [`last_frame_return`] -#[inline] -pub fn frame_return_with_refund_flag( - env: &Env, - frame_result: &mut FrameResult, - refund_enabled: bool, -) { - let instruction_result = frame_result.interpreter_result().result; - let gas = frame_result.gas_mut(); - let remaining = gas.remaining(); - let refunded = gas.refunded(); - - // Spend the gas limit. Gas is reimbursed when the tx returns successfully. - *gas = Gas::new_spent(env.tx.gas_limit); - - match instruction_result { - return_ok!() => { - gas.erase_cost(remaining); - gas.record_refund(refunded); - } - return_revert!() => { - gas.erase_cost(remaining); - } - _ => {} - } - - // Calculate gas refund for transaction. - // If config is set to disable gas refund, it will return 0. - // If spec is set to london, it will decrease the maximum refund amount to 5th part of - // gas spend. (Before london it was 2th part of gas spend) - if refund_enabled { - // EIP-3529: Reduction in refunds - gas.set_final_refund(SPEC::SPEC_ID.is_enabled_in(SpecId::LONDON)); - } -} - -/// Handle output of the transaction -#[inline] -pub fn last_frame_return( - context: &mut Context, - frame_result: &mut FrameResult, -) -> Result<(), EVMError> { - frame_return_with_refund_flag::(&context.evm.env, frame_result, true); - Ok(()) -} - -/// Handle frame sub call. -#[inline] -pub fn call( - context: &mut Context, - inputs: Box, -) -> Result> { - context.evm.make_call_frame(&inputs) -} - -#[inline] -pub fn call_return( - context: &mut Context, - frame: Box, - interpreter_result: InterpreterResult, -) -> Result> { - context - .evm - .call_return(&interpreter_result, frame.frame_data.checkpoint); - Ok(CallOutcome::new( - interpreter_result, - frame.return_memory_range, - )) -} - -#[inline] -pub fn insert_call_outcome( - context: &mut Context, - frame: &mut Frame, - shared_memory: &mut SharedMemory, - outcome: CallOutcome, -) -> Result<(), EVMError> { - context.evm.take_error()?; - frame - .frame_data_mut() - .interpreter - .insert_call_outcome(shared_memory, outcome); - Ok(()) -} - -/// Handle frame sub create. -#[inline] -pub fn create( - context: &mut Context, - inputs: Box, -) -> Result> { - context.evm.make_create_frame(SPEC::SPEC_ID, &inputs) -} - -#[inline] -pub fn create_return( - context: &mut Context, - frame: Box, - mut interpreter_result: InterpreterResult, -) -> Result> { - context.evm.create_return::( - &mut interpreter_result, - frame.created_address, - frame.frame_data.checkpoint, - ); - Ok(CreateOutcome::new( - interpreter_result, - Some(frame.created_address), - )) -} - -#[inline] -pub fn insert_create_outcome( - context: &mut Context, - frame: &mut Frame, - outcome: CreateOutcome, -) -> Result<(), EVMError> { - context.evm.take_error()?; - frame - .frame_data_mut() - .interpreter - .insert_create_outcome(outcome); - Ok(()) -} - -/// Handle frame sub create. -#[inline] -pub fn eofcreate( - context: &mut Context, - inputs: Box, -) -> Result> { - context.evm.make_eofcreate_frame(SPEC::SPEC_ID, &inputs) -} - -#[inline] -pub fn eofcreate_return( - context: &mut Context, - frame: Box, - mut interpreter_result: InterpreterResult, -) -> Result> { - context.evm.eofcreate_return::( - &mut interpreter_result, - frame.created_address, - frame.frame_data.checkpoint, - ); - Ok(EOFCreateOutcome::new( - interpreter_result, - frame.created_address, - frame.return_memory_range, - )) -} - -#[inline] -pub fn insert_eofcreate_outcome( - context: &mut Context, - frame: &mut Frame, - outcome: EOFCreateOutcome, -) -> Result<(), EVMError> { - core::mem::replace(&mut context.evm.error, Ok(()))?; - frame - .frame_data_mut() - .interpreter - .insert_eofcreate_outcome(outcome); - Ok(()) -} - -#[cfg(test)] -mod tests { - use super::*; - use revm_interpreter::primitives::CancunSpec; - use revm_precompile::Bytes; - - /// Creates frame result. - fn call_last_frame_return(instruction_result: InstructionResult, gas: Gas) -> Gas { - let mut env = Env::default(); - env.tx.gas_limit = 100; - - let mut first_frame = FrameResult::Call(CallOutcome::new( - InterpreterResult { - result: instruction_result, - output: Bytes::new(), - gas, - }, - 0..0, - )); - frame_return_with_refund_flag::(&env, &mut first_frame, true); - *first_frame.gas() - } - - #[test] - fn test_consume_gas() { - let gas = call_last_frame_return(InstructionResult::Stop, Gas::new(90)); - assert_eq!(gas.remaining(), 90); - assert_eq!(gas.spent(), 10); - assert_eq!(gas.refunded(), 0); - } - - // TODO - #[test] - fn test_consume_gas_with_refund() { - let mut return_gas = Gas::new(90); - return_gas.record_refund(30); - - let gas = call_last_frame_return(InstructionResult::Stop, return_gas); - assert_eq!(gas.remaining(), 90); - assert_eq!(gas.spent(), 10); - assert_eq!(gas.refunded(), 2); - - let gas = call_last_frame_return(InstructionResult::Revert, return_gas); - assert_eq!(gas.remaining(), 90); - assert_eq!(gas.spent(), 10); - assert_eq!(gas.refunded(), 0); - } - - #[test] - fn test_revert_gas() { - let gas = call_last_frame_return(InstructionResult::Revert, Gas::new(90)); - assert_eq!(gas.remaining(), 90); - assert_eq!(gas.spent(), 10); - assert_eq!(gas.refunded(), 0); - } -} diff --git a/crates/revm/src/handler/mainnet/post_execution.rs b/crates/revm/src/handler/mainnet/post_execution.rs deleted file mode 100644 index bf73236159..0000000000 --- a/crates/revm/src/handler/mainnet/post_execution.rs +++ /dev/null @@ -1,125 +0,0 @@ -use crate::{ - interpreter::{Gas, SuccessOrHalt}, - primitives::{ - db::Database, EVMError, ExecutionResult, ResultAndState, Spec, SpecId::LONDON, U256, - }, - Context, FrameResult, -}; - -/// Mainnet end handle does not change the output. -#[inline] -pub fn end( - _context: &mut Context, - evm_output: Result>, -) -> Result> { - evm_output -} - -/// Clear handle clears error and journal state. -#[inline] -pub fn clear(context: &mut Context) { - // clear error and journaled state. - let _ = context.evm.take_error(); - context.evm.inner.journaled_state.clear(); -} - -/// Reward beneficiary with gas fee. -#[inline] -pub fn reward_beneficiary( - context: &mut Context, - gas: &Gas, -) -> Result<(), EVMError> { - let beneficiary = context.evm.env.block.coinbase; - let effective_gas_price = context.evm.env.effective_gas_price(); - - // transfer fee to coinbase/beneficiary. - // EIP-1559 discard basefee for coinbase transfer. Basefee amount of gas is discarded. - let coinbase_gas_price = if SPEC::enabled(LONDON) { - effective_gas_price.saturating_sub(context.evm.env.block.basefee) - } else { - effective_gas_price - }; - - let (coinbase_account, _) = context - .evm - .inner - .journaled_state - .load_account(beneficiary, &mut context.evm.inner.db)?; - - coinbase_account.mark_touch(); - coinbase_account.info.balance = coinbase_account - .info - .balance - .saturating_add(coinbase_gas_price * U256::from(gas.spent() - gas.refunded() as u64)); - - Ok(()) -} - -#[inline] -pub fn reimburse_caller( - context: &mut Context, - gas: &Gas, -) -> Result<(), EVMError> { - let caller = context.evm.env.tx.caller; - let effective_gas_price = context.evm.env.effective_gas_price(); - - // return balance of not spend gas. - let (caller_account, _) = context - .evm - .inner - .journaled_state - .load_account(caller, &mut context.evm.inner.db)?; - - caller_account.info.balance = caller_account - .info - .balance - .saturating_add(effective_gas_price * U256::from(gas.remaining() + gas.refunded() as u64)); - - Ok(()) -} - -/// Main return handle, returns the output of the transaction. -#[inline] -pub fn output( - context: &mut Context, - result: FrameResult, -) -> Result> { - context.evm.take_error()?; - // used gas with refund calculated. - let gas_refunded = result.gas().refunded() as u64; - let final_gas_used = result.gas().spent() - gas_refunded; - let output = result.output(); - let instruction_result = result.into_interpreter_result(); - - // reset journal and return present state. - let (state, logs) = context.evm.journaled_state.finalize(); - - let result = match instruction_result.result.into() { - SuccessOrHalt::Success(reason) => ExecutionResult::Success { - reason, - gas_used: final_gas_used, - gas_refunded, - logs, - output, - }, - SuccessOrHalt::Revert => ExecutionResult::Revert { - gas_used: final_gas_used, - output: output.into_data(), - }, - SuccessOrHalt::Halt(reason) => ExecutionResult::Halt { - reason, - gas_used: final_gas_used, - }, - // Only two internal return flags. - flag @ (SuccessOrHalt::FatalExternalError - | SuccessOrHalt::InternalContinue - | SuccessOrHalt::InternalCallOrCreate) => { - panic!( - "Encountered unexpected internal return flag: {:?} with instruction result: {:?}", - flag, instruction_result - ) - } - }; - - Ok(ResultAndState { result, state }) -} diff --git a/crates/revm/src/handler/mainnet/pre_execution.rs b/crates/revm/src/handler/mainnet/pre_execution.rs deleted file mode 100644 index c0f4fe7bde..0000000000 --- a/crates/revm/src/handler/mainnet/pre_execution.rs +++ /dev/null @@ -1,98 +0,0 @@ -//! Handles related to the main function of the EVM. -//! -//! They handle initial setup of the EVM, call loop and the final return of the EVM - -use crate::{ - precompile::{PrecompileSpecId, Precompiles}, - primitives::{ - db::Database, - Account, EVMError, Env, Spec, - SpecId::{CANCUN, PRAGUE, SHANGHAI}, - TransactTo, BLOCKHASH_STORAGE_ADDRESS, U256, - }, - Context, ContextPrecompiles, -}; - -/// Main precompile load -#[inline] -pub fn load_precompiles() -> ContextPrecompiles { - Precompiles::new(PrecompileSpecId::from_spec_id(SPEC::SPEC_ID)) - .clone() - .into() -} - -/// Main load handle -#[inline] -pub fn load_accounts( - context: &mut Context, -) -> Result<(), EVMError> { - // set journaling state flag. - context.evm.journaled_state.set_spec_id(SPEC::SPEC_ID); - - // load coinbase - // EIP-3651: Warm COINBASE. Starts the `COINBASE` address warm - if SPEC::enabled(SHANGHAI) { - context.evm.inner.journaled_state.initial_account_load( - context.evm.inner.env.block.coinbase, - &[], - &mut context.evm.inner.db, - )?; - } - - // Load blockhash storage address - // EIP-2935: Serve historical block hashes from state - if SPEC::enabled(PRAGUE) { - context.evm.inner.journaled_state.initial_account_load( - BLOCKHASH_STORAGE_ADDRESS, - &[], - &mut context.evm.inner.db, - )?; - } - - context.evm.load_access_list()?; - Ok(()) -} - -/// Helper function that deducts the caller balance. -#[inline] -pub fn deduct_caller_inner(caller_account: &mut Account, env: &Env) { - // Subtract gas costs from the caller's account. - // We need to saturate the gas cost to prevent underflow in case that `disable_balance_check` is enabled. - let mut gas_cost = U256::from(env.tx.gas_limit).saturating_mul(env.effective_gas_price()); - - // EIP-4844 - if SPEC::enabled(CANCUN) { - let data_fee = env.calc_data_fee().expect("already checked"); - gas_cost = gas_cost.saturating_add(data_fee); - } - - // set new caller account balance. - caller_account.info.balance = caller_account.info.balance.saturating_sub(gas_cost); - - // bump the nonce for calls. Nonce for CREATE will be bumped in `handle_create`. - if matches!(env.tx.transact_to, TransactTo::Call(_)) { - // Nonce is already checked - caller_account.info.nonce = caller_account.info.nonce.saturating_add(1); - } - - // touch account so we know it is changed. - caller_account.mark_touch(); -} - -/// Deducts the caller balance to the transaction limit. -#[inline] -pub fn deduct_caller( - context: &mut Context, -) -> Result<(), EVMError> { - // load caller's account. - let (caller_account, _) = context - .evm - .inner - .journaled_state - .load_account(context.evm.inner.env.tx.caller, &mut context.evm.inner.db)?; - - // deduct gas cost from caller's account. - deduct_caller_inner::(caller_account, &context.evm.inner.env); - - Ok(()) -} diff --git a/crates/revm/src/handler/mainnet/validation.rs b/crates/revm/src/handler/mainnet/validation.rs deleted file mode 100644 index 176e0e8282..0000000000 --- a/crates/revm/src/handler/mainnet/validation.rs +++ /dev/null @@ -1,54 +0,0 @@ -use revm_interpreter::gas; - -use crate::{ - primitives::{db::Database, EVMError, Env, InvalidTransaction, Spec}, - Context, -}; - -/// Validate environment for the mainnet. -pub fn validate_env(env: &Env) -> Result<(), EVMError> { - // Important: validate block before tx. - env.validate_block_env::()?; - env.validate_tx::()?; - Ok(()) -} - -/// Validates transaction against the state. -pub fn validate_tx_against_state( - context: &mut Context, -) -> Result<(), EVMError> { - // load acc - let tx_caller = context.evm.env.tx.caller; - let (caller_account, _) = context - .evm - .inner - .journaled_state - .load_account(tx_caller, &mut context.evm.inner.db)?; - - context - .evm - .inner - .env - .validate_tx_against_state::(caller_account) - .map_err(EVMError::Transaction)?; - - Ok(()) -} - -/// Validate initial transaction gas. -pub fn validate_initial_tx_gas( - env: &Env, -) -> Result> { - let input = &env.tx.data; - let is_create = env.tx.transact_to.is_create(); - let access_list = &env.tx.access_list; - - let initial_gas_spend = - gas::validate_initial_tx_gas(SPEC::SPEC_ID, input, is_create, access_list); - - // Additional check to see if limit is big enough to cover initial gas. - if initial_gas_spend > env.tx.gas_limit { - return Err(InvalidTransaction::CallGasCostMoreThanGasLimit.into()); - } - Ok(initial_gas_spend) -} diff --git a/crates/revm/src/handler/register.rs b/crates/revm/src/handler/register.rs deleted file mode 100644 index 4b9fa31377..0000000000 --- a/crates/revm/src/handler/register.rs +++ /dev/null @@ -1,28 +0,0 @@ -use crate::{db::Database, handler::Handler, Context}; -use std::boxed::Box; - -/// EVM Handler -pub type EvmHandler<'a, EXT, DB> = Handler<'a, Context, EXT, DB>; - -// Handle register -pub type HandleRegister = for<'a> fn(&mut EvmHandler<'a, EXT, DB>); - -// Boxed handle register -pub type HandleRegisterBox = Box Fn(&mut EvmHandler<'a, EXT, DB>)>; - -pub enum HandleRegisters { - /// Plain function register - Plain(HandleRegister), - /// Boxed function register. - Box(HandleRegisterBox), -} - -impl HandleRegisters { - /// Call register function to modify EvmHandler. - pub fn register(&self, handler: &mut EvmHandler<'_, EXT, DB>) { - match self { - HandleRegisters::Plain(f) => f(handler), - HandleRegisters::Box(f) => f(handler), - } - } -} diff --git a/crates/revm/src/inspector.rs b/crates/revm/src/inspector.rs deleted file mode 100644 index 170a42cd26..0000000000 --- a/crates/revm/src/inspector.rs +++ /dev/null @@ -1,166 +0,0 @@ -use crate::{ - interpreter::{CallInputs, CreateInputs, EOFCreateInput, EOFCreateOutcome, Interpreter}, - primitives::{db::Database, Address, Log, U256}, - EvmContext, -}; -use auto_impl::auto_impl; - -#[cfg(feature = "std")] -mod customprinter; -#[cfg(all(feature = "std", feature = "serde-json"))] -mod eip3155; -mod gas; -mod handler_register; -mod noop; - -// Exports. - -pub use handler_register::{inspector_handle_register, inspector_instruction, GetInspector}; -use revm_interpreter::{CallOutcome, CreateOutcome}; - -/// [Inspector] implementations. -pub mod inspectors { - #[cfg(feature = "std")] - pub use super::customprinter::CustomPrintTracer; - #[cfg(all(feature = "std", feature = "serde-json"))] - pub use super::eip3155::TracerEip3155; - pub use super::gas::GasInspector; - pub use super::noop::NoOpInspector; -} - -/// EVM [Interpreter] callbacks. -#[auto_impl(&mut, Box)] -pub trait Inspector { - /// Called before the interpreter is initialized. - /// - /// If `interp.instruction_result` is set to anything other than [crate::interpreter::InstructionResult::Continue] then the execution of the interpreter - /// is skipped. - #[inline] - fn initialize_interp(&mut self, interp: &mut Interpreter, context: &mut EvmContext) { - let _ = interp; - let _ = context; - } - - /// Called on each step of the interpreter. - /// - /// Information about the current execution, including the memory, stack and more is available - /// on `interp` (see [Interpreter]). - /// - /// # Example - /// - /// To get the current opcode, use `interp.current_opcode()`. - #[inline] - fn step(&mut self, interp: &mut Interpreter, context: &mut EvmContext) { - let _ = interp; - let _ = context; - } - - /// Called after `step` when the instruction has been executed. - /// - /// Setting `interp.instruction_result` to anything other than [crate::interpreter::InstructionResult::Continue] alters the execution - /// of the interpreter. - #[inline] - fn step_end(&mut self, interp: &mut Interpreter, context: &mut EvmContext) { - let _ = interp; - let _ = context; - } - - /// Called when a log is emitted. - #[inline] - fn log(&mut self, context: &mut EvmContext, log: &Log) { - let _ = context; - let _ = log; - } - - /// Called whenever a call to a contract is about to start. - /// - /// InstructionResulting anything other than [crate::interpreter::InstructionResult::Continue] overrides the result of the call. - #[inline] - fn call( - &mut self, - context: &mut EvmContext, - inputs: &mut CallInputs, - ) -> Option { - let _ = context; - let _ = inputs; - None - } - - /// Called when a call to a contract has concluded. - /// - /// The returned [CallOutcome] is used as the result of the call. - /// - /// This allows the inspector to modify the given `result` before returning it. - #[inline] - fn call_end( - &mut self, - context: &mut EvmContext, - inputs: &CallInputs, - outcome: CallOutcome, - ) -> CallOutcome { - let _ = context; - let _ = inputs; - outcome - } - - /// Called when a contract is about to be created. - /// - /// If this returns `Some` then the [CreateOutcome] is used to override the result of the creation. - /// - /// If this returns `None` then the creation proceeds as normal. - #[inline] - fn create( - &mut self, - context: &mut EvmContext, - inputs: &mut CreateInputs, - ) -> Option { - let _ = context; - let _ = inputs; - None - } - - /// Called when a contract has been created. - /// - /// InstructionResulting anything other than the values passed to this function (`(ret, remaining_gas, - /// address, out)`) will alter the result of the create. - #[inline] - fn create_end( - &mut self, - context: &mut EvmContext, - inputs: &CreateInputs, - outcome: CreateOutcome, - ) -> CreateOutcome { - let _ = context; - let _ = inputs; - outcome - } - - fn eofcreate( - &mut self, - context: &mut EvmContext, - inputs: &mut EOFCreateInput, - ) -> Option { - let _ = context; - let _ = inputs; - None - } - - fn eofcreate_end( - &mut self, - context: &mut EvmContext, - inputs: &EOFCreateInput, - outcome: EOFCreateOutcome, - ) -> EOFCreateOutcome { - let _ = context; - let _ = inputs; - outcome - } - - /// Called when a contract has been self-destructed with funds transferred to target. - #[inline] - fn selfdestruct(&mut self, contract: Address, target: Address, value: U256) { - let _ = contract; - let _ = target; - let _ = value; - } -} diff --git a/crates/revm/src/inspector/customprinter.rs b/crates/revm/src/inspector/customprinter.rs deleted file mode 100644 index ac7dd26537..0000000000 --- a/crates/revm/src/inspector/customprinter.rs +++ /dev/null @@ -1,154 +0,0 @@ -//! Custom print inspector, it has step level information of execution. -//! It is a great tool if some debugging is needed. - -use revm_interpreter::CallOutcome; -use revm_interpreter::CreateOutcome; -use revm_interpreter::OpCode; - -use crate::{ - inspectors::GasInspector, - interpreter::{CallInputs, CreateInputs, Interpreter}, - primitives::{Address, U256}, - Database, EvmContext, Inspector, -}; - -/// Custom print [Inspector], it has step level information of execution. -/// -/// It is a great tool if some debugging is needed. -#[derive(Clone, Debug, Default)] -pub struct CustomPrintTracer { - gas_inspector: GasInspector, -} - -impl Inspector for CustomPrintTracer { - fn initialize_interp(&mut self, interp: &mut Interpreter, context: &mut EvmContext) { - self.gas_inspector.initialize_interp(interp, context); - } - - // get opcode by calling `interp.contract.opcode(interp.program_counter())`. - // all other information can be obtained from interp. - fn step(&mut self, interp: &mut Interpreter, context: &mut EvmContext) { - let opcode = interp.current_opcode(); - let name = OpCode::name_by_op(opcode); - - let gas_remaining = self.gas_inspector.gas_remaining(); - - let memory_size = interp.shared_memory.len(); - - println!( - "depth:{}, PC:{}, gas:{:#x}({}), OPCODE: {:?}({:?}) refund:{:#x}({}) Stack:{:?}, Data size:{}", - context.journaled_state.depth(), - interp.program_counter(), - gas_remaining, - gas_remaining, - name, - opcode, - interp.gas.refunded(), - interp.gas.refunded(), - interp.stack.data(), - memory_size, - ); - - self.gas_inspector.step(interp, context); - } - - fn step_end(&mut self, interp: &mut Interpreter, context: &mut EvmContext) { - self.gas_inspector.step_end(interp, context); - } - - fn call_end( - &mut self, - context: &mut EvmContext, - inputs: &CallInputs, - outcome: CallOutcome, - ) -> CallOutcome { - self.gas_inspector.call_end(context, inputs, outcome) - } - - fn create_end( - &mut self, - context: &mut EvmContext, - inputs: &CreateInputs, - outcome: CreateOutcome, - ) -> CreateOutcome { - self.gas_inspector.create_end(context, inputs, outcome) - } - - fn call( - &mut self, - _context: &mut EvmContext, - inputs: &mut CallInputs, - ) -> Option { - println!( - "SM Address: {:?}, caller:{:?},target:{:?} is_static:{:?}, transfer:{:?}, input_size:{:?}", - inputs.bytecode_address, - inputs.caller, - inputs.target_address, - inputs.is_static, - inputs.value, - inputs.input.len(), - ); - None - } - - fn create( - &mut self, - _context: &mut EvmContext, - inputs: &mut CreateInputs, - ) -> Option { - println!( - "CREATE CALL: caller:{:?}, scheme:{:?}, value:{:?}, init_code:{:?}, gas:{:?}", - inputs.caller, inputs.scheme, inputs.value, inputs.init_code, inputs.gas_limit - ); - None - } - - fn selfdestruct(&mut self, contract: Address, target: Address, value: U256) { - println!( - "SELFDESTRUCT: contract: {:?}, refund target: {:?}, value {:?}", - contract, target, value - ); - } -} - -#[cfg(test)] -mod test { - use crate::{ - inspector_handle_register, - inspectors::CustomPrintTracer, - primitives::{address, bytes, SpecId}, - Evm, InMemoryDB, - }; - - #[test] - fn gas_calculation_underflow() { - let callee = address!("5fdcca53617f4d2b9134b29090c87d01058e27e9"); - - // https://github.com/bluealloy/revm/issues/277 - // checks this use case - let mut evm = Evm::builder() - .with_db(InMemoryDB::default()) - .modify_db(|db| { - let code = bytes!("5b597fb075978b6c412c64d169d56d839a8fe01b3f4607ed603b2c78917ce8be1430fe6101e8527ffe64706ecad72a2f5c97a95e006e279dc57081902029ce96af7edae5de116fec610208527f9fc1ef09d4dd80683858ae3ea18869fe789ddc365d8d9d800e26c9872bac5e5b6102285260276102485360d461024953601661024a53600e61024b53607d61024c53600961024d53600b61024e5360b761024f5360596102505360796102515360a061025253607261025353603a6102545360fb61025553601261025653602861025753600761025853606f61025953601761025a53606161025b53606061025c5360a661025d53602b61025e53608961025f53607a61026053606461026153608c6102625360806102635360d56102645360826102655360ae61026653607f6101e8610146610220677a814b184591c555735fdcca53617f4d2b9134b29090c87d01058e27e962047654f259595947443b1b816b65cdb6277f4b59c10a36f4e7b8658f5a5e6f5561"); - let info = crate::primitives::AccountInfo { - balance: "0x100c5d668240db8e00".parse().unwrap(), - code_hash: crate::primitives::keccak256(&code), - code: Some(crate::primitives::Bytecode::new_raw(code.clone())), - nonce: 1, - }; - db.insert_account_info(callee, info); - }) - .modify_tx_env(|tx| { - tx.caller = address!("5fdcca53617f4d2b9134b29090c87d01058e27e0"); - tx.transact_to = crate::primitives::TransactTo::Call(callee); - tx.data = crate::primitives::Bytes::new(); - tx.value = crate::primitives::U256::ZERO; - }) - .with_external_context(CustomPrintTracer::default()) - .with_spec_id(SpecId::BERLIN) - .append_handler_register(inspector_handle_register) - .build(); - - evm.transact().expect("Transaction to work"); - } -} diff --git a/crates/revm/src/inspector/eip3155.rs b/crates/revm/src/inspector/eip3155.rs deleted file mode 100644 index aec20ffd8f..0000000000 --- a/crates/revm/src/inspector/eip3155.rs +++ /dev/null @@ -1,286 +0,0 @@ -use crate::{ - inspectors::GasInspector, - interpreter::{ - CallInputs, CallOutcome, CreateInputs, CreateOutcome, Interpreter, InterpreterResult, - }, - primitives::{db::Database, hex, HashMap, B256, U256}, - EvmContext, Inspector, -}; -use revm_interpreter::OpCode; -use serde::Serialize; -use std::io::Write; - -/// [EIP-3155](https://eips.ethereum.org/EIPS/eip-3155) tracer [Inspector]. -pub struct TracerEip3155 { - output: Box, - gas_inspector: GasInspector, - - /// Print summary of the execution. - print_summary: bool, - - stack: Vec, - pc: usize, - opcode: u8, - gas: u64, - refunded: i64, - mem_size: usize, - skip: bool, - include_memory: bool, - memory: Option, -} - -// # Output -// The CUT MUST output a `json` object for EACH operation. -#[derive(Serialize)] -#[serde(rename_all = "camelCase")] -struct Output { - // Required fields: - /// Program counter - pc: u64, - /// OpCode - op: u8, - /// Gas left before executing this operation - gas: String, - /// Gas cost of this operation - gas_cost: String, - /// Array of all values on the stack - stack: Vec, - /// Depth of the call stack - depth: u64, - /// Data returned by the function call - return_data: String, - /// Amount of **global** gas refunded - refund: String, - /// Size of memory array - mem_size: String, - - // Optional fields: - /// Name of the operation - #[serde(default, skip_serializing_if = "Option::is_none")] - op_name: Option<&'static str>, - /// Description of an error (should contain revert reason if supported) - #[serde(default, skip_serializing_if = "Option::is_none")] - error: Option, - /// Array of all allocated values - #[serde(default, skip_serializing_if = "Option::is_none")] - memory: Option, - /// Array of all stored values - #[serde(default, skip_serializing_if = "Option::is_none")] - storage: Option>, - /// Array of values, Stack of the called function - #[serde(default, skip_serializing_if = "Option::is_none")] - return_stack: Option>, -} - -// # Summary and error handling -#[derive(Serialize)] -#[serde(rename_all = "camelCase")] -struct Summary { - // Required fields: - /// Root of the state trie after executing the transaction - state_root: String, - /// Return values of the function - output: String, - /// All gas used by the transaction - gas_used: String, - /// Bool whether transaction was executed successfully - pass: bool, - - // Optional fields: - /// Time in nanoseconds needed to execute the transaction - #[serde(default, skip_serializing_if = "Option::is_none")] - time: Option, - /// Name of the fork rules used for execution - #[serde(default, skip_serializing_if = "Option::is_none")] - fork: Option, -} - -impl TracerEip3155 { - /// Sets the writer to use for the output. - pub fn set_writer(&mut self, writer: Box) { - self.output = writer; - } - - /// Resets the Tracer to its initial state of [Self::new]. - /// This makes the inspector ready to be used again. - pub fn clear(&mut self) { - let Self { - gas_inspector, - stack, - pc, - opcode, - gas, - refunded, - mem_size, - skip, - .. - } = self; - *gas_inspector = GasInspector::default(); - stack.clear(); - *pc = 0; - *opcode = 0; - *gas = 0; - *refunded = 0; - *mem_size = 0; - *skip = false; - } -} - -impl TracerEip3155 { - pub fn new(output: Box) -> Self { - Self { - output, - gas_inspector: GasInspector::default(), - print_summary: true, - include_memory: false, - stack: Default::default(), - memory: Default::default(), - pc: 0, - opcode: 0, - gas: 0, - refunded: 0, - mem_size: 0, - skip: false, - } - } - - /// Don't include a summary at the end of the trace - pub fn without_summary(mut self) -> Self { - self.print_summary = false; - self - } - - /// Include a memory field for each step. This significantly increases processing time and output size. - pub fn with_memory(mut self) -> Self { - self.include_memory = true; - self - } - - fn write_value(&mut self, value: &impl serde::Serialize) -> std::io::Result<()> { - serde_json::to_writer(&mut *self.output, value)?; - self.output.write_all(b"\n")?; - self.output.flush() - } - - fn print_summary( - &mut self, - result: &InterpreterResult, - context: &mut EvmContext, - ) { - if self.print_summary { - let spec_name: &str = context.spec_id().into(); - let value = Summary { - state_root: B256::ZERO.to_string(), - output: result.output.to_string(), - gas_used: hex_number( - context.inner.env().tx.gas_limit - self.gas_inspector.gas_remaining(), - ), - pass: result.is_ok(), - time: None, - fork: Some(spec_name.to_string()), - }; - let _ = self.write_value(&value); - } - } -} - -impl Inspector for TracerEip3155 { - fn initialize_interp(&mut self, interp: &mut Interpreter, context: &mut EvmContext) { - self.gas_inspector.initialize_interp(interp, context); - } - - fn step(&mut self, interp: &mut Interpreter, context: &mut EvmContext) { - self.gas_inspector.step(interp, context); - self.stack.clone_from(interp.stack.data()); - self.memory = if self.include_memory { - Some(hex::encode_prefixed(interp.shared_memory.context_memory())) - } else { - None - }; - self.pc = interp.program_counter(); - self.opcode = interp.current_opcode(); - self.mem_size = interp.shared_memory.len(); - self.gas = interp.gas.remaining(); - self.refunded = interp.gas.refunded(); - } - - fn step_end(&mut self, interp: &mut Interpreter, context: &mut EvmContext) { - self.gas_inspector.step_end(interp, context); - if self.skip { - self.skip = false; - return; - } - - let value = Output { - pc: self.pc as u64, - op: self.opcode, - gas: hex_number(self.gas), - gas_cost: hex_number(self.gas_inspector.last_gas_cost()), - stack: self.stack.iter().map(hex_number_u256).collect(), - depth: context.journaled_state.depth(), - return_data: "0x".to_string(), - refund: hex_number(self.refunded as u64), - mem_size: self.mem_size.to_string(), - - op_name: OpCode::new(self.opcode).map(|i| i.as_str()), - error: if !interp.instruction_result.is_ok() { - Some(format!("{:?}", interp.instruction_result)) - } else { - None - }, - memory: self.memory.take(), - storage: None, - return_stack: None, - }; - let _ = self.write_value(&value); - } - - fn call_end( - &mut self, - context: &mut EvmContext, - inputs: &CallInputs, - outcome: CallOutcome, - ) -> CallOutcome { - let outcome = self.gas_inspector.call_end(context, inputs, outcome); - - if context.journaled_state.depth() == 0 { - self.print_summary(&outcome.result, context); - // clear the state if we are at the top level - self.clear(); - } - - outcome - } - - fn create_end( - &mut self, - context: &mut EvmContext, - inputs: &CreateInputs, - outcome: CreateOutcome, - ) -> CreateOutcome { - let outcome = self.gas_inspector.create_end(context, inputs, outcome); - - if context.journaled_state.depth() == 0 { - self.print_summary(&outcome.result, context); - - // clear the state if we are at the top level - self.clear(); - } - - outcome - } -} - -fn hex_number(uint: u64) -> String { - format!("0x{uint:x}") -} - -fn hex_number_u256(b: &U256) -> String { - let s = hex::encode(b.to_be_bytes::<32>()); - let s = s.trim_start_matches('0'); - if s.is_empty() { - "0x0".to_string() - } else { - format!("0x{s}") - } -} diff --git a/crates/revm/src/inspector/gas.rs b/crates/revm/src/inspector/gas.rs deleted file mode 100644 index 7542c3d3bf..0000000000 --- a/crates/revm/src/inspector/gas.rs +++ /dev/null @@ -1,220 +0,0 @@ -//! GasIspector. Helper Inspector to calculate gas for others. - -use revm_interpreter::CallOutcome; - -use crate::{ - interpreter::{CallInputs, CreateInputs, CreateOutcome}, - primitives::db::Database, - EvmContext, Inspector, -}; - -/// Helper [Inspector] that keeps track of gas. -#[allow(dead_code)] -#[derive(Clone, Copy, Debug, Default)] -pub struct GasInspector { - gas_remaining: u64, - last_gas_cost: u64, -} - -impl GasInspector { - pub fn gas_remaining(&self) -> u64 { - self.gas_remaining - } - - pub fn last_gas_cost(&self) -> u64 { - self.last_gas_cost - } -} - -impl Inspector for GasInspector { - fn initialize_interp( - &mut self, - interp: &mut crate::interpreter::Interpreter, - _context: &mut EvmContext, - ) { - self.gas_remaining = interp.gas.limit(); - } - - fn step( - &mut self, - interp: &mut crate::interpreter::Interpreter, - _context: &mut EvmContext, - ) { - self.gas_remaining = interp.gas.remaining(); - } - - fn step_end( - &mut self, - interp: &mut crate::interpreter::Interpreter, - _context: &mut EvmContext, - ) { - let remaining = interp.gas.remaining(); - self.last_gas_cost = self.gas_remaining.saturating_sub(remaining); - self.gas_remaining = remaining; - } - - fn call_end( - &mut self, - _context: &mut EvmContext, - _inputs: &CallInputs, - mut outcome: CallOutcome, - ) -> CallOutcome { - if outcome.result.result.is_error() { - outcome.result.gas.spend_all(); - self.gas_remaining = 0; - } - outcome - } - - fn create_end( - &mut self, - _context: &mut EvmContext, - _inputs: &CreateInputs, - mut outcome: CreateOutcome, - ) -> CreateOutcome { - if outcome.result.result.is_error() { - outcome.result.gas.spend_all(); - self.gas_remaining = 0; - } - outcome - } -} - -#[cfg(test)] -mod tests { - - use revm_interpreter::CallOutcome; - use revm_interpreter::CreateOutcome; - - use crate::{ - inspectors::GasInspector, - interpreter::{CallInputs, CreateInputs, Interpreter}, - primitives::Log, - Database, EvmContext, Inspector, - }; - - #[derive(Default, Debug)] - struct StackInspector { - pc: usize, - gas_inspector: GasInspector, - gas_remaining_steps: Vec<(usize, u64)>, - } - - impl Inspector for StackInspector { - fn initialize_interp(&mut self, interp: &mut Interpreter, context: &mut EvmContext) { - self.gas_inspector.initialize_interp(interp, context); - } - - fn step(&mut self, interp: &mut Interpreter, context: &mut EvmContext) { - self.pc = interp.program_counter(); - self.gas_inspector.step(interp, context); - } - - fn log(&mut self, context: &mut EvmContext, log: &Log) { - self.gas_inspector.log(context, log); - } - - fn step_end(&mut self, interp: &mut Interpreter, context: &mut EvmContext) { - self.gas_inspector.step_end(interp, context); - self.gas_remaining_steps - .push((self.pc, self.gas_inspector.gas_remaining())); - } - - fn call( - &mut self, - context: &mut EvmContext, - call: &mut CallInputs, - ) -> Option { - self.gas_inspector.call(context, call) - } - - fn call_end( - &mut self, - context: &mut EvmContext, - inputs: &CallInputs, - outcome: CallOutcome, - ) -> CallOutcome { - self.gas_inspector.call_end(context, inputs, outcome) - } - - fn create( - &mut self, - context: &mut EvmContext, - call: &mut CreateInputs, - ) -> Option { - self.gas_inspector.create(context, call); - None - } - - fn create_end( - &mut self, - context: &mut EvmContext, - inputs: &CreateInputs, - outcome: CreateOutcome, - ) -> CreateOutcome { - self.gas_inspector.create_end(context, inputs, outcome) - } - } - - #[test] - fn test_gas_inspector() { - use crate::{ - db::BenchmarkDB, - inspector::inspector_handle_register, - interpreter::opcode, - primitives::{address, Bytecode, Bytes, TransactTo}, - Evm, - }; - - let contract_data: Bytes = Bytes::from(vec![ - opcode::PUSH1, - 0x1, - opcode::PUSH1, - 0xb, - opcode::JUMPI, - opcode::PUSH1, - 0x1, - opcode::PUSH1, - 0x1, - opcode::PUSH1, - 0x1, - opcode::JUMPDEST, - opcode::STOP, - ]); - let bytecode = Bytecode::new_raw(contract_data); - - let mut evm: Evm<'_, StackInspector, BenchmarkDB> = Evm::builder() - .with_db(BenchmarkDB::new_bytecode(bytecode.clone())) - .with_external_context(StackInspector::default()) - .modify_tx_env(|tx| { - tx.clear(); - tx.caller = address!("1000000000000000000000000000000000000000"); - tx.transact_to = - TransactTo::Call(address!("0000000000000000000000000000000000000000")); - tx.gas_limit = 21100; - }) - .append_handler_register(inspector_handle_register) - .build(); - - // run evm. - evm.transact().unwrap(); - - let inspector = evm.into_context().external; - - // starting from 100gas - let steps = vec![ - // push1 -3 - (0, 97), - // push1 -3 - (2, 94), - // jumpi -10 - (4, 84), - // jumpdest 1 - (11, 83), - // stop 0 - (12, 83), - ]; - - assert_eq!(inspector.gas_remaining_steps, steps); - } -} diff --git a/crates/revm/src/inspector/handler_register.rs b/crates/revm/src/inspector/handler_register.rs deleted file mode 100644 index 01bc11c577..0000000000 --- a/crates/revm/src/inspector/handler_register.rs +++ /dev/null @@ -1,405 +0,0 @@ -use crate::{ - db::Database, - handler::register::EvmHandler, - interpreter::{ - opcode::{self, BoxedInstruction}, - InstructionResult, Interpreter, - }, - primitives::EVMError, - Context, FrameOrResult, FrameResult, Inspector, JournalEntry, -}; -use core::cell::RefCell; -use revm_interpreter::opcode::InstructionTables; -use std::{boxed::Box, rc::Rc, sync::Arc, vec::Vec}; - -/// Provides access to an `Inspector` instance. -pub trait GetInspector { - /// Returns the associated `Inspector`. - fn get_inspector(&mut self) -> &mut impl Inspector; -} - -impl> GetInspector for INSP { - #[inline] - fn get_inspector(&mut self) -> &mut impl Inspector { - self - } -} - -/// Register Inspector handles that interact with Inspector instance. -/// -/// -/// # Note -/// -/// Inspector handle register does not override any existing handlers, and it -/// calls them before (or after) calling Inspector. This means that it is safe -/// to use this register with any other register. -/// -/// A few instructions handlers are wrapped twice once for `step` and `step_end` -/// and in case of Logs and Selfdestruct wrapper is wrapped again for the -/// `log` and `selfdestruct` calls. -pub fn inspector_handle_register>( - handler: &mut EvmHandler<'_, EXT, DB>, -) { - // Every instruction inside flat table that is going to be wrapped by inspector calls. - let table = handler.take_instruction_table(); - let mut table = match table { - InstructionTables::Plain(table) => table - .into_iter() - .map(|i| inspector_instruction(i)) - .collect::>(), - InstructionTables::Boxed(table) => table - .into_iter() - .map(|i| inspector_instruction(i)) - .collect::>(), - }; - - // Register inspector Log instruction. - let mut inspect_log = |index: u8| { - if let Some(i) = table.get_mut(index as usize) { - let old = core::mem::replace(i, Box::new(|_, _| ())); - *i = Box::new( - move |interpreter: &mut Interpreter, host: &mut Context| { - let old_log_len = host.evm.journaled_state.logs.len(); - old(interpreter, host); - // check if log was added. It is possible that revert happened - // cause of gas or stack underflow. - if host.evm.journaled_state.logs.len() == old_log_len + 1 { - // clone log. - // TODO decide if we should remove this and leave the comment - // that log can be found as journaled_state. - let last_log = host.evm.journaled_state.logs.last().unwrap().clone(); - // call Inspector - host.external.get_inspector().log(&mut host.evm, &last_log); - } - }, - ) - } - }; - - inspect_log(opcode::LOG0); - inspect_log(opcode::LOG1); - inspect_log(opcode::LOG2); - inspect_log(opcode::LOG3); - inspect_log(opcode::LOG4); - - // // register selfdestruct function. - if let Some(i) = table.get_mut(opcode::SELFDESTRUCT as usize) { - let old = core::mem::replace(i, Box::new(|_, _| ())); - *i = Box::new( - move |interpreter: &mut Interpreter, host: &mut Context| { - // execute selfdestruct - old(interpreter, host); - // check if selfdestruct was successful and if journal entry is made. - if let Some(JournalEntry::AccountDestroyed { - address, - target, - had_balance, - .. - }) = host.evm.journaled_state.journal.last().unwrap().last() - { - host.external - .get_inspector() - .selfdestruct(*address, *target, *had_balance); - } - }, - ) - } - - // cast vector to array. - handler.set_instruction_table(InstructionTables::Boxed( - table.try_into().unwrap_or_else(|_| unreachable!()), - )); - - // call and create input stack shared between handlers. They are used to share - // inputs in *_end Inspector calls. - let call_input_stack = Rc::>>::new(RefCell::new(Vec::new())); - let create_input_stack = Rc::>>::new(RefCell::new(Vec::new())); - let eofcreate_input_stack = Rc::>>::new(RefCell::new(Vec::new())); - - // Create handler - let create_input_stack_inner = create_input_stack.clone(); - let old_handle = handler.execution.create.clone(); - handler.execution.create = Arc::new( - move |ctx, mut inputs| -> Result> { - let inspector = ctx.external.get_inspector(); - // call inspector create to change input or return outcome. - if let Some(outcome) = inspector.create(&mut ctx.evm, &mut inputs) { - create_input_stack_inner.borrow_mut().push(inputs.clone()); - return Ok(FrameOrResult::Result(FrameResult::Create(outcome))); - } - create_input_stack_inner.borrow_mut().push(inputs.clone()); - - let mut frame_or_result = old_handle(ctx, inputs); - if let Ok(FrameOrResult::Frame(frame)) = &mut frame_or_result { - ctx.external - .get_inspector() - .initialize_interp(frame.interpreter_mut(), &mut ctx.evm) - } - frame_or_result - }, - ); - - // Call handler - let call_input_stack_inner = call_input_stack.clone(); - let old_handle = handler.execution.call.clone(); - handler.execution.call = Arc::new( - move |ctx, mut inputs| -> Result> { - // Call inspector to change input or return outcome. - let outcome = ctx.external.get_inspector().call(&mut ctx.evm, &mut inputs); - call_input_stack_inner.borrow_mut().push(inputs.clone()); - if let Some(outcome) = outcome { - return Ok(FrameOrResult::Result(FrameResult::Call(outcome))); - } - - let mut frame_or_result = old_handle(ctx, inputs); - if let Ok(FrameOrResult::Frame(frame)) = &mut frame_or_result { - ctx.external - .get_inspector() - .initialize_interp(frame.interpreter_mut(), &mut ctx.evm) - } - frame_or_result - }, - ); - - // TODO(EOF) EOF create call. - - // call outcome - let call_input_stack_inner = call_input_stack.clone(); - let old_handle = handler.execution.insert_call_outcome.clone(); - handler.execution.insert_call_outcome = - Arc::new(move |ctx, frame, shared_memory, mut outcome| { - let call_inputs = call_input_stack_inner.borrow_mut().pop().unwrap(); - outcome = ctx - .external - .get_inspector() - .call_end(&mut ctx.evm, &call_inputs, outcome); - old_handle(ctx, frame, shared_memory, outcome) - }); - - // create outcome - let create_input_stack_inner = create_input_stack.clone(); - let old_handle = handler.execution.insert_create_outcome.clone(); - handler.execution.insert_create_outcome = Arc::new(move |ctx, frame, mut outcome| { - let create_inputs = create_input_stack_inner.borrow_mut().pop().unwrap(); - outcome = ctx - .external - .get_inspector() - .create_end(&mut ctx.evm, &create_inputs, outcome); - old_handle(ctx, frame, outcome) - }); - - // TODO(EOF) EOF create handle. - - // last frame outcome - let old_handle = handler.execution.last_frame_return.clone(); - handler.execution.last_frame_return = Arc::new(move |ctx, frame_result| { - let inspector = ctx.external.get_inspector(); - match frame_result { - FrameResult::Call(outcome) => { - let call_inputs = call_input_stack.borrow_mut().pop().unwrap(); - *outcome = inspector.call_end(&mut ctx.evm, &call_inputs, outcome.clone()); - } - FrameResult::Create(outcome) => { - let create_inputs = create_input_stack.borrow_mut().pop().unwrap(); - *outcome = inspector.create_end(&mut ctx.evm, &create_inputs, outcome.clone()); - } - FrameResult::EOFCreate(outcome) => { - let eofcreate_inputs = eofcreate_input_stack.borrow_mut().pop().unwrap(); - *outcome = - inspector.eofcreate_end(&mut ctx.evm, &eofcreate_inputs, outcome.clone()); - } - } - old_handle(ctx, frame_result) - }); -} - -/// Outer closure that calls Inspector for every instruction. -pub fn inspector_instruction< - 'a, - INSP: GetInspector, - DB: Database, - Instruction: Fn(&mut Interpreter, &mut Context) + 'a, ->( - instruction: Instruction, -) -> BoxedInstruction<'a, Context> { - Box::new( - move |interpreter: &mut Interpreter, host: &mut Context| { - // SAFETY: as the PC was already incremented we need to subtract 1 to preserve the - // old Inspector behavior. - interpreter.instruction_pointer = unsafe { interpreter.instruction_pointer.sub(1) }; - - host.external - .get_inspector() - .step(interpreter, &mut host.evm); - if interpreter.instruction_result != InstructionResult::Continue { - return; - } - - // return PC to old value - interpreter.instruction_pointer = unsafe { interpreter.instruction_pointer.add(1) }; - - // execute instruction. - instruction(interpreter, host); - - host.external - .get_inspector() - .step_end(interpreter, &mut host.evm); - }, - ) -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::{ - db::EmptyDB, - inspectors::NoOpInspector, - interpreter::{opcode::*, CallInputs, CallOutcome, CreateInputs, CreateOutcome}, - primitives::BerlinSpec, - Evm, EvmContext, - }; - - // Test that this pattern builds. - #[test] - fn test_make_boxed_instruction_table() { - type MyContext = Context; - let table: InstructionTable = make_instruction_table::(); - let _boxed_table: BoxedInstructionTable<'_, MyContext> = - make_boxed_instruction_table::<'_, MyContext, BerlinSpec, _>( - table, - inspector_instruction, - ); - } - - #[derive(Default, Debug)] - struct StackInspector { - initialize_interp_called: bool, - step: u32, - step_end: u32, - call: bool, - call_end: bool, - } - - impl Inspector for StackInspector { - fn initialize_interp(&mut self, _interp: &mut Interpreter, _context: &mut EvmContext) { - if self.initialize_interp_called { - unreachable!("initialize_interp should not be called twice") - } - self.initialize_interp_called = true; - } - - fn step(&mut self, _interp: &mut Interpreter, _context: &mut EvmContext) { - self.step += 1; - } - - fn step_end(&mut self, _interp: &mut Interpreter, _context: &mut EvmContext) { - self.step_end += 1; - } - - fn call( - &mut self, - context: &mut EvmContext, - _call: &mut CallInputs, - ) -> Option { - if self.call { - unreachable!("call should not be called twice") - } - self.call = true; - assert_eq!(context.journaled_state.depth(), 0); - None - } - - fn call_end( - &mut self, - context: &mut EvmContext, - _inputs: &CallInputs, - outcome: CallOutcome, - ) -> CallOutcome { - if self.call_end { - unreachable!("call_end should not be called twice") - } - assert_eq!(context.journaled_state.depth(), 0); - self.call_end = true; - outcome - } - - fn create( - &mut self, - context: &mut EvmContext, - _call: &mut CreateInputs, - ) -> Option { - assert_eq!(context.journaled_state.depth(), 0); - None - } - - fn create_end( - &mut self, - context: &mut EvmContext, - _inputs: &CreateInputs, - outcome: CreateOutcome, - ) -> CreateOutcome { - assert_eq!(context.journaled_state.depth(), 0); - outcome - } - } - - #[test] - fn test_inspector_handlers() { - use crate::{ - db::BenchmarkDB, - inspector::inspector_handle_register, - interpreter::opcode, - primitives::{address, Bytecode, Bytes, TransactTo}, - Evm, - }; - - let contract_data: Bytes = Bytes::from(vec![ - opcode::PUSH1, - 0x1, - opcode::PUSH1, - 0xb, - opcode::PUSH1, - 0x1, - opcode::PUSH1, - 0x1, - opcode::PUSH1, - 0x1, - opcode::CREATE, - opcode::STOP, - ]); - let bytecode = Bytecode::new_raw(contract_data); - - let mut evm: Evm<'_, StackInspector, BenchmarkDB> = Evm::builder() - .with_db(BenchmarkDB::new_bytecode(bytecode.clone())) - .with_external_context(StackInspector::default()) - .modify_tx_env(|tx| { - tx.clear(); - tx.caller = address!("1000000000000000000000000000000000000000"); - tx.transact_to = - TransactTo::Call(address!("0000000000000000000000000000000000000000")); - tx.gas_limit = 21100; - }) - .append_handler_register(inspector_handle_register) - .build(); - - // run evm. - evm.transact().unwrap(); - - let inspector = evm.into_context().external; - - assert_eq!(inspector.step, 6); - assert_eq!(inspector.step_end, 6); - assert!(inspector.initialize_interp_called); - assert!(inspector.call); - assert!(inspector.call_end); - } - - #[test] - fn test_inspector_reg() { - let mut noop = NoOpInspector; - let _evm = Evm::builder() - .with_external_context(&mut noop) - .append_handler_register(inspector_handle_register) - .build(); - } -} diff --git a/crates/revm/src/journaled_state.rs b/crates/revm/src/journaled_state.rs deleted file mode 100644 index 51b27b32b9..0000000000 --- a/crates/revm/src/journaled_state.rs +++ /dev/null @@ -1,849 +0,0 @@ -use crate::interpreter::{InstructionResult, SelfDestructResult}; -use crate::primitives::{ - db::Database, hash_map::Entry, Account, Address, Bytecode, EVMError, EvmState, EvmStorageSlot, - HashMap, HashSet, Log, SpecId::*, TransientStorage, KECCAK_EMPTY, PRECOMPILE3, U256, -}; -use core::mem; -use revm_interpreter::primitives::SpecId; -use revm_interpreter::{LoadAccountResult, SStoreResult}; -use std::vec::Vec; - -/// JournalState is internal EVM state that is used to contain state and track changes to that state. -/// It contains journal of changes that happened to state so that they can be reverted. -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct JournaledState { - /// Current state. - pub state: EvmState, - /// [EIP-1153](https://eips.ethereum.org/EIPS/eip-1153) transient storage that is discarded after every transactions - pub transient_storage: TransientStorage, - /// logs - pub logs: Vec, - /// how deep are we in call stack. - pub depth: usize, - /// journal with changes that happened between calls. - pub journal: Vec>, - /// Ethereum before EIP-161 differently defined empty and not-existing account - /// Spec is needed for two things SpuriousDragon's `EIP-161 State clear`, - /// and for Cancun's `EIP-6780: SELFDESTRUCT in same transaction` - pub spec: SpecId, - /// Warm loaded addresses are used to check if loaded address - /// should be considered cold or warm loaded when the account - /// is first accessed. - /// - /// Note that this not include newly loaded accounts, account and storage - /// is considered warm if it is found in the `State`. - pub warm_preloaded_addresses: HashSet
, -} - -impl JournaledState { - /// Create new JournaledState. - /// - /// warm_preloaded_addresses is used to determine if address is considered warm loaded. - /// In ordinary case this is precompile or beneficiary. - /// - /// Note: This function will journal state after Spurious Dragon fork. - /// And will not take into account if account is not existing or empty. - /// - /// # Note - /// - /// - pub fn new(spec: SpecId, warm_preloaded_addresses: HashSet
) -> JournaledState { - Self { - state: HashMap::new(), - transient_storage: TransientStorage::default(), - logs: Vec::new(), - journal: vec![vec![]], - depth: 0, - spec, - warm_preloaded_addresses, - } - } - - /// Return reference to state. - #[inline] - pub fn state(&mut self) -> &mut EvmState { - &mut self.state - } - - /// Sets SpecId. - #[inline] - pub fn set_spec_id(&mut self, spec: SpecId) { - self.spec = spec; - } - - /// Mark account as touched as only touched accounts will be added to state. - /// This is especially important for state clear where touched empty accounts needs to - /// be removed from state. - #[inline] - pub fn touch(&mut self, address: &Address) { - if let Some(account) = self.state.get_mut(address) { - Self::touch_account(self.journal.last_mut().unwrap(), address, account); - } - } - - /// Mark account as touched. - #[inline] - fn touch_account(journal: &mut Vec, address: &Address, account: &mut Account) { - if !account.is_touched() { - journal.push(JournalEntry::AccountTouched { address: *address }); - account.mark_touch(); - } - } - - /// Clears the JournaledState. Preserving only the spec. - pub fn clear(&mut self) { - let spec = self.spec; - *self = Self::new(spec, HashSet::new()); - } - - /// Does cleanup and returns modified state. - /// - /// This resets the [JournaledState] to its initial state in [Self::new] - #[inline] - pub fn finalize(&mut self) -> (EvmState, Vec) { - let Self { - state, - transient_storage, - logs, - depth, - journal, - // kept, see [Self::new] - spec: _, - warm_preloaded_addresses: _, - } = self; - - *transient_storage = TransientStorage::default(); - *journal = vec![vec![]]; - *depth = 0; - let state = mem::take(state); - let logs = mem::take(logs); - - (state, logs) - } - - /// Returns the _loaded_ [Account] for the given address. - /// - /// This assumes that the account has already been loaded. - /// - /// # Panics - /// - /// Panics if the account has not been loaded and is missing from the state set. - #[inline] - pub fn account(&self, address: Address) -> &Account { - self.state - .get(&address) - .expect("Account expected to be loaded") // Always assume that acc is already loaded - } - - /// Returns call depth. - #[inline] - pub fn depth(&self) -> u64 { - self.depth as u64 - } - - /// use it only if you know that acc is warm - /// Assume account is warm - #[inline] - pub fn set_code(&mut self, address: Address, code: Bytecode) { - let account = self.state.get_mut(&address).unwrap(); - Self::touch_account(self.journal.last_mut().unwrap(), &address, account); - - self.journal - .last_mut() - .unwrap() - .push(JournalEntry::CodeChange { address }); - - account.info.code_hash = code.hash_slow(); - account.info.code = Some(code); - } - - #[inline] - pub fn inc_nonce(&mut self, address: Address) -> Option { - let account = self.state.get_mut(&address).unwrap(); - // Check if nonce is going to overflow. - if account.info.nonce == u64::MAX { - return None; - } - Self::touch_account(self.journal.last_mut().unwrap(), &address, account); - self.journal - .last_mut() - .unwrap() - .push(JournalEntry::NonceChange { address }); - - account.info.nonce += 1; - - Some(account.info.nonce) - } - - /// Transfers balance from two accounts. Returns error if sender balance is not enough. - #[inline] - pub fn transfer( - &mut self, - from: &Address, - to: &Address, - balance: U256, - db: &mut DB, - ) -> Result, EVMError> { - // load accounts - self.load_account(*from, db)?; - self.load_account(*to, db)?; - - // sub balance from - let from_account = &mut self.state.get_mut(from).unwrap(); - Self::touch_account(self.journal.last_mut().unwrap(), from, from_account); - let from_balance = &mut from_account.info.balance; - - let Some(from_balance_incr) = from_balance.checked_sub(balance) else { - return Ok(Some(InstructionResult::OutOfFunds)); - }; - *from_balance = from_balance_incr; - - // add balance to - let to_account = &mut self.state.get_mut(to).unwrap(); - Self::touch_account(self.journal.last_mut().unwrap(), to, to_account); - let to_balance = &mut to_account.info.balance; - let Some(to_balance_decr) = to_balance.checked_add(balance) else { - return Ok(Some(InstructionResult::OverflowPayment)); - }; - *to_balance = to_balance_decr; - // Overflow of U256 balance is not possible to happen on mainnet. We don't bother to return funds from from_acc. - - self.journal - .last_mut() - .unwrap() - .push(JournalEntry::BalanceTransfer { - from: *from, - to: *to, - balance, - }); - - Ok(None) - } - - /// Create account or return false if collision is detected. - /// - /// There are few steps done: - /// 1. Make created account warm loaded (AccessList) and this should - /// be done before subroutine checkpoint is created. - /// 2. Check if there is collision of newly created account with existing one. - /// 3. Mark created account as created. - /// 4. Add fund to created account - /// 5. Increment nonce of created account if SpuriousDragon is active - /// 6. Decrease balance of caller account. - /// - /// # Panics - /// - /// Panics if the caller is not loaded inside of the EVM state. - /// This is should have been done inside `create_inner`. - #[inline] - pub fn create_account_checkpoint( - &mut self, - caller: Address, - address: Address, - balance: U256, - spec_id: SpecId, - ) -> Result { - // Enter subroutine - let checkpoint = self.checkpoint(); - - // Newly created account is present, as we just loaded it. - let account = self.state.get_mut(&address).unwrap(); - let last_journal = self.journal.last_mut().unwrap(); - - // New account can be created if: - // Bytecode is not empty. - // Nonce is not zero - // Account is not precompile. - if account.info.code_hash != KECCAK_EMPTY - || account.info.nonce != 0 - || self.warm_preloaded_addresses.contains(&address) - { - self.checkpoint_revert(checkpoint); - return Err(InstructionResult::CreateCollision); - } - - // set account status to created. - account.mark_created(); - - // this entry will revert set nonce. - last_journal.push(JournalEntry::AccountCreated { address }); - account.info.code = None; - - // Set all storages to default value. They need to be present to act as accessed slots in access list. - // it shouldn't be possible for them to have different values then zero as code is not existing for this account, - // but because tests can change that assumption we are doing it. - let empty = EvmStorageSlot::default(); - account - .storage - .iter_mut() - .for_each(|(_, slot)| *slot = empty.clone()); - - // touch account. This is important as for pre SpuriousDragon account could be - // saved even empty. - Self::touch_account(last_journal, &address, account); - - // Add balance to created account, as we already have target here. - let Some(new_balance) = account.info.balance.checked_add(balance) else { - self.checkpoint_revert(checkpoint); - return Err(InstructionResult::OverflowPayment); - }; - account.info.balance = new_balance; - - // EIP-161: State trie clearing (invariant-preserving alternative) - if spec_id.is_enabled_in(SPURIOUS_DRAGON) { - // nonce is going to be reset to zero in AccountCreated journal entry. - account.info.nonce = 1; - } - - // Sub balance from caller - let caller_account = self.state.get_mut(&caller).unwrap(); - // Balance is already checked in `create_inner`, so it is safe to just subtract. - caller_account.info.balance -= balance; - - // add journal entry of transferred balance - last_journal.push(JournalEntry::BalanceTransfer { - from: caller, - to: address, - balance, - }); - - Ok(checkpoint) - } - - /// Revert all changes that happened in given journal entries. - #[inline] - fn journal_revert( - state: &mut EvmState, - transient_storage: &mut TransientStorage, - journal_entries: Vec, - is_spurious_dragon_enabled: bool, - ) { - for entry in journal_entries.into_iter().rev() { - match entry { - JournalEntry::AccountLoaded { address } => { - state.remove(&address); - } - JournalEntry::AccountTouched { address } => { - if is_spurious_dragon_enabled && address == PRECOMPILE3 { - continue; - } - // remove touched status - state.get_mut(&address).unwrap().unmark_touch(); - } - JournalEntry::AccountDestroyed { - address, - target, - was_destroyed, - had_balance, - } => { - let account = state.get_mut(&address).unwrap(); - // set previous state of selfdestructed flag, as there could be multiple - // selfdestructs in one transaction. - if was_destroyed { - // flag is still selfdestructed - account.mark_selfdestruct(); - } else { - // flag that is not selfdestructed - account.unmark_selfdestruct(); - } - account.info.balance += had_balance; - - if address != target { - let target = state.get_mut(&target).unwrap(); - target.info.balance -= had_balance; - } - } - JournalEntry::BalanceTransfer { from, to, balance } => { - // we don't need to check overflow and underflow when adding and subtracting the balance. - let from = state.get_mut(&from).unwrap(); - from.info.balance += balance; - let to = state.get_mut(&to).unwrap(); - to.info.balance -= balance; - } - JournalEntry::NonceChange { address } => { - state.get_mut(&address).unwrap().info.nonce -= 1; - } - JournalEntry::AccountCreated { address } => { - let account = &mut state.get_mut(&address).unwrap(); - account.unmark_created(); - account.info.nonce = 0; - } - JournalEntry::StorageChange { - address, - key, - had_value, - } => { - let storage = &mut state.get_mut(&address).unwrap().storage; - if let Some(had_value) = had_value { - storage.get_mut(&key).unwrap().present_value = had_value; - } else { - storage.remove(&key); - } - } - JournalEntry::TransientStorageChange { - address, - key, - had_value, - } => { - let tkey = (address, key); - if had_value == U256::ZERO { - // if previous value is zero, remove it - transient_storage.remove(&tkey); - } else { - // if not zero, reinsert old value to transient storage. - transient_storage.insert(tkey, had_value); - } - } - JournalEntry::CodeChange { address } => { - let acc = state.get_mut(&address).unwrap(); - acc.info.code_hash = KECCAK_EMPTY; - acc.info.code = None; - } - } - } - } - - /// Makes a checkpoint that in case of Revert can bring back state to this point. - #[inline] - pub fn checkpoint(&mut self) -> JournalCheckpoint { - let checkpoint = JournalCheckpoint { - log_i: self.logs.len(), - journal_i: self.journal.len(), - }; - self.depth += 1; - self.journal.push(Default::default()); - checkpoint - } - - /// Commit the checkpoint. - #[inline] - pub fn checkpoint_commit(&mut self) { - self.depth -= 1; - } - - /// Reverts all changes to state until given checkpoint. - #[inline] - pub fn checkpoint_revert(&mut self, checkpoint: JournalCheckpoint) { - let is_spurious_dragon_enabled = SpecId::enabled(self.spec, SPURIOUS_DRAGON); - let state = &mut self.state; - let transient_storage = &mut self.transient_storage; - self.depth -= 1; - // iterate over last N journals sets and revert our global state - let leng = self.journal.len(); - self.journal - .iter_mut() - .rev() - .take(leng - checkpoint.journal_i) - .for_each(|cs| { - Self::journal_revert( - state, - transient_storage, - mem::take(cs), - is_spurious_dragon_enabled, - ) - }); - - self.logs.truncate(checkpoint.log_i); - self.journal.truncate(checkpoint.journal_i); - } - - /// Performances selfdestruct action. - /// Transfers balance from address to target. Check if target exist/is_cold - /// - /// Note: balance will be lost if address and target are the same BUT when - /// current spec enables Cancun, this happens only when the account associated to address - /// is created in the same tx - /// - /// references: - /// * - /// * - /// * - #[inline] - pub fn selfdestruct( - &mut self, - address: Address, - target: Address, - db: &mut DB, - ) -> Result> { - let load_result = self.load_account_exist(target, db)?; - - if address != target { - // Both accounts are loaded before this point, `address` as we execute its contract. - // and `target` at the beginning of the function. - let acc_balance = self.state.get_mut(&address).unwrap().info.balance; - - let target_account = self.state.get_mut(&target).unwrap(); - Self::touch_account(self.journal.last_mut().unwrap(), &target, target_account); - target_account.info.balance += acc_balance; - } - - let acc = self.state.get_mut(&address).unwrap(); - let balance = acc.info.balance; - let previously_destroyed = acc.is_selfdestructed(); - let is_cancun_enabled = SpecId::enabled(self.spec, CANCUN); - - // EIP-6780 (Cancun hard-fork): selfdestruct only if contract is created in the same tx - let journal_entry = if acc.is_created() || !is_cancun_enabled { - acc.mark_selfdestruct(); - acc.info.balance = U256::ZERO; - Some(JournalEntry::AccountDestroyed { - address, - target, - was_destroyed: previously_destroyed, - had_balance: balance, - }) - } else if address != target { - acc.info.balance = U256::ZERO; - Some(JournalEntry::BalanceTransfer { - from: address, - to: target, - balance, - }) - } else { - // State is not changed: - // * if we are after Cancun upgrade and - // * Selfdestruct account that is created in the same transaction and - // * Specify the target is same as selfdestructed account. The balance stays unchanged. - None - }; - - if let Some(entry) = journal_entry { - self.journal.last_mut().unwrap().push(entry); - }; - - Ok(SelfDestructResult { - had_value: balance != U256::ZERO, - is_cold: load_result.is_cold, - target_exists: !load_result.is_empty, - previously_destroyed, - }) - } - - /// Initial load of account. This load will not be tracked inside journal - #[inline] - pub fn initial_account_load( - &mut self, - address: Address, - slots: &[U256], - db: &mut DB, - ) -> Result<&mut Account, EVMError> { - // load or get account. - let account = match self.state.entry(address) { - Entry::Occupied(entry) => entry.into_mut(), - Entry::Vacant(vac) => vac.insert( - db.basic(address) - .map_err(EVMError::Database)? - .map(|i| i.into()) - .unwrap_or(Account::new_not_existing()), - ), - }; - // preload storages. - for slot in slots { - if let Entry::Vacant(entry) = account.storage.entry(*slot) { - let storage = db.storage(address, *slot).map_err(EVMError::Database)?; - entry.insert(EvmStorageSlot::new(storage)); - } - } - Ok(account) - } - - /// load account into memory. return if it is cold or warm accessed - #[inline] - pub fn load_account( - &mut self, - address: Address, - db: &mut DB, - ) -> Result<(&mut Account, bool), EVMError> { - Ok(match self.state.entry(address) { - Entry::Occupied(entry) => (entry.into_mut(), false), - Entry::Vacant(vac) => { - let account = - if let Some(account) = db.basic(address).map_err(EVMError::Database)? { - account.into() - } else { - Account::new_not_existing() - }; - - // journal loading of account. AccessList touch. - self.journal - .last_mut() - .unwrap() - .push(JournalEntry::AccountLoaded { address }); - - // precompiles are warm loaded so we need to take that into account - let is_cold = !self.warm_preloaded_addresses.contains(&address); - - (vac.insert(account), is_cold) - } - }) - } - - /// Load account from database to JournaledState. - /// - /// Return boolean pair where first is `is_cold` second bool `is_exists`. - #[inline] - pub fn load_account_exist( - &mut self, - address: Address, - db: &mut DB, - ) -> Result> { - let spec = self.spec; - let (acc, is_cold) = self.load_account(address, db)?; - - let is_spurious_dragon_enabled = SpecId::enabled(spec, SPURIOUS_DRAGON); - let is_empty = if is_spurious_dragon_enabled { - acc.is_empty() - } else { - let loaded_not_existing = acc.is_loaded_as_not_existing(); - let is_not_touched = !acc.is_touched(); - loaded_not_existing && is_not_touched - }; - - Ok(LoadAccountResult { is_empty, is_cold }) - } - - /// Loads code. - #[inline] - pub fn load_code( - &mut self, - address: Address, - db: &mut DB, - ) -> Result<(&mut Account, bool), EVMError> { - let (acc, is_cold) = self.load_account(address, db)?; - if acc.info.code.is_none() { - if acc.info.code_hash == KECCAK_EMPTY { - let empty = Bytecode::default(); - acc.info.code = Some(empty); - } else { - let code = db - .code_by_hash(acc.info.code_hash) - .map_err(EVMError::Database)?; - acc.info.code = Some(code); - } - } - Ok((acc, is_cold)) - } - - /// Load storage slot - /// - /// # Panics - /// - /// Panics if the account is not present in the state. - #[inline] - pub fn sload( - &mut self, - address: Address, - key: U256, - db: &mut DB, - ) -> Result<(U256, bool), EVMError> { - // assume acc is warm - let account = self.state.get_mut(&address).unwrap(); - // only if account is created in this tx we can assume that storage is empty. - let is_newly_created = account.is_created(); - let load = match account.storage.entry(key) { - Entry::Occupied(occ) => (occ.get().present_value, false), - Entry::Vacant(vac) => { - // if storage was cleared, we don't need to ping db. - let value = if is_newly_created { - U256::ZERO - } else { - db.storage(address, key).map_err(EVMError::Database)? - }; - // add it to journal as cold loaded. - self.journal - .last_mut() - .unwrap() - .push(JournalEntry::StorageChange { - address, - key, - had_value: None, - }); - - vac.insert(EvmStorageSlot::new(value)); - - (value, true) - } - }; - Ok(load) - } - - /// Stores storage slot. - /// And returns (original,present,new) slot value. - /// - /// Note: - /// - /// account should already be present in our state. - #[inline] - pub fn sstore( - &mut self, - address: Address, - key: U256, - new: U256, - db: &mut DB, - ) -> Result> { - // assume that acc exists and load the slot. - let (present, is_cold) = self.sload(address, key, db)?; - let acc = self.state.get_mut(&address).unwrap(); - - // if there is no original value in dirty return present value, that is our original. - let slot = acc.storage.get_mut(&key).unwrap(); - - // new value is same as present, we don't need to do anything - if present == new { - return Ok(SStoreResult { - original_value: slot.original_value(), - present_value: present, - new_value: new, - is_cold, - }); - } - - self.journal - .last_mut() - .unwrap() - .push(JournalEntry::StorageChange { - address, - key, - had_value: Some(present), - }); - // insert value into present state. - slot.present_value = new; - Ok(SStoreResult { - original_value: slot.original_value(), - present_value: present, - new_value: new, - is_cold, - }) - } - - /// Read transient storage tied to the account. - /// - /// EIP-1153: Transient storage opcodes - #[inline] - pub fn tload(&mut self, address: Address, key: U256) -> U256 { - self.transient_storage - .get(&(address, key)) - .copied() - .unwrap_or_default() - } - - /// Store transient storage tied to the account. - /// - /// If values is different add entry to the journal - /// so that old state can be reverted if that action is needed. - /// - /// EIP-1153: Transient storage opcodes - #[inline] - pub fn tstore(&mut self, address: Address, key: U256, new: U256) { - let had_value = if new == U256::ZERO { - // if new values is zero, remove entry from transient storage. - // if previous values was some insert it inside journal. - // If it is none nothing should be inserted. - self.transient_storage.remove(&(address, key)) - } else { - // insert values - let previous_value = self - .transient_storage - .insert((address, key), new) - .unwrap_or_default(); - - // check if previous value is same - if previous_value != new { - // if it is different, insert previous values inside journal. - Some(previous_value) - } else { - None - } - }; - - if let Some(had_value) = had_value { - // insert in journal only if value was changed. - self.journal - .last_mut() - .unwrap() - .push(JournalEntry::TransientStorageChange { - address, - key, - had_value, - }); - } - } - - /// push log into subroutine - #[inline] - pub fn log(&mut self, log: Log) { - self.logs.push(log); - } -} - -/// Journal entries that are used to track changes to the state and are used to revert it. -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum JournalEntry { - /// Used to mark account that is warm inside EVM in regards to EIP-2929 AccessList. - /// Action: We will add Account to state. - /// Revert: we will remove account from state. - AccountLoaded { address: Address }, - /// Mark account to be destroyed and journal balance to be reverted - /// Action: Mark account and transfer the balance - /// Revert: Unmark the account and transfer balance back - AccountDestroyed { - address: Address, - target: Address, - was_destroyed: bool, // if account had already been destroyed before this journal entry - had_balance: U256, - }, - /// Loading account does not mean that account will need to be added to MerkleTree (touched). - /// Only when account is called (to execute contract or transfer balance) only then account is made touched. - /// Action: Mark account touched - /// Revert: Unmark account touched - AccountTouched { address: Address }, - /// Transfer balance between two accounts - /// Action: Transfer balance - /// Revert: Transfer balance back - BalanceTransfer { - from: Address, - to: Address, - balance: U256, - }, - /// Increment nonce - /// Action: Increment nonce by one - /// Revert: Decrement nonce by one - NonceChange { - address: Address, //geth has nonce value, - }, - /// Create account: - /// Actions: Mark account as created - /// Revert: Unmart account as created and reset nonce to zero. - AccountCreated { address: Address }, - /// It is used to track both storage change and warm load of storage slot. For warm load in regard - /// to EIP-2929 AccessList had_value will be None - /// Action: Storage change or warm load - /// Revert: Revert to previous value or remove slot from storage - StorageChange { - address: Address, - key: U256, - had_value: Option, //if none, storage slot was cold loaded from db and needs to be removed - }, - /// It is used to track an EIP-1153 transient storage change. - /// Action: Transient storage changed. - /// Revert: Revert to previous value. - TransientStorageChange { - address: Address, - key: U256, - had_value: U256, - }, - /// Code changed - /// Action: Account code changed - /// Revert: Revert to previous bytecode. - CodeChange { address: Address }, -} - -/// SubRoutine checkpoint that will help us to go back from this -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct JournalCheckpoint { - log_i: usize, - journal_i: usize, -} diff --git a/crates/revm/src/lib.rs b/crates/revm/src/lib.rs index 6b69b5bd2a..091f6807e7 100644 --- a/crates/revm/src/lib.rs +++ b/crates/revm/src/lib.rs @@ -2,55 +2,37 @@ #![cfg_attr(not(test), warn(unused_crate_dependencies))] #![cfg_attr(not(feature = "std"), no_std)] -#[macro_use] -#[cfg(not(feature = "std"))] -extern crate alloc as std; - -// Define modules. - -mod builder; -mod context; - -#[cfg(any(test, feature = "test-utils"))] -pub mod test_utils; - -pub mod db; -mod evm; -mod frame; -pub mod handler; -mod inspector; -mod journaled_state; -#[cfg(feature = "optimism")] -pub mod optimism; +// reexport dependencies +#[doc(inline)] +pub use bytecode; +#[doc(inline)] +pub use context; +#[doc(inline)] +pub use context_interface; +#[doc(inline)] +pub use database; +#[doc(inline)] +pub use database_interface; +#[doc(inline)] +pub use handler; +#[doc(inline)] +pub use inspector; +#[doc(inline)] +pub use interpreter; +#[doc(inline)] +pub use precompile; +#[doc(inline)] +pub use primitives; +#[doc(inline)] +pub use state; // Export items. -pub use builder::EvmBuilder; -pub use context::{ - Context, ContextPrecompile, ContextPrecompiles, ContextStatefulPrecompile, - ContextStatefulPrecompileArc, ContextStatefulPrecompileBox, ContextStatefulPrecompileMut, - ContextWithHandlerCfg, EvmContext, InnerEvmContext, -}; -pub use db::{ - CacheState, DBBox, State, StateBuilder, StateDBBox, TransitionAccount, TransitionState, -}; -pub use db::{Database, DatabaseCommit, DatabaseRef, InMemoryDB}; -pub use evm::{Evm, CALL_STACK_LIMIT}; -pub use frame::{CallFrame, CreateFrame, Frame, FrameData, FrameOrResult, FrameResult}; -pub use handler::Handler; -pub use inspector::{ - inspector_handle_register, inspector_instruction, inspectors, GetInspector, Inspector, +pub use context::journal::{Journal, JournalEntry}; +pub use context::Context; +pub use database_interface::{Database, DatabaseCommit, DatabaseRef}; +pub use handler::{ + ExecuteCommitEvm, ExecuteEvm, MainBuilder, MainContext, MainnetEvm, SystemCallCommitEvm, + SystemCallEvm, }; -pub use journaled_state::{JournalCheckpoint, JournalEntry, JournaledState}; -// export Optimism types, helpers, and constants -#[cfg(feature = "optimism")] -pub use optimism::{L1BlockInfo, BASE_FEE_RECIPIENT, L1_BLOCK_CONTRACT, L1_FEE_RECIPIENT}; - -// Reexport libraries - -#[doc(inline)] -pub use revm_interpreter as interpreter; -#[doc(inline)] -pub use revm_interpreter::primitives; -#[doc(inline)] -pub use revm_precompile as precompile; +pub use inspector::{InspectCommitEvm, InspectEvm, Inspector}; diff --git a/crates/revm/src/optimism.rs b/crates/revm/src/optimism.rs deleted file mode 100644 index 12f3db9969..0000000000 --- a/crates/revm/src/optimism.rs +++ /dev/null @@ -1,11 +0,0 @@ -//! Optimism-specific constants, types, and helpers. - -mod fast_lz; -mod handler_register; -mod l1block; - -pub use handler_register::{ - deduct_caller, end, last_frame_return, load_accounts, load_precompiles, - optimism_handle_register, output, reward_beneficiary, validate_env, validate_tx_against_state, -}; -pub use l1block::{L1BlockInfo, BASE_FEE_RECIPIENT, L1_BLOCK_CONTRACT, L1_FEE_RECIPIENT}; diff --git a/crates/revm/src/optimism/handler_register.rs b/crates/revm/src/optimism/handler_register.rs deleted file mode 100644 index d4996cca21..0000000000 --- a/crates/revm/src/optimism/handler_register.rs +++ /dev/null @@ -1,640 +0,0 @@ -//! Handler related to Optimism chain - -use crate::{ - handler::{ - mainnet::{self, deduct_caller_inner}, - register::EvmHandler, - }, - interpreter::{return_ok, return_revert, Gas, InstructionResult}, - optimism, - primitives::{ - db::Database, spec_to_generic, Account, EVMError, Env, ExecutionResult, HaltReason, - HashMap, InvalidTransaction, ResultAndState, Spec, SpecId, SpecId::REGOLITH, U256, - }, - Context, ContextPrecompiles, FrameResult, -}; -use core::ops::Mul; -use revm_precompile::{secp256r1, PrecompileSpecId, Precompiles}; -use std::string::ToString; -use std::sync::Arc; - -pub fn optimism_handle_register(handler: &mut EvmHandler<'_, EXT, DB>) { - spec_to_generic!(handler.cfg.spec_id, { - // validate environment - handler.validation.env = Arc::new(validate_env::); - // Validate transaction against state. - handler.validation.tx_against_state = Arc::new(validate_tx_against_state::); - // Load additional precompiles for the given chain spec. - handler.pre_execution.load_precompiles = Arc::new(load_precompiles::); - // load l1 data - handler.pre_execution.load_accounts = Arc::new(load_accounts::); - // An estimated batch cost is charged from the caller and added to L1 Fee Vault. - handler.pre_execution.deduct_caller = Arc::new(deduct_caller::); - // Refund is calculated differently then mainnet. - handler.execution.last_frame_return = Arc::new(last_frame_return::); - handler.post_execution.reward_beneficiary = Arc::new(reward_beneficiary::); - // In case of halt of deposit transaction return Error. - handler.post_execution.output = Arc::new(output::); - handler.post_execution.end = Arc::new(end::); - }); -} - -/// Validate environment for the Optimism chain. -pub fn validate_env(env: &Env) -> Result<(), EVMError> { - // Do not perform any extra validation for deposit transactions, they are pre-verified on L1. - if env.tx.optimism.source_hash.is_some() { - return Ok(()); - } - // Important: validate block before tx. - env.validate_block_env::()?; - - // Do not allow for a system transaction to be processed if Regolith is enabled. - let tx = &env.tx.optimism; - if tx.is_system_transaction.unwrap_or(false) && SPEC::enabled(SpecId::REGOLITH) { - return Err(InvalidTransaction::DepositSystemTxPostRegolith.into()); - } - - env.validate_tx::()?; - Ok(()) -} - -/// Don not perform any extra validation for deposit transactions, they are pre-verified on L1. -pub fn validate_tx_against_state( - context: &mut Context, -) -> Result<(), EVMError> { - if context.evm.inner.env.tx.optimism.source_hash.is_some() { - return Ok(()); - } - mainnet::validate_tx_against_state::(context) -} - -/// Handle output of the transaction -#[inline] -pub fn last_frame_return( - context: &mut Context, - frame_result: &mut FrameResult, -) -> Result<(), EVMError> { - let env = context.evm.inner.env(); - let is_deposit = env.tx.optimism.source_hash.is_some(); - let tx_system = env.tx.optimism.is_system_transaction; - let tx_gas_limit = env.tx.gas_limit; - let is_regolith = SPEC::enabled(REGOLITH); - - let instruction_result = frame_result.interpreter_result().result; - let gas = frame_result.gas_mut(); - let remaining = gas.remaining(); - let refunded = gas.refunded(); - // Spend the gas limit. Gas is reimbursed when the tx returns successfully. - *gas = Gas::new_spent(tx_gas_limit); - - match instruction_result { - return_ok!() => { - // On Optimism, deposit transactions report gas usage uniquely to other - // transactions due to them being pre-paid on L1. - // - // Hardfork Behavior: - // - Bedrock (success path): - // - Deposit transactions (non-system) report their gas limit as the usage. - // No refunds. - // - Deposit transactions (system) report 0 gas used. No refunds. - // - Regular transactions report gas usage as normal. - // - Regolith (success path): - // - Deposit transactions (all) report their gas used as normal. Refunds - // enabled. - // - Regular transactions report their gas used as normal. - if !is_deposit || is_regolith { - // For regular transactions prior to Regolith and all transactions after - // Regolith, gas is reported as normal. - gas.erase_cost(remaining); - gas.record_refund(refunded); - } else if is_deposit && tx_system.unwrap_or(false) { - // System transactions were a special type of deposit transaction in - // the Bedrock hardfork that did not incur any gas costs. - gas.erase_cost(tx_gas_limit); - } - } - return_revert!() => { - // On Optimism, deposit transactions report gas usage uniquely to other - // transactions due to them being pre-paid on L1. - // - // Hardfork Behavior: - // - Bedrock (revert path): - // - Deposit transactions (all) report the gas limit as the amount of gas - // used on failure. No refunds. - // - Regular transactions receive a refund on remaining gas as normal. - // - Regolith (revert path): - // - Deposit transactions (all) report the actual gas used as the amount of - // gas used on failure. Refunds on remaining gas enabled. - // - Regular transactions receive a refund on remaining gas as normal. - if !is_deposit || is_regolith { - gas.erase_cost(remaining); - } - } - _ => {} - } - // Prior to Regolith, deposit transactions did not receive gas refunds. - let is_gas_refund_disabled = env.cfg.is_gas_refund_disabled() || (is_deposit && !is_regolith); - if !is_gas_refund_disabled { - gas.set_final_refund(SPEC::SPEC_ID.is_enabled_in(SpecId::LONDON)); - } - Ok(()) -} - -/// Load precompiles for Optimism chain. -#[inline] -pub fn load_precompiles() -> ContextPrecompiles { - let mut precompiles = Precompiles::new(PrecompileSpecId::from_spec_id(SPEC::SPEC_ID)).clone(); - - if SPEC::enabled(SpecId::FJORD) { - precompiles.extend([ - // EIP-7212: secp256r1 P256verify - secp256r1::P256VERIFY, - ]) - } - - precompiles.into() -} - -/// Load account (make them warm) and l1 data from database. -#[inline] -pub fn load_accounts( - context: &mut Context, -) -> Result<(), EVMError> { - // the L1-cost fee is only computed for Optimism non-deposit transactions. - - if context.evm.inner.env.tx.optimism.source_hash.is_none() { - let l1_block_info = - crate::optimism::L1BlockInfo::try_fetch(&mut context.evm.inner.db, SPEC::SPEC_ID) - .map_err(EVMError::Database)?; - - // storage l1 block info for later use. - context.evm.inner.l1_block_info = Some(l1_block_info); - } - - mainnet::load_accounts::(context) -} - -/// Deduct max balance from caller -#[inline] -pub fn deduct_caller( - context: &mut Context, -) -> Result<(), EVMError> { - // load caller's account. - let (caller_account, _) = context - .evm - .inner - .journaled_state - .load_account(context.evm.inner.env.tx.caller, &mut context.evm.inner.db)?; - - // If the transaction is a deposit with a `mint` value, add the mint value - // in wei to the caller's balance. This should be persisted to the database - // prior to the rest of execution. - if let Some(mint) = context.evm.inner.env.tx.optimism.mint { - caller_account.info.balance += U256::from(mint); - } - - // We deduct caller max balance after minting and before deducing the - // l1 cost, max values is already checked in pre_validate but l1 cost wasn't. - deduct_caller_inner::(caller_account, &context.evm.inner.env); - - // If the transaction is not a deposit transaction, subtract the L1 data fee from the - // caller's balance directly after minting the requested amount of ETH. - if context.evm.inner.env.tx.optimism.source_hash.is_none() { - // get envelope - let Some(enveloped_tx) = &context.evm.inner.env.tx.optimism.enveloped_tx else { - return Err(EVMError::Custom( - "[OPTIMISM] Failed to load enveloped transaction.".to_string(), - )); - }; - - let tx_l1_cost = context - .evm - .inner - .l1_block_info - .as_ref() - .expect("L1BlockInfo should be loaded") - .calculate_tx_l1_cost(enveloped_tx, SPEC::SPEC_ID); - if tx_l1_cost.gt(&caller_account.info.balance) { - return Err(EVMError::Transaction( - InvalidTransaction::LackOfFundForMaxFee { - fee: tx_l1_cost.into(), - balance: caller_account.info.balance.into(), - }, - )); - } - caller_account.info.balance = caller_account.info.balance.saturating_sub(tx_l1_cost); - } - Ok(()) -} - -/// Reward beneficiary with gas fee. -#[inline] -pub fn reward_beneficiary( - context: &mut Context, - gas: &Gas, -) -> Result<(), EVMError> { - let is_deposit = context.evm.inner.env.tx.optimism.source_hash.is_some(); - - // transfer fee to coinbase/beneficiary. - if !is_deposit { - mainnet::reward_beneficiary::(context, gas)?; - } - - if !is_deposit { - // If the transaction is not a deposit transaction, fees are paid out - // to both the Base Fee Vault as well as the L1 Fee Vault. - let Some(l1_block_info) = &context.evm.inner.l1_block_info else { - return Err(EVMError::Custom( - "[OPTIMISM] Failed to load L1 block information.".to_string(), - )); - }; - - let Some(enveloped_tx) = &context.evm.inner.env.tx.optimism.enveloped_tx else { - return Err(EVMError::Custom( - "[OPTIMISM] Failed to load enveloped transaction.".to_string(), - )); - }; - - let l1_cost = l1_block_info.calculate_tx_l1_cost(enveloped_tx, SPEC::SPEC_ID); - - // Send the L1 cost of the transaction to the L1 Fee Vault. - let (l1_fee_vault_account, _) = context - .evm - .inner - .journaled_state - .load_account(optimism::L1_FEE_RECIPIENT, &mut context.evm.inner.db)?; - l1_fee_vault_account.mark_touch(); - l1_fee_vault_account.info.balance += l1_cost; - - // Send the base fee of the transaction to the Base Fee Vault. - let (base_fee_vault_account, _) = context - .evm - .inner - .journaled_state - .load_account(optimism::BASE_FEE_RECIPIENT, &mut context.evm.inner.db)?; - base_fee_vault_account.mark_touch(); - base_fee_vault_account.info.balance += context - .evm - .inner - .env - .block - .basefee - .mul(U256::from(gas.spent() - gas.refunded() as u64)); - } - Ok(()) -} - -/// Main return handle, returns the output of the transaction. -#[inline] -pub fn output( - context: &mut Context, - frame_result: FrameResult, -) -> Result> { - let result = mainnet::output::(context, frame_result)?; - - if result.result.is_halt() { - // Post-regolith, if the transaction is a deposit transaction and it halts, - // we bubble up to the global return handler. The mint value will be persisted - // and the caller nonce will be incremented there. - let is_deposit = context.evm.inner.env.tx.optimism.source_hash.is_some(); - if is_deposit && SPEC::enabled(REGOLITH) { - return Err(EVMError::Transaction( - InvalidTransaction::HaltedDepositPostRegolith, - )); - } - } - Ok(result) -} -/// Optimism end handle changes output if the transaction is a deposit transaction. -/// Deposit transaction can't be reverted and is always successful. -#[inline] -pub fn end( - context: &mut Context, - evm_output: Result>, -) -> Result> { - evm_output.or_else(|err| { - if matches!(err, EVMError::Transaction(_)) - && context.evm.inner.env().tx.optimism.source_hash.is_some() - { - // If the transaction is a deposit transaction and it failed - // for any reason, the caller nonce must be bumped, and the - // gas reported must be altered depending on the Hardfork. This is - // also returned as a special Halt variant so that consumers can more - // easily distinguish between a failed deposit and a failed - // normal transaction. - let caller = context.evm.inner.env().tx.caller; - - // Increment sender nonce and account balance for the mint amount. Deposits - // always persist the mint amount, even if the transaction fails. - let account = { - let mut acc = Account::from( - context - .evm - .db - .basic(caller) - .unwrap_or_default() - .unwrap_or_default(), - ); - acc.info.nonce = acc.info.nonce.saturating_add(1); - acc.info.balance = acc.info.balance.saturating_add(U256::from( - context.evm.inner.env().tx.optimism.mint.unwrap_or(0), - )); - acc.mark_touch(); - acc - }; - let state = HashMap::from([(caller, account)]); - - // The gas used of a failed deposit post-regolith is the gas - // limit of the transaction. pre-regolith, it is the gas limit - // of the transaction for non system transactions and 0 for system - // transactions. - let is_system_tx = context - .evm - .env() - .tx - .optimism - .is_system_transaction - .unwrap_or(false); - let gas_used = if SPEC::enabled(REGOLITH) || !is_system_tx { - context.evm.inner.env().tx.gas_limit - } else { - 0 - }; - - Ok(ResultAndState { - result: ExecutionResult::Halt { - reason: HaltReason::FailedDeposit, - gas_used, - }, - state, - }) - } else { - Err(err) - } - }) -} - -#[cfg(test)] -mod tests { - use revm_interpreter::{CallOutcome, InterpreterResult}; - - use super::*; - use crate::{ - db::{EmptyDB, InMemoryDB}, - primitives::{ - bytes, state::AccountInfo, Address, BedrockSpec, Bytes, Env, LatestSpec, RegolithSpec, - B256, - }, - L1BlockInfo, - }; - - /// Creates frame result. - fn call_last_frame_return( - env: Env, - instruction_result: InstructionResult, - gas: Gas, - ) -> Gas { - let mut ctx = Context::new_empty(); - ctx.evm.inner.env = Box::new(env); - let mut first_frame = FrameResult::Call(CallOutcome::new( - InterpreterResult { - result: instruction_result, - output: Bytes::new(), - gas, - }, - 0..0, - )); - last_frame_return::(&mut ctx, &mut first_frame).unwrap(); - *first_frame.gas() - } - - #[test] - fn test_revert_gas() { - let mut env = Env::default(); - env.tx.gas_limit = 100; - env.tx.optimism.source_hash = None; - - let gas = - call_last_frame_return::(env, InstructionResult::Revert, Gas::new(90)); - assert_eq!(gas.remaining(), 90); - assert_eq!(gas.spent(), 10); - assert_eq!(gas.refunded(), 0); - } - - #[test] - fn test_consume_gas() { - let mut env = Env::default(); - env.tx.gas_limit = 100; - env.tx.optimism.source_hash = Some(B256::ZERO); - - let gas = - call_last_frame_return::(env, InstructionResult::Stop, Gas::new(90)); - assert_eq!(gas.remaining(), 90); - assert_eq!(gas.spent(), 10); - assert_eq!(gas.refunded(), 0); - } - - #[test] - fn test_consume_gas_with_refund() { - let mut env = Env::default(); - env.tx.gas_limit = 100; - env.tx.optimism.source_hash = Some(B256::ZERO); - - let mut ret_gas = Gas::new(90); - ret_gas.record_refund(20); - - let gas = - call_last_frame_return::(env.clone(), InstructionResult::Stop, ret_gas); - assert_eq!(gas.remaining(), 90); - assert_eq!(gas.spent(), 10); - assert_eq!(gas.refunded(), 2); // min(20, 10/5) - - let gas = call_last_frame_return::(env, InstructionResult::Revert, ret_gas); - assert_eq!(gas.remaining(), 90); - assert_eq!(gas.spent(), 10); - assert_eq!(gas.refunded(), 0); - } - - #[test] - fn test_consume_gas_sys_deposit_tx() { - let mut env = Env::default(); - env.tx.gas_limit = 100; - env.tx.optimism.source_hash = Some(B256::ZERO); - - let gas = call_last_frame_return::(env, InstructionResult::Stop, Gas::new(90)); - assert_eq!(gas.remaining(), 0); - assert_eq!(gas.spent(), 100); - assert_eq!(gas.refunded(), 0); - } - - #[test] - fn test_commit_mint_value() { - let caller = Address::ZERO; - let mut db = InMemoryDB::default(); - db.insert_account_info( - caller, - AccountInfo { - balance: U256::from(1000), - ..Default::default() - }, - ); - let mut context: Context<(), InMemoryDB> = Context::new_with_db(db); - context.evm.inner.l1_block_info = Some(L1BlockInfo { - l1_base_fee: U256::from(1_000), - l1_fee_overhead: Some(U256::from(1_000)), - l1_base_fee_scalar: U256::from(1_000), - ..Default::default() - }); - // Enveloped needs to be some but it will deduce zero fee. - context.evm.inner.env.tx.optimism.enveloped_tx = Some(bytes!("")); - // added mint value is 10. - context.evm.inner.env.tx.optimism.mint = Some(10); - - deduct_caller::(&mut context).unwrap(); - - // Check the account balance is updated. - let (account, _) = context - .evm - .inner - .journaled_state - .load_account(caller, &mut context.evm.inner.db) - .unwrap(); - assert_eq!(account.info.balance, U256::from(1010)); - } - - #[test] - fn test_remove_l1_cost_non_deposit() { - let caller = Address::ZERO; - let mut db = InMemoryDB::default(); - db.insert_account_info( - caller, - AccountInfo { - balance: U256::from(1000), - ..Default::default() - }, - ); - let mut context: Context<(), InMemoryDB> = Context::new_with_db(db); - context.evm.inner.l1_block_info = Some(L1BlockInfo { - l1_base_fee: U256::from(1_000), - l1_fee_overhead: Some(U256::from(1_000)), - l1_base_fee_scalar: U256::from(1_000), - ..Default::default() - }); - // l1block cost is 1048 fee. - context.evm.inner.env.tx.optimism.enveloped_tx = Some(bytes!("FACADE")); - // added mint value is 10. - context.evm.inner.env.tx.optimism.mint = Some(10); - // Putting source_hash to some makes it a deposit transaction. - // so enveloped_tx gas cost is ignored. - context.evm.inner.env.tx.optimism.source_hash = Some(B256::ZERO); - - deduct_caller::(&mut context).unwrap(); - - // Check the account balance is updated. - let (account, _) = context - .evm - .inner - .journaled_state - .load_account(caller, &mut context.evm.inner.db) - .unwrap(); - assert_eq!(account.info.balance, U256::from(1010)); - } - - #[test] - fn test_remove_l1_cost() { - let caller = Address::ZERO; - let mut db = InMemoryDB::default(); - db.insert_account_info( - caller, - AccountInfo { - balance: U256::from(1049), - ..Default::default() - }, - ); - let mut context: Context<(), InMemoryDB> = Context::new_with_db(db); - context.evm.inner.l1_block_info = Some(L1BlockInfo { - l1_base_fee: U256::from(1_000), - l1_fee_overhead: Some(U256::from(1_000)), - l1_base_fee_scalar: U256::from(1_000), - ..Default::default() - }); - // l1block cost is 1048 fee. - context.evm.inner.env.tx.optimism.enveloped_tx = Some(bytes!("FACADE")); - deduct_caller::(&mut context).unwrap(); - - // Check the account balance is updated. - let (account, _) = context - .evm - .inner - .journaled_state - .load_account(caller, &mut context.evm.inner.db) - .unwrap(); - assert_eq!(account.info.balance, U256::from(1)); - } - - #[test] - fn test_remove_l1_cost_lack_of_funds() { - let caller = Address::ZERO; - let mut db = InMemoryDB::default(); - db.insert_account_info( - caller, - AccountInfo { - balance: U256::from(48), - ..Default::default() - }, - ); - let mut context: Context<(), InMemoryDB> = Context::new_with_db(db); - context.evm.inner.l1_block_info = Some(L1BlockInfo { - l1_base_fee: U256::from(1_000), - l1_fee_overhead: Some(U256::from(1_000)), - l1_base_fee_scalar: U256::from(1_000), - ..Default::default() - }); - // l1block cost is 1048 fee. - context.evm.inner.env.tx.optimism.enveloped_tx = Some(bytes!("FACADE")); - - assert_eq!( - deduct_caller::(&mut context), - Err(EVMError::Transaction( - InvalidTransaction::LackOfFundForMaxFee { - fee: Box::new(U256::from(1048)), - balance: Box::new(U256::from(48)), - }, - )) - ); - } - - #[test] - fn test_validate_sys_tx() { - // mark the tx as a system transaction. - let mut env = Env::default(); - env.tx.optimism.is_system_transaction = Some(true); - assert_eq!( - validate_env::(&env), - Err(EVMError::Transaction( - InvalidTransaction::DepositSystemTxPostRegolith - )) - ); - - // Pre-regolith system transactions should be allowed. - assert!(validate_env::(&env).is_ok()); - } - - #[test] - fn test_validate_deposit_tx() { - // Set source hash. - let mut env = Env::default(); - env.tx.optimism.source_hash = Some(B256::ZERO); - assert!(validate_env::(&env).is_ok()); - } - - #[test] - fn test_validate_tx_against_state_deposit_tx() { - // Set source hash. - let mut env = Env::default(); - env.tx.optimism.source_hash = Some(B256::ZERO); - - // Nonce and balance checks should be skipped for deposit transactions. - assert!(validate_env::(&env).is_ok()); - } -} diff --git a/crates/revm/src/optimism/l1block.rs b/crates/revm/src/optimism/l1block.rs deleted file mode 100644 index 2dab41a4e4..0000000000 --- a/crates/revm/src/optimism/l1block.rs +++ /dev/null @@ -1,413 +0,0 @@ -use crate::optimism::fast_lz::flz_compress_len; -use crate::primitives::{address, db::Database, Address, SpecId, U256}; -use core::ops::Mul; - -const ZERO_BYTE_COST: u64 = 4; -const NON_ZERO_BYTE_COST: u64 = 16; - -/// The two 4-byte Ecotone fee scalar values are packed into the same storage slot as the 8-byte sequence number. -/// Byte offset within the storage slot of the 4-byte baseFeeScalar attribute. -const BASE_FEE_SCALAR_OFFSET: usize = 16; -/// The two 4-byte Ecotone fee scalar values are packed into the same storage slot as the 8-byte sequence number. -/// Byte offset within the storage slot of the 4-byte blobBaseFeeScalar attribute. -const BLOB_BASE_FEE_SCALAR_OFFSET: usize = 20; - -const L1_BASE_FEE_SLOT: U256 = U256::from_limbs([1u64, 0, 0, 0]); -const L1_OVERHEAD_SLOT: U256 = U256::from_limbs([5u64, 0, 0, 0]); -const L1_SCALAR_SLOT: U256 = U256::from_limbs([6u64, 0, 0, 0]); - -/// [ECOTONE_L1_BLOB_BASE_FEE_SLOT] was added in the Ecotone upgrade and stores the L1 blobBaseFee attribute. -const ECOTONE_L1_BLOB_BASE_FEE_SLOT: U256 = U256::from_limbs([7u64, 0, 0, 0]); - -/// As of the ecotone upgrade, this storage slot stores the 32-bit basefeeScalar and blobBaseFeeScalar attributes at -/// offsets [BASE_FEE_SCALAR_OFFSET] and [BLOB_BASE_FEE_SCALAR_OFFSET] respectively. -const ECOTONE_L1_FEE_SCALARS_SLOT: U256 = U256::from_limbs([3u64, 0, 0, 0]); - -/// An empty 64-bit set of scalar values. -const EMPTY_SCALARS: [u8; 8] = [0u8; 8]; - -/// The address of L1 fee recipient. -pub const L1_FEE_RECIPIENT: Address = address!("420000000000000000000000000000000000001A"); - -/// The address of the base fee recipient. -pub const BASE_FEE_RECIPIENT: Address = address!("4200000000000000000000000000000000000019"); - -/// The address of the L1Block contract. -pub const L1_BLOCK_CONTRACT: Address = address!("4200000000000000000000000000000000000015"); - -/// L1 block info -/// -/// We can extract L1 epoch data from each L2 block, by looking at the `setL1BlockValues` -/// transaction data. This data is then used to calculate the L1 cost of a transaction. -/// -/// Here is the format of the `setL1BlockValues` transaction data: -/// -/// setL1BlockValues(uint64 _number, uint64 _timestamp, uint256 _basefee, bytes32 _hash, -/// uint64 _sequenceNumber, bytes32 _batcherHash, uint256 _l1FeeOverhead, uint256 _l1FeeScalar) -/// -/// For now, we only care about the fields necessary for L1 cost calculation. -#[derive(Clone, Debug, Default)] -pub struct L1BlockInfo { - /// The base fee of the L1 origin block. - pub l1_base_fee: U256, - /// The current L1 fee overhead. None if Ecotone is activated. - pub l1_fee_overhead: Option, - /// The current L1 fee scalar. - pub l1_base_fee_scalar: U256, - /// The current L1 blob base fee. None if Ecotone is not activated, except if `empty_scalars` is `true`. - pub l1_blob_base_fee: Option, - /// The current L1 blob base fee scalar. None if Ecotone is not activated. - pub l1_blob_base_fee_scalar: Option, - /// True if Ecotone is activated, but the L1 fee scalars have not yet been set. - pub(crate) empty_scalars: bool, -} - -impl L1BlockInfo { - /// Try to fetch the L1 block info from the database. - pub fn try_fetch(db: &mut DB, spec_id: SpecId) -> Result { - // Ensure the L1 Block account is loaded into the cache after Ecotone. With EIP-4788, it is no longer the case - // that the L1 block account is loaded into the cache prior to the first inquiry for the L1 block info. - if spec_id.is_enabled_in(SpecId::CANCUN) { - let _ = db.basic(L1_BLOCK_CONTRACT)?; - } - - let l1_base_fee = db.storage(L1_BLOCK_CONTRACT, L1_BASE_FEE_SLOT)?; - - if !spec_id.is_enabled_in(SpecId::ECOTONE) { - let l1_fee_overhead = db.storage(L1_BLOCK_CONTRACT, L1_OVERHEAD_SLOT)?; - let l1_fee_scalar = db.storage(L1_BLOCK_CONTRACT, L1_SCALAR_SLOT)?; - - Ok(L1BlockInfo { - l1_base_fee, - l1_fee_overhead: Some(l1_fee_overhead), - l1_base_fee_scalar: l1_fee_scalar, - ..Default::default() - }) - } else { - let l1_blob_base_fee = db.storage(L1_BLOCK_CONTRACT, ECOTONE_L1_BLOB_BASE_FEE_SLOT)?; - let l1_fee_scalars = db - .storage(L1_BLOCK_CONTRACT, ECOTONE_L1_FEE_SCALARS_SLOT)? - .to_be_bytes::<32>(); - - let l1_base_fee_scalar = U256::from_be_slice( - l1_fee_scalars[BASE_FEE_SCALAR_OFFSET..BASE_FEE_SCALAR_OFFSET + 4].as_ref(), - ); - let l1_blob_base_fee_scalar = U256::from_be_slice( - l1_fee_scalars[BLOB_BASE_FEE_SCALAR_OFFSET..BLOB_BASE_FEE_SCALAR_OFFSET + 4] - .as_ref(), - ); - - // Check if the L1 fee scalars are empty. If so, we use the Bedrock cost function. The L1 fee overhead is - // only necessary if `empty_scalars` is true, as it was deprecated in Ecotone. - let empty_scalars = l1_blob_base_fee == U256::ZERO - && l1_fee_scalars[BASE_FEE_SCALAR_OFFSET..BLOB_BASE_FEE_SCALAR_OFFSET + 4] - == EMPTY_SCALARS; - let l1_fee_overhead = empty_scalars - .then(|| db.storage(L1_BLOCK_CONTRACT, L1_OVERHEAD_SLOT)) - .transpose()?; - - Ok(L1BlockInfo { - l1_base_fee, - l1_base_fee_scalar, - l1_blob_base_fee: Some(l1_blob_base_fee), - l1_blob_base_fee_scalar: Some(l1_blob_base_fee_scalar), - empty_scalars, - l1_fee_overhead, - }) - } - } - - /// Calculate the data gas for posting the transaction on L1. Calldata costs 16 gas per byte - /// after compression. - /// - /// Prior to fjord, calldata costs 16 gas per non-zero byte and 4 gas per zero byte. - /// - /// Prior to regolith, an extra 68 non-zero bytes were included in the rollup data costs to - /// account for the empty signature. - pub fn data_gas(&self, input: &[u8], spec_id: SpecId) -> U256 { - if spec_id.is_enabled_in(SpecId::FJORD) { - let estimated_size = self.tx_estimated_size_fjord(input); - - return estimated_size - .saturating_mul(U256::from(NON_ZERO_BYTE_COST)) - .wrapping_div(U256::from(1_000_000)); - }; - - let mut rollup_data_gas_cost = U256::from(input.iter().fold(0, |acc, byte| { - acc + if *byte == 0x00 { - ZERO_BYTE_COST - } else { - NON_ZERO_BYTE_COST - } - })); - - // Prior to regolith, an extra 68 non zero bytes were included in the rollup data costs. - if !spec_id.is_enabled_in(SpecId::REGOLITH) { - rollup_data_gas_cost += U256::from(NON_ZERO_BYTE_COST).mul(U256::from(68)); - } - - rollup_data_gas_cost - } - - // Calculate the estimated compressed transaction size in bytes, scaled by 1e6. - // This value is computed based on the following formula: - // max(minTransactionSize, intercept + fastlzCoef*fastlzSize) - fn tx_estimated_size_fjord(&self, input: &[u8]) -> U256 { - let fastlz_size = U256::from(flz_compress_len(input)); - - fastlz_size - .saturating_mul(U256::from(836_500)) - .saturating_sub(U256::from(42_585_600)) - .max(U256::from(100_000_000)) - } - - /// Calculate the gas cost of a transaction based on L1 block data posted on L2, depending on the [SpecId] passed. - pub fn calculate_tx_l1_cost(&self, input: &[u8], spec_id: SpecId) -> U256 { - // If the input is a deposit transaction or empty, the default value is zero. - if input.is_empty() || input.first() == Some(&0x7F) { - return U256::ZERO; - } - - if spec_id.is_enabled_in(SpecId::FJORD) { - self.calculate_tx_l1_cost_fjord(input) - } else if spec_id.is_enabled_in(SpecId::ECOTONE) { - self.calculate_tx_l1_cost_ecotone(input, spec_id) - } else { - self.calculate_tx_l1_cost_bedrock(input, spec_id) - } - } - - /// Calculate the gas cost of a transaction based on L1 block data posted on L2, pre-Ecotone. - fn calculate_tx_l1_cost_bedrock(&self, input: &[u8], spec_id: SpecId) -> U256 { - let rollup_data_gas_cost = self.data_gas(input, spec_id); - rollup_data_gas_cost - .saturating_add(self.l1_fee_overhead.unwrap_or_default()) - .saturating_mul(self.l1_base_fee) - .saturating_mul(self.l1_base_fee_scalar) - .wrapping_div(U256::from(1_000_000)) - } - - /// Calculate the gas cost of a transaction based on L1 block data posted on L2, post-Ecotone. - /// - /// [SpecId::ECOTONE] L1 cost function: - /// `(calldataGas/16)*(l1BaseFee*16*l1BaseFeeScalar + l1BlobBaseFee*l1BlobBaseFeeScalar)/1e6` - /// - /// We divide "calldataGas" by 16 to change from units of calldata gas to "estimated # of bytes when compressed". - /// Known as "compressedTxSize" in the spec. - /// - /// Function is actually computed as follows for better precision under integer arithmetic: - /// `calldataGas*(l1BaseFee*16*l1BaseFeeScalar + l1BlobBaseFee*l1BlobBaseFeeScalar)/16e6` - fn calculate_tx_l1_cost_ecotone(&self, input: &[u8], spec_id: SpecId) -> U256 { - // There is an edgecase where, for the very first Ecotone block (unless it is activated at Genesis), we must - // use the Bedrock cost function. To determine if this is the case, we can check if the Ecotone parameters are - // unset. - if self.empty_scalars { - return self.calculate_tx_l1_cost_bedrock(input, spec_id); - } - - let rollup_data_gas_cost = self.data_gas(input, spec_id); - let l1_fee_scaled = self.calculate_l1_fee_scaled_ecotone(); - - l1_fee_scaled - .saturating_mul(rollup_data_gas_cost) - .wrapping_div(U256::from(1_000_000 * NON_ZERO_BYTE_COST)) - } - - /// Calculate the gas cost of a transaction based on L1 block data posted on L2, post-Fjord. - /// - /// [SpecId::FJORD] L1 cost function: - /// `estimatedSize*(baseFeeScalar*l1BaseFee*16 + blobFeeScalar*l1BlobBaseFee)/1e12` - fn calculate_tx_l1_cost_fjord(&self, input: &[u8]) -> U256 { - let l1_fee_scaled = self.calculate_l1_fee_scaled_ecotone(); - let estimated_size = self.tx_estimated_size_fjord(input); - - estimated_size - .saturating_mul(l1_fee_scaled) - .wrapping_div(U256::from(1e12)) - } - - // l1BaseFee*16*l1BaseFeeScalar + l1BlobBaseFee*l1BlobBaseFeeScalar - fn calculate_l1_fee_scaled_ecotone(&self) -> U256 { - let calldata_cost_per_byte = self - .l1_base_fee - .saturating_mul(U256::from(NON_ZERO_BYTE_COST)) - .saturating_mul(self.l1_base_fee_scalar); - let blob_cost_per_byte = self - .l1_blob_base_fee - .unwrap_or_default() - .saturating_mul(self.l1_blob_base_fee_scalar.unwrap_or_default()); - - calldata_cost_per_byte.saturating_add(blob_cost_per_byte) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::primitives::bytes; - - #[test] - fn test_data_gas_non_zero_bytes() { - let l1_block_info = L1BlockInfo { - l1_base_fee: U256::from(1_000_000), - l1_fee_overhead: Some(U256::from(1_000_000)), - l1_base_fee_scalar: U256::from(1_000_000), - ..Default::default() - }; - - // 0xFACADE = 6 nibbles = 3 bytes - // 0xFACADE = 1111 1010 . 1100 1010 . 1101 1110 - - // Pre-regolith (ie bedrock) has an extra 68 non-zero bytes - // gas cost = 3 non-zero bytes * NON_ZERO_BYTE_COST + NON_ZERO_BYTE_COST * 68 - // gas cost = 3 * 16 + 68 * 16 = 1136 - let input = bytes!("FACADE"); - let bedrock_data_gas = l1_block_info.data_gas(&input, SpecId::BEDROCK); - assert_eq!(bedrock_data_gas, U256::from(1136)); - - // Regolith has no added 68 non zero bytes - // gas cost = 3 * 16 = 48 - let regolith_data_gas = l1_block_info.data_gas(&input, SpecId::REGOLITH); - assert_eq!(regolith_data_gas, U256::from(48)); - - // Fjord has a minimum compressed size of 100 bytes - // gas cost = 100 * 16 = 1600 - let fjord_data_gas = l1_block_info.data_gas(&input, SpecId::FJORD); - assert_eq!(fjord_data_gas, U256::from(1600)); - } - - #[test] - fn test_data_gas_zero_bytes() { - let l1_block_info = L1BlockInfo { - l1_base_fee: U256::from(1_000_000), - l1_fee_overhead: Some(U256::from(1_000_000)), - l1_base_fee_scalar: U256::from(1_000_000), - ..Default::default() - }; - - // 0xFA00CA00DE = 10 nibbles = 5 bytes - // 0xFA00CA00DE = 1111 1010 . 0000 0000 . 1100 1010 . 0000 0000 . 1101 1110 - - // Pre-regolith (ie bedrock) has an extra 68 non-zero bytes - // gas cost = 3 non-zero * NON_ZERO_BYTE_COST + 2 * ZERO_BYTE_COST + NON_ZERO_BYTE_COST * 68 - // gas cost = 3 * 16 + 2 * 4 + 68 * 16 = 1144 - let input = bytes!("FA00CA00DE"); - let bedrock_data_gas = l1_block_info.data_gas(&input, SpecId::BEDROCK); - assert_eq!(bedrock_data_gas, U256::from(1144)); - - // Regolith has no added 68 non zero bytes - // gas cost = 3 * 16 + 2 * 4 = 56 - let regolith_data_gas = l1_block_info.data_gas(&input, SpecId::REGOLITH); - assert_eq!(regolith_data_gas, U256::from(56)); - - // Fjord has a minimum compressed size of 100 bytes - // gas cost = 100 * 16 = 1600 - let fjord_data_gas = l1_block_info.data_gas(&input, SpecId::FJORD); - assert_eq!(fjord_data_gas, U256::from(1600)); - } - - #[test] - fn test_calculate_tx_l1_cost() { - let l1_block_info = L1BlockInfo { - l1_base_fee: U256::from(1_000), - l1_fee_overhead: Some(U256::from(1_000)), - l1_base_fee_scalar: U256::from(1_000), - ..Default::default() - }; - - let input = bytes!("FACADE"); - let gas_cost = l1_block_info.calculate_tx_l1_cost(&input, SpecId::REGOLITH); - assert_eq!(gas_cost, U256::from(1048)); - - // Zero rollup data gas cost should result in zero - let input = bytes!(""); - let gas_cost = l1_block_info.calculate_tx_l1_cost(&input, SpecId::REGOLITH); - assert_eq!(gas_cost, U256::ZERO); - - // Deposit transactions with the EIP-2718 type of 0x7F should result in zero - let input = bytes!("7FFACADE"); - let gas_cost = l1_block_info.calculate_tx_l1_cost(&input, SpecId::REGOLITH); - assert_eq!(gas_cost, U256::ZERO); - } - - #[test] - fn test_calculate_tx_l1_cost_ecotone() { - let mut l1_block_info = L1BlockInfo { - l1_base_fee: U256::from(1_000), - l1_base_fee_scalar: U256::from(1_000), - l1_blob_base_fee: Some(U256::from(1_000)), - l1_blob_base_fee_scalar: Some(U256::from(1_000)), - l1_fee_overhead: Some(U256::from(1_000)), - ..Default::default() - }; - - // calldataGas * (l1BaseFee * 16 * l1BaseFeeScalar + l1BlobBaseFee * l1BlobBaseFeeScalar) / (16 * 1e6) - // = (16 * 3) * (1000 * 16 * 1000 + 1000 * 1000) / (16 * 1e6) - // = 51 - let input = bytes!("FACADE"); - let gas_cost = l1_block_info.calculate_tx_l1_cost(&input, SpecId::ECOTONE); - assert_eq!(gas_cost, U256::from(51)); - - // Zero rollup data gas cost should result in zero - let input = bytes!(""); - let gas_cost = l1_block_info.calculate_tx_l1_cost(&input, SpecId::ECOTONE); - assert_eq!(gas_cost, U256::ZERO); - - // Deposit transactions with the EIP-2718 type of 0x7F should result in zero - let input = bytes!("7FFACADE"); - let gas_cost = l1_block_info.calculate_tx_l1_cost(&input, SpecId::ECOTONE); - assert_eq!(gas_cost, U256::ZERO); - - // If the scalars are empty, the bedrock cost function should be used. - l1_block_info.empty_scalars = true; - let input = bytes!("FACADE"); - let gas_cost = l1_block_info.calculate_tx_l1_cost(&input, SpecId::ECOTONE); - assert_eq!(gas_cost, U256::from(1048)); - } - - #[test] - fn test_calculate_tx_l1_cost_fjord() { - // l1FeeScaled = baseFeeScalar*l1BaseFee*16 + blobFeeScalar*l1BlobBaseFee - // = 1000 * 1000 * 16 + 1000 * 1000 - // = 17e6 - let l1_block_info = L1BlockInfo { - l1_base_fee: U256::from(1_000), - l1_base_fee_scalar: U256::from(1_000), - l1_blob_base_fee: Some(U256::from(1_000)), - l1_blob_base_fee_scalar: Some(U256::from(1_000)), - ..Default::default() - }; - - // fastLzSize = 4 - // estimatedSize = max(minTransactionSize, intercept + fastlzCoef*fastlzSize) - // = max(100e6, 836500*4 - 42585600) - // = 100e6 - let input = bytes!("FACADE"); - // l1Cost = estimatedSize * l1FeeScaled / 1e12 - // = 100e6 * 17 / 1e6 - // = 1700 - let gas_cost = l1_block_info.calculate_tx_l1_cost(&input, SpecId::FJORD); - assert_eq!(gas_cost, U256::from(1700)); - - // fastLzSize = 202 - // estimatedSize = max(minTransactionSize, intercept + fastlzCoef*fastlzSize) - // = max(100e6, 836500*202 - 42585600) - // = 126387400 - let input = bytes!("02f901550a758302df1483be21b88304743f94f80e51afb613d764fa61751affd3313c190a86bb870151bd62fd12adb8e41ef24f3f000000000000000000000000000000000000000000000000000000000000006e000000000000000000000000af88d065e77c8cc2239327c5edb3a432268e5831000000000000000000000000000000000000000000000000000000000003c1e5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000148c89ed219d02f1a5be012c689b4f5b731827bebe000000000000000000000000c001a033fd89cb37c31b2cba46b6466e040c61fc9b2a3675a7f5f493ebd5ad77c497f8a07cdf65680e238392693019b4092f610222e71b7cec06449cb922b93b6a12744e"); - // l1Cost = estimatedSize * l1FeeScaled / 1e12 - // = 126387400 * 17 / 1e6 - // = 2148 - let gas_cost = l1_block_info.calculate_tx_l1_cost(&input, SpecId::FJORD); - assert_eq!(gas_cost, U256::from(2148)); - - // Zero rollup data gas cost should result in zero - let input = bytes!(""); - let gas_cost = l1_block_info.calculate_tx_l1_cost(&input, SpecId::FJORD); - assert_eq!(gas_cost, U256::ZERO); - - // Deposit transactions with the EIP-2718 type of 0x7F should result in zero - let input = bytes!("7FFACADE"); - let gas_cost = l1_block_info.calculate_tx_l1_cost(&input, SpecId::FJORD); - assert_eq!(gas_cost, U256::ZERO); - } -} diff --git a/crates/revm/src/test_utils.rs b/crates/revm/src/test_utils.rs deleted file mode 100644 index 5740022066..0000000000 --- a/crates/revm/src/test_utils.rs +++ /dev/null @@ -1,2 +0,0 @@ -#[doc(hidden)] -pub use crate::context::evm_context::test_utils::*; diff --git a/crates/revm/tests/common.rs b/crates/revm/tests/common.rs new file mode 100644 index 0000000000..c3a909de08 --- /dev/null +++ b/crates/revm/tests/common.rs @@ -0,0 +1,108 @@ +//! Common test utilities used to compare execution results against testdata. +#![allow(dead_code)] + +use revm::{ + context::result::ResultAndState, + context_interface::result::{ExecutionResult, HaltReason, Output, SuccessReason}, + primitives::Bytes, + state::EvmState, +}; + +// Constant for testdata directory path +pub(crate) const TESTS_TESTDATA: &str = "tests/testdata"; + +#[cfg(not(feature = "serde"))] +pub(crate) fn compare_or_save_testdata(_filename: &str, _output: I) { + // serde needs to be enabled to use this function +} + +/// Compares or saves the execution output to a testdata file. +/// +/// This utility helps maintain consistent test behavior by comparing +/// execution results against known-good outputs stored in JSON files. +/// +/// # Arguments +/// +/// * `filename` - The name of the testdata file, relative to tests/testdata/ +/// * `output` - The execution output to compare or save +/// +/// # Returns +/// +/// `Ok(())` if the comparison or save was successful +/// `Err(anyhow::Error)` if there was an error +/// +/// # Note +/// +/// Tests using this function require the `serde` feature to be enabled: +/// ```bash +/// cargo test --features serde +/// ``` +#[cfg(feature = "serde")] +pub(crate) fn compare_or_save_testdata< + I: serde::Serialize + for<'a> serde::Deserialize<'a> + PartialEq, +>( + filename: &str, + output: I, +) { + use std::{fs, path::PathBuf}; + + let tests_dir = PathBuf::from(TESTS_TESTDATA); + let testdata_file = tests_dir.join(filename); + + // Create directory if it doesn't exist + if !tests_dir.exists() { + fs::create_dir_all(&tests_dir).unwrap(); + } + + // Serialize the output to JSON for saving + let output_json = serde_json::to_string_pretty(&output).unwrap(); + + // If the testdata file doesn't exist, save the output + if !testdata_file.exists() { + fs::write(&testdata_file, &output_json).unwrap(); + println!("Saved testdata to {}", testdata_file.display()); + return; + } + + // Read the expected output from the testdata file + let expected_json = fs::read_to_string(&testdata_file).unwrap(); + + // Deserialize to actual ResultAndState object for proper comparison + let expected = serde_json::from_str(&expected_json).unwrap(); + + // Compare the output objects directly + if output != expected { + // If they don't match, generate a nicer error by pretty-printing both as JSON + // This helps with debugging by showing the exact differences + let expected_pretty = serde_json::to_string_pretty(&expected).unwrap(); + + panic!( + "Value does not match testdata.\nExpected:\n{expected_pretty}\n\nActual:\n{output_json}" + ); + } +} + +/// Example showing how to migrate an existing test to use the testdata comparison. +/// +/// This example consists of: +/// 1. The "original" test with standard assertions +/// 2. The migration approach - running assertions and saving testdata +/// 3. The final migrated test that only uses testdata comparison +#[test] +fn template_test() { + // Create a minimal result and state + let result = ResultAndState::new( + ExecutionResult::::Success { + reason: SuccessReason::Stop, + gas_used: 1000, + gas_refunded: 0, + logs: vec![], + output: Output::Call(Bytes::from(vec![4, 5, 6])), + }, + EvmState::default(), + ); + + // Simply use the testdata comparison utility + // No assertions needed - full validation is done by comparing with testdata + compare_or_save_testdata("template_test.json", result); +} diff --git a/crates/revm/tests/integration.rs b/crates/revm/tests/integration.rs new file mode 100644 index 0000000000..4aa41ce0c2 --- /dev/null +++ b/crates/revm/tests/integration.rs @@ -0,0 +1,274 @@ +//! Integration tests for the `op-revm` crate. +mod common; + +use common::compare_or_save_testdata; +use context::ContextTr; +use database::BENCH_CALLER; +use primitives::{address, b256, hardfork::SpecId, Bytes, TxKind, KECCAK_EMPTY}; +use revm::{ + bytecode::opcode, + context::TxEnv, + database::{BenchmarkDB, BENCH_TARGET}, + primitives::U256, + state::Bytecode, + Context, ExecuteEvm, MainBuilder, MainContext, +}; +use state::AccountStatus; + +const SELFDESTRUCT_BYTECODE: &[u8] = &[ + opcode::PUSH2, + 0xFF, + 0xFF, + opcode::SELFDESTRUCT, + opcode::STOP, +]; + +#[test] +fn test_selfdestruct_multi_tx() { + let mut evm = Context::mainnet() + .modify_cfg_chained(|cfg| cfg.spec = SpecId::BERLIN) + .with_db(BenchmarkDB::new_bytecode(Bytecode::new_legacy( + SELFDESTRUCT_BYTECODE.into(), + ))) + .build_mainnet(); + + // trigger selfdestruct + let result1 = evm + .transact_one(TxEnv::builder_for_bench().build_fill()) + .unwrap(); + + let destroyed_acc = evm.ctx.journal_mut().state.get_mut(&BENCH_TARGET).unwrap(); + + // balance got transferred to 0x0000..00FFFF + assert_eq!(destroyed_acc.info.balance, U256::ZERO); + assert_eq!(destroyed_acc.info.nonce, 1); + assert_eq!( + destroyed_acc.info.code_hash, + b256!("0x9125466aa9ef15459d85e7318f6d3bdc5f6978c0565bee37a8e768d7c202a67a") + ); + + // call on destroyed account. This accounts gets loaded and should contain empty code_hash afterwards. + let result2 = evm + .transact_one(TxEnv::builder_for_bench().nonce(1).build_fill()) + .unwrap(); + + let destroyed_acc = evm.ctx.journal_mut().state.get_mut(&BENCH_TARGET).unwrap(); + + assert_eq!(destroyed_acc.info.code_hash, KECCAK_EMPTY); + assert_eq!(destroyed_acc.info.nonce, 0); + assert_eq!(destroyed_acc.info.code, Some(Bytecode::default())); + + let output = evm.finalize(); + + compare_or_save_testdata( + "test_selfdestruct_multi_tx.json", + (result1, result2, output), + ); +} + +/// Tests multiple transactions with contract creation. +/// Verifies that created contracts persist correctly across transactions +/// and that their state is properly maintained. +#[test] +pub fn test_multi_tx_create() { + let mut evm = Context::mainnet() + .modify_cfg_chained(|cfg| { + cfg.spec = SpecId::BERLIN; + cfg.disable_nonce_check = true; + }) + .with_db(BenchmarkDB::new_bytecode(Bytecode::new())) + .build_mainnet(); + + let result1 = evm + .transact_one( + TxEnv::builder_for_bench() + .kind(TxKind::Create) + .data(deployment_contract(SELFDESTRUCT_BYTECODE)) + .build_fill(), + ) + .unwrap(); + + let created_address = result1.created_address().unwrap(); + + let created_acc = evm + .ctx + .journal_mut() + .state + .get_mut(&created_address) + .unwrap(); + + assert_eq!( + created_acc.status, + AccountStatus::Created + | AccountStatus::CreatedLocal + | AccountStatus::Touched + | AccountStatus::LoadedAsNotExisting + ); + + let result2 = evm + .transact_one( + TxEnv::builder_for_bench() + .nonce(1) + .kind(TxKind::Call(created_address)) + .build_fill(), + ) + .unwrap(); + + let created_acc = evm + .ctx + .journal_mut() + .state + .get_mut(&created_address) + .unwrap(); + + // reset nonce to trigger create on same address. + assert_eq!( + created_acc.status, + AccountStatus::Created + | AccountStatus::SelfDestructed + | AccountStatus::SelfDestructedLocal + | AccountStatus::Touched + | AccountStatus::LoadedAsNotExisting + ); + + // reset caller nonce + evm.ctx + .journal_mut() + .state + .get_mut(&BENCH_CALLER) + .unwrap() + .info + .nonce = 0; + + // re create the contract. + let result3 = evm + .transact_one( + TxEnv::builder_for_bench() + .nonce(0) + .kind(TxKind::Create) + .data(deployment_contract(SELFDESTRUCT_BYTECODE)) + .build_fill(), + ) + .unwrap(); + + let created_address_new = result3.created_address().unwrap(); + assert_eq!(created_address, created_address_new); + + let created_acc = evm + .ctx + .journal_mut() + .state + .get_mut(&created_address) + .unwrap(); + + assert_eq!( + created_acc.status, + AccountStatus::Created + | AccountStatus::CreatedLocal + | AccountStatus::Touched + | AccountStatus::SelfDestructed + | AccountStatus::LoadedAsNotExisting + ); + let output = evm.finalize(); + + compare_or_save_testdata( + "test_multi_tx_create.json", + (result1, result2, result3, output), + ); +} + +/// Creates deployment bytecode for a contract. +/// Prepends the initialization code that will deploy the provided runtime bytecode. +pub fn deployment_contract(bytes: &[u8]) -> Bytes { + assert!(bytes.len() < 256); + let len = bytes.len(); + let ret = &[ + opcode::PUSH1, + len as u8, + opcode::PUSH1, + 12, + opcode::PUSH1, + 0, + // Copy code to memory. + opcode::CODECOPY, + opcode::PUSH1, + len as u8, + opcode::PUSH1, + 0, + // Return copied code. + opcode::RETURN, + ]; + + [ret, bytes].concat().into() +} + +#[test] +fn test_frame_stack_index() { + let mut evm = Context::mainnet() + .modify_cfg_chained(|cfg| cfg.spec = SpecId::BERLIN) + .with_db(BenchmarkDB::new_bytecode(Bytecode::new_legacy( + SELFDESTRUCT_BYTECODE.into(), + ))) + .build_mainnet(); + + // transfer to other account + let result1 = evm + .transact_one( + TxEnv::builder_for_bench() + .to(address!("0xc000000000000000000000000000000000000000")) + .build_fill(), + ) + .unwrap(); + + assert_eq!(evm.frame_stack.index(), None); + compare_or_save_testdata("test_frame_stack_index.json", result1); +} + +#[test] +#[cfg(feature = "optional_balance_check")] +fn test_disable_balance_check() { + use database::BENCH_CALLER_BALANCE; + + const RETURN_CALLER_BALANCE_BYTECODE: &[u8] = &[ + opcode::CALLER, + opcode::BALANCE, + opcode::PUSH1, + 0x00, + opcode::MSTORE, + opcode::PUSH1, + 0x20, + opcode::PUSH1, + 0x00, + opcode::RETURN, + ]; + + let mut evm = Context::mainnet() + .modify_cfg_chained(|cfg| cfg.disable_balance_check = true) + .with_db(BenchmarkDB::new_bytecode(Bytecode::new_legacy( + RETURN_CALLER_BALANCE_BYTECODE.into(), + ))) + .build_mainnet(); + + // Construct tx so that effective cost is more than caller balance. + let gas_price = 1; + let gas_limit = 100_000; + // Make sure value doesn't consume all balance since we want to validate that all effective + // cost is deducted. + let tx_value = BENCH_CALLER_BALANCE - U256::from(1); + + let result = evm + .transact_one( + TxEnv::builder_for_bench() + .gas_price(gas_price) + .gas_limit(gas_limit) + .value(tx_value) + .build_fill(), + ) + .unwrap(); + + assert!(result.is_success()); + + let returned_balance = U256::from_be_slice(result.output().unwrap().as_ref()); + let expected_balance = U256::ZERO; + assert_eq!(returned_balance, expected_balance); +} diff --git a/crates/revm/tests/testdata/template_test.json b/crates/revm/tests/testdata/template_test.json new file mode 100644 index 0000000000..5c35711ddd --- /dev/null +++ b/crates/revm/tests/testdata/template_test.json @@ -0,0 +1,14 @@ +{ + "result": { + "Success": { + "reason": "Stop", + "gas_used": 1000, + "gas_refunded": 0, + "logs": [], + "output": { + "Call": "0x040506" + } + } + }, + "state": {} +} \ No newline at end of file diff --git a/crates/revm/tests/testdata/test_frame_stack_index.json b/crates/revm/tests/testdata/test_frame_stack_index.json new file mode 100644 index 0000000000..c5981e4b93 --- /dev/null +++ b/crates/revm/tests/testdata/test_frame_stack_index.json @@ -0,0 +1,11 @@ +{ + "Success": { + "reason": "Stop", + "gas_used": 21000, + "gas_refunded": 0, + "logs": [], + "output": { + "Call": "0x" + } + } +} \ No newline at end of file diff --git a/crates/revm/tests/testdata/test_multi_tx_create.json b/crates/revm/tests/testdata/test_multi_tx_create.json new file mode 100644 index 0000000000..10d184d7de --- /dev/null +++ b/crates/revm/tests/testdata/test_multi_tx_create.json @@ -0,0 +1,145 @@ +[ + { + "Success": { + "reason": "Return", + "gas_used": 54260, + "gas_refunded": 0, + "logs": [], + "output": { + "Create": [ + "0x61ffffff00", + "0x84bcbaa99ae6d1f7f70b37d5f6c27c9631eeb2f2" + ] + } + } + }, + { + "Success": { + "reason": "SelfDestruct", + "gas_used": 14302, + "gas_refunded": 14301, + "logs": [], + "output": { + "Call": "0x" + } + } + }, + { + "Success": { + "reason": "Return", + "gas_used": 54260, + "gas_refunded": 0, + "logs": [], + "output": { + "Create": [ + "0x61ffffff00", + "0x84bcbaa99ae6d1f7f70b37d5f6c27c9631eeb2f2" + ] + } + } + }, + { + "0x0000000000000000000000000000000000000000": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 2, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee": { + "info": { + "balance": "0x2386f26fc10000", + "nonce": 1, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 2, + "storage": {}, + "status": "Touched" + }, + "0x000000000000000000000000000000000000ffff": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 1, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x84bcbaa99ae6d1f7f70b37d5f6c27c9631eeb2f2": { + "info": { + "balance": "0x0", + "nonce": 1, + "code_hash": "0x9125466aa9ef15459d85e7318f6d3bdc5f6978c0565bee37a8e768d7c202a67a", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x61ffffff00", + "original_len": 5, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 5, + "data": [ + 0 + ] + } + } + } + }, + "transaction_id": 2, + "storage": {}, + "status": "Created | CreatedLocal | SelfDestructed | Touched | LoadedAsNotExisting" + } + } +] \ No newline at end of file diff --git a/crates/revm/tests/testdata/test_selfdestruct_multi_tx.json b/crates/revm/tests/testdata/test_selfdestruct_multi_tx.json new file mode 100644 index 0000000000..3db1e8eec5 --- /dev/null +++ b/crates/revm/tests/testdata/test_selfdestruct_multi_tx.json @@ -0,0 +1,126 @@ +[ + { + "Success": { + "reason": "SelfDestruct", + "gas_used": 29603, + "gas_refunded": 24000, + "logs": [], + "output": { + "Call": "0x" + } + } + }, + { + "Success": { + "reason": "Stop", + "gas_used": 21000, + "gas_refunded": 0, + "logs": [], + "output": { + "Call": "0x" + } + } + }, + { + "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee": { + "info": { + "balance": "0x2386f26fc10000", + "nonce": 2, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 1, + "storage": {}, + "status": "Touched" + }, + "0xffffffffffffffffffffffffffffffffffffffff": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 1, + "storage": {}, + "status": "SelfDestructed | Touched" + }, + "0x0000000000000000000000000000000000000000": { + "info": { + "balance": "0x0", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 1, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + }, + "0x000000000000000000000000000000000000ffff": { + "info": { + "balance": "0x2386f26fc10000", + "nonce": 0, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "original_len": 0, + "jump_table": { + "order": "bitvec::order::Lsb0", + "head": { + "width": 8, + "index": 0 + }, + "bits": 0, + "data": [] + } + } + } + }, + "transaction_id": 0, + "storage": {}, + "status": "Touched | LoadedAsNotExisting" + } + } +] \ No newline at end of file diff --git a/crates/state/CHANGELOG.md b/crates/state/CHANGELOG.md new file mode 100644 index 0000000000..dcb663e857 --- /dev/null +++ b/crates/state/CHANGELOG.md @@ -0,0 +1,221 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [7.0.4](https://github.com/bluealloy/revm/compare/revm-state-v7.0.3...revm-state-v7.0.4) - 2025-08-12 + +### Other + +- small performance and safety improvements ([#2868](https://github.com/bluealloy/revm/pull/2868)) + +## [7.0.3](https://github.com/bluealloy/revm/compare/revm-state-v7.0.2...revm-state-v7.0.3) - 2025-08-06 + +### Fixed + +- manally implementation PartialOrd and Ord for AccountInfo ([#2835](https://github.com/bluealloy/revm/pull/2835)) + +### Other + +- update README.md ([#2842](https://github.com/bluealloy/revm/pull/2842)) +- add rust-version and note about MSRV ([#2789](https://github.com/bluealloy/revm/pull/2789)) +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + + +## [4.0.0](https://github.com/bluealloy/revm/compare/revm-state-v3.0.1...revm-state-v4.0.0) - 2025-05-07 + +Dependency bump + +## [Unreleased] + +## [7.0.2](https://github.com/bluealloy/revm/compare/revm-state-v7.0.1...revm-state-v7.0.2) - 2025-07-23 + +### Other + +- updated the following local packages: revm-primitives, revm-bytecode + +## [7.0.1](https://github.com/bluealloy/revm/compare/revm-state-v7.0.0...revm-state-v7.0.1) - 2025-07-03 + +### Other + +- updated the following local packages: revm-bytecode + +## [6.0.1](https://github.com/bluealloy/revm/compare/revm-state-v6.0.0...revm-state-v6.0.1) - 2025-06-30 + +### Other + +- fix copy-pasted inner doc comments ([#2663](https://github.com/bluealloy/revm/pull/2663)) + +## [5.1.0](https://github.com/bluealloy/revm/compare/revm-state-v5.0.0...revm-state-v5.1.0) - 2025-06-19 + +### Added + +- *(precompile)* rug/gmp-based modexp ([#2596](https://github.com/bluealloy/revm/pull/2596)) + +## [5.0.0](https://github.com/bluealloy/revm/compare/revm-state-v4.0.1...revm-state-v5.0.0) - 2025-06-06 + +### Added + +- transact multi tx ([#2517](https://github.com/bluealloy/revm/pull/2517)) + +### Fixed + +- *(multitx)* Add local flags for create and selfdestruct ([#2581](https://github.com/bluealloy/revm/pull/2581)) + +### Other + +- unify calling of journal account loading ([#2561](https://github.com/bluealloy/revm/pull/2561)) + +## [4.0.1](https://github.com/bluealloy/revm/compare/revm-state-v4.0.0...revm-state-v4.0.1) - 2025-05-22 + +### Other + +- make crates.io version badge clickable ([#2526](https://github.com/bluealloy/revm/pull/2526)) +- Storage Types Alias ([#2461](https://github.com/bluealloy/revm/pull/2461)) + +## [3.0.1](https://github.com/bluealloy/revm/compare/revm-state-v3.0.0...revm-state-v3.0.1) - 2025-05-07 + +Yanked release + +### Other + +- copy edit The Book ([#2463](https://github.com/bluealloy/revm/pull/2463)) +- cache and use JumpTable::default ([#2439](https://github.com/bluealloy/revm/pull/2439)) +- bump dependency version ([#2431](https://github.com/bluealloy/revm/pull/2431)) +- add AccountInfo setters ([#2429](https://github.com/bluealloy/revm/pull/2429)) +- fixed broken link ([#2421](https://github.com/bluealloy/revm/pull/2421)) +- *(lints)* revm-context lints ([#2404](https://github.com/bluealloy/revm/pull/2404)) + +## [3.0.0](https://github.com/bluealloy/revm/compare/revm-state-v2.0.0...revm-state-v3.0.0) - 2025-04-09 + +### Added + +- Account helper builder functions ([#2355](https://github.com/bluealloy/revm/pull/2355)) +- support for system calls ([#2350](https://github.com/bluealloy/revm/pull/2350)) + +### Other + +- *(state)* Add AccountInfo builder util methods ([#2357](https://github.com/bluealloy/revm/pull/2357)) + +## [2.0.0](https://github.com/bluealloy/revm/compare/revm-state-v1.0.0...revm-state-v2.0.0) - 2025-03-28 + +### Other + +- updated the following local packages: revm-primitives, revm-bytecode + +## [1.0.0](https://github.com/bluealloy/revm/compare/revm-state-v1.0.0-alpha.4...revm-state-v1.0.0) - 2025-03-24 + +Stable version + +## [1.0.0-alpha.5](https://github.com/bluealloy/revm/compare/revm-state-v1.0.0-alpha.4...revm-state-v1.0.0-alpha.5) - 2025-03-21 + +### Other + +- updated the following local packages: revm-primitives + +## [1.0.0-alpha.4](https://github.com/bluealloy/revm/compare/revm-state-v1.0.0-alpha.3...revm-state-v1.0.0-alpha.4) - 2025-03-16 + +### Other + +- updated the following local packages: revm-primitives, revm-bytecode + +## [1.0.0-alpha.3](https://github.com/bluealloy/revm/compare/revm-state-v1.0.0-alpha.2...revm-state-v1.0.0-alpha.3) - 2025-03-11 + +### Fixed + +- correct propagate features ([#2177](https://github.com/bluealloy/revm/pull/2177)) + +## [1.0.0-alpha.2](https://github.com/bluealloy/revm/compare/revm-state-v1.0.0-alpha.1...revm-state-v1.0.0-alpha.2) - 2025-03-10 + +### Added + +- remove specification crate ([#2165](https://github.com/bluealloy/revm/pull/2165)) + +### Other + +- docs and cleanup (rm Custom Inst) ([#2151](https://github.com/bluealloy/revm/pull/2151)) +- move all dependencies to workspace ([#2092](https://github.com/bluealloy/revm/pull/2092)) + +## [1.0.0-alpha.1](https://github.com/bluealloy/revm/releases/tag/revm-state-v1.0.0-alpha.1) - 2025-02-16 + +### Added + +- *(database)* implement order-independent equality for Reverts (#1827) +- Restucturing Part7 Handler and Context rework (#1865) +- restructuring Part6 transaction crate (#1814) +- restructure Part2 database crate (#1784) +- project restructuring Part1 (#1776) +- *(examples)* generate block traces (#895) +- implement EIP-4844 (#668) +- *(Shanghai)* All EIPs: push0, warm coinbase, limit/measure initcode (#376) +- Migrate `primitive_types::U256` to `ruint::Uint<256, 4>` (#239) +- Introduce ByteCode format, Update Readme (#156) + +### Fixed + +- fix typos ([#620](https://github.com/bluealloy/revm/pull/620)) + +### Other + +- set alpha.1 version +- Bump licence year to 2025 (#2058) +- fix comments and docs into more sensible (#1920) +- inline more `AccountInfo` fns and add docs (#1819) +- *(primitives)* replace HashMap re-exports with alloy_primitives::map (#1805) +- Bump new logo (#1735) +- *(README)* add rbuilder to used-by (#1585) +- added simular to used-by (#1521) +- add Trin to used by list (#1393) +- Fix typo in readme ([#1185](https://github.com/bluealloy/revm/pull/1185)) +- Add Hardhat to the "Used by" list ([#1164](https://github.com/bluealloy/revm/pull/1164)) +- Add VERBS to used by list ([#1141](https://github.com/bluealloy/revm/pull/1141)) +- license date and revm docs (#1080) +- *(docs)* Update the benchmark docs to point to revm package (#906) +- *(docs)* Update top-level benchmark docs (#894) +- clang requirement (#784) +- Readme Updates (#756) +- Logo (#743) +- book workflow ([#537](https://github.com/bluealloy/revm/pull/537)) +- add example to revm crate ([#468](https://github.com/bluealloy/revm/pull/468)) +- Update README.md ([#424](https://github.com/bluealloy/revm/pull/424)) +- add no_std to primitives ([#366](https://github.com/bluealloy/revm/pull/366)) +- revm-precompiles to revm-precompile +- Bump v20, changelog ([#350](https://github.com/bluealloy/revm/pull/350)) +- typos (#232) +- Add support for old forks. ([#191](https://github.com/bluealloy/revm/pull/191)) +- revm bump 1.8. update libs. snailtracer rename ([#159](https://github.com/bluealloy/revm/pull/159)) +- typo fixes +- fix readme typo +- Big Refactor. Machine to Interpreter. refactor instructions. call/create struct ([#52](https://github.com/bluealloy/revm/pull/52)) +- readme. debuger update +- Bump revm v0.3.0. README updated +- readme +- Add time elapsed for tests +- readme updated +- Include Basefee into cost calc. readme change +- Initialize precompile accounts +- Status update. Taking a break +- Merkle calc. Tweaks and debugging for eip158 +- Replace aurora bn lib with parity's. All Bn128Add/Mul/Pair tests passes +- TEMP +- one tab removed +- readme +- README Example simplified +- Gas calculation for Call/Create. Example Added +- readme usage +- README changes +- Static gas cost added +- Subroutine changelogs and reverts +- Readme postulates +- Spelling +- Restructure project +- First iteration. Machine is looking okay diff --git a/crates/state/Cargo.toml b/crates/state/Cargo.toml new file mode 100644 index 0000000000..4ecf37a991 --- /dev/null +++ b/crates/state/Cargo.toml @@ -0,0 +1,33 @@ +[package] +name = "revm-state" +description = "Revm state types" +version = "7.0.4" +authors.workspace = true +edition.workspace = true +keywords.workspace = true +license.workspace = true +repository.workspace = true +readme.workspace = true + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] + +[lints] +workspace = true + +[dependencies] +# revm +primitives.workspace = true +bytecode.workspace = true + +# misc +bitflags.workspace = true + +# Optional +serde = { workspace = true, features = ["derive", "rc"], optional = true } + +[features] +default = ["std"] +std = ["serde?/std", "primitives/std", "bitflags/std", "bytecode/std"] +serde = ["dep:serde", "primitives/serde", "bitflags/serde", "bytecode/serde"] diff --git a/crates/state/LICENSE b/crates/state/LICENSE new file mode 100644 index 0000000000..be6d350ebe --- /dev/null +++ b/crates/state/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021-2025 draganrakita + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/crates/state/src/account_info.rs b/crates/state/src/account_info.rs new file mode 100644 index 0000000000..11e39a0e09 --- /dev/null +++ b/crates/state/src/account_info.rs @@ -0,0 +1,347 @@ +use bytecode::Bytecode; +use core::{ + cmp::Ordering, + hash::{Hash, Hasher}, +}; +use primitives::{B256, KECCAK_EMPTY, U256}; + +/// Account information that contains balance, nonce, code hash and code +/// +/// Code is set as optional. +#[derive(Clone, Debug, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct AccountInfo { + /// Account balance. + pub balance: U256, + /// Account nonce. + pub nonce: u64, + /// Hash of the raw bytes in `code`, or [`KECCAK_EMPTY`]. + pub code_hash: B256, + /// [`Bytecode`] data associated with this account. + /// + /// If [`None`], `code_hash` will be used to fetch it from the database, if code needs to be + /// loaded from inside `revm`. + /// + /// By default, this is `Some(Bytecode::default())`. + pub code: Option, +} + +impl Default for AccountInfo { + fn default() -> Self { + Self { + balance: U256::ZERO, + code_hash: KECCAK_EMPTY, + code: Some(Bytecode::default()), + nonce: 0, + } + } +} + +impl PartialEq for AccountInfo { + fn eq(&self, other: &Self) -> bool { + self.balance == other.balance + && self.nonce == other.nonce + && self.code_hash == other.code_hash + } +} + +impl Hash for AccountInfo { + fn hash(&self, state: &mut H) { + self.balance.hash(state); + self.nonce.hash(state); + self.code_hash.hash(state); + } +} + +impl PartialOrd for AccountInfo { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for AccountInfo { + fn cmp(&self, other: &Self) -> Ordering { + self.balance + .cmp(&other.balance) + .then_with(|| self.nonce.cmp(&other.nonce)) + .then_with(|| self.code_hash.cmp(&other.code_hash)) + } +} + +impl AccountInfo { + /// Creates a new [`AccountInfo`] with the given fields. + #[inline] + pub fn new(balance: U256, nonce: u64, code_hash: B256, code: Bytecode) -> Self { + Self { + balance, + nonce, + code: Some(code), + code_hash, + } + } + + /// Creates a new [`AccountInfo`] with the given code. + /// + /// # Note + /// + /// As code hash is calculated with [`Bytecode::hash_slow`] there will be performance penalty if used frequently. + pub fn with_code(self, code: Bytecode) -> Self { + Self { + balance: self.balance, + nonce: self.nonce, + code_hash: code.hash_slow(), + code: Some(code), + } + } + + /// Creates a new [`AccountInfo`] with the given code hash. + /// + /// # Note + /// + /// Resets code to `None`. Not guaranteed to maintain invariant `code` and `code_hash`. See + /// also [Self::with_code_and_hash]. + pub fn with_code_hash(self, code_hash: B256) -> Self { + Self { + balance: self.balance, + nonce: self.nonce, + code_hash, + code: None, + } + } + + /// Creates a new [`AccountInfo`] with the given code and code hash. + /// + /// # Note + /// + /// In debug mode panics if [`Bytecode::hash_slow`] called on `code` is not equivalent to + /// `code_hash`. See also [`Self::with_code`]. + pub fn with_code_and_hash(self, code: Bytecode, code_hash: B256) -> Self { + debug_assert_eq!(code.hash_slow(), code_hash); + Self { + balance: self.balance, + nonce: self.nonce, + code_hash, + code: Some(code), + } + } + + /// Creates a new [`AccountInfo`] with the given balance. + pub fn with_balance(mut self, balance: U256) -> Self { + self.balance = balance; + self + } + + /// Creates a new [`AccountInfo`] with the given nonce. + pub fn with_nonce(mut self, nonce: u64) -> Self { + self.nonce = nonce; + self + } + + /// Sets the [`AccountInfo`] `balance`. + #[inline] + pub fn set_balance(&mut self, balance: U256) -> &mut Self { + self.balance = balance; + self + } + + /// Sets the [`AccountInfo`] `nonce`. + #[inline] + pub fn set_nonce(&mut self, nonce: u64) -> &mut Self { + self.nonce = nonce; + self + } + + /// Sets the [`AccountInfo`] `code_hash` and clears any cached bytecode. + /// + /// # Note + /// + /// Calling this after `set_code(...)` will remove the bytecode you just set. + /// If you intend to mutate the code, use only `set_code`. + #[inline] + pub fn set_code_hash(&mut self, code_hash: B256) -> &mut Self { + self.code = None; + self.code_hash = code_hash; + self + } + + /// Replaces the [`AccountInfo`] bytecode and recalculates `code_hash`. + /// + /// # Note + /// + /// As code hash is calculated with [`Bytecode::hash_slow`] there will be performance penalty if used frequently. + #[inline] + pub fn set_code(&mut self, code: Bytecode) -> &mut Self { + self.code_hash = code.hash_slow(); + self.code = Some(code); + self + } + /// Sets the bytecode and its hash. + /// + /// # Note + /// + /// It is on the caller's responsibility to ensure that the bytecode hash is correct. + pub fn set_code_and_hash(&mut self, code: Bytecode, code_hash: B256) { + self.code_hash = code_hash; + self.code = Some(code); + } + /// Returns a copy of this account with the [`Bytecode`] removed. + /// + /// This is useful when creating journals or snapshots of the state, where it is + /// desirable to store the code blobs elsewhere. + /// + /// ## Note + /// + /// This is distinct from [`without_code`][Self::without_code] in that it returns + /// a new [`AccountInfo`] instance with the code removed. + /// + /// [`without_code`][Self::without_code] will modify and return the same instance. + #[inline] + pub fn copy_without_code(&self) -> Self { + Self { + balance: self.balance, + nonce: self.nonce, + code_hash: self.code_hash, + code: None, + } + } + + /// Strips the [`Bytecode`] from this account and drop it. + /// + /// This is useful when creating journals or snapshots of the state, where it is + /// desirable to store the code blobs elsewhere. + /// + /// ## Note + /// + /// This is distinct from [`copy_without_code`][Self::copy_without_code] in that it + /// modifies the account in place. + /// + /// [`copy_without_code`][Self::copy_without_code] + /// will copy the non-code fields and return a new [`AccountInfo`] instance. + pub fn without_code(mut self) -> Self { + self.take_bytecode(); + self + } + + /// Returns if an account is empty. + /// + /// An account is empty if the following conditions are met. + /// - code hash is zero or set to the Keccak256 hash of the empty string `""` + /// - balance is zero + /// - nonce is zero + #[inline] + pub fn is_empty(&self) -> bool { + let code_empty = self.is_empty_code_hash() || self.code_hash.is_zero(); + code_empty && self.balance.is_zero() && self.nonce == 0 + } + + /// Returns `true` if the account is not empty. + #[inline] + pub fn exists(&self) -> bool { + !self.is_empty() + } + + /// Returns `true` if account has no nonce and code. + #[inline] + pub fn has_no_code_and_nonce(&self) -> bool { + self.is_empty_code_hash() && self.nonce == 0 + } + + /// Returns bytecode hash associated with this account. + /// + /// If account does not have code, it returns `KECCAK_EMPTY` hash. + #[inline] + pub fn code_hash(&self) -> B256 { + self.code_hash + } + + /// Returns true if the code hash is the Keccak256 hash of the empty string `""`. + #[inline] + pub fn is_empty_code_hash(&self) -> bool { + self.code_hash == KECCAK_EMPTY + } + + /// Takes bytecode from account. + /// + /// Code will be set to [None]. + #[inline] + pub fn take_bytecode(&mut self) -> Option { + self.code.take() + } + + /// Initializes an [`AccountInfo`] with the given balance, setting all other fields to their + /// default values. + #[inline] + pub fn from_balance(balance: U256) -> Self { + AccountInfo { + balance, + ..Default::default() + } + } + + /// Initializes an [`AccountInfo`] with the given bytecode, setting its balance to zero, its + /// nonce to `1`, and calculating the code hash from the given bytecode. + #[inline] + pub fn from_bytecode(bytecode: Bytecode) -> Self { + let hash = bytecode.hash_slow(); + + AccountInfo { + balance: U256::ZERO, + nonce: 1, + code: Some(bytecode), + code_hash: hash, + } + } +} + +#[cfg(test)] +mod tests { + use crate::AccountInfo; + use bytecode::Bytecode; + use core::cmp::Ordering; + use primitives::{KECCAK_EMPTY, U256}; + use std::collections::BTreeSet; + + #[test] + fn test_account_info_trait_consistency() { + let bytecode = Bytecode::default(); + let account1 = AccountInfo { + balance: U256::ZERO, + nonce: 0, + code_hash: KECCAK_EMPTY, + code: Some(bytecode.clone()), + }; + + let account2 = AccountInfo { + balance: U256::ZERO, + nonce: 0, + code_hash: KECCAK_EMPTY, + code: None, + }; + + assert_eq!(account1, account2, "Accounts should be equal ignoring code"); + + assert_eq!( + account1.cmp(&account2), + Ordering::Equal, + "Ordering should be equal after ignoring code in Ord" + ); + + let mut set = BTreeSet::new(); + assert!(set.insert(account1.clone()), "Inserted account1"); + assert!( + !set.insert(account2.clone()), + "account2 not inserted (treated as duplicate)" + ); + + assert_eq!(set.len(), 1, "Set should have only one unique account"); + assert!(set.contains(&account1), "Set contains account1"); + assert!( + set.contains(&account2), + "Set contains account2 (since equal)" + ); + + let mut accounts = vec![account2.clone(), account1.clone()]; + accounts.sort(); + assert_eq!(accounts[0], accounts[1], "Sorted vec treats them as equal"); + } +} diff --git a/crates/state/src/lib.rs b/crates/state/src/lib.rs new file mode 100644 index 0000000000..985af53a3d --- /dev/null +++ b/crates/state/src/lib.rs @@ -0,0 +1,643 @@ +//! Account and storage state. +#![cfg_attr(not(test), warn(unused_crate_dependencies))] +#![cfg_attr(not(feature = "std"), no_std)] + +mod account_info; +mod types; +pub use bytecode; + +pub use account_info::AccountInfo; +pub use bytecode::Bytecode; +pub use primitives; +pub use types::{EvmState, EvmStorage, TransientStorage}; + +use bitflags::bitflags; +use core::hash::Hash; +use primitives::hardfork::SpecId; +use primitives::{HashMap, StorageKey, StorageValue}; + +/// Account type used inside Journal to track changed to state. +#[derive(Debug, Clone, PartialEq, Eq, Default)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct Account { + /// Balance, nonce, and code + pub info: AccountInfo, + /// Transaction id, used to track when account was toched/loaded into journal. + pub transaction_id: usize, + /// Storage cache + pub storage: EvmStorage, + /// Account status flags + pub status: AccountStatus, +} + +impl Account { + /// Creates new account and mark it as non existing. + pub fn new_not_existing(transaction_id: usize) -> Self { + Self { + info: AccountInfo::default(), + storage: HashMap::default(), + transaction_id, + status: AccountStatus::LoadedAsNotExisting, + } + } + + /// Checks if account is empty and check if empty state before spurious dragon hardfork. + #[inline] + pub fn state_clear_aware_is_empty(&self, spec: SpecId) -> bool { + if SpecId::is_enabled_in(spec, SpecId::SPURIOUS_DRAGON) { + self.is_empty() + } else { + self.is_loaded_as_not_existing_not_touched() + } + } + + /// Marks the account as self destructed. + #[inline] + pub fn mark_selfdestruct(&mut self) { + self.status |= AccountStatus::SelfDestructed; + } + + /// Unmarks the account as self destructed. + #[inline] + pub fn unmark_selfdestruct(&mut self) { + self.status -= AccountStatus::SelfDestructed; + } + + /// Is account marked for self destruct. + #[inline] + pub fn is_selfdestructed(&self) -> bool { + self.status.contains(AccountStatus::SelfDestructed) + } + + /// Marks the account as touched + #[inline] + pub fn mark_touch(&mut self) { + self.status |= AccountStatus::Touched; + } + + /// Unmarks the touch flag. + #[inline] + pub fn unmark_touch(&mut self) { + self.status -= AccountStatus::Touched; + } + + /// If account status is marked as touched. + #[inline] + pub fn is_touched(&self) -> bool { + self.status.contains(AccountStatus::Touched) + } + + /// Marks the account as newly created. + #[inline] + pub fn mark_created(&mut self) { + self.status |= AccountStatus::Created; + } + + /// Unmarks the created flag. + #[inline] + pub fn unmark_created(&mut self) { + self.status -= AccountStatus::Created; + } + + /// Marks the account as cold. + #[inline] + pub fn mark_cold(&mut self) { + self.status |= AccountStatus::Cold; + } + + /// Marks the account as warm and return true if it was previously cold. + #[inline] + pub fn mark_warm_with_transaction_id(&mut self, transaction_id: usize) -> bool { + let same_id = self.transaction_id == transaction_id; + let is_cold = self.status.contains(AccountStatus::Cold); + + self.status -= AccountStatus::Cold; + self.transaction_id = transaction_id; + + if !same_id { + return true; + } + + is_cold + } + + /// Is account locally created + #[inline] + pub fn is_created_locally(&self) -> bool { + self.status.contains(AccountStatus::CreatedLocal) + } + + /// Is account locally selfdestructed + #[inline] + pub fn is_selfdestructed_locally(&self) -> bool { + self.status.contains(AccountStatus::SelfDestructedLocal) + } + + /// Selfdestruct the account by clearing its storage and resetting its account info + #[inline] + pub fn selfdestruct(&mut self) { + self.storage.clear(); + self.info = AccountInfo::default(); + } + + /// Mark account as locally created and mark global created flag. + /// + /// Returns true if it is created globally for first time. + #[inline] + pub fn mark_created_locally(&mut self) -> bool { + self.status |= AccountStatus::CreatedLocal; + let is_created_globaly = !self.status.contains(AccountStatus::Created); + self.status |= AccountStatus::Created; + is_created_globaly + } + + /// Unmark account as locally created + #[inline] + pub fn unmark_created_locally(&mut self) { + self.status -= AccountStatus::CreatedLocal; + } + + /// Mark account as locally and globally selfdestructed + #[inline] + pub fn mark_selfdestructed_locally(&mut self) -> bool { + self.status |= AccountStatus::SelfDestructedLocal; + let is_global_selfdestructed = !self.status.contains(AccountStatus::SelfDestructed); + self.status |= AccountStatus::SelfDestructed; + is_global_selfdestructed + } + + /// Unmark account as locally selfdestructed + #[inline] + pub fn unmark_selfdestructed_locally(&mut self) { + self.status -= AccountStatus::SelfDestructedLocal; + } + + /// Is account loaded as not existing from database. + /// + /// This is needed for pre spurious dragon hardforks where + /// existing and empty were two separate states. + pub fn is_loaded_as_not_existing(&self) -> bool { + self.status.contains(AccountStatus::LoadedAsNotExisting) + } + + /// Is account loaded as not existing from database and not touched. + pub fn is_loaded_as_not_existing_not_touched(&self) -> bool { + self.is_loaded_as_not_existing() && !self.is_touched() + } + + /// Is account newly created in this transaction. + pub fn is_created(&self) -> bool { + self.status.contains(AccountStatus::Created) + } + + /// Is account empty, check if nonce and balance are zero and code is empty. + pub fn is_empty(&self) -> bool { + self.info.is_empty() + } + + /// Returns an iterator over the storage slots that have been changed. + /// + /// See also [EvmStorageSlot::is_changed]. + pub fn changed_storage_slots(&self) -> impl Iterator { + self.storage.iter().filter(|(_, slot)| slot.is_changed()) + } + + /// Sets account info and returns self for method chaining. + pub fn with_info(mut self, info: AccountInfo) -> Self { + self.info = info; + self + } + + /// Populates storage from an iterator of storage slots and returns self for method chaining. + pub fn with_storage(mut self, storage_iter: I) -> Self + where + I: Iterator, + { + for (key, slot) in storage_iter { + self.storage.insert(key, slot); + } + self + } + + /// Marks the account as self destructed and returns self for method chaining. + pub fn with_selfdestruct_mark(mut self) -> Self { + self.mark_selfdestruct(); + self + } + + /// Marks the account as touched and returns self for method chaining. + pub fn with_touched_mark(mut self) -> Self { + self.mark_touch(); + self + } + + /// Marks the account as newly created and returns self for method chaining. + pub fn with_created_mark(mut self) -> Self { + self.mark_created(); + self + } + + /// Marks the account as cold and returns self for method chaining. + pub fn with_cold_mark(mut self) -> Self { + self.mark_cold(); + self + } + + /// Marks the account as warm (not cold) and returns self for method chaining. + /// Also returns whether the account was previously cold. + pub fn with_warm_mark(mut self, transaction_id: usize) -> (Self, bool) { + let was_cold = self.mark_warm_with_transaction_id(transaction_id); + (self, was_cold) + } + + /// Variant of with_warm_mark that doesn't return the previous state. + pub fn with_warm(mut self, transaction_id: usize) -> Self { + self.mark_warm_with_transaction_id(transaction_id); + self + } +} + +impl From for Account { + fn from(info: AccountInfo) -> Self { + Self { + info, + storage: HashMap::default(), + transaction_id: 0, + status: AccountStatus::empty(), + } + } +} + +// The `bitflags!` macro generates `struct`s that manage a set of flags. +bitflags! { + /// Account status flags. Generated by bitflags crate. + /// + /// With multi transaction feature there is a need to have both global and local fields. + /// Global across multiple transaction and local across one transaction execution. + /// + /// Empty state without any flags set represent account that is loaded from db but not interacted with. + /// + /// `Touched` flag is used by database to check if account is potentially changed in some way. + /// Additionally, after EIP-161 touch on empty-existing account would remove this account from state + /// after transaction execution ends. Touch can span across multiple transactions as it is needed + /// to be marked only once so it is safe to have only one global flag. + /// Only first touch have different behaviour from others, and touch in first transaction will invalidate + /// touch functionality in next transactions. + /// + /// `Created` flag is used to mark account as newly created in this transaction. This is used for optimization + /// where if this flag is set we will not access database to fetch storage values. + /// + /// `CreatedLocal` flag is used after cancun to enable selfdestruct cleanup if account is created in same transaction. + /// + /// `Selfdestructed` flag is used to mark account as selfdestructed. On multiple calls this flag is preserved + /// and on revert will stay selfdestructed. + /// + /// `SelfdestructLocal` is needed to award refund on first selfdestruct call. This flag is cleared on account loading. + /// Over multiple transaction account can be selfdestructed in one tx, created in second tx and selfdestructed again in + /// third tx. + /// Additionally if account is loaded in second tx, storage and account that was destroyed in first tx needs to be cleared. + /// + /// `LoadedAsNotExisting` is used to mark account as loaded from database but with `balance == 0 && nonce == 0 && code = 0x`. + /// This flag is fine to span across multiple transactions as it interucts with `Touched` flag this is used in global scope. + /// + /// `CreatedLocal`, `SelfdestructedLocal` and `Cold` flags are reset on first account loading of local scope. + #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] + #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] + #[cfg_attr(feature = "serde", serde(transparent))] + pub struct AccountStatus: u8 { + /// When account is newly created we will not access database + /// to fetch storage values. + const Created = 0b00000001; + /// When accounts gets loaded this flag is set to false. Create will always be true if CreatedLocal is true. + const CreatedLocal = 0b10000000; + /// If account is marked for self destruction. + const SelfDestructed = 0b00000010; + /// If account is marked for self destruction. + const SelfDestructedLocal = 0b01000000; + /// Only when account is marked as touched we will save it to database. + /// Additionally first touch on empty existing account (After EIP-161) will mark it + /// for removal from state after transaction execution. + const Touched = 0b00000100; + /// used only for pre spurious dragon hardforks where existing and empty were two separate states. + /// it became same state after EIP-161: State trie clearing + const LoadedAsNotExisting = 0b00001000; + /// used to mark account as cold. + /// It is used only in local scope and it is reset on account loading. + const Cold = 0b00010000; + } +} + +impl Default for AccountStatus { + fn default() -> Self { + AccountStatus::empty() + } +} + +/// This type keeps track of the current value of a storage slot. +#[derive(Debug, Clone, Default, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct EvmStorageSlot { + /// Original value of the storage slot + pub original_value: StorageValue, + /// Present value of the storage slot + pub present_value: StorageValue, + /// Transaction id, used to track when storage slot was made warm. + pub transaction_id: usize, + /// Represents if the storage slot is cold + pub is_cold: bool, +} + +impl EvmStorageSlot { + /// Creates a new _unchanged_ `EvmStorageSlot` for the given value. + pub fn new(original: StorageValue, transaction_id: usize) -> Self { + Self { + original_value: original, + present_value: original, + transaction_id, + is_cold: false, + } + } + + /// Creates a new _changed_ `EvmStorageSlot`. + pub fn new_changed( + original_value: StorageValue, + present_value: StorageValue, + transaction_id: usize, + ) -> Self { + Self { + original_value, + present_value, + transaction_id, + is_cold: false, + } + } + /// Returns true if the present value differs from the original value. + pub fn is_changed(&self) -> bool { + self.original_value != self.present_value + } + + /// Returns the original value of the storage slot. + #[inline] + pub fn original_value(&self) -> StorageValue { + self.original_value + } + + /// Returns the current value of the storage slot. + #[inline] + pub fn present_value(&self) -> StorageValue { + self.present_value + } + + /// Marks the storage slot as cold. Does not change transaction_id. + #[inline] + pub fn mark_cold(&mut self) { + self.is_cold = true; + } + + /// Marks the storage slot as warm and sets transaction_id to the given value + /// + /// + /// Returns false if old transition_id is different from given id or in case they are same return `Self::is_cold` value. + #[inline] + pub fn mark_warm_with_transaction_id(&mut self, transaction_id: usize) -> bool { + let same_id = self.transaction_id == transaction_id; + self.transaction_id = transaction_id; + let was_cold = core::mem::take(&mut self.is_cold); + + if same_id { + // only if transaction id is same we are returning was_cold. + return was_cold; + } + true + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::EvmStorageSlot; + use primitives::{StorageKey, KECCAK_EMPTY, U256}; + + #[test] + fn account_is_empty_balance() { + let mut account = Account::default(); + assert!(account.is_empty()); + + account.info.balance = U256::from(1); + assert!(!account.is_empty()); + + account.info.balance = U256::ZERO; + assert!(account.is_empty()); + } + + #[test] + fn account_is_empty_nonce() { + let mut account = Account::default(); + assert!(account.is_empty()); + + account.info.nonce = 1; + assert!(!account.is_empty()); + + account.info.nonce = 0; + assert!(account.is_empty()); + } + + #[test] + fn account_is_empty_code_hash() { + let mut account = Account::default(); + assert!(account.is_empty()); + + account.info.code_hash = [1; 32].into(); + assert!(!account.is_empty()); + + account.info.code_hash = [0; 32].into(); + assert!(account.is_empty()); + + account.info.code_hash = KECCAK_EMPTY; + assert!(account.is_empty()); + } + + #[test] + fn account_state() { + let mut account = Account::default(); + + assert!(!account.is_touched()); + assert!(!account.is_selfdestructed()); + + account.mark_touch(); + assert!(account.is_touched()); + assert!(!account.is_selfdestructed()); + + account.mark_selfdestruct(); + assert!(account.is_touched()); + assert!(account.is_selfdestructed()); + + account.unmark_selfdestruct(); + assert!(account.is_touched()); + assert!(!account.is_selfdestructed()); + } + + #[test] + fn account_is_cold() { + let mut account = Account::default(); + + // Account is not cold by default + assert!(!account.status.contains(crate::AccountStatus::Cold)); + + // When marking warm account as warm again, it should return false + assert!(!account.mark_warm_with_transaction_id(0)); + + // Mark account as cold + account.mark_cold(); + + // Account is cold + assert!(account.status.contains(crate::AccountStatus::Cold)); + + // When marking cold account as warm, it should return true + assert!(account.mark_warm_with_transaction_id(0)); + } + + #[test] + fn test_account_with_info() { + let info = AccountInfo::default(); + let account = Account::default().with_info(info.clone()); + + assert_eq!(account.info, info); + assert_eq!(account.storage, HashMap::default()); + assert_eq!(account.status, AccountStatus::empty()); + } + + #[test] + fn test_account_with_storage() { + let mut storage = HashMap::new(); + let key1 = StorageKey::from(1); + let key2 = StorageKey::from(2); + let slot1 = EvmStorageSlot::new(StorageValue::from(10), 0); + let slot2 = EvmStorageSlot::new(StorageValue::from(20), 0); + + storage.insert(key1, slot1.clone()); + storage.insert(key2, slot2.clone()); + + let account = Account::default().with_storage(storage.clone().into_iter()); + + assert_eq!(account.storage.len(), 2); + assert_eq!(account.storage.get(&key1), Some(&slot1)); + assert_eq!(account.storage.get(&key2), Some(&slot2)); + } + + #[test] + fn test_account_with_selfdestruct_mark() { + let account = Account::default().with_selfdestruct_mark(); + + assert!(account.is_selfdestructed()); + assert!(!account.is_touched()); + assert!(!account.is_created()); + } + + #[test] + fn test_account_with_touched_mark() { + let account = Account::default().with_touched_mark(); + + assert!(!account.is_selfdestructed()); + assert!(account.is_touched()); + assert!(!account.is_created()); + } + + #[test] + fn test_account_with_created_mark() { + let account = Account::default().with_created_mark(); + + assert!(!account.is_selfdestructed()); + assert!(!account.is_touched()); + assert!(account.is_created()); + } + + #[test] + fn test_account_with_cold_mark() { + let account = Account::default().with_cold_mark(); + + assert!(account.status.contains(AccountStatus::Cold)); + } + + #[test] + fn test_storage_mark_warm_with_transaction_id() { + let mut slot = EvmStorageSlot::new(U256::ZERO, 0); + slot.is_cold = true; + slot.transaction_id = 0; + assert!(slot.mark_warm_with_transaction_id(1)); + + slot.is_cold = false; + slot.transaction_id = 0; + assert!(slot.mark_warm_with_transaction_id(1)); + + slot.is_cold = true; + slot.transaction_id = 1; + assert!(slot.mark_warm_with_transaction_id(1)); + + slot.is_cold = false; + slot.transaction_id = 1; + // Only if transaction id is same and is_cold is false, return false. + assert!(!slot.mark_warm_with_transaction_id(1)); + } + + #[test] + fn test_account_with_warm_mark() { + // Start with a cold account + let cold_account = Account::default().with_cold_mark(); + assert!(cold_account.status.contains(AccountStatus::Cold)); + + // Use with_warm_mark to warm it + let (warm_account, was_cold) = cold_account.with_warm_mark(0); + + // Check that it's now warm and previously was cold + assert!(!warm_account.status.contains(AccountStatus::Cold)); + assert!(was_cold); + + // Try with an already warm account + let (still_warm_account, was_cold) = warm_account.with_warm_mark(0); + assert!(!still_warm_account.status.contains(AccountStatus::Cold)); + assert!(!was_cold); + } + + #[test] + fn test_account_with_warm() { + // Start with a cold account + let cold_account = Account::default().with_cold_mark(); + assert!(cold_account.status.contains(AccountStatus::Cold)); + + // Use with_warm to warm it + let warm_account = cold_account.with_warm(0); + + // Check that it's now warm + assert!(!warm_account.status.contains(AccountStatus::Cold)); + } + + #[test] + fn test_account_builder_chaining() { + let info = AccountInfo { + nonce: 5, + ..AccountInfo::default() + }; + + let slot_key = StorageKey::from(42); + let slot_value = EvmStorageSlot::new(StorageValue::from(123), 0); + let mut storage = HashMap::new(); + storage.insert(slot_key, slot_value.clone()); + + // Chain multiple builder methods together + let account = Account::default() + .with_info(info.clone()) + .with_storage(storage.into_iter()) + .with_created_mark() + .with_touched_mark() + .with_cold_mark() + .with_warm(0); + + // Verify all modifications were applied + assert_eq!(account.info, info); + assert_eq!(account.storage.get(&slot_key), Some(&slot_value)); + assert!(account.is_created()); + assert!(account.is_touched()); + assert!(!account.status.contains(AccountStatus::Cold)); + } +} diff --git a/crates/state/src/types.rs b/crates/state/src/types.rs new file mode 100644 index 0000000000..7c656428ba --- /dev/null +++ b/crates/state/src/types.rs @@ -0,0 +1,11 @@ +use super::{Account, EvmStorageSlot}; +use primitives::{Address, HashMap, StorageKey, StorageValue}; + +/// EVM State is a mapping from addresses to accounts. +pub type EvmState = HashMap; + +/// Structure used for EIP-1153 transient storage +pub type TransientStorage = HashMap<(Address, StorageKey), StorageValue>; + +/// An account's Storage is a mapping from 256-bit integer keys to [EvmStorageSlot]s. +pub type EvmStorage = HashMap; diff --git a/crates/statetest-types/CHANGELOG.md b/crates/statetest-types/CHANGELOG.md new file mode 100644 index 0000000000..ae820d737d --- /dev/null +++ b/crates/statetest-types/CHANGELOG.md @@ -0,0 +1,221 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [8.0.5](https://github.com/bluealloy/revm/compare/revm-statetest-types-v8.0.4...revm-statetest-types-v8.0.5) - 2025-07-23 + +### Other + +- updated the following local packages: revm + +## [8.0.4](https://github.com/bluealloy/revm/compare/revm-statetest-types-v8.0.3...revm-statetest-types-v8.0.4) - 2025-07-14 + +### Other + +- updated the following local packages: revm + +## [8.0.3](https://github.com/bluealloy/revm/compare/revm-statetest-types-v8.0.2...revm-statetest-types-v8.0.3) - 2025-07-03 + +### Other + +- updated the following local packages: revm + +## [8.0.2](https://github.com/bluealloy/revm/compare/revm-statetest-types-v8.0.1...revm-statetest-types-v8.0.2) - 2025-06-30 + +### Other + +- cargo clippy --fix --all ([#2671](https://github.com/bluealloy/revm/pull/2671)) +- statetest runner cleanup ([#2665](https://github.com/bluealloy/revm/pull/2665)) + +## [8.0.1](https://github.com/bluealloy/revm/compare/revm-statetest-types-v8.0.0...revm-statetest-types-v8.0.1) - 2025-06-20 + +### Other + +- updated the following local packages: revm + +## [8.0.0](https://github.com/bluealloy/revm/compare/revm-statetest-types-v7.0.0...revm-statetest-types-v8.0.0) - 2025-06-19 + +### Added + +- *(precompile)* rug/gmp-based modexp ([#2596](https://github.com/bluealloy/revm/pull/2596)) + +### Other + +- lints for examples ([#2650](https://github.com/bluealloy/revm/pull/2650)) + +## [7.0.0](https://github.com/bluealloy/revm/compare/revm-statetest-types-v6.0.0...revm-statetest-types-v7.0.0) - 2025-06-06 + +### Added + +- transact multi tx ([#2517](https://github.com/bluealloy/revm/pull/2517)) + +### Other + +- tag v75 revm v24.0.1 ([#2563](https://github.com/bluealloy/revm/pull/2563)) ([#2589](https://github.com/bluealloy/revm/pull/2589)) +- unify calling of journal account loading ([#2561](https://github.com/bluealloy/revm/pull/2561)) + +## [6.0.0](https://github.com/bluealloy/revm/compare/revm-statetest-types-v5.0.0...revm-statetest-types-v6.0.0) - 2025-05-31 + +### Other + +- unify calling of journal account loading + +## [5.0.0](https://github.com/bluealloy/revm/compare/revm-statetest-types-v4.1.0...revm-statetest-types-v5.0.0) - 2025-05-22 + +### Other + +- add TxEnvBuilder::build_fill ([#2536](https://github.com/bluealloy/revm/pull/2536)) +- make crates.io version badge clickable ([#2526](https://github.com/bluealloy/revm/pull/2526)) +- Storage Types Alias ([#2461](https://github.com/bluealloy/revm/pull/2461)) + +## [4.1.0](https://github.com/bluealloy/revm/compare/revm-statetest-types-v4.0.0...revm-statetest-types-v4.1.0) - 2025-05-07 + +Dependency bump + +## [4.0.0](https://github.com/bluealloy/revm/compare/revm-statetest-types-v3.0.1...revm-statetest-types-v4.0.0) - 2025-05-07 + +### Added + +- *(EOF)* Changes needed for devnet-1 ([#2377](https://github.com/bluealloy/revm/pull/2377)) + +### Other + +- copy edit The Book ([#2463](https://github.com/bluealloy/revm/pull/2463)) +- bump dependency version ([#2431](https://github.com/bluealloy/revm/pull/2431)) +- fixed broken link ([#2421](https://github.com/bluealloy/revm/pull/2421)) + +## [3.0.1](https://github.com/bluealloy/revm/compare/revm-statetest-types-v3.0.0..revm-statetest-types-v3.0.1) - 2025-04-15 + +### Other + +## [3.0.0](https://github.com/bluealloy/revm/compare/revm-statetest-types-v2.0.0...revm-statetest-types-v3.0.0) - 2025-04-09 + +### Other + +- updated the following local packages: revm + +## [2.0.0](https://github.com/bluealloy/revm/compare/revm-statetest-types-v1.0.0...revm-statetest-types-v2.0.0) - 2025-03-28 + +### Other + +- updated the following local packages: revm + +## [1.0.0](https://github.com/bluealloy/revm/compare/revm-statetest-types-v1.0.0-alpha.4...revm-statetest-types-v1.0.0) - 2025-03-24 + +Stable version + +## [1.0.0-alpha.5](https://github.com/bluealloy/revm/compare/revm-statetest-types-v1.0.0-alpha.4...revm-statetest-types-v1.0.0-alpha.5) - 2025-03-11 + +### Other + +- updated the following local packages: revm + +## [1.0.0-alpha.4](https://github.com/bluealloy/revm/compare/revm-statetest-types-v1.0.0-alpha.3...revm-statetest-types-v1.0.0-alpha.4) - 2025-03-11 + +### Other + +- updated the following local packages: revm + +## [1.0.0-alpha.3](https://github.com/bluealloy/revm/compare/revm-statetest-types-v1.0.0-alpha.2...revm-statetest-types-v1.0.0-alpha.3) - 2025-03-10 + +### Other + +- updated the following local packages: revm + +## [1.0.0-alpha.2](https://github.com/bluealloy/revm/compare/revm-statetest-types-v1.0.0-alpha.1...revm-statetest-types-v1.0.0-alpha.2) - 2025-03-10 + +### Added + +- remove specification crate ([#2165](https://github.com/bluealloy/revm/pull/2165)) + +### Other + +- docs and cleanup (rm Custom Inst) ([#2151](https://github.com/bluealloy/revm/pull/2151)) +- allow duplicate v and yparity in test files ([#2150](https://github.com/bluealloy/revm/pull/2150)) +- export eip2930 eip7702 types from one place ([#2097](https://github.com/bluealloy/revm/pull/2097)) +- move all dependencies to workspace ([#2092](https://github.com/bluealloy/revm/pull/2092)) + +## [1.0.0-alpha.1](https://github.com/bluealloy/revm/releases/tag/revm-statetest-types-v1.0.0-alpha.1) - 2025-02-16 + +### Added + +- Introduce Auth and AccessList traits (#2079) +- integrate alloy-eips (#2078) +- *(EIP-7623)* adjuct floor gas check order (main) (#1991) +- *(EIP-7840)* Add blob schedule to execution client cfg (#1980) +- *(eip7702)* apply latest EIP-7702 changes, backport from v52 (#1969) +- simplify Transaction trait (#1959) +- Restucturing Part7 Handler and Context rework (#1865) +- restructuring Part6 transaction crate (#1814) +- extract statetest models/structs to standalone crate (#1808) +- *(examples)* generate block traces (#895) +- implement EIP-4844 (#668) +- *(Shanghai)* All EIPs: push0, warm coinbase, limit/measure initcode (#376) +- Migrate `primitive_types::U256` to `ruint::Uint<256, 4>` (#239) +- Introduce ByteCode format, Update Readme (#156) + +### Fixed + +- *(eof)* dont run precompile on ext delegate call (#1964) +- fix typos ([#620](https://github.com/bluealloy/revm/pull/620)) + +### Other + +- set alpha.1 version +- Bump licence year to 2025 (#2058) +- bump devnet5 v1.3.0 tests (#2020) +- align crates versions (#1983) +- fix comments and docs into more sensible (#1920) +- Bump new logo (#1735) +- *(README)* add rbuilder to used-by (#1585) +- added simular to used-by (#1521) +- add Trin to used by list (#1393) +- Fix typo in readme ([#1185](https://github.com/bluealloy/revm/pull/1185)) +- Add Hardhat to the "Used by" list ([#1164](https://github.com/bluealloy/revm/pull/1164)) +- Add VERBS to used by list ([#1141](https://github.com/bluealloy/revm/pull/1141)) +- license date and revm docs (#1080) +- *(docs)* Update the benchmark docs to point to revm package (#906) +- *(docs)* Update top-level benchmark docs (#894) +- clang requirement (#784) +- Readme Updates (#756) +- Logo (#743) +- book workflow ([#537](https://github.com/bluealloy/revm/pull/537)) +- add example to revm crate ([#468](https://github.com/bluealloy/revm/pull/468)) +- Update README.md ([#424](https://github.com/bluealloy/revm/pull/424)) +- add no_std to primitives ([#366](https://github.com/bluealloy/revm/pull/366)) +- revm-precompiles to revm-precompile +- Bump v20, changelog ([#350](https://github.com/bluealloy/revm/pull/350)) +- typos (#232) +- Add support for old forks. ([#191](https://github.com/bluealloy/revm/pull/191)) +- revm bump 1.8. update libs. snailtracer rename ([#159](https://github.com/bluealloy/revm/pull/159)) +- typo fixes +- fix readme typo +- Big Refactor. Machine to Interpreter. refactor instructions. call/create struct ([#52](https://github.com/bluealloy/revm/pull/52)) +- readme. debuger update +- Bump revm v0.3.0. README updated +- readme +- Add time elapsed for tests +- readme updated +- Include Basefee into cost calc. readme change +- Initialize precompile accounts +- Status update. Taking a break +- Merkle calc. Tweaks and debugging for eip158 +- Replace aurora bn lib with parity's. All Bn128Add/Mul/Pair tests passes +- TEMP +- one tab removed +- readme +- README Example simplified +- Gas calculation for Call/Create. Example Added +- readme usage +- README changes +- Static gas cost added +- Subroutine changelogs and reverts +- Readme postulates +- Spelling +- Restructure project +- First iteration. Machine is looking okay diff --git a/crates/statetest-types/Cargo.toml b/crates/statetest-types/Cargo.toml new file mode 100644 index 0000000000..e866c2100c --- /dev/null +++ b/crates/statetest-types/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "revm-statetest-types" +description = "Statetest types for revme" +version = "8.0.5" +authors.workspace = true +edition.workspace = true +keywords.workspace = true +license.workspace = true +repository.workspace = true +readme.workspace = true + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] + +[lints] +workspace = true + +[dependencies] +# revm +revm = { workspace = true, features = ["std", "serde"] } +serde = { workspace = true, features = ["derive", "rc"] } +serde_json = { workspace = true, features = ["preserve_order"] } +k256 = { workspace = true } +thiserror = { workspace = true } diff --git a/crates/statetest-types/LICENSE b/crates/statetest-types/LICENSE new file mode 100644 index 0000000000..be6d350ebe --- /dev/null +++ b/crates/statetest-types/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021-2025 draganrakita + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/crates/statetest-types/src/account_info.rs b/crates/statetest-types/src/account_info.rs new file mode 100644 index 0000000000..df87ec10e8 --- /dev/null +++ b/crates/statetest-types/src/account_info.rs @@ -0,0 +1,19 @@ +use revm::primitives::{Bytes, HashMap, StorageKey, StorageValue, U256}; +use serde::Deserialize; + +use crate::deserializer::deserialize_str_as_u64; + +/// Account information +#[derive(Clone, Debug, PartialEq, Eq, Deserialize)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +pub struct AccountInfo { + /// Account balance in wei + pub balance: U256, + /// Account bytecode + pub code: Bytes, + /// Account nonce (transaction count) + #[serde(deserialize_with = "deserialize_str_as_u64")] + pub nonce: u64, + /// Account storage (key-value pairs) + pub storage: HashMap, +} diff --git a/bins/revme/src/cmd/statetest/models/deserializer.rs b/crates/statetest-types/src/deserializer.rs similarity index 86% rename from bins/revme/src/cmd/statetest/models/deserializer.rs rename to crates/statetest-types/src/deserializer.rs index a89c70a99c..8ba97e928e 100644 --- a/bins/revme/src/cmd/statetest/models/deserializer.rs +++ b/crates/statetest-types/src/deserializer.rs @@ -1,6 +1,7 @@ use revm::primitives::Address; use serde::{de, Deserialize}; +/// Deserializes a [string][String] as a [u64]. pub fn deserialize_str_as_u64<'de, D>(deserializer: D) -> Result where D: de::Deserializer<'de>, @@ -15,6 +16,7 @@ where .map_err(serde::de::Error::custom) } +/// Deserializes a [string][String] as an optional [Address]. pub fn deserialize_maybe_empty<'de, D>(deserializer: D) -> Result, D::Error> where D: de::Deserializer<'de>, diff --git a/crates/statetest-types/src/env.rs b/crates/statetest-types/src/env.rs new file mode 100644 index 0000000000..36995efe2c --- /dev/null +++ b/crates/statetest-types/src/env.rs @@ -0,0 +1,42 @@ +use revm::primitives::{Address, B256, U256}; +use serde::Deserialize; + +/// Environment variables +#[derive(Debug, PartialEq, Eq, Deserialize)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +pub struct Env { + /// Chain ID for the current execution + #[serde(rename = "currentChainID")] + pub current_chain_id: Option, + /// Block coinbase address (miner/validator) + pub current_coinbase: Address, + /// Block difficulty (pre-merge) or prevrandao (post-merge) + #[serde(default)] + pub current_difficulty: U256, + /// Block gas limit + pub current_gas_limit: U256, + /// Current block number + pub current_number: U256, + /// Current block timestamp + pub current_timestamp: U256, + /// EIP-1559 base fee per gas + pub current_base_fee: Option, + /// Previous block hash + pub previous_hash: Option, + + /// Current block randomness (EIP-4399 prevrandao) + pub current_random: Option, + /// Current beacon chain root (EIP-4788) + pub current_beacon_root: Option, + /// Current withdrawals root + pub current_withdrawals_root: Option, + + /// Parent block blob gas used (EIP-4844) + pub parent_blob_gas_used: Option, + /// Parent block excess blob gas (EIP-4844) + pub parent_excess_blob_gas: Option, + /// Parent block target blobs per block (EIP-4844) + pub parent_target_blobs_per_block: Option, + /// Current block excess blob gas (EIP-4844) + pub current_excess_blob_gas: Option, +} diff --git a/crates/statetest-types/src/error.rs b/crates/statetest-types/src/error.rs new file mode 100644 index 0000000000..3146a2f37a --- /dev/null +++ b/crates/statetest-types/src/error.rs @@ -0,0 +1,21 @@ +use revm::primitives::B256; +use thiserror::Error; + +/// Errors that can occur during test setup and execution +#[derive(Debug, Error)] +pub enum TestError { + /// Unknown private key. + #[error("unknown private key: {0:?}")] + UnknownPrivateKey(B256), + /// Invalid transaction type. + #[error("invalid transaction type")] + InvalidTransactionType, + /// Unexpected exception. + #[error("unexpected exception: got {got_exception:?}, expected {expected_exception:?}")] + UnexpectedException { + /// Expected exception. + expected_exception: Option, + /// Got exception. + got_exception: Option, + }, +} diff --git a/crates/statetest-types/src/lib.rs b/crates/statetest-types/src/lib.rs new file mode 100644 index 0000000000..e407782de8 --- /dev/null +++ b/crates/statetest-types/src/lib.rs @@ -0,0 +1,31 @@ +//! # revm-statetest-types +//! +//! This crate provides type definitions and utilities for Ethereum state tests, +//! specifically tailored for use with REVM. +//! +//! It includes structures for representing account information, environment settings, +//! test cases, and transaction data used in Ethereum state tests. + +mod account_info; +mod deserializer; +mod env; +mod error; +mod spec; +mod test; +mod test_authorization; +mod test_suite; +mod test_unit; +mod transaction; +mod utils; + +pub use account_info::*; +pub use deserializer::*; +pub use env::*; +pub use error::*; +pub use spec::*; +pub use test::*; +pub use test_authorization::*; +pub use test_suite::*; +pub use test_unit::*; +pub use transaction::*; +pub use utils::*; diff --git a/bins/revme/src/cmd/statetest/models/spec.rs b/crates/statetest-types/src/spec.rs similarity index 50% rename from bins/revme/src/cmd/statetest/models/spec.rs rename to crates/statetest-types/src/spec.rs index 53c134e479..434b73bdcc 100644 --- a/bins/revme/src/cmd/statetest/models/spec.rs +++ b/crates/statetest-types/src/spec.rs @@ -1,33 +1,62 @@ -use revm::primitives::SpecId; +use revm::primitives::hardfork::SpecId; use serde::Deserialize; +/// Ethereum specification names #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Deserialize, Hash)] pub enum SpecName { + /// Frontier hardfork (Ethereum launch, July 2015) Frontier, + /// Transition from Frontier to Homestead at block 5 FrontierToHomesteadAt5, + /// Homestead hardfork (March 2016) Homestead, + /// Transition from Homestead to DAO fork at block 5 HomesteadToDaoAt5, + /// Transition from Homestead to EIP-150 at block 5 HomesteadToEIP150At5, + /// EIP-150 hardfork (Tangerine Whistle, October 2016) EIP150, + /// EIP-158/EIP-161 hardfork (Spurious Dragon, November 2016) EIP158, // EIP-161: State trie clearing + /// Transition from EIP-158 to Byzantium at block 5 EIP158ToByzantiumAt5, + /// Byzantium hardfork (October 2017) Byzantium, + /// Transition from Byzantium to Constantinople at block 5 (skipped) ByzantiumToConstantinopleAt5, // SKIPPED + /// Transition from Byzantium to Constantinople Fix at block 5 ByzantiumToConstantinopleFixAt5, + /// Constantinople hardfork (skipped due to reentrancy bug) Constantinople, // SKIPPED + /// Constantinople Fix hardfork (Petersburg, February 2019) ConstantinopleFix, + /// Istanbul hardfork (December 2019) Istanbul, + /// Berlin hardfork (April 2021) Berlin, + /// Transition from Berlin to London at block 5 BerlinToLondonAt5, + /// London hardfork (August 2021, includes EIP-1559) London, + /// Paris hardfork (part of The Merge) + Paris, + /// The Merge (September 2022, PoW to PoS transition) Merge, + /// Shanghai hardfork (April 2023, includes withdrawals) Shanghai, + /// Cancun hardfork (March 2024, includes EIP-4844) Cancun, + /// Prague hardfork (future) + Prague, + /// Osaka hardfork (skipped) + Osaka, // SKIPPED + /// Unknown or unsupported specification #[serde(other)] Unknown, } impl SpecName { + /// Converts to a [SpecId]. pub fn to_spec_id(&self) -> SpecId { match self { Self::Frontier => SpecId::FRONTIER, @@ -41,9 +70,11 @@ impl SpecName { Self::Istanbul => SpecId::ISTANBUL, Self::Berlin => SpecId::BERLIN, Self::London | Self::BerlinToLondonAt5 => SpecId::LONDON, - Self::Merge => SpecId::MERGE, + Self::Paris | Self::Merge => SpecId::MERGE, Self::Shanghai => SpecId::SHANGHAI, Self::Cancun => SpecId::CANCUN, + Self::Prague => SpecId::PRAGUE, + Self::Osaka => SpecId::OSAKA, Self::ByzantiumToConstantinopleAt5 | Self::Constantinople => { panic!("Overridden with PETERSBURG") } diff --git a/crates/statetest-types/src/test.rs b/crates/statetest-types/src/test.rs new file mode 100644 index 0000000000..8bc7cb9c42 --- /dev/null +++ b/crates/statetest-types/src/test.rs @@ -0,0 +1,135 @@ +use revm::{ + context::tx::TxEnv, + primitives::{Address, Bytes, HashMap, TxKind, B256}, +}; +use serde::Deserialize; + +use crate::{ + error::TestError, transaction::TxPartIndices, utils::recover_address, AccountInfo, TestUnit, +}; + +/// State test indexed state result deserialization. +#[derive(Debug, PartialEq, Eq, Deserialize)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +pub struct Test { + /// Expected exception for this test case, if any. + /// + /// This field contains an optional string describing an expected error or exception + /// that should occur during the execution of this state test. If present, the test + /// is expected to fail with this specific error message or exception type. + pub expect_exception: Option, + + /// Indexes + pub indexes: TxPartIndices, + /// Post state hash + pub hash: B256, + /// Post state + #[serde(default)] + pub post_state: HashMap, + + /// Logs root + pub logs: B256, + + /// Output state. + /// + /// Note: Not used. + #[serde(default)] + state: HashMap, + + /// Tx bytes + pub txbytes: Option, +} + +impl Test { + /// Create a transaction environment from this test and the test unit. + /// + /// This function sets up the transaction environment using the test's + /// indices to select the appropriate transaction parameters from the + /// test unit. + /// + /// # Arguments + /// + /// * `unit` - The test unit containing transaction parts + /// + /// # Returns + /// + /// A configured [`TxEnv`] ready for execution, or an error if setup fails + /// + /// # Errors + /// + /// Returns an error if: + /// - The private key cannot be used to recover the sender address + /// - The transaction type is invalid and no exception is expected + pub fn tx_env(&self, unit: &TestUnit) -> Result { + // Setup sender + let caller = if let Some(address) = unit.transaction.sender { + address + } else { + recover_address(unit.transaction.secret_key.as_slice()) + .ok_or(TestError::UnknownPrivateKey(unit.transaction.secret_key))? + }; + + // Transaction specific fields + let tx_type = unit.transaction.tx_type(self.indexes.data).ok_or_else(|| { + if self.expect_exception.is_some() { + TestError::UnexpectedException { + expected_exception: self.expect_exception.clone(), + got_exception: Some("Invalid transaction type".to_string()), + } + } else { + TestError::InvalidTransactionType + } + })?; + + let tx = TxEnv { + caller, + gas_price: unit + .transaction + .gas_price + .or(unit.transaction.max_fee_per_gas) + .unwrap_or_default() + .try_into() + .unwrap_or(u128::MAX), + gas_priority_fee: unit + .transaction + .max_priority_fee_per_gas + .map(|b| u128::try_from(b).expect("max priority fee less than u128::MAX")), + blob_hashes: unit.transaction.blob_versioned_hashes.clone(), + max_fee_per_blob_gas: unit + .transaction + .max_fee_per_blob_gas + .map(|b| u128::try_from(b).expect("max fee less than u128::MAX")) + .unwrap_or(u128::MAX), + tx_type: tx_type as u8, + gas_limit: unit.transaction.gas_limit[self.indexes.gas].saturating_to(), + data: unit.transaction.data[self.indexes.data].clone(), + nonce: u64::try_from(unit.transaction.nonce).unwrap(), + value: unit.transaction.value[self.indexes.value], + access_list: unit + .transaction + .access_lists + .get(self.indexes.data) + .cloned() + .flatten() + .unwrap_or_default(), + authorization_list: unit + .transaction + .authorization_list + .clone() + .map(|auth_list| { + auth_list + .into_iter() + .map(|i| revm::context::either::Either::Left(i.into())) + .collect::>() + }) + .unwrap_or_default(), + kind: match unit.transaction.to { + Some(add) => TxKind::Call(add), + None => TxKind::Create, + }, + ..TxEnv::default() + }; + + Ok(tx) + } +} diff --git a/crates/statetest-types/src/test_authorization.rs b/crates/statetest-types/src/test_authorization.rs new file mode 100644 index 0000000000..c71977c1d1 --- /dev/null +++ b/crates/statetest-types/src/test_authorization.rs @@ -0,0 +1,74 @@ +use revm::context_interface::transaction::SignedAuthorization; +use serde::de::Error; +use serde::{Deserialize, Deserializer, Serialize}; + +/// Struct for test authorization +#[derive(Debug, Clone, PartialEq, Eq, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct TestAuthorization { + #[serde(flatten)] + inner: SignedAuthorization, +} + +impl From for SignedAuthorization { + fn from(auth: TestAuthorization) -> Self { + auth.inner + } +} + +impl<'de> Deserialize<'de> for TestAuthorization { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + // This is a hack to remove duplicate yParity and v fields which can be used by the test files for cross client compat + let mut value: serde_json::Value = Deserialize::deserialize(deserializer)?; + if let Some(val) = value.as_object_mut() { + if val.contains_key("v") && val.contains_key("yParity") { + val.remove("v"); + } + } + let inner: SignedAuthorization = serde_json::from_value(value).map_err(D::Error::custom)?; + Ok(Self { inner }) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn recover_auth() { + // Test named: + // tests/prague/eip7702_set_code_tx/test_gas.py::test_account_warming[fork_Prague-state_test-single_valid_authorization_single_signer-check_delegated_account_first_True] + + let auth = r#"{ + "chainId": "0x00", + "address": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "nonce": "0x00", + "v": "0x01", + "r": "0x5a8cac98fd240d8ef83c22db4a061ffa0facb1801245283cc05fc809d8b92837", + "s": "0x1c3162fe11d91bc24d4fa00fb19ca34531e0eacdf8142c804be44058d5b8244f", + "signer": "0x6389e7f33ce3b1e94e4325ef02829cd12297ef71" + }"#; + + let auth: TestAuthorization = serde_json::from_str(auth).unwrap(); + println!("{auth:?}"); + } + + #[test] + fn recover_auth_duplicate_v_yparity() { + let auth = r#"{ + "chainId": "0x00", + "address": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "nonce": "0x00", + "v": "0x01", + "yParity": "0x01", + "r": "0x5a8cac98fd240d8ef83c22db4a061ffa0facb1801245283cc05fc809d8b92837", + "s": "0x1c3162fe11d91bc24d4fa00fb19ca34531e0eacdf8142c804be44058d5b8244f", + "signer": "0x6389e7f33ce3b1e94e4325ef02829cd12297ef71" + }"#; + + let _: TestAuthorization = serde_json::from_str(auth).unwrap(); + } +} diff --git a/crates/statetest-types/src/test_suite.rs b/crates/statetest-types/src/test_suite.rs new file mode 100644 index 0000000000..1065d2e526 --- /dev/null +++ b/crates/statetest-types/src/test_suite.rs @@ -0,0 +1,8 @@ +use serde::Deserialize; +use std::collections::BTreeMap; + +use crate::TestUnit; + +/// The top level test suite struct +#[derive(Debug, PartialEq, Eq, Deserialize)] +pub struct TestSuite(pub BTreeMap); diff --git a/crates/statetest-types/src/test_unit.rs b/crates/statetest-types/src/test_unit.rs new file mode 100644 index 0000000000..f92caf4fe6 --- /dev/null +++ b/crates/statetest-types/src/test_unit.rs @@ -0,0 +1,149 @@ +use serde::Deserialize; +use std::collections::{BTreeMap, HashMap}; + +use crate::{AccountInfo, Env, SpecName, Test, TransactionParts}; +use revm::{ + context::{block::BlockEnv, cfg::CfgEnv}, + context_interface::block::calc_excess_blob_gas, + database::CacheState, + primitives::{ + eip4844::TARGET_BLOB_GAS_PER_BLOCK_CANCUN, hardfork::SpecId, keccak256, Address, Bytes, + B256, + }, + state::Bytecode, +}; + +/// Single test unit struct +#[derive(Debug, PartialEq, Eq, Deserialize)] +//#[serde(deny_unknown_fields)] +// field config +pub struct TestUnit { + /// Test info is optional. + #[serde(default, rename = "_info")] + pub info: Option, + + /// Test environment configuration. + /// + /// Contains the environmental information for executing the test, including + /// block information, coinbase address, difficulty, gas limit, and other + /// blockchain state parameters required for proper test execution. + pub env: Env, + + /// Pre-execution state. + /// + /// A mapping of addresses to their account information before the transaction + /// is executed. This represents the initial state of all accounts involved + /// in the test, including their balances, nonces, code, and storage. + pub pre: HashMap, + + /// Post-execution expectations per specification. + /// + /// Maps each Ethereum specification name (hardfork) to a vector of expected + /// test results. This allows a single test to define different expected outcomes + /// for different protocol versions, enabling comprehensive testing across + /// multiple Ethereum upgrades. + pub post: BTreeMap>, + + /// Transaction details to be executed. + /// + /// Contains the transaction parameters that will be executed against the + /// pre-state. This includes sender, recipient, value, data, gas limits, + /// and other transaction fields that may vary based on indices. + pub transaction: TransactionParts, + + /// Expected output data from the transaction execution. + /// + /// Optional field containing the expected return data from the transaction. + /// This is typically used for testing contract calls that return specific + /// values or for CREATE operations that return deployed contract addresses. + #[serde(default)] + pub out: Option, + //pub config +} + +impl TestUnit { + /// Prepare the state from the test unit. + /// + /// This function uses [`TestUnit::pre`] to prepare the pre-state from the test unit. + /// It creates a new cache state and inserts the accounts from the test unit. + /// + /// # Returns + /// + /// A [`CacheState`] object containing the pre-state accounts and storages. + pub fn state(&self) -> CacheState { + let mut cache_state = CacheState::new(false); + for (address, info) in &self.pre { + let code_hash = keccak256(&info.code); + let bytecode = Bytecode::new_raw_checked(info.code.clone()) + .unwrap_or(Bytecode::new_legacy(info.code.clone())); + let acc_info = revm::state::AccountInfo { + balance: info.balance, + code_hash, + code: Some(bytecode), + nonce: info.nonce, + }; + cache_state.insert_account_with_storage(*address, acc_info, info.storage.clone()); + } + cache_state + } + + /// Create a block environment from the test unit. + /// + /// This function sets up the block environment using the current test unit's + /// environment settings and the provided configuration. + /// + /// # Arguments + /// + /// * `cfg` - The configuration environment containing spec and blob settings + /// + /// # Returns + /// + /// A configured [`BlockEnv`] ready for execution + pub fn block_env(&self, cfg: &CfgEnv) -> BlockEnv { + let mut block = BlockEnv { + number: self.env.current_number, + beneficiary: self.env.current_coinbase, + timestamp: self.env.current_timestamp, + gas_limit: self.env.current_gas_limit.try_into().unwrap_or(u64::MAX), + basefee: self + .env + .current_base_fee + .unwrap_or_default() + .try_into() + .unwrap_or(u64::MAX), + difficulty: self.env.current_difficulty, + prevrandao: self.env.current_random, + ..BlockEnv::default() + }; + + // Handle EIP-4844 blob gas + if let Some(current_excess_blob_gas) = self.env.current_excess_blob_gas { + block.set_blob_excess_gas_and_price( + current_excess_blob_gas.to(), + revm::primitives::eip4844::BLOB_BASE_FEE_UPDATE_FRACTION_CANCUN, + ); + } else if let (Some(parent_blob_gas_used), Some(parent_excess_blob_gas)) = ( + self.env.parent_blob_gas_used, + self.env.parent_excess_blob_gas, + ) { + block.set_blob_excess_gas_and_price( + calc_excess_blob_gas( + parent_blob_gas_used.to(), + parent_excess_blob_gas.to(), + self.env + .parent_target_blobs_per_block + .map(|i| i.to()) + .unwrap_or(TARGET_BLOB_GAS_PER_BLOCK_CANCUN), + ), + revm::primitives::eip4844::BLOB_BASE_FEE_UPDATE_FRACTION_CANCUN, + ); + } + + // Set default prevrandao for merge + if cfg.spec.is_enabled_in(SpecId::MERGE) && block.prevrandao.is_none() { + block.prevrandao = Some(B256::default()); + } + + block + } +} diff --git a/crates/statetest-types/src/transaction.rs b/crates/statetest-types/src/transaction.rs new file mode 100644 index 0000000000..81a98a30a7 --- /dev/null +++ b/crates/statetest-types/src/transaction.rs @@ -0,0 +1,157 @@ +use crate::{deserializer::deserialize_maybe_empty, TestAuthorization}; +use revm::{ + context::TransactionType, + context_interface::transaction::AccessList, + primitives::{Address, Bytes, B256, U256}, +}; +use serde::{Deserialize, Serialize}; + +/// Transaction parts. +#[derive(Debug, Default, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct TransactionParts { + /// Transaction type (0=Legacy, 1=EIP-2930, 2=EIP-1559, 3=EIP-4844, 4=EIP-7702) + #[serde(rename = "type")] + pub tx_type: Option, + /// Transaction data/input (multiple variants for different test cases) + pub data: Vec, + /// Gas limit values (multiple variants for different test cases) + pub gas_limit: Vec, + /// Gas price (for legacy and EIP-2930 transactions) + pub gas_price: Option, + /// Transaction nonce + pub nonce: U256, + /// Private key for signing the transaction + pub secret_key: B256, + /// if sender is not present we need to derive it from secret key. + #[serde(default)] + pub sender: Option
, + /// Recipient address (None for contract creation) + #[serde(default, deserialize_with = "deserialize_maybe_empty")] + pub to: Option
, + /// Ether value to transfer (multiple variants for different test cases) + pub value: Vec, + /// Maximum fee per gas (EIP-1559 transactions) + pub max_fee_per_gas: Option, + /// Maximum priority fee per gas (EIP-1559 transactions) + pub max_priority_fee_per_gas: Option, + /// Initcodes for contract creation (EIP-7873) + pub initcodes: Option>, + /// Access lists for different test cases (EIP-2930) + #[serde(default)] + pub access_lists: Vec>, + /// Authorization list (EIP-7702) + pub authorization_list: Option>, + /// Blob versioned hashes (EIP-4844) + #[serde(default)] + pub blob_versioned_hashes: Vec, + /// Maximum fee per blob gas (EIP-4844) + pub max_fee_per_blob_gas: Option, +} + +impl TransactionParts { + /// Returns the transaction type. + /// + /// As this information is derived from the fields it is not stored in the struct. + /// + /// Returns `None` if the transaction is invalid: + /// * It has both blob gas and no destination. + /// * It has authorization list and no destination. + pub fn tx_type(&self, access_list_index: usize) -> Option { + if let Some(tx_type) = self.tx_type { + return Some(TransactionType::from(tx_type)); + } + + let mut tx_type = TransactionType::Legacy; + + // If it has access list it is EIP-2930 tx + if let Some(access_list) = self.access_lists.get(access_list_index) { + if access_list.is_some() { + tx_type = TransactionType::Eip2930; + } + } + + // If there is max_fee it is EIP-1559 tx + if self.max_fee_per_gas.is_some() { + tx_type = TransactionType::Eip1559; + } + + // If it has max_fee_per_blob_gas it is EIP-4844 tx + if self.max_fee_per_blob_gas.is_some() { + // target need to be present for EIP-4844 tx + self.to?; + return Some(TransactionType::Eip4844); + } + + // And if it has authorization list it is EIP-7702 tx + if self.authorization_list.is_some() { + // Target need to be present for EIP-7702 tx + self.to?; + return Some(TransactionType::Eip7702); + } + + Some(tx_type) + } +} + +/// Transaction part indices. +#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +pub struct TxPartIndices { + /// Index into the data array + pub data: usize, + /// Index into the gas_limit array + pub gas: usize, + /// Index into the value array + pub value: usize, +} + +#[cfg(test)] +mod test { + + use super::*; + + #[test] + fn decode_tx_parts() { + let tx = r#"{ + "nonce": "0x00", + "maxPriorityFeePerGas": "0x00", + "maxFeePerGas": "0x07", + "gasLimit": [ + "0x0423ff" + ], + "to": "0x0000000000000000000000000000000000001000", + "value": [ + "0x00" + ], + "data": [ + "0x" + ], + "accessLists": [ + [ + { + "address": "0x6389e7f33ce3b1e94e4325ef02829cd12297ef71", + "storageKeys": [ + "0x0000000000000000000000000000000000000000000000000000000000000000" + ] + } + ] + ], + "authorizationList": [ + { + "chainId": "0x00", + "address": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "nonce": "0x00", + "v": "0x01", + "r": "0x5a8cac98fd240d8ef83c22db4a061ffa0facb1801245283cc05fc809d8b92837", + "s": "0x1c3162fe11d91bc24d4fa00fb19ca34531e0eacdf8142c804be44058d5b8244f", + "signer": "0x6389e7f33ce3b1e94e4325ef02829cd12297ef71" + } + ], + "sender": "0x8a0a19589531694250d570040a0c4b74576919b8", + "secretKey": "0x9e7645d0cfd9c3a04eb7a9db59a4eb7d359f2e75c9164a9d6b9a7d54e1b6a36f" + }"#; + + let _: TransactionParts = serde_json::from_str(tx).unwrap(); + } +} diff --git a/crates/statetest-types/src/utils.rs b/crates/statetest-types/src/utils.rs new file mode 100644 index 0000000000..3ecc89594a --- /dev/null +++ b/crates/statetest-types/src/utils.rs @@ -0,0 +1,25 @@ +use k256::ecdsa::SigningKey; +use revm::primitives::Address; + +/// Recover the address from a private key ([SigningKey]). +pub fn recover_address(private_key: &[u8]) -> Option
{ + let key = SigningKey::from_slice(private_key).ok()?; + let public_key = key.verifying_key().to_encoded_point(false); + Some(Address::from_raw_public_key(&public_key.as_bytes()[1..])) +} + +#[cfg(test)] +mod tests { + use super::*; + use revm::primitives::{address, hex}; + + #[test] + fn sanity_test() { + assert_eq!( + Some(address!("a94f5374fce5edbc8e2a8697c15331677e6ebf0b")), + recover_address(&hex!( + "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8" + )) + ) + } +} diff --git a/documentation/src/SUMMARY.md b/documentation/src/SUMMARY.md deleted file mode 100644 index 1d2900f332..0000000000 --- a/documentation/src/SUMMARY.md +++ /dev/null @@ -1,36 +0,0 @@ -# Summary - -- [Introduction](./introduction.md) -- [Revm](./crates/revm.md) - - [evm](./crates/revm/evm.md) - - [builder](./crates/revm/builder.md) - - [handler](./crates/revm/handler.md) - - [inspector](./crates/revm/inspector.md) - - [state](./crates/revm/state.md) - - [journaled_state](./crates/revm/journaled_state.md) -- [Interpreter](./crates/interpreter.md) - - [gas](./crates/interpreter/gas.md) - - [memory](./crates/interpreter/memory.md) - - [host](./crates/interpreter/host.md) - - [interpreter_action](./crates/interpreter/interpreter_action.md) - - [instruction_result](./crates/interpreter/instruction_result.md) - - [instructions](./crates/interpreter/instructions.md) -- [Primitives](./crates/primitives.md) - - [database](./crates/primitives/database.md) - - [result](./crates/primitives/result.md) - - [environment](./crates/primitives/environment.md) - - [specifications](./crates/primitives/specifications.md) - - [bytecode](./crates/primitives/bytecode.md) - - [constants](./crates/primitives/constants.md) - - [precompile](./crates/primitives/precompile.md) - - [state](./crates/primitives/state.md) - - [utils](./crates/primitives/utils.md) - - [kzg](./crates/primitives/kzg.md) -- [Precompile](./crates/precompile.md) - - [blake2](./crates/precompile/blake2.md) - - [bn128 curve](./crates/precompile/bn128.md) - - [Hash functions](./crates/precompile/hash.md) - - [Identity function](./crates/precompile/identity.md) - - [Modular Exponentiation](./crates/precompile/modexp.md) - - [Secp256k1](./crates/precompile/secp256k1.md) - - [Point Evaluation](./crates/precompile/point_evaluation.md) diff --git a/documentation/src/bins/revm-test.md b/documentation/src/bins/revm-test.md deleted file mode 100644 index 2757b53d14..0000000000 --- a/documentation/src/bins/revm-test.md +++ /dev/null @@ -1 +0,0 @@ -# revm-test diff --git a/documentation/src/bins/revme.md b/documentation/src/bins/revme.md deleted file mode 100644 index 15bca4c3fd..0000000000 --- a/documentation/src/bins/revme.md +++ /dev/null @@ -1 +0,0 @@ -# revme diff --git a/documentation/src/crates/interpreter.md b/documentation/src/crates/interpreter.md deleted file mode 100644 index 0ad39b0b6c..0000000000 --- a/documentation/src/crates/interpreter.md +++ /dev/null @@ -1,27 +0,0 @@ -# Interpreter - -The `interpreter` crate is concerned with the execution of the EVM opcodes and serves as the event loop to step through the opcodes. -The interpreter is concerned with attributes like gas, contracts, memory, stack, and returning execution results. -It is structured as follows: - -### Modules: - -- [gas](./interpreter/gas.md): Handles gas mechanics in the EVM, such as calculating gas costs for operations. -- [host](./interpreter/host.md): Defines the EVM context `Host` trait. -- [interpreter_action](./interpreter/interpreter_action.md): Contains data structures used in the EVM implementation. -- [instruction_result](./interpreter/instruction_result.md): Defines results of instruction execution. -- [instructions](./interpreter/instructions.md): Defines the EVM opcodes (i.e. instructions). - -### External Crates: - -- [alloc](https://doc.rust-lang.org/alloc/): - The `alloc` crate is used to provide the ability to allocate memory on the heap. - It's a part of Rust's standard library that can be used in environments without a full host OS. -- [core](https://doc.rust-lang.org/core/): - The `core` crate is the dependency-free foundation of the Rust standard library. - It includes fundamental types, macros, and traits. - -### Re-exports: -- Several types and functions are re-exported for easier access by users of this library, such as `Gas`, `Host`, `InstructionResult`, `OpCode`, `Interpreter`, `Memory`, `Stack`, and others. - This allows users to import these items directly from the library root instead of from their individual modules. -- `revm_primitives`: This crate is re-exported, providing primitive types or functionality used in the EVM implementation. diff --git a/documentation/src/crates/interpreter/gas.md b/documentation/src/crates/interpreter/gas.md deleted file mode 100644 index cebad5eed2..0000000000 --- a/documentation/src/crates/interpreter/gas.md +++ /dev/null @@ -1,29 +0,0 @@ -# The `gas.rs` Module - -The `gas.rs` module in this Rust EVM implementation manages the concept of "gas" within the Ethereum network. In Ethereum, "gas" signifies the computational effort needed to execute operations, whether a simple transfer of ether or the execution of a smart contract function. Each operation carries a gas cost, and transactions must specify the maximum amount of gas they are willing to consume. - -## Data Structures -- `Gas` Struct - - The `Gas` struct represents the gas state for a particular operation or transaction. The struct is defined as follows: - - ### Fields in `Gas` Struct - - - `limit`: The maximum amount of gas allowed for the operation or transaction. - - `all_used_gas`: The total gas used, inclusive of memory expansion costs. - - `used`: The gas used, excluding memory expansion costs. - - `memory`: The gas used for memory expansion. - - `refunded`: The gas refunded. Certain operations in Ethereum allow for gas refunds, up to half the gas used by a transaction. - -## Methods of the `Gas` Struct - -The `Gas` struct also includes several methods to manage the gas state. Here's a brief summary of their functions: - -- `new`: Creates a new `Gas` instance with a specified gas limit and zero usage and refunds. -- `limit`, `memory`, `refunded`, `spend`, `remaining`: These getters return the current state of the corresponding field. -- `erase_cost`: Decreases the gas usage by a specified amount. -- `record_refund`: Increases the refunded gas by a specified amount. -- `record_cost`: Increases the used gas by a specified amount. It also checks for gas limit overflow. If the new total used gas would exceed the gas limit, it returns `false` and doesn't change the state. -- `record_memory`: This method works similarly to `record_cost`, but specifically for memory expansion gas. It only updates the state if the new memory gas usage is greater than the current usage. -- `gas_refund`: Increases the refunded gas by a specified amount. - diff --git a/documentation/src/crates/interpreter/host.md b/documentation/src/crates/interpreter/host.md deleted file mode 100644 index 90752f3a7d..0000000000 --- a/documentation/src/crates/interpreter/host.md +++ /dev/null @@ -1,24 +0,0 @@ -# The `host.rs` Module - -The `host.rs` module in this Rust EVM implementation defines a crucial trait `Host`. The `Host` trait outlines an interface for the interaction of the EVM interpreter with its environment (or "host"), encompassing essential operations such as account and storage access, creating logs, and invoking transactions. - -The [`Evm`](./../revm/evm.md) struct implements this `Host` trait. - -## Trait Methods - -- `env`: This method provides access to the EVM environment, including information about the current block and transaction. - -- `load_account`: Retrieves information about a given Ethereum account. - -- `block_hash`: Retrieves the block hash for a given block number. - -- `balance`, `code`, `code_hash`, `sload`: These methods retrieve specific information (balance, code, code hash, and specific storage value) for a given Ethereum account. - -- `sstore`: This method sets the value of a specific storage slot in a given Ethereum account. - -- `log`: Creates a log entry with the specified address, topics, and data. Log entries are used by smart contracts to emit events. - -- `selfdestruct`: Marks an Ethereum account to be self-destructed, transferring its funds to a target account. - - -The `Host` trait provides a standard interface that any host environment for the EVM must implement. This abstraction allows the EVM code to interact with the state of the Ethereum network in a generic way, thereby enhancing modularity and interoperability. Different implementations of the `Host` trait can be used to simulate different environments for testing or for connecting to different Ethereum-like networks. \ No newline at end of file diff --git a/documentation/src/crates/interpreter/instruction_result.md b/documentation/src/crates/interpreter/instruction_result.md deleted file mode 100644 index b2b6b4e0c1..0000000000 --- a/documentation/src/crates/interpreter/instruction_result.md +++ /dev/null @@ -1,19 +0,0 @@ -# The `instruction_result.rs` Module - -The `instruction_result.rs` module of this Rust EVM implementation includes the definitions of the `InstructionResult` and `SuccessOrHalt` enum, which represent the possible outcomes of EVM instruction execution, and functions to work with these types. - -- `InstructionResult` Enum - - The `InstructionResult` enum categorizes the different types of results that can arise from executing an EVM instruction. This enumeration uses the `#[repr(u8)]` attribute, meaning its variants have an explicit storage representation of an 8-bit unsigned integer. The different instruction results represent outcomes such as successful continuation, stop, return, self-destruction, reversion, deep call, out of funds, out of gas, and various error conditions. - -- `SuccessOrHalt` Enum - - The `SuccessOrHalt` enum represents the outcome of a transaction execution, distinguishing successful operations, reversion, halting conditions, fatal external errors, and internal continuation. It also provides several methods to check the kind of result and to extract the value of the successful evaluation or halt. - -- `From for SuccessOrHalt` Implementation - - This implementation provides a way to convert an `InstructionResult` into a `SuccessOrHalt`. It maps each instruction result to the corresponding `SuccessOrHalt` variant. - -- Macros for returning instruction results - - The module provides two macros, `return_ok!` and `return_revert!`, which simplify returning some common sets of instruction results. diff --git a/documentation/src/crates/interpreter/instructions.md b/documentation/src/crates/interpreter/instructions.md deleted file mode 100644 index 84b5b8a857..0000000000 --- a/documentation/src/crates/interpreter/instructions.md +++ /dev/null @@ -1,15 +0,0 @@ -# The `instruction.rs` Module in the Rust Ethereum Virtual Machine (EVM) - -The `instruction.rs` module defines interpretation mappings for EVM bytecode. It provides the definition of the `Instruction` struct, as well as the `Opcode` enumeration and the `execute` function, which runs a specific instruction. - -## `Opcode` Enum - -The `Opcode` enum represents the opcodes that are available in the Ethereum Virtual Machine. Each variant corresponds to an operation that can be performed, such as addition, multiplication, subtraction, jumps, and memory operations. - -## `Instruction` Struct - -The `Instruction` struct represents a single instruction in the EVM. It contains the opcode, which is the operation to be performed, and a list of bytes representing the operands for the instruction. - -## `step` Function - -The `step` function interprets an instruction. It uses the opcode to determine what operation to perform and then performs the operation using the operands in the instruction. \ No newline at end of file diff --git a/documentation/src/crates/interpreter/interpreter_action.md b/documentation/src/crates/interpreter/interpreter_action.md deleted file mode 100644 index 9654b43e16..0000000000 --- a/documentation/src/crates/interpreter/interpreter_action.md +++ /dev/null @@ -1,39 +0,0 @@ -# The `interpreter_action.rs` Module in the Rust Ethereum Virtual Machine (EVM) - -The `interpreter_action.rs` module within this Rust EVM implementation encompasses a collection of datastructures used as internal models within the EVM. These models represent various aspects of EVM operations such as call and create inputs, call context, value transfers, and the result of self-destruction operations. - -## Data Structures - -- `CallInputs` Struct - - The `CallInputs` struct is used to encapsulate the inputs to a smart contract call in the EVM. This struct includes the target contract address, the value to be transferred (if any), the input data, the gas limit for the call, the call context, and a boolean indicating if the call is a static call (a read-only operation). - -- `CallScheme` Enum - - The `CallScheme` enum represents the type of call being made to a smart contract. The different types of calls (`CALL`, `CALLCODE`, `DELEGATECALL`, `STATICCALL`) represent different modes of interaction with a smart contract, each with its own semantics concerning the treatment of the message sender, value transfer, and the context in which the called code executes. - -- `CallValue` Enum - - The `CallValue` Enum represents a value transfer between two accounts. - -- `CallOutcome` - - Represents the outcome of a call operation in a virtual machine. This struct encapsulates the result of executing an instruction by an interpreter, including the result itself, gas usage information, and the memory offset where output data is stored. - -- `CreateInputs` Struct - - The `CreateInputs` struct encapsulates the inputs for creating a new smart contract. This includes the address of the creator, the creation scheme, the value to be transferred, the initialization code for the new contract, and the gas limit for the creation operation. - -- `CreateOutcome` Struct - - Represents the outcome of a create operation in an interpreter. This struct holds the result of the operation along with an optional address. It provides methods to determine the next action based on the result of the operation. - -- `EOFCreateInput` Struct - - Inputs for EOF create call. - -- `EOFCreateOutcome` Struct - - Represents the outcome of a create operation in an interpreter. - -In summary, the `interpreter_action.rs` module provides several crucial data structures that facilitate the representation and handling of various EVM operations and their associated data within this Rust EVM implementation. diff --git a/documentation/src/crates/interpreter/memory.md b/documentation/src/crates/interpreter/memory.md deleted file mode 100644 index 24d4c39edc..0000000000 --- a/documentation/src/crates/interpreter/memory.md +++ /dev/null @@ -1,35 +0,0 @@ -# EVM Memory - -Is a memory localized to the current Interpreter context. Interpreter context is a call or create frame. It is used by opcodes to store or format data that are more then 32 bytes long, for example calls to format input, return output or for logs data. Revm has a shared memory between all the Interpreters but Interpreter loop only see the part it is allocated to it. - -Extending memory is paid by the gas. It consumes 3 gas per word plus square of the number of words added divided by `512` (`3*N+ N^2/512`). There is no limit on the size of the memory, but it is limited by logaritmic growth of the gas cost. For 30M there is a calculated max memory of 32MB (Blog post by ramco: [Upper bound for transaction memory](https://xn--2-umb.com/22/eth-max-mem/)). - -## Opcodes - -Here is a list of all opcodes that are reading or writing to the memory. All read on memory can still change the memory size by extending it with zeroes. Call opcodes are specific as they read input before the call but also write their output after the call (if call is okay and there is an output to write) to the memory. - -These opcodes read from the memory: -* RETURN -* REVERT -* LOG -* KECCAK256 -* CREATE -* CREATE2 -* CALL -* CALLCODE -* DELEGATECALL -* STATICCALL - -These opcodes change the memory: -* EXTCODECOPY -* MLOAD -* MSTORE -* MSTORE8 -* MCOPY -* CODECOPY -* CALLDATACOPY -* RETURNDATACOPY -* CALL -* CALLCODE -* DELEGATECALL -* STATICCALL \ No newline at end of file diff --git a/documentation/src/crates/precompile.md b/documentation/src/crates/precompile.md deleted file mode 100644 index 643ba75942..0000000000 --- a/documentation/src/crates/precompile.md +++ /dev/null @@ -1,47 +0,0 @@ -# Precompile - -The `precompile` crate contains the implementation of the Ethereum precompile opcodes in the EVM. -Precompiles are a shortcut to execute a function implemented by the EVM itself, rather than an actual contract. -Precompiled contracts are essentially predefined smart contracts on Ethereum, residing at hardcoded addresses and used for computationally heavy operations that are cheaper when implemented this way. -There are 6 precompiles implemented in REVM, and they are: `blake2`, `bn128` curve, `identity`, `secp256k1`, `modexp`, and `sha256` and `ripemd160` hash functions. - -### Modules: - -- [blake2](./precompile/blake2.md): Implements the `BLAKE2` compression function, as specified in [EIP-152](https://eips.ethereum.org/EIPS/eip-152). -- [bn128](./precompile/bn128.md): Implements precompiled contracts for addition, scalar multiplication, and optimal ate pairing check on the `alt_bn128` elliptic curve. -- [hash](./precompile/hash.md): Implements the `SHA256` and `RIPEMD160` hash functions. -- [identity](./precompile/identity.md): Implements the `Identity` precompile, which returns the input data unchanged. -- [point_evaluation](./precompile/point_evaluation.md): Implements the point evaluation precompile for [EIP-4844](https://eips.ethereum.org/EIPS/eip-4844). -- [modexp](./precompile/modexp.md): Implements the big integer modular exponentiation precompile. -- [secp256k1](./precompile/secp256k1.md): Implements the ECDSA public key recovery precompile, based on `secp256k1` curves. - -### Types and Constants: - -- `Address`: A type alias for an array of 20 bytes. This is typically used to represent Ethereum addresses. -- `B256`: A type alias for an array of 32 bytes, typically used to represent 256-bit hashes or integer values in Ethereum. -- `PrecompileOutput`: Represents the output of a precompiled contract execution, including the gas cost, output data, and any logs generated. -- `Log`: Represents an Ethereum log, with an address, a list of topics, and associated data. -- `Precompiles`: A collection of precompiled contracts available in a particular hard fork of Ethereum. -- `Precompile`: Represents a precompiled contract, which can either be a standard Ethereum precompile, or a custom precompile. -- `PrecompileWithAddress`: Associates a precompiled contract with its address. -- `SpecId`: An enumeration representing different hard fork specifications in Ethereum, such as Homestead, Byzantium, Istanbul, Berlin, and Latest. - -### Functions: - -- `calc_linear_cost_u32`: A utility function to calculate the gas cost for certain precompiles based on their input length. -- `u64_to_b160`: A utility function for converting a 64-bit unsigned integer into a 20-byte Ethereum address. - -### External Crates: - -- [alloc](https://doc.rust-lang.org/alloc/): The alloc crate provides types for heap allocation, and is used here for the `Vec` type. -- [core](https://doc.rust-lang.org/core/): The core crate provides fundamental Rust types, macros, and traits, and is used here for `fmt::Result`. - -### Re-exported Crates and Types: - -- `revm_primitives`: This crate is re-exported, indicating it provides some types used by the precompile crate. -- `primitives`: Types from the `primitives` module of `revm_primitives` are re-exported, including `Bytes`, `HashMap`, and all types under `precompile`. The latter includes the `PrecompileError` type, which is aliased to `Error`. - -### Re-exported Functionality: - -- `Precompiles` provides a static method for each Ethereum hard fork specification (e.g., `homestead`, `byzantium`, `istanbul`, `berlin`, `cancun`, and `latest`), each returning a set of precompiles for that specification. -- `Precompiles` also provides methods to retrieve the list of precompile addresses (`addresses`), to check if a given address is a precompile (`contains`), to get the precompile at a given address (`get`), to check if there are no precompiles (`is_empty`), and to get the number of precompiles (`len`). diff --git a/documentation/src/crates/precompile/blake2.md b/documentation/src/crates/precompile/blake2.md deleted file mode 100644 index 43b409cb94..0000000000 --- a/documentation/src/crates/precompile/blake2.md +++ /dev/null @@ -1,47 +0,0 @@ -# blake2 hash - -This module represents a Rust implementation of the `Blake2b` cryptographic hash function, a vital component of Ethereum's broader EIP-152 proposal. The primary purpose of this module is to integrate the `Blake2b` function into Ethereum's precompiled contract mechanism, providing a consistent and efficient way to perform the cryptographic hashing that underpins Ethereum's functionality. - -In [EIP-152](https://eips.ethereum.org/EIPS/eip-152) introduced a new precompiled contract that implements the `BLAKE2` cryptographic hashing algorithm's compression function. The purpose of this is to enhance the interoperability between Ethereum and Zcash, as well as to introduce more versatile cryptographic hash primitives to the Ethereum Virtual Machine (EVM). - -BLAKE2 is not just a powerful cryptographic hash function and SHA3 contender, but it also allows for the efficient validation of the Equihash Proof of Work (PoW) used in Zcash. This could make a Bitcoin Relay-style Simplified Payment Verification (SPV) client feasible on Ethereum, as it enables the verification of Zcash block headers without excessive computational cost. `BLAKE2b`, a common 64-bit `BLAKE2` variant, is highly optimized and performs faster than MD5 on modern processors. - -The rationale behind incorporating `Blake2b` into Ethereum's suite of precompiled contracts is multifaceted: - -- Performance: The `Blake2b` hash function offers excellent performance, particularly when processing large inputs. -- Security: `Blake2b` also provides a high degree of security, making it a suitable choice for cryptographic operations. -- Interoperability: This function is widely used in various parts of the ecosystem, making it a prime candidate for inclusion in Ethereum's precompiled contracts. -- Gas Cost: The gas cost per round (F_ROUND) is specified as 1. This number was decided considering the computational complexity and the necessity to keep the blockchain efficient and prevent spamming. - -## Core Components - -Two primary constants provide the framework for the precompiled contract: - -`F_ROUND: u64`: This is the cost of each round of computation in gas units. Currently set to 1. -`INPUT_LENGTH: usize`: This specifies the required length of the input data, 213 bytes in this case. - -## Precompile Function - run - -The `run` function is the main entry point for the precompiled contract. It consumes an input byte slice and a gas limit, returning a `PrecompileResult`. This function handles input validation, gas cost computation, data manipulation, and the compression algorithm. - -It checks for correct input length and reads the final `block` flag. It then calculates the gas cost based on the number of rounds to be executed. If the gas cost exceeds the provided gas limit, it immediately returns an error. - -Once the validation and gas cost computation are complete, it parses the input into three components: state vector `h`, message `block` vector `m`, and offset counter `t`. - -Following this, it calls the `compress` function from the algo module, passing in the parsed input data and the final `block` flag. - -Finally, it constructs and returns the `PrecompileResult` containing the gas used and the output data. - -## Algorithm Module - algo - -The algo module encapsulates the technical implementation of the `Blake2b` hash function. It includes several key elements: - -Constants: - -- `SIGMA`: This 2D array represents the message word selection permutation used in each round of the algorithm. - -- `IV`: These are the initialization vectors for the `Blake2b` algorithm. - -- The `g` Function: This is the core function within each round of the `Blake2b` algorithm. It manipulates the state vector and mixes in the message data. - -- The `compress` Function: This is the main function that executes the rounds of the `g` function, handles the last `block` flag, and updates the state vector with the output of each round. diff --git a/documentation/src/crates/precompile/bn128.md b/documentation/src/crates/precompile/bn128.md deleted file mode 100644 index 72bfbba1f7..0000000000 --- a/documentation/src/crates/precompile/bn128.md +++ /dev/null @@ -1,13 +0,0 @@ -# bn128 curve - -[EIP-197](https://eips.ethereum.org/EIPS/eip-197) proposed the addition of precompiled contracts for a pairing function on a specific pairing-friendly elliptic curve. This complements [EIP-196](https://eips.ethereum.org/EIPS/eip-196) in enabling zkSNARKs verification within Ethereum smart contracts. zkSNARKs (Zero-Knowledge Succinct Non-Interactive Argument of Knowledge) technology can enhance privacy for Ethereum users due to its Zero-Knowledge property. Moreover, it may offer a scalability solution because of its succinctness and efficient verifiability property. - -Prior to this EIP, Ethereum's smart contract executions were fully transparent, limiting their use in cases involving private information, such as location, identity, or transaction history. While the Ethereum Virtual Machine (EVM) can theoretically use zkSNARKs, their implementation was presently too costly to fit within the block gas limit. [EIP-197](https://eips.ethereum.org/EIPS/eip-197) defines specific parameters for basic primitives that facilitate zkSNARKs. This allows for more efficient implementation, thereby reducing gas costs. - -Notably, setting these parameters doesn't restrict zkSNARKs' use-cases but actually enables the integration of zkSNARK research advancements without requiring further hard forks. Pairing functions, which enable a limited form of multiplicatively homomorphic operations necessary for zkSNARKs, could then be executed within the block gas limit through this precompiled contract. - -The code consists of three modules: `add`, `mul`, and `pair`. The add and `mul` modules implement elliptic curve point addition and scalar multiplication respectively on the bn128 curve, an elliptic curve utilized within Ethereum. Each module defines two versions of the contract, one for the Istanbul and another for the Byzantium Ethereum network upgrades. - -The pair module conducts the pairing check, an operation that enables comparison of two points on the elliptic curve, an essential part of many zero-knowledge proof systems, including zk-SNARKs. Again, two versions for Istanbul and Byzantium are defined. The `run_add`, `run_mul`, and run_pair functions embody the main implementations of the precompiled contracts, with each function accepting an input byte array, executing the appropriate elliptic curve operations, and outputting the results as a byte array. - -The code ensures the allocation of sufficient gas for each operation by stipulating gas costs as constants at the start of each module. It employs the bn library to carry out the actual bn128 operations. As the functions operate with byte arrays, the code features significant byte manipulation and conversion. Consequently, the code presents an implementation of specific elliptic curve operations utilized in Ethereum. diff --git a/documentation/src/crates/precompile/hash.md b/documentation/src/crates/precompile/hash.md deleted file mode 100644 index 2f54cf3740..0000000000 --- a/documentation/src/crates/precompile/hash.md +++ /dev/null @@ -1,7 +0,0 @@ -## SHA256 and RIPEMD160 - -REVM includes precompiled contracts for `SHA256` and `RIPEMD160`, cryptographic hashing functions integral for data integrity and security. The addresses for these precompiled contracts are `0x0000000000000000000000000000000000000002` for `SHA256` and `0x0000000000000000000000000000000000000003` for `RIPEMD160`. - -Each function (`sha256_run` and `ripemd160_run`) accepts two arguments, the input data to be hashed and the gas_limit representing the maximum amount of computational work permissible for the function. They both calculate the gas cost of the operation based on the input data length. If the computed cost surpasses the `gas_limit`, an `Error::OutOfGas` is triggered. - -The `sha256_run` function, corresponding to the `SHA256` precompiled contract, computes the `SHA256` hash of the input data. The `ripemd160_run` function computes the `RIPEMD160` hash of the input and pads it to match Ethereum's 256-bit word size. These precompiled contracts offer a computationally efficient way for Ethereum contracts to perform necessary cryptographic operations. diff --git a/documentation/src/crates/precompile/identity.md b/documentation/src/crates/precompile/identity.md deleted file mode 100644 index 64bd834818..0000000000 --- a/documentation/src/crates/precompile/identity.md +++ /dev/null @@ -1,7 +0,0 @@ -## Identity function - -This precompiled contract performs the identity function. In mathematics, an identity function is a function that always returns the same value as its argument. In this context, the contract takes the input data and returns it as is. This precompiled contract resides at the hardcoded Ethereum address `0x0000000000000000000000000000000000000004`. - -The `identity_run` function takes two arguments: input data, which it returns unaltered, and `gas_limit` which defines the maximum computational work the function is allowed to do. A linear gas cost calculation based on the size of the input data and two constants, `IDENTITY_BASE` (the base cost of the operation) and `IDENTITY_PER_WORD` (the cost per word), is performed. If the calculated gas cost exceeds the `gas_limit`, an `Error::OutOfGas` is returned. - -This identity function can be useful in various scenarios such as forwarding data or acting as a data validation check within a contract. Despite its simplicity, it contributes to the flexibility and broad utility of the Ethereum platform. diff --git a/documentation/src/crates/precompile/modexp.md b/documentation/src/crates/precompile/modexp.md deleted file mode 100644 index ed548e94ea..0000000000 --- a/documentation/src/crates/precompile/modexp.md +++ /dev/null @@ -1,9 +0,0 @@ -# Modular Exponentiation - -REVM also implements two versions of a precompiled contract (Modular Exponential operation), each corresponding to different Ethereum hard forks: Byzantium and Berlin. The contract addresses are `0x0000000000000000000000000000000000000005` for both versions, as they replaced each other in subsequent network upgrades. This operation is used for cryptographic computations and is a crucial part of Ethereum's toolkit. - -The byzantium_run and berlin_run functions each run the modular exponential operation using the `run_inner` function, but each uses a different gas calculation method: `byzantium_gas_calc` for Byzantium and `berlin_gas_calc` for Berlin. The gas calculation method used is chosen based on the Ethereum network's current version. The `run_inner` function is a core function that reads the inputs and performs the modular exponential operation. If the calculated gas cost is higher than the gas limit, an error `Error::OutOfGas` is returned. If all computations are successful, the function returns the result of the operation and the gas cost. - -The calculate_iteration_count function calculates the number of iterations required to compute the operation, based on the length and value of the exponent. The `read_u64_with_overflow` macro reads input data and checks for potential overflows. - -The byzantium_gas_calc function calculates the gas cost for the modular exponential operation as defined in the Byzantium version of the Ethereum protocol. The `berlin_gas_calc` function calculates the gas cost according to the Berlin version, as defined in [EIP-2565](https://eips.ethereum.org/EIPS/eip-2565). These two versions have different formulas to calculate the gas cost of the operation, reflecting the evolution of the Ethereum network. diff --git a/documentation/src/crates/precompile/point_evaluation.md b/documentation/src/crates/precompile/point_evaluation.md deleted file mode 100644 index df982cfe43..0000000000 --- a/documentation/src/crates/precompile/point_evaluation.md +++ /dev/null @@ -1,5 +0,0 @@ -# Point Evaluation Precompile - -This precompile is introduced in [EIP-4844](https://eips.ethereum.org/EIPS/eip-4844) and is used to verify KZG commitments of blobs. The precompile allows for efficient verification of commitments to blob transactions. Blob transactions contain a large amount of data that cannot be accessed by EVM execution, but has a commitment that can be accessed and verified. The EIP is designed to be forward compatible with [Danksharding](https://ethereum.org/en/roadmap/danksharding/) architecture while giving L2s access to cheaper L1 commitments. This precompiled contract resides at the hardcoded Ethereum address `0x000000000000000000000000000000000000000A`. - -A useful resource is the Python reference implementation for the precompile, which can be found [here](https://github.com/ethereum/consensus-specs/blob/86fb82b221474cc89387fa6436806507b3849d88/specs/deneb/polynomial-commitments.md). The implementation in REVM uses [c-kzg-4844](https://github.com/ethereum/c-kzg-4844), via its [foreign function interface](https://en.wikipedia.org/wiki/Foreign_function_interface) bindings, from the Ethereum Foundation. \ No newline at end of file diff --git a/documentation/src/crates/precompile/secp256k1.md b/documentation/src/crates/precompile/secp256k1.md deleted file mode 100644 index 4146448c1e..0000000000 --- a/documentation/src/crates/precompile/secp256k1.md +++ /dev/null @@ -1,9 +0,0 @@ -# Secp256k1 - -This implements Ethereum's precompiled contract `ECRECOVER`, an elliptic curve digital signature algorithm (ECDSA) recovery function that recovers the Ethereum address (public key hash) associated with a given signature. The implementation features two versions, each contingent on whether the secp256k1 cryptographic library is enabled, which depends on the build configuration. - -Both versions define a `secp256k1` module that includes an `ecrecover` function. This function takes a digital signature and a message as input, both represented as byte arrays, and returns the recovered Ethereum address. It performs this operation by using the signature to recover the original public key used for signing, then hashing this public key with `Keccak256`, Ethereum's chosen hash function. The hash is then truncated to match Ethereum's 20-byte address size. - -When `secp256k1` is not enabled, the ecrecover function uses the `k256` library to parse the signature, recover the public key, and perform the hashing. When `secp256k1` is enabled, the function uses the `secp256k1` library for these operations. Although both versions perform the same fundamental operation, they use different cryptographic libraries, which can offer different optimizations and security properties. - -The `ec_recover_run` function is the primary entry point for this precompiled contract. It parses the input to extract the message and signature, checks if enough gas is provided for execution, and calls the appropriate ecrecover function. The result of the recovery operation is returned as a `PrecompileResult`, a type that represents the outcome of a precompiled contract execution in Ethereum. diff --git a/documentation/src/crates/primitives.md b/documentation/src/crates/primitives.md deleted file mode 100644 index 45d57594ef..0000000000 --- a/documentation/src/crates/primitives.md +++ /dev/null @@ -1,40 +0,0 @@ -# Primitives - -This crate is a core component of the revm system. -It is designed to provide definitions for a range of types and structures commonly used throughout the application. -It is set up to be compatible with environments that do not include Rust's standard library, as indicated by the `no_std` attribute. - -### Modules: - -- [bytecode](./primitives/bytecode.md): This module provides functionality related to EVM bytecode. -- [constants](./primitives/constants.md): This module contains constant values used throughout the EVM implementation. -- [db](./primitives/database.md): This module contains data structures and functions related to the EVM's database implementation. -- [env](./primitives/environment.md): This module contains types and functions related to the EVM's environment, including block headers, and environment values. -- [precompile](./primitives/precompile.md): This module contains types related to Ethereum's precompiled contracts. -- [result](./primitives/result.md): This module provides types for representing execution results and errors in the EVM. -- [specification](./primitives/specifications.md): This module defines types related to Ethereum specifications (also known as hard forks). -- [state](./primitives/state.md): This module provides types and functions for managing Ethereum state, including accounts and storage. -- [utilities](./primitives/utils.md): This module provides utility functions used in multiple places across the EVM implementation. -- [kzg](./primitives/kzg.md): This module provides types and functions related to KZG commitment, it is empolyed visibly in the Point Evalution Precompile. - -### External Crates: - -- `alloc`: The alloc crate provides types for heap allocation. -- `bitvec`: The bitvec crate provides a data structure to handle sequences of bits. -- `bytes`: The bytes crate provides utilities for working with bytes. -- `hex`: The hex crate provides utilities for encoding and decoding hexadecimal. -- `hex_literal`: The hex_literal crate provides a macro for including hexadecimal data directly in the source code. -- `hashbrown`: The hashbrown crate provides high-performance hash map and hash set data structures. -- `ruint`: The ruint crate provides types and functions for big unsigned integer arithmetic. -- `c-kzg`: A minimal implementation of the Polynomial Commitments API for EIP-4844, written in C. (With rust bindings) - -### Re-exported Types: - -- `Address`: A type representing a 160-bit (or 20-byte) array, typically used for Ethereum addresses. -- `B256`: A type representing a 256-bit (or 32-byte) array, typically used for Ethereum hashes or integers. -- `Bytes`: A type representing a sequence of bytes. -- `U256`: A 256-bit unsigned integer type from the `ruint` crate. -- `HashMap` and `HashSet`: High-performance hash map and hash set data structures from the hashbrown crate. - -Re-exported Modules: -All types, constants, and functions from the `bytecode`, `constants`, `env`, `precompile`, `result`, `specification`, `state`, `utilities`, `KzgSettings`, `EnvKzgSettings`, `trusted_setup_points` types and methods were all re-exported, allowing users to import these items directly from the `primitives` crate. diff --git a/documentation/src/crates/primitives/bits.md b/documentation/src/crates/primitives/bits.md deleted file mode 100644 index 6378c0730a..0000000000 --- a/documentation/src/crates/primitives/bits.md +++ /dev/null @@ -1,17 +0,0 @@ -# Bits - -> NOTE: This module's types have been replaced by [`alloy_primitives`](https://github.com/alloy-rs/core)'s `Address` and `FixedBytes`. - -This module houses the definitions for fixed-size bit arrays, `Address` and `B256`, showcasing its role in managing bits-related operations, to represent 256-bit and 160-bit fixed-size hashes respectively. These are defined using the `construct_fixed_hash!` macro from the `fixed_hash` crate. - -The `AsRef` and `Deref` traits from `derive_more` crate are derived for both of these structures, providing convenient methods for converting these types to and from references of their underlying data. - -The `Arbitrary` trait from the `arbitrary` crate and the `PropTestArbitrary` trait from `proptest_derive` crate are derived conditionally when either testing or the "arbitrary" feature is enabled. - -The code also provides conversions between `B256`, `Address` and various other types such as `u64`, `primitive_types::H256`, `primitive_types::H160`, `primitive_types::U256`, and `ruint::aliases::U256`. The `impl` From blocks specify how to convert from one type to another. - -`impl_fixed_hash_conversions!` macro is used to define conversions between `B256` and `Address` types. - -If the "serde" feature is enabled, the Serialize and Deserialize traits from the serde crate are implemented for `B256` and `Address` using a custom serialization method that outputs/reads these types as hexadecimal strings. This includes a custom serialization/deserialization module for handling hexadecimal data. - -This module (serialize) provides functionality to serialize a slice of bytes to a hexadecimal string, and deserialize a hexadecimal string to a byte vector with size checks. It handles both "0x" prefixed and non-prefixed hexadecimal strings. It also provides functions to convert raw bytes to hexadecimal strings and vice versa, handling potential errors related to non-hexadecimal characters. The module also defines the `ExpectedLen` enum which is used to specify the expected length of the byte vectors during deserialization. diff --git a/documentation/src/crates/primitives/bytecode.md b/documentation/src/crates/primitives/bytecode.md deleted file mode 100644 index 5696488c23..0000000000 --- a/documentation/src/crates/primitives/bytecode.md +++ /dev/null @@ -1,9 +0,0 @@ -# Bytecode - -This module defines structures and methods to manipulate Ethereum bytecode and manage its state. It's built around three main components: `JumpTable`, `BytecodeState`, and `Bytecode`. - -The `JumpTable` structure stores a map of valid `jump` destinations within a given Ethereum bytecode sequence. It is essentially an `Arc` (Atomic Reference Counter) wrapping a `BitVec` (bit vector), which can be accessed and modified using the defined methods, such as `as_slice()`, `from_slice()`, and `is_valid()`. - -The `BytecodeState` is an enumeration, capturing the three possible states of the bytecode: `Raw`, `Checked`, and `Analysed`. In the `Checked` and `Analysed` states, additional data is provided, such as the length of the bytecode and, in the `Analysed` state, a `JumpTable`. - -The `Bytecode` struct holds the actual bytecode, its hash, and its current state (`BytecodeState`). It provides several methods to interact with the bytecode, such as getting the length of the bytecode, checking if it's empty, retrieving its state, and converting the bytecode to a checked state. It also provides methods to create new instances of the `Bytecode` struct in different states. diff --git a/documentation/src/crates/primitives/constants.md b/documentation/src/crates/primitives/constants.md deleted file mode 100644 index 893b067f09..0000000000 --- a/documentation/src/crates/primitives/constants.md +++ /dev/null @@ -1,7 +0,0 @@ -# Constants - -Holds constant values used throughout the system. This module defines important constants that help limit and manage resources in the Ethereum Virtual Machine (EVM). The constants include `STACK_LIMIT` and `CALL_STACK_LIMIT`, which restrict the size of the interpreter stack and the EVM call stack, respectively. Both are set to 1024. - -The module also defines `MAX_CODE_SIZE`, which is set according to [EIP-170](https://eips.ethereum.org/EIPS/eip-170)'s specification. [EIP-170](https://eips.ethereum.org/EIPS/eip-170) imposes a maximum limit on the contract code size to mitigate potential vulnerabilities and inefficiencies in Ethereum. Without this cap, the act of calling a contract can trigger costly operations that scale with the size of the contract's code. These operations include reading the code from disk, preprocessing the code for VM execution, and adding data to the block's proof-of-validity. By implementing `MAX_CODE_SIZE` (set to `0x6000` or ~25kb), the EVM ensures that the cost of these operations remains manageable, even under high gas levels that could be encountered in the future. [EIP-170](https://eips.ethereum.org/EIPS/eip-170)'s implementation thus offers crucial protection against potential DoS attacks and maintains efficiency, especially for future light clients verifying proofs of validity or invalidity. - -Another constant defined here is `MAX_INITCODE_SIZE`, set in accordance with [EIP-3860](https://eips.ethereum.org/EIPS/eip-3860). [EIP-3860](https://eips.ethereum.org/EIPS/eip-3860) extends EIP-170 by introducing a maximum size limit for initialization code (initcode) and enforcing a gas charge for every 32-byte chunk of initcode, to account for the cost of jump destination analysis. Before [EIP-3860](https://eips.ethereum.org/EIPS/eip-3860), initcode analysis during contract creation wasn't metered, nor was there an upper limit for its size, resulting in potential inefficiencies and vulnerabilities. By setting `MAX_INITCODE_SIZE` to 2 \* `MAX_CODE_SIZE` and introducing the said gas charge, [EIP-3860](https://eips.ethereum.org/EIPS/eip-3860) ensures that the cost of initcode analysis scales proportionately with its size. This constant, therefore, facilitates fair charging, simplifies EVM engines by setting explicit limits, and helps to create an extendable cost system for the future. diff --git a/documentation/src/crates/primitives/database.md b/documentation/src/crates/primitives/database.md deleted file mode 100644 index bf7fbbfeee..0000000000 --- a/documentation/src/crates/primitives/database.md +++ /dev/null @@ -1,12 +0,0 @@ -# Database - -Responsible for database operations. This module is where the blockchain's state persistence is managed. -The module defines three primary traits (`Database`, `DatabaseCommit`, and `DatabaseRef`), a structure `RefDBWrapper`, and their associated methods. - -The `Database` trait defines an interface for mutable interaction with the database. It has a generic associated type `Error` to handle different kinds of errors that might occur during these interactions. It provides methods to retrieve basic account information (`basic`), retrieve account code by its hash (`code_by_hash`), retrieve the storage value of an address at a certain index (`storage`), and retrieve the block hash for a certain block number (`block_hash`). - -The `DatabaseCommit` trait defines a single `commit` method for committing changes to the database. The changes are a map between Ethereum-like addresses (type `Address`) and accounts. - -The `DatabaseRef` trait is similar to the `Database` trait but is designed for read-only or immutable interactions. It has the same `Error` associated type and the same set of methods as `Database`, but these methods take `&self` instead of `&mut self`, indicating that they do not mutate the database. - -The `RefDBWrapper` structure is a wrapper around a reference to a `DatabaseRef` type. It implements the `Database` trait, essentially providing a way to treat a `DatabaseRef` as a `Database` by forwarding the `Database` methods to the corresponding `DatabaseRef` methods. diff --git a/documentation/src/crates/primitives/environment.md b/documentation/src/crates/primitives/environment.md deleted file mode 100644 index 8e33181527..0000000000 --- a/documentation/src/crates/primitives/environment.md +++ /dev/null @@ -1,5 +0,0 @@ -# Environment - -A significant module that manages the execution environment of the EVM. The module contains objects and methods associated with processing transactions and blocks within such a blockchain environment. It defines several structures: `Env`, `BlockEnv`, `TxEnv`, `CfgEnv`, `TransactTo`, and `CreateScheme`. These structures contain various fields representing the block data, transaction data, environmental configurations, transaction recipient details, and the method of contract creation respectively. - -The `Env` structure, which encapsulates the environment of the EVM, contains methods for calculating effective gas prices and for validating block and transaction data. It also checks transactions against the current state of the associated account, which is necessary to validate the transaction's nonce and the account balance. Various Ethereum Improvement Proposals (EIPs) are also considered in these validations, such as [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559) for the base fee, [EIP-3607](https://eips.ethereum.org/EIPS/eip-3607) for rejecting transactions from senders with deployed code, and [EIP-3298](https://eips.ethereum.org/EIPS/eip-3298) for disabling gas refunds. The code is structured to include optional features and to allow for changes in the EVM specifications. diff --git a/documentation/src/crates/primitives/kzg.md b/documentation/src/crates/primitives/kzg.md deleted file mode 100644 index 7e7e6316d3..0000000000 --- a/documentation/src/crates/primitives/kzg.md +++ /dev/null @@ -1,12 +0,0 @@ -# KZG - -With the introduction of [EIP4844](https://eips.ethereum.org/EIPS/eip-4844), this use of blobs for a more efficent short term storage is employed, the validity of this blob stored in the consensus layer is verified using the `Point Evaluation` pre-compile, a fancy way of verifing that and evaluation at a given point of a commited polynomial is vaild, in a much more bigger scale, implies that `Data is Available`. - -This module houses; - -1. `KzgSettings`: Stores the setup and parameters needed for computing and verify KZG proofs. - - The `KZG` premitive provides a default `KZGSettings` obtained from [this]( https://ceremony.ethereum.org/) trusted setup ceremony, a provision is also made for using a custom `KZGSettings` if need be, this is available in the `env.cfg`. - - -2. `trusted_setup_points`: This module contains functions and types used for parsing and utilizing the [Trusted Setup]( https://ceremony.ethereum.org/) for the `KzgSettings`. \ No newline at end of file diff --git a/documentation/src/crates/primitives/log.md b/documentation/src/crates/primitives/log.md deleted file mode 100644 index accd1be6cc..0000000000 --- a/documentation/src/crates/primitives/log.md +++ /dev/null @@ -1,11 +0,0 @@ -# Log - -> NOTE: This module's types have been replaced by [`alloy_primitives`](https://github.com/alloy-rs/core)'s `Log` and `LogData`. - -This piece of Rust code defines a structure called Log which represents an Ethereum log entry. These logs are integral parts of the Ethereum network and are typically produced by smart contracts during execution. Each Log has three components: - -- `address`: This field represents the address of the log originator, typically the smart contract that generated the log. The `Address` data type signifies a 160-bit Ethereum address. - -- `topics`: This field is a vector of `B256` type. In Ethereum, logs can have multiple '`topics`'. These are events that can be used to categorize and filter logs. The `B256` type denotes a 256-bit hash, which corresponds to the size of a topic in Ethereum. - -- `data`: This is the actual data of the log entry. The Bytes type is a dynamically-sized byte array, and it can contain any arbitrary data. It contains additional information associated with the event logged by a smart contract. diff --git a/documentation/src/crates/primitives/precompile.md b/documentation/src/crates/primitives/precompile.md deleted file mode 100644 index 965068d4d8..0000000000 --- a/documentation/src/crates/primitives/precompile.md +++ /dev/null @@ -1,9 +0,0 @@ -# precompile - -This module implements precompiled contracts in the EVM, adding a layer of pre-set functionalities. These are documented in more detail in the next section. The module defines the types and the enum that are used to handle precompiled contracts. - -`PrecompileResult`: This is a type alias for a `Result` type. The `Ok` variant of this type contains a tuple (`u64`, `Vec`), where the `u64` integer likely represents gas used by the precompiled contract, and the `Vec` holds the output data. The Err variant contains a PrecompileError. - -`StandardPrecompileFn` and `CustomPrecompileFn`: These are type aliases for function pointers. Both functions take a byte slice and a `u64` (probably the available gas) as arguments and return a `PrecompileResult`. The naming suggests that the former refers to built-in precompiled contracts, while the latter may refer to custom, user-defined contracts. - -`PrecompileError`: This is an enumeration (enum) which describes the different types of errors that could occur while executing a precompiled contract. The listed variants suggest these errors are related to gas consumption, `Blake2` hash function, modular exponentiation ("`Modexp`"), and `Bn128`, which is a specific elliptic curve used in cryptography. diff --git a/documentation/src/crates/primitives/result.md b/documentation/src/crates/primitives/result.md deleted file mode 100644 index 647a35aa48..0000000000 --- a/documentation/src/crates/primitives/result.md +++ /dev/null @@ -1,11 +0,0 @@ -# Result - -At the core of this module is the `ExecutionResult` enum, which describes the possible outcomes of an EVM execution: `Success`, `Revert`, and `Halt`. `Success` represents a successful transaction execution, and it holds important information such as the reason for `success` (an Eval enum), the gas used, the gas refunded, a vector of logs (`Vec`), and the output of the execution. This aligns with the stipulation in [EIP-658](https://eips.ethereum.org/EIPS/eip-658) that introduces a status code in the receipt of a transaction, indicating whether the top-level call was successful or failed. - -`Revert` represents a transaction that was reverted by the `REVERT` opcode without spending all of its gas. It stores the gas used and the output. `Halt` represents a transaction that was reverted for various reasons and consumed all its gas. It stores the reason for halting (a `Halt` enum) and the gas used. - -The `ExecutionResult` enum provides several methods to extract important data from an execution result, such as `is_success()`, `logs()`, `output()`, `into_output()`, `into_logs()`, and `gas_used()`. These methods facilitate accessing key details of a transaction execution. - -The `EVMError` and `InvalidTransaction` enums handle different kinds of errors that can occur in an EVM, including database errors, errors specific to the transaction itself, and errors that occur due to issues with gas, among others. - -The `Output` enum handles different kinds of outputs of an EVM execution, including `Call` and `Create`. This is where the output data from a successful execution or a reverted transaction is stored. diff --git a/documentation/src/crates/primitives/specifications.md b/documentation/src/crates/primitives/specifications.md deleted file mode 100644 index 7b3873fb02..0000000000 --- a/documentation/src/crates/primitives/specifications.md +++ /dev/null @@ -1,15 +0,0 @@ -# Specifications - -Holds data related to Ethereum's technical specifications, serving as a reference point for Ethereum's rules and procedures obtained from the [Ethereum execution specifications](https://github.com/ethereum/execution-specs). The module is primarily used to enumerate and handle Ethereum's network upgrades or "hard forks" within the Ethereum Virtual Machine (EVM). These hard forks are referred to as `SpecId` in the code, representing different phases of Ethereum's development. - -The `SpecId` enum assigns a unique numerical value and a unique string identifier to each Ethereum hard fork. These upgrades range from the earliest ones such as `FRONTIER` and `HOMESTEAD`, through to the most recent ones, including `LONDON`, `MERGE`, `SHANGHAI`, and `LATEST`. - -The code also includes conversion methods such as `try_from_u8()` and `from()`. The former attempts to create a `SpecId` from a given u8 integer, while the latter creates a `SpecId` based on a string representing the name of the hard fork. - -The `enabled()` method in `SpecId` is used to check if one spec is enabled on another, considering the order in which the hard forks were enacted. - -The `Spec` trait is used to abstract the process of checking whether a given spec is enabled. It only has one method, `enabled()`, and a constant `SPEC_ID`. - -The module then defines various `Spec` structs, each representing a different hard fork. These structs implement the `Spec` trait and each struct's `SPEC_ID` corresponds to the correct `SpecId` variant. - -This module provides the necessary framework to handle and interact with the different Ethereum hard forks within the EVM, making it possible to handle transactions and contracts differently depending on which hard fork rules apply. It also simplifies the process of adapting to future hard forks by creating a new `SpecId` and corresponding `Spec` struct. diff --git a/documentation/src/crates/primitives/state.md b/documentation/src/crates/primitives/state.md deleted file mode 100644 index d12a86f001..0000000000 --- a/documentation/src/crates/primitives/state.md +++ /dev/null @@ -1,15 +0,0 @@ -# State - -Manages the EVM's state, including account balances, contract storage, and more. - -This module models an Ethereum account and its state, which includes balance, nonce, code, storage, and status flags. The module also includes methods for interacting with the account's state. - -The `Account` struct includes fields for info (of type `AccountInfo`), storage (a `HashMap` mapping a `U256` value to a `StorageSlot`), and status (of type `AccountStatus`). `AccountInfo` represents the basic information about an Ethereum account, including its balance (`balance`), nonce (`nonce`), code (`code`), and a hash of its code (`code_hash`). - -The `AccountStatus` is a set of bitflags, representing the state of the account. The flags include `Loaded`, `Created`, `SelfDestructed`, `Touched`, and `LoadedAsNotExisting`. The different methods provided within the `Account` struct allow for manipulating these statuses. - -The `StorageSlot` struct represents a storage slot in the Ethereum Virtual Machine. It holds an `original_value` and a `present_value` and includes methods for creating a new slot and checking if the slot's value has been modified. - -Two `HashMap` type aliases are created: `State` and `Storage`. `State` maps from a `Address` address to an `Account` and `Storage` maps from a `U256` key to a `StorageSlot`. - -The module includes a series of methods implemented for `Account` to manipulate and query the account's status. These include methods like `mark_selfdestruct`, `unmark_selfdestruct`, `is_selfdestructed`, `mark_touch`, `unmark_touch`, `is_touched`, `mark_created`, `is_newly_created`, `is_empty`, and `new_not_existing`. diff --git a/documentation/src/crates/primitives/utils.md b/documentation/src/crates/primitives/utils.md deleted file mode 100644 index 5819c091f9..0000000000 --- a/documentation/src/crates/primitives/utils.md +++ /dev/null @@ -1,7 +0,0 @@ -# Utilities - -This Rust module provides utility functions and constants for handling Keccak hashing (used in Ethereum) and creating Ethereum addresses via legacy and `CREATE2` methods. It also includes serialization and deserialization methods for hexadecimal strings representing byte arrays. - -The `KECCAK_EMPTY` constant represents the Keccak-256 hash of an empty input. - -The `keccak256` function takes a byte slice input and returns its Keccak-256 hash as a `B256` value. diff --git a/documentation/src/crates/revm.md b/documentation/src/crates/revm.md deleted file mode 100644 index 2ad609f40a..0000000000 --- a/documentation/src/crates/revm.md +++ /dev/null @@ -1,39 +0,0 @@ -# Rust Ethereum Virtual Machine (revm) - -The `evm` crate is focused on the implementation of Ethereum Virtual Machine (EVM) including call loop and host implementation, database handling, state journaling and powerful logic handlers that can be overwritten. -This crate pulls Primitives, Interpreter and Precompiles together to deliver the rust evm. - -The starting point for reading the documentation is [`Evm`](./revm/evm.md), that is main structure of EVM. -Then, you can read about the [`EvmBuilder`](./revm/builder.md) that is used to create the `Evm` and modify it. -After, you can read about the [`Handler`](./revm/handler.md) that is used to modify the logic of the Evm, and it will tie with how Evm introspection can be done. -Finally, you can read about the [`Inspector`](./revm/inspector.md), a legacy interface for inspecting execution that is now repurposed as a handler register example. - -### Modules: - -- `evm`: This is main module that executes EVM calls. -- `builder`: - This module builds the Evm, sets database, handlers and other parameters. - Here is where we set handlers for specific fork or external state for inspection. -- `db`: - This module includes structures and functions for database interaction. - It is a glue between EVM and database. - It transforms or aggregates the EVM changes. -- `inspector`: - This module introduces the `Inspector` trait and its implementations for observing the EVM execution. - This was the main way to inspect EVM execution before the Builder and Handlers were introduced. - It is still enabled through the Builder. -- `journaled_state`: This module manages the state of the EVM and implements a journaling system to handle changes and reverts. - -### Re-exported Modules: - -- `revm_precompile`: Crate that provides precompiled contracts used in the EVM implementation. -- `revm_interpreter`: Crate that provides execution engine for EVM opcodes. -- `revm_interpreter::primitives`: This module from the `revm_interpreter` crate provides primitive types and other functionality used in the EVM implementation. - -### Re-exported Types: - -- `Database`, `DatabaseCommit`, `InMemoryDB`: These types from the `db` module are re-exported for handling the database operations. -- `EVM`: The `EVM` struct from the `evm` module is re-exported, serving as the main interface to the EVM implementation. -- `EvmContext`: The `EvmContext` struct from the `context` module is re-exported, providing data structures to encapsulate EVM execution data. -- `JournalEntry`, `JournaledState`: These types from the `journaled_state` module are re-exported, providing the journaling system for the EVM state. -- `inspectors`, `Inspector`: The `Inspector` trait and its implementations from the `inspector` module are re-exported for observing the EVM execution. diff --git a/documentation/src/crates/revm/builder.md b/documentation/src/crates/revm/builder.md deleted file mode 100644 index 2414bb8964..0000000000 --- a/documentation/src/crates/revm/builder.md +++ /dev/null @@ -1,164 +0,0 @@ - -# Evm Builder - -The builder creates or modifies the EVM and applies different handlers. -It allows setting external context and registering handler custom logic. - -The revm `Evm` consists of `Context` and `Handler`. -`Context` is additionally split between `EvmContext` (contains generic `Database`) and `External` context (generic without restrain). -Read [evm](./evm.md) for more information on the internals. - -The `Builder` ties dependencies between generic `Database`, `External` context and `Spec`. -It allows handle registers to be added that implement logic on those generics. -As they are interconnected, setting `Database` or `ExternalContext` resets handle registers, so builder stages are introduced to mitigate those misuses. - -Simple example of using `EvmBuilder`: - -```rust,ignore - use crate::evm::Evm; - - // build Evm with default values. - let mut evm = Evm::builder().build(); - let output = evm.transact(); -``` - -## Builder Stages - -There are two builder stages that are used to mitigate potential misuse of the builder: - * `SetGenericStage`: Initial stage that allows setting the database and external context. - * `HandlerStage`: Allows setting the handler registers but is explicit about setting new generic type as it will void the handler registers. - -Functions from one stage are just renamed functions from other stage, it is made so that user is more aware of what underlying function does. -For example, in `SettingDbStage` we have `with_db` function while in `HandlerStage` we have `reset_handler_with_db`, both of them set the database but the latter also resets the handler. -There are multiple functions that are common to both stages such as `build`. - -### Builder naming conventions -In both stages we have: - * `build` creates the Evm. - * `spec_id` creates new mainnet handler and reapplies all the handler registers. - * `modify_*` functions are used to modify the database, external context or Env. - * `clear_*` functions allows setting default values for Environment. - * `append_handler_register_*` functions are used to push handler registers. - This will transition the builder to the `HandlerStage`. - -In `SetGenericStage` we have: - * `with_*` are found in `SetGenericStage` and are used to set the generics. - -In `HandlerStage` we have: - * `reset_handler_with_*` is used if we want to change some of the generic types this will reset the handler registers. - This will transition the builder to the `SetGenericStage`. - -# Creating and modification of Evm - -Evm implements functions that allow using the `EvmBuilder` without even knowing that it exists. -The most obvious one is `Evm::builder()` that creates a new builder with default values. - -Additionally, a function that is very important is `evm.modify()` that allows modifying the Evm. -It returns a builder, allowing users to modify the Evm. - -# Examples -The following example uses the builder to create an `Evm` with inspector: -```rust,ignore - use crate::{ - db::EmptyDB, Context, EvmContext, inspector::inspector_handle_register, inspectors::NoOpInspector, Evm, - }; - - // Create the evm. - let evm = Evm::builder() - .with_db(EmptyDB::default()) - .with_external_context(NoOpInspector) - // Register will modify Handler and call NoOpInspector. - .append_handler_register(inspector_handle_register) - // .with_db(..) does not compile as we already locked the builder generics, - // alternative fn is reset_handler_with_db(..) - .build(); - - // Execute the evm. - let output = evm.transact(); - - // Extract evm context. - let Context { - external, - evm: EvmContext { db, .. }, - } = evm.into_context(); -``` - -The next example changes the spec id and environment of an already built evm. -```rust,ignore - use crate::{Evm,SpecId::BERLIN}; - - // Create default evm. - let evm = Evm::builder().build(); - - // Modify evm spec. - let evm = evm.modify().with_spec_id(BERLIN).build(); - - // Shortcut for above. - let mut evm = evm.modify_spec_id(BERLIN); - - // Execute the evm. - let output1 = evm.transact(); - - // Example of modifying the tx env. - let mut evm = evm.modify().modify_tx_env(|env| env.gas_price = 0.into()).build(); - - // Execute the evm with modified tx env. - let output2 = evm.transact(); -``` - -Example of adding custom precompiles to Evm. - -```rust,ignore -use super::SpecId; -use crate::{ - db::EmptyDB, - inspector::inspector_handle_register, - inspectors::NoOpInspector, - primitives::{Address, Bytes, ContextStatefulPrecompile, ContextPrecompile, PrecompileResult}, - Context, Evm, EvmContext, -}; -use std::sync::Arc; - -struct CustomPrecompile; - -impl ContextStatefulPrecompile, ()> for CustomPrecompile { - fn call( - &self, - _input: &Bytes, - _gas_price: u64, - _context: &mut EvmContext, - _extctx: &mut (), - ) -> PrecompileResult { - Ok((10, Bytes::new())) - } -} -fn main() { - let mut evm = Evm::builder() - .with_empty_db() - .with_spec_id(SpecId::HOMESTEAD) - .append_handler_register(|handler| { - let precompiles = handler.pre_execution.load_precompiles(); - handler.pre_execution.load_precompiles = Arc::new(move || { - let mut precompiles = precompiles.clone(); - precompiles.extend([( - Address::ZERO, - ContextPrecompile::ContextStateful(Arc::new(CustomPrecompile)), - )]); - precompiles - }); - }) - .build(); - - evm.transact().unwrap(); -} - -``` - -## Appending handler registers - -Handler registers are simple functions that allow modifying the `Handler` logic by replacing the handler functions. -They are used to add custom logic to the evm execution but as they are free to modify the `Handler` in any form they want. -There may be conflicts if handlers that override the same function are added. - -The most common use case for adding new logic to `Handler` is `Inspector` that is used to inspect the execution of the evm. -Example of this can be found in [`Inspector`](./inspector.md) documentation. diff --git a/documentation/src/crates/revm/evm.md b/documentation/src/crates/revm/evm.md deleted file mode 100644 index 264e890d06..0000000000 --- a/documentation/src/crates/revm/evm.md +++ /dev/null @@ -1,56 +0,0 @@ -# EVM - -`Evm` is the primary structure that implements the Ethereum Virtual Machine (EVM), a stack-based virtual machine that executes Ethereum smart contracts. - -## What is inside - -It is consisting of two main parts the `Context` and the `Handler`. `Context` represent the state that is needed for execution and `Handler` contains list of functions that act as a logic. - -`Context` is additionally split between `EvmContext` and `External` context. `EvmContext` is internal and contains `Database`, `Environment`, `JournaledState` and `Precompiles`. And `External` context is fully generic without any trait restrains and its purpose is to allow custom handlers to save state in runtime or allows hooks to be added (For example external contexts can be a Inspector), more on its usage can be seen in [`EvmBuilder`](./builder.md). - -`Evm` implements the [`Host`](./../interpreter/host.md) trait, which defines an interface for the interaction of the EVM Interpreter with its environment (or "host"), encompassing essential operations such as account and storage access, creating logs, and invoking sub calls and selfdestruct. - -Data structures of block and transaction can be found inside `Environment`. And more information on journaled state can be found in [`JournaledState`](../revm/journaled_state.md) documentation. - -## Runtime - -Runtime consists of list of functions from `Handler` that are called in predefined order. -They are grouped by functionality on `Verification`, `PreExecution`, `Execution`, `PostExecution` and `Instruction` functions. -Verification function are related to the pre-verification of set `Environment` data. -Pre-/Post-execution functions deduct and reward caller beneficiary. -And `Execution` functions handle initial call and creates and sub calls. -`Instruction` functions are part of the instruction table that is used inside `Interpreter` to execute opcodes. - -The `Evm` execution runs **two** loops: - - -### Call loop -The first loop is call loop that everything starts with, it creates call frames, handles subcalls, it returns outputs and calls `Interpreter` loop to execute bytecode instructions. -It is handled by `ExecutionHandler`. - -The first loop implements a stack of `Frames`. -It is responsible for handling sub calls and its return outputs. -At the start, `Evm` creates `Frame` containing `Interpreter` and starts the loop. - -The `Interpreter` returns the `InterpreterAction` which can be: -- `Return`: This interpreter finished its run. - `Frame` is popped from the stack and its return value is pushed to the parent `Frame` stack. -- `SubCall`/`SubCreate`: A new `Frame` needs to be created and pushed to the stack. - A new `Frame` is created and pushed to the stack and the loop continues. - When the stack is empty, the loop finishes. - -### Interpreter loop -The second loop is the `Interpreter` loop which is called by the call loop and loops over bytecode opcodes and executes instructions based on the `InstructionTable`. -It is implemented in the [`Interpreter`](../interpreter.md) crate. - -To dive deeper into the `Evm` logic check [`Handler`](./handler.md) documentation. - -# Functionalities - -The function of `Evm` is to start execution, but setting up what it is going to execute is done by `EvmBuilder`. -The main functions of the builder are: -* `preverify` - that only pre-verifies transaction information. -* `transact preverified` - is next step after pre-verification that executes transactions. -* `transact` - it calls both preverifies and executes transactions. -* `builder` and `modify` functions - allow building or modifying the `Evm`, more on this can be found in [`EvmBuilder`](./builder.md) documentation. `builder` is the main way of creating `Evm` and `modify` allows you to modify parts of it without dissolving `Evm`. -* `into_context` - is used when we want to get the `Context` from `Evm`. diff --git a/documentation/src/crates/revm/handler.md b/documentation/src/crates/revm/handler.md deleted file mode 100644 index 9222d8ba9e..0000000000 --- a/documentation/src/crates/revm/handler.md +++ /dev/null @@ -1,111 +0,0 @@ -# Handler - -This is the logic part of the Evm. -It contains the Specification ID, list of functions that do the logic and list of registers that can change behavior of the Handler when it is build. - -Functions can be grouped in five categories and are marked in that way in the code: -* Validation functions: [`ValidationHandler`](https://github.com/bluealloy/revm/blob/main/crates/revm/src/handler/handle_types/validation.rs) -* Pre-execution functions: [`PreExecutionHandler`](https://github.com/bluealloy/revm/blob/main/crates/revm/src/handler/handle_types/pre_execution.rs) -* Execution functions: [`ExecutionHandler`](https://github.com/bluealloy/revm/blob/main/crates/revm/src/handler/handle_types/execution.rs) -* Post-execution functions: [`PostExecutionHandler`](https://github.com/bluealloy/revm/blob/main/crates/revm/src/handler/handle_types/post_execution.rs) -* Instruction table: [`InstructionTable`](https://github.com/bluealloy/revm/blob/main/crates/interpreter/src/opcode.rs) - -### Handle Registers - -This is a simple function that is used to modify handler functions. -The amazing thing about them is that they can be done over generic external type. -For example, this allows to have a register over trait that allows to add hooks to any type that implements the trait. -That trait can be a `GetInspector` trait, so any implementation is able to register inspector-related functions. -`GetInspector` is implemented on every `Inspector` and it is used inside the `EvmBuilder` to change behavior of the default mainnet Handler. - -Handle registers are set in `EvmBuilder`. -The order of the registers is important as they are called in the order they are registered. -It matters if register overrides the previous handle or just wraps it, overriding handle can disrupt the logic of previous registered handles. - -Registers are very powerful as they allow modification of any part of the Evm and with additional of the `External` context it becomes a powerful combo. -A simple example is to register new pre-compiles for the Evm. - -### ValidationHandler - -Consists of functions that are used to validate transaction and block data. -They are called before the execution of the transaction, to check whether the (`Environment`) data is valid. -They are called in the following order: -* `validate_env`: - Verifies if all data is set in `Environment` and if valid, for example if `gas_limit` is smaller than block `gas_limit`. -* `validate_initial_tx_gas`: - Calculates initial gas needed for the transaction to be executed and checks if it is less than the transaction gas_limit. - Note that this does not touch the `Database` or state. -* `validate_tx_against_state`: - Loads the caller account and checks their information. - Among them the nonce, if there is enough balance to pay for max gas spent and balance transferred. - -### PreExecutionHandler - -Consists of functions that are called before execution. -They are called in the following order: -* `load`: - Loads access list and beneficiary from `Database`. Cold load is done here. -* `load_precompiles`: - Retrieves the precompiles for the given spec ID. - More info: [precompile](../precompile.md). -* `deduct_caller`: - Deducts values from the caller to calculate the maximum amount of gas that can be spent on the transaction. - This loads the caller account from the `Database`. - -### ExecutionHandler - -Consists of functions that handle the execution of the transaction and the stack of the call frames. - -* `call`: - Called on every frame. - It creates a new call frame or returns the frame result (the frame result is only returned when calling `precompile`). - If `FrameReturn` is returned, then the next function that is called is `insert_call_outcome`. - -* `call_return`: - Called after call frame returns from execution. - It is used to calculate the gas that is returned from the frame and create the `FrameResult` that is used to apply the outcome to parent frame in `insert_call_outcome`. - -* `insert_call_outcome`: - Inserts the call outcome to the parent frame. - It is called on every frame that is created except the first one. - For the first frame we use `last_frame_return`. - -* `create`: - Creates new create call frame, create new account and execute bytecode that outputs the code of the new account. - -* `create_return`: - This handler is called after every frame is executed (Expect first). - It will calculate the gas that is returned from the frame and apply output to the parent frame. - -* `insert_create_outcome`: - Inserts the outcome of a call into the virtual machine's state. - -* `last_frame_return`: - This handler is called after last frame is returned. - It is used to calculate the gas that is returned from the first frame and incorporate transaction gas limit (the first frame has limit `gas_limit - initial_gas`). - -### InstructionTable - -This is a list of 256 function pointers that are used to execute instructions. -They have two types, first is simple function that is faster and second is `BoxedInstruction` that has a small performance penalty but allows to capture the data. -Look at the Interpreter documentation for more information. - -### PostExecutionHandler - -Is a list of functions that are called after the execution. They are called in the following order: - -* `reimburse_caller`: - Reimburse the caller with gas that was not spent during the execution of the transaction. - Or balance of gas that needs to be refunded. - -* `reward_beneficiary`: - Reward the beneficiary with the fee that was paid for the transaction. - -* `output`: - Returns the state changes and the result of the execution. - -* `end`: - Always called after transaction. End handler will not be called if validation fails. - -* `clear`: - Clears journal state and error and it is always called for the cleanup. \ No newline at end of file diff --git a/documentation/src/crates/revm/inspector.md b/documentation/src/crates/revm/inspector.md deleted file mode 100644 index d9bdfe8b65..0000000000 --- a/documentation/src/crates/revm/inspector.md +++ /dev/null @@ -1,37 +0,0 @@ -# Inspectors - -This module contains various inspectors that can be used to execute and monitor transactions on the Ethereum Virtual Machine (EVM) through the `revm` library. - -## Overview - -There are several built-in inspectors in this module: - -- `NoOpInspector`: A basic inspector that does nothing, which can be used when you don't need to monitor transactions. -- `GasInspector`: Monitors the gas usage of transactions. -- `CustomPrintTracer`: - Traces and prints custom messages during EVM execution. - Available only when the `std` feature is enabled. -- `TracerEip3155`: - This is an inspector that conforms to the [EIP-3155](https://eips.ethereum.org/EIPS/eip-3155) standard for tracing Ethereum transactions. - It's used to generate detailed trace data of transaction execution, which can be useful for debugging, analysis, or for building tools that need to understand the inner workings of Ethereum transactions. - This is only available when both `std` and `serde-json` features are enabled. - -## Inspector trait - -The `Inspector` trait defines methods that are called during various stages of EVM execution. -You can implement this trait to create your own custom inspectors. - -Each of these methods is called at different stages of the execution of a transaction. -They can be used to monitor, debug, or modify the execution of the EVM. - -For example, the `step` method is called on each step of the interpreter, and the `log` method is called when a log is emitted. - -You can implement this trait for a custom database type `DB` that implements the `Database` trait. - -## Usage - -To use an inspector, you need to implement the `Inspector` trait. -For each method, you can decide what you want to do at each point in the EVM execution. -For example, to capture all `SELFDESTRUCT` operations, implement the `selfdestruct` method. - -All methods in the `Inspector` trait are optional to implement; if you do not need specific functionality, you can use the provided default implementations. diff --git a/documentation/src/crates/revm/journaled_state.md b/documentation/src/crates/revm/journaled_state.md deleted file mode 100644 index 91545a8ece..0000000000 --- a/documentation/src/crates/revm/journaled_state.md +++ /dev/null @@ -1,147 +0,0 @@ -# Journaled State - -The `journaled_state` module of the `revm` crate provides a state management implementation for Ethereum-style accounts. It includes support for various actions such as self-destruction of accounts, initial account loading, account state modification, and logging. It also contains several important utility functions such as `is_precompile`. - -This module is built around the `JournaledState` structure, which encapsulates the entire state of the blockchain. `JournaledState` uses an internal state representation (a `HashMap`) that tracks all accounts. Each account is represented by the `Account` structure, which includes fields like balance, nonce, and code hash. For state-changing operations, the module keeps track of all the changes within a "journal" for easy reversion and commitment to the database. This feature is particularly useful for handling reversion of state changes in case of transaction failures or other exceptions. The module interacts with a database through the `Database` trait, which abstracts the operations for fetching and storing data. This design allows for a pluggable backend where different implementations of the `Database` trait can be used to persist the state in various ways (for instance, in-memory or disk-based databases). - -## Data Structures - -- `JournaledState`: - This structure represents the entire state of the blockchain, including accounts, their associated balances, nonces, and code hashes. - It maintains a journal of all state changes that allows for easy reversion and commitment of changes to the database. - -- `Account`: - This structure represents an individual account on the blockchain. - It includes the account's balance, nonce, and code hash. - It also includes a flag indicating if the account is self-destructed, and a map representing the account's storage. - -- `JournalEntry`: - This structure represents an entry in the `JournaledState`'s journal. - Each entry describes an operation that changes the state, such as an account loading, an account destruction, or a storage change. - -## Methods - -- `selfdestruct`: - This method marks an account as self-destructed and transfers its balance to a target account. - If the target account does not exist, it's created. - If the self-destructed account and the target are the same, the balance will be lost. - -- `initial_account_load`: - This method loads an account's basic information from the database without loading the code. - It also loads specified storage slots into memory. - -- `load_account`: - This method loads an account's information into memory and returns whether the account was cold or warm accessed. - -- `load_account_exist`: - This method checks whether an account exists or not. - It returns whether the account was cold or warm accessed and whether it exists. - -- `load_code`: - This method loads an account's code into memory from the database. - -- `sload`: - This method loads a specified storage value of an account. - It returns the value and whether the storage was cold loaded. - -- `sstore`: - This method changes the value of a specified storage slot in an account and returns the original value, the present value, the new value, and whether the storage was cold loaded. - -- `log`: - This method adds a log entry to the journal. - -- `is_precompile`: - This method checks whether an address is a precompiled contract or not. - -# Relevant EIPs - -The JournaledState module's operations are primarily designed to comply with the Ethereum standards defined in several Ethereum Improvement Proposals (EIPs). -More specifically: - -## [EIP-161](https://eips.ethereum.org/EIPS/eip-161): State Trie Clearing - -[EIP-161](https://eips.ethereum.org/EIPS/eip-161) aims to optimize Ethereum's state management by deleting empty accounts. The specification was proposed by Gavin Wood and was activated in the Spurious Dragon hardfork at block number `2,675,000` on the Ethereum mainnet.proposal. The EIP focuses on four main changes: - -- **Account Creation**: - During the creation of an account (whether by transactions or the `CREATE` operation), the nonce of the new account is incremented by one before the execution of the initialization code. - For most networks, the starting value is 1, but this may vary for test networks with non-zero default starting nonces. - -- **`CALL` and `SELFDESTRUCT` charges**: - Prior to [EIP-161](https://eips.ethereum.org/EIPS/eip-161), a gas charge of `25,000` was levied for `CALL` and `SELFDESTRUCT` operations if the destination account did not exist. - With [EIP-161](https://eips.ethereum.org/EIPS/eip-161), this charge is only applied if the operation transfers more than zero value and the destination account is dead (non-existent or empty). - -- **Existence of Empty Accounts**: - An account cannot change its state from non-existent to existent-but-empty. - If an operation resulted in an empty account, the account remains non-existent. - -- **Removal of Empty Accounts**: - At the end of a transaction, any account that was involved in potentially state-changing operations and is now empty will be deleted. - -#### Definitions: -- **empty**: An account is considered "empty" if it has no code, and its nonce and balance are both zero. -- **dead**: An account is considered "dead" if it is non-existent or empty. -- **touched**: An account is considered "touched" when it is involved in any potentially state-changing operation. - -These rules have an impact on how state is managed within the [EIP-161](https://eips.ethereum.org/EIPS/eip-161) context, and this affects how the JournaledState module functions. -For example, operations like `initial_account_load`, and `selfdestruct` all need to take into account whether an account is empty and/or dead. - -## Rationale - -The rationale behind [EIP-161](https://eips.ethereum.org/EIPS/eip-161) is to optimize the Ethereum state management by getting rid of unnecessary data. -Prior to this change, it was possible for the state trie to become bloated with empty accounts. -This bloating resulted in increased storage requirements and slower processing times for Ethereum nodes. - -By removing these empty accounts, the size of the state trie can be reduced, leading to improvements in the performance of Ethereum nodes. -Additionally, the changes regarding the gas costs for `CALL` and `SELFDESTRUCT` operations add a new level of nuance to the Ethereum gas model, further optimizing transaction processing. - -[EIP-161](https://eips.ethereum.org/EIPS/eip-161) has a significant impact on the state management of Ethereum, and thus is highly relevant to the JournaledState module of the revm crate. -The operations defined in this module, such as loading accounts, self-destructing accounts, and changing storage, must all conform to the rules defined in [EIP-161](https://eips.ethereum.org/EIPS/eip-161). - -## [EIP-658](https://eips.ethereum.org/EIPS/eip-658): Embedding transaction status code in receipts - -This EIP is particularly important because it introduced a way to unambiguously determine whether a transaction was successful or not. Before the introduction of [EIP-658](https://eips.ethereum.org/EIPS/eip-658), it was impossible to determine with certainty if a transaction was successful simply based on its gas consumption. This was because with the introduction of the `REVERT` opcode in [EIP-140](https://eips.ethereum.org/EIPS/eip-140), transactions could fail without consuming all gas. - -[EIP-658](https://eips.ethereum.org/EIPS/eip-658) replaced the intermediate state root field in the receipt with a status code that indicates whether the top-level call of the transaction succeeded or failed. The status code is 1 for success and 0 for failure. - -This EIP affects the JournaledState module, as the result of executing transactions and their success or failure status directly influences the state of the blockchain. The execution of state-modifying methods like , `selfdestruct`, `sstore`, and `log` can result in success or failure, and the status needs to be properly reflected in the transaction receipt. - -## Rationale - -The main motivation behind [EIP-658](https://eips.ethereum.org/EIPS/eip-658) was to provide an unambiguous way to determine the success or failure of a transaction. -Before [EIP-658](https://eips.ethereum.org/EIPS/eip-658), users had to rely on checking if a transaction had consumed all gas to guess if it had failed. -However, this was not reliable because of the introduction of the `REVERT` opcode in [EIP-140](https://eips.ethereum.org/EIPS/eip-140). - -Moreover, although full nodes can replay transactions to get their return status, fast nodes can only do this for transactions after their pivot point, and light nodes cannot do it at all. -This means that without [EIP-658](https://eips.ethereum.org/EIPS/eip-658), it is impractical for a non-full node to reliably determine the status of a transaction. - -[EIP-658](https://eips.ethereum.org/EIPS/eip-658) addressed this problem by embedding the status code directly in the transaction receipt, making it easily accessible. This change was minimal and non-disruptive, while it significantly improved the clarity and usability of transaction receipts. - -## [EIP-2929](https://eips.ethereum.org/EIPS/eip-2929): Gas cost increases for state access opcodes - -[EIP-2929](https://eips.ethereum.org/EIPS/eip-2929) proposes an increase in the gas costs for several opcodes when they're used for the first time in a transaction. The EIP was created to mitigate potential DDoS (Distributed Denial of Service) attacks by increasing the cost of potential attack vectors, and to make the stateless witness sizes in Ethereum more manageable. - -[EIP-2929](https://eips.ethereum.org/EIPS/eip-2929) also introduces two sets, `accessed_addresses` and `accessed_storage_keys`, to track the addresses and storage slots that have been accessed within a transaction. This mitigates the additional gas cost for repeated operations on the same address or storage slot within a transaction, as any repeated operation on an already accessed address or storage slot will cost less gas. - -In the context of this EIP, "cold" and "warm" (or "hot") refer to whether an address or storage slot has been accessed before during the execution of a transaction. If an address or storage slot is being accessed for the first time in a transaction, it is referred to as a "cold" access. If it has already been accessed within the same transaction, any subsequent access is referred to as "warm" or "hot". - -- **Parameters**: The EIP defines new parameters such as `COLD_SLOAD_COST` (2100 gas) for a "cold" storage read, `COLD_ACCOUNT_ACCESS_COST` (2600 gas) for a "cold" account access, and `WARM_STORAGE_READ_COST` (100 gas) for a "warm" storage read. - -- **Storage read changes**: For `SLOAD` operation, if the (address, storage_key) pair is not yet in `accessed_storage_keys`, `COLD_SLOAD_COST` gas is charged and the pair is added to `accessed_storage_keys`. If the pair is already in `accessed_storage_keys`, `WARM_STORAGE_READ_COST` gas is charged. - -- **Account access changes**: When an address is the target of certain opcodes (`EXTCODESIZE`, `EXTCODECOPY`, `EXTCODEHASH`, `BALANCE`, `CALL`, `CALLCODE`, `DELEGATECALL`, `STATICCALL`), if the target is not in `accessed_addresses`, `COLD_ACCOUNT_ACCESS_COST` gas is charged, and the address is added to `accessed_addresses`. Otherwise, `WARM_STORAGE_READ_COST` gas is charged. - -- **`SSTORE` changes**: For `SSTORE` operation, if the (address, storage_key) pair is not in `accessed_storage_keys`, an additional `COLD_SLOAD_COST` gas is charged, and the pair is added to `accessed_storage_keys`. - -- **`SELFDESTRUCT` changes**: If the recipient of `SELFDESTRUCT` is not in `accessed_addresses`, an additional `COLD_ACCOUNT_ACCESS_COST` is charged, and the recipient is added to the set. - -This methodology allows Ethereum to maintain an internal record of accessed accounts and storage slots within a transaction, making it possible to charge lower gas fees for repeated operations, thereby reducing the cost for such operations. - -## Rationale - -- **Security**: - Previously, these opcodes were underpriced, making them susceptible to DoS attacks where an attacker sends transactions that access or call a large number of accounts. - By increasing the gas costs, the EIP intends to mitigate these potential security risks. - -- **Improving stateless witness sizes**: - Stateless Ethereum clients don't maintain the complete state of the blockchain, but instead rely on block "witnesses" (a list of all the accounts, storage, and contract code accessed during transaction execution) to validate transactions. - This EIP helps in reducing the size of these witnesses, thereby making stateless Ethereum more viable. diff --git a/documentation/src/crates/revm/state.md b/documentation/src/crates/revm/state.md deleted file mode 100644 index 5951f3cdd7..0000000000 --- a/documentation/src/crates/revm/state.md +++ /dev/null @@ -1,20 +0,0 @@ -# State implementations - -State inherits the `Database` trait and implements fetching of external state and storage, and various functionality on output of the EVM execution. -Most notably, caching changes while execution multiple transactions. - -## Database Abstractions - -You can implement the traits `Database`, `DatabaseRef` or `Database + DatabaseCommit` depending on the desired handling of the struct. - -- `Database`: - Has mutable `self` in its functions. - It is useful if you want to modify your cache or update some statistics on `get` calls. - This trait enables `preverify_transaction`, `transact_preverified`, `transact` and `inspect` functions. -- `DatabaseRef`: - Takes a reference on the object. - It is useful if you only have a reference on the state and don't want to update anything on it. - It enables `preverify_transaction`, `transact_preverified_ref`, `transact_ref` and `inspect_ref` functions. -- `Database + DatabaseCommit`: - Allows directly committing changes of a transaction. - It enables `transact_commit` and `inspect_commit` functions. diff --git a/documentation/src/introduction.md b/documentation/src/introduction.md deleted file mode 100644 index 272bd488af..0000000000 --- a/documentation/src/introduction.md +++ /dev/null @@ -1,30 +0,0 @@ -# Introduction - -`revm` is an Ethereum Virtual Machine (EVM) written in Rust that is focused on speed and simplicity. This documentation is very much a work in progress and a community effort. If you would like to contribute and improve these docs please make a pr to the [github repo](https://github.com/bluealloy/revm/tree/main). Most importantly, Revm is just the execution environment for ethereum; there is no networking or consensus related work in this repository. - -## Crates - -The project has 4 main crates that are used to build revm. These are: - -- `revm`: The main EVM library. -- `interpreter`: Execution loop with instructions. -- `primitives`: Primitive data types. -- `precompile`: EVM precompiles. - -## Testing with the binaries - -There are two binaries both of which are used for testing. To install them run `cargo install --path bins/`. The binaries are: - -- `revme`: A CLI binary, used for running state test json. Currently it is used to run [ethereum tests](https://github.com/ethereum/tests) to check if revm is compliant. For example if you have the eth tests cloned into a directory called eth tests and the EIP tests in the following directories you can run -```bash -cargo run --profile ethtests -p revme -- \ - statetest \ - ../ethtests/GeneralStateTests/ \ - ../ethtests/LegacyTests/Constantinople/GeneralStateTests/ \ - bins/revme/tests/EIPTests/StateTests/stEIP5656-MCOPY/ \ - bins/revme/tests/EIPTests/StateTests/stEIP1153-transientStorage/ -``` - -- `revm-test`: test binaries with contracts; used mostly to check performance - -If you are interested in contributing, be sure to run the statetests. It is recommended to read about the [ethereum tests](https://ethereum-tests.readthedocs.io/en/latest/). diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 0000000000..d33d5093e3 --- /dev/null +++ b/examples/README.md @@ -0,0 +1,9 @@ +# examples: +* `contract_deployment`: Example of deployment of the contract from solidity compilation and calling deployed contract. +* `my_evm`: Example and tutorial on how to create your custom evm. +* `erc20_gas`: Example of custom EVM that uses ERC20 token to pay for Gas. +* `uniswap_get_reserves`: Example of using alloy to fetch state and sol! to call a function of the contract. +* `uniswap_v2_usdc_swap`: Similar to `uniswap_get_reserves` with more examples of usage. +* `block_traces`: Uses Alloy to fetch blocks transaction and state from provider to execute full block. It uses Eip3155 opcode tracer and saves output to the file. +* `custom_opcodes`: Example of introducing a custom instruction to the mainnet Evm. +* `database_components`: Example of decouples Database in `State` and `BlockHash` and how to use it inside Revm. \ No newline at end of file diff --git a/examples/block_traces/Cargo.toml b/examples/block_traces/Cargo.toml new file mode 100644 index 0000000000..c21dc78c70 --- /dev/null +++ b/examples/block_traces/Cargo.toml @@ -0,0 +1,35 @@ +[package] +name = "example-block-traces" +version = "0.0.0" +publish = false +authors.workspace = true +edition.workspace = true +keywords.workspace = true +license.workspace = true +repository.workspace = true +readme.workspace = true + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] + +[lints] +workspace = true + +[dependencies] +# revm +revm = { workspace = true, features = ["std", "alloydb", "tracer"] } + +# tokio +tokio = { workspace = true, features = ["rt-multi-thread", "macros"] } + +# alloy +alloy-eips.workspace = true +alloy-provider = { workspace = true, default-features = true } +alloy-consensus.workspace = true + +# progress bar +indicatif.workspace = true + +# misc +anyhow.workspace = true diff --git a/examples/block_traces/src/main.rs b/examples/block_traces/src/main.rs new file mode 100644 index 0000000000..af1b3f95e9 --- /dev/null +++ b/examples/block_traces/src/main.rs @@ -0,0 +1,174 @@ +//! Example that show how to replay a block and trace the execution of each transaction. +//! +//! The EIP3155 trace of each transaction is saved into file `traces/{tx_number}.json`. +#![cfg_attr(not(test), warn(unused_crate_dependencies))] + +use alloy_consensus::Transaction; +use alloy_eips::{BlockId, BlockNumberOrTag}; +use alloy_provider::{network::primitives::BlockTransactions, Provider, ProviderBuilder}; +use indicatif::ProgressBar; +use revm::{ + context::TxEnv, + database::{AlloyDB, CacheDB, StateBuilder}, + database_interface::WrapDatabaseAsync, + inspector::{inspectors::TracerEip3155, InspectEvm}, + primitives::{TxKind, U256}, + Context, MainBuilder, MainContext, +}; +use std::fs::create_dir_all; +use std::fs::OpenOptions; +use std::io::BufWriter; +use std::io::Write; +use std::sync::Arc; +use std::sync::Mutex; +use std::time::Instant; + +struct FlushWriter { + writer: Arc>>, +} + +impl FlushWriter { + fn new(writer: Arc>>) -> Self { + Self { writer } + } +} + +impl Write for FlushWriter { + fn write(&mut self, buf: &[u8]) -> std::io::Result { + self.writer.lock().unwrap().write(buf) + } + + fn flush(&mut self) -> std::io::Result<()> { + self.writer.lock().unwrap().flush() + } +} + +#[tokio::main] +async fn main() -> anyhow::Result<()> { + create_dir_all("traces")?; + + // Set up the HTTP transport which is consumed by the RPC client. + let rpc_url = "https://mainnet.infura.io/v3/c60b0bb42f8a4c6481ecd229eddaca27".parse()?; + + // Create a provider + let client = ProviderBuilder::new().connect_http(rpc_url); + + // Params + let chain_id: u64 = 1; + let block_number = 10889447; + + // Fetch the transaction-rich block + let block = match client + .get_block_by_number(BlockNumberOrTag::Number(block_number)) + .full() + .await + { + Ok(Some(block)) => block, + Ok(None) => anyhow::bail!("Block not found"), + Err(error) => anyhow::bail!("Error: {:?}", error), + }; + println!("Fetched block number: {}", block.header.number); + let previous_block_number = block_number - 1; + + // Use the previous block state as the db with caching + let prev_id: BlockId = previous_block_number.into(); + // SAFETY: This cannot fail since this is in the top-level tokio runtime + + let state_db = WrapDatabaseAsync::new(AlloyDB::new(client, prev_id)).unwrap(); + let cache_db: CacheDB<_> = CacheDB::new(state_db); + let mut state = StateBuilder::new_with_database(cache_db).build(); + let ctx = Context::mainnet() + .with_db(&mut state) + .modify_block_chained(|b| { + b.number = U256::from(block.header.number); + b.beneficiary = block.header.beneficiary; + b.timestamp = U256::from(block.header.timestamp); + + b.difficulty = block.header.difficulty; + b.gas_limit = block.header.gas_limit; + b.basefee = block.header.base_fee_per_gas.unwrap_or_default(); + }) + .modify_cfg_chained(|c| { + c.chain_id = chain_id; + }); + + let write = OpenOptions::new() + .write(true) + .create(true) + .truncate(true) + .open("traces/0.json"); + let inner = Arc::new(Mutex::new(BufWriter::new( + write.expect("Failed to open file"), + ))); + let writer = FlushWriter::new(Arc::clone(&inner)); + let mut evm = ctx.build_mainnet_with_inspector(TracerEip3155::new(Box::new(writer))); + + let txs = block.transactions.len(); + println!("Found {txs} transactions."); + + let console_bar = Arc::new(ProgressBar::new(txs as u64)); + let start = Instant::now(); + + // Create the traces directory if it doesn't exist + std::fs::create_dir_all("traces").expect("Failed to create traces directory"); + + // Fill in CfgEnv + let BlockTransactions::Full(transactions) = block.transactions else { + panic!("Wrong transaction type") + }; + + for tx in transactions { + // Construct the file writer to write the trace to + let tx_number = tx.transaction_index.unwrap_or_default(); + + let tx = TxEnv::builder() + .caller(tx.inner.signer()) + .gas_limit(tx.gas_limit()) + .gas_price(tx.gas_price().unwrap_or(tx.inner.max_fee_per_gas())) + .value(tx.value()) + .data(tx.input().to_owned()) + .gas_priority_fee(tx.max_priority_fee_per_gas()) + .chain_id(Some(chain_id)) + .nonce(tx.nonce()) + .access_list(tx.access_list().cloned().unwrap_or_default()) + .kind(match tx.to() { + Some(to_address) => TxKind::Call(to_address), + None => TxKind::Create, + }) + .build() + .unwrap(); + + let file_name = format!("traces/{tx_number}.json"); + let write = OpenOptions::new() + .write(true) + .create(true) + .truncate(true) + .open(file_name); + let inner = Arc::new(Mutex::new(BufWriter::new( + write.expect("Failed to open file"), + ))); + let writer = FlushWriter::new(Arc::clone(&inner)); + + // Inspect and commit the transaction to the EVM + let res: Result<_, _> = evm.inspect_one(tx, TracerEip3155::new(Box::new(writer))); + + if let Err(error) = res { + println!("Got error: {error:?}"); + } + + // Flush the file writer + inner.lock().unwrap().flush().expect("Failed to flush file"); + + console_bar.inc(1); + } + + console_bar.finish_with_message("Finished all transactions."); + + let elapsed = start.elapsed(); + println!( + "Finished execution. Total CPU time: {:.6}s", + elapsed.as_secs_f64() + ); + + Ok(()) +} diff --git a/examples/cheatcode_inspector/Cargo.toml b/examples/cheatcode_inspector/Cargo.toml new file mode 100644 index 0000000000..b346d37688 --- /dev/null +++ b/examples/cheatcode_inspector/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "example-cheatcode-inspector" +version = "0.0.0" +publish = false +authors.workspace = true +edition.workspace = true +keywords.workspace = true +license.workspace = true +repository.workspace = true +readme.workspace = true + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] + +[lints] +workspace = true + +[dependencies] +# revms +revm = { workspace = true, features = ["std", "tracer"] } + +# misc +anyhow = "1.0.89" diff --git a/examples/cheatcode_inspector/src/main.rs b/examples/cheatcode_inspector/src/main.rs new file mode 100644 index 0000000000..5ca73b86d9 --- /dev/null +++ b/examples/cheatcode_inspector/src/main.rs @@ -0,0 +1,613 @@ +//! An example that shows how to implement a Foundry-style Solidity test cheatcode inspector. +//! +//! The code below mimics relevant parts of the implementation of the [`transact`](https://book.getfoundry.sh/cheatcodes/transact) +//! and [`rollFork(uint256 forkId, bytes32 transaction)`](https://book.getfoundry.sh/cheatcodes/roll-fork#rollfork) cheatcodes. +//! Both of these cheatcodes initiate transactions from a call step in the cheatcode inspector which is the most +//! advanced cheatcode use-case. +#![cfg_attr(not(test), warn(unused_crate_dependencies))] + +use revm::{ + context::{ + result::InvalidTransaction, BlockEnv, Cfg, CfgEnv, ContextTr, Evm, LocalContext, TxEnv, + }, + context_interface::{ + journaled_state::{AccountLoad, JournalCheckpoint, TransferError}, + result::EVMError, + Block, JournalTr, Transaction, + }, + database::InMemoryDB, + handler::{ + instructions::{EthInstructions, InstructionProvider}, + EthPrecompiles, PrecompileProvider, + }, + inspector::{inspectors::TracerEip3155, JournalExt}, + interpreter::{ + interpreter::EthInterpreter, CallInputs, CallOutcome, InterpreterResult, SStoreResult, + SelfDestructResult, StateLoad, + }, + primitives::{hardfork::SpecId, Address, HashSet, Log, StorageKey, StorageValue, B256, U256}, + state::{Account, Bytecode, EvmState}, + Context, Database, DatabaseCommit, InspectEvm, Inspector, Journal, JournalEntry, +}; +use std::{convert::Infallible, fmt::Debug}; + +/// Backend for cheatcodes. +/// The problematic cheatcodes are only supported in fork mode, so we'll omit the non-fork behavior of the Foundry +/// `Backend`. +#[derive(Clone, Debug)] +struct Backend { + /// In fork mode, Foundry stores (`JournaledState`, `Database`) pairs for each fork. + journaled_state: Journal, + /// Counters to be able to assert that we mutated the object that we expected to mutate. + method_with_inspector_counter: usize, + method_without_inspector_counter: usize, +} + +impl Backend { + fn new(spec: SpecId, db: InMemoryDB) -> Self { + let mut journaled_state = Journal::new(db); + journaled_state.set_spec_id(spec); + Self { + journaled_state, + method_with_inspector_counter: 0, + method_without_inspector_counter: 0, + } + } +} + +impl JournalTr for Backend { + type Database = InMemoryDB; + type State = EvmState; + + fn new(database: InMemoryDB) -> Self { + Self::new(SpecId::default(), database) + } + + fn db(&self) -> &Self::Database { + self.journaled_state.db() + } + + fn db_mut(&mut self) -> &mut Self::Database { + self.journaled_state.db_mut() + } + + fn sload( + &mut self, + address: Address, + key: StorageKey, + ) -> Result, ::Error> { + self.journaled_state.sload(address, key) + } + + fn sstore( + &mut self, + address: Address, + key: StorageKey, + value: StorageValue, + ) -> Result, ::Error> { + self.journaled_state.sstore(address, key, value) + } + + fn tload(&mut self, address: Address, key: StorageKey) -> StorageValue { + self.journaled_state.tload(address, key) + } + + fn tstore(&mut self, address: Address, key: StorageKey, value: StorageValue) { + self.journaled_state.tstore(address, key, value) + } + + fn log(&mut self, log: Log) { + self.journaled_state.log(log) + } + + fn selfdestruct( + &mut self, + address: Address, + target: Address, + ) -> Result, Infallible> { + self.journaled_state.selfdestruct(address, target) + } + + fn warm_account_and_storage( + &mut self, + address: Address, + storage_keys: impl IntoIterator, + ) -> Result<(), ::Error> { + self.journaled_state + .warm_account_and_storage(address, storage_keys) + } + + fn warm_account(&mut self, address: Address) { + self.journaled_state + .warm_preloaded_addresses + .insert(address); + } + + fn warm_coinbase_account(&mut self, address: Address) { + self.journaled_state.warm_coinbase_address = Some(address) + } + + fn warm_precompiles(&mut self, addresses: HashSet
) { + self.journaled_state.warm_precompiles(addresses) + } + + fn precompile_addresses(&self) -> &HashSet
{ + self.journaled_state.precompile_addresses() + } + + fn set_spec_id(&mut self, spec_id: SpecId) { + self.journaled_state.set_spec_id(spec_id); + } + + fn touch_account(&mut self, address: Address) { + self.journaled_state.touch_account(address); + } + + fn transfer( + &mut self, + from: Address, + to: Address, + balance: U256, + ) -> Result, Infallible> { + self.journaled_state.transfer(from, to, balance) + } + + fn load_account(&mut self, address: Address) -> Result, Infallible> { + self.journaled_state.load_account(address) + } + + fn load_account_code( + &mut self, + address: Address, + ) -> Result, Infallible> { + self.journaled_state.load_account_code(address) + } + + fn load_account_delegated( + &mut self, + address: Address, + ) -> Result, Infallible> { + self.journaled_state.load_account_delegated(address) + } + + fn set_code_with_hash(&mut self, address: Address, code: Bytecode, hash: B256) { + self.journaled_state.set_code_with_hash(address, code, hash); + } + + fn code( + &mut self, + address: Address, + ) -> Result, ::Error> { + self.journaled_state.code(address) + } + + fn code_hash( + &mut self, + address: Address, + ) -> Result, ::Error> { + self.journaled_state.code_hash(address) + } + + fn clear(&mut self) { + self.journaled_state.clear(); + } + + fn checkpoint(&mut self) -> JournalCheckpoint { + self.journaled_state.checkpoint() + } + + fn checkpoint_commit(&mut self) { + self.journaled_state.checkpoint_commit() + } + + fn checkpoint_revert(&mut self, checkpoint: JournalCheckpoint) { + self.journaled_state.checkpoint_revert(checkpoint) + } + + fn create_account_checkpoint( + &mut self, + caller: Address, + address: Address, + balance: U256, + spec_id: SpecId, + ) -> Result { + self.journaled_state + .create_account_checkpoint(caller, address, balance, spec_id) + } + + /// Returns call depth. + #[inline] + fn depth(&self) -> usize { + self.journaled_state.depth() + } + + fn finalize(&mut self) -> Self::State { + self.journaled_state.finalize() + } + + fn caller_accounting_journal_entry( + &mut self, + address: Address, + old_balance: U256, + bump_nonce: bool, + ) { + self.journaled_state + .caller_accounting_journal_entry(address, old_balance, bump_nonce) + } + + fn balance_incr( + &mut self, + address: Address, + balance: U256, + ) -> Result<(), ::Error> { + self.journaled_state.balance_incr(address, balance) + } + + fn nonce_bump_journal_entry(&mut self, address: Address) { + self.journaled_state.nonce_bump_journal_entry(address) + } + + fn take_logs(&mut self) -> Vec { + self.journaled_state.take_logs() + } + + fn commit_tx(&mut self) { + self.journaled_state.commit_tx() + } + + fn discard_tx(&mut self) { + self.journaled_state.discard_tx() + } +} + +impl JournalExt for Backend { + fn logs(&self) -> &[Log] { + self.journaled_state.logs() + } + + fn journal(&self) -> &[JournalEntry] { + self.journaled_state.journal() + } + + fn evm_state(&self) -> &EvmState { + self.journaled_state.evm_state() + } + + fn evm_state_mut(&mut self) -> &mut EvmState { + self.journaled_state.evm_state_mut() + } +} + +/// Used in Foundry to provide extended functionality to cheatcodes. +/// The methods are called from the `Cheatcodes` inspector. +trait DatabaseExt: JournalTr { + /// Mimics `DatabaseExt::transact` + /// See `commit_transaction` for the generics + fn method_that_takes_inspector_as_argument< + InspectorT, + BlockT, + TxT, + CfgT, + InstructionProviderT, + PrecompileT, + >( + &mut self, + env: Env, + inspector: InspectorT, + ) -> anyhow::Result<()> + where + InspectorT: Inspector, EthInterpreter>, + BlockT: Block, + TxT: Transaction + Clone, + CfgT: Cfg, + InstructionProviderT: InstructionProvider< + Context = Context, + InterpreterTypes = EthInterpreter, + > + Default, + PrecompileT: PrecompileProvider< + Context, + Output = InterpreterResult, + > + Default; + + /// Mimics `DatabaseExt::roll_fork_to_transaction` + fn method_that_constructs_inspector( + &mut self, + env: Env, + ) -> anyhow::Result<()> + where + BlockT: Block, + TxT: Transaction + Clone, + CfgT: Cfg, + InstructionProviderT: InstructionProvider< + Context = Context, + InterpreterTypes = EthInterpreter, + > + Default, + PrecompileT: PrecompileProvider< + Context, + Output = InterpreterResult, + > + Default; +} + +impl DatabaseExt for Backend { + fn method_that_takes_inspector_as_argument< + InspectorT, + BlockT, + TxT, + CfgT, + InstructionProviderT, + PrecompileT, + >( + &mut self, + env: Env, + inspector: InspectorT, + ) -> anyhow::Result<()> + where + InspectorT: Inspector, EthInterpreter>, + BlockT: Block, + TxT: Transaction + Clone, + CfgT: Cfg, + InstructionProviderT: InstructionProvider< + Context = Context, + InterpreterTypes = EthInterpreter, + > + Default, + PrecompileT: PrecompileProvider< + Context, + Output = InterpreterResult, + > + Default, + { + commit_transaction::( + self, env, inspector, + )?; + self.method_with_inspector_counter += 1; + Ok(()) + } + + fn method_that_constructs_inspector( + &mut self, + env: Env, + ) -> anyhow::Result<()> + where + BlockT: Block, + TxT: Transaction + Clone, + CfgT: Cfg, + InstructionProviderT: InstructionProvider< + Context = Context, + InterpreterTypes = EthInterpreter, + > + Default, + PrecompileT: PrecompileProvider< + Context, + Output = InterpreterResult, + > + Default, + { + let inspector = TracerEip3155::new(Box::new(std::io::sink())); + commit_transaction::< + // Generic interpreter types are not supported yet in the `Evm` implementation + TracerEip3155, + BlockT, + TxT, + CfgT, + InstructionProviderT, + PrecompileT, + >(self, env, inspector)?; + + self.method_without_inspector_counter += 1; + Ok(()) + } +} + +/// An REVM inspector that intercepts calls to the cheatcode address and executes them with the help of the +/// `DatabaseExt` trait. +#[derive(Clone, Default)] +struct Cheatcodes { + call_count: usize, + phantom: core::marker::PhantomData<(BlockT, TxT, CfgT, InstructionProviderT, PrecompileT)>, +} + +impl + Cheatcodes +where + BlockT: Block + Clone, + TxT: Transaction + Clone, + CfgT: Cfg + Clone, + InstructionProviderT: InstructionProvider< + Context = Context, + InterpreterTypes = EthInterpreter, + > + Default, + PrecompileT: PrecompileProvider< + Context, + Output = InterpreterResult, + > + Default, +{ + fn apply_cheatcode( + &mut self, + context: &mut Context, + ) -> anyhow::Result<()> { + // We cannot avoid cloning here, because we need to mutably borrow the context to get the journal. + let block = context.block.clone(); + let tx = context.tx.clone(); + let cfg = context.cfg.clone(); + + // `transact` cheatcode would do this + context + .journal_mut() + .method_that_takes_inspector_as_argument::<_, _, _, _, InstructionProviderT, PrecompileT>( + Env { + block: block.clone(), + tx: tx.clone(), + cfg: cfg.clone(), + }, + self, + )?; + + // `rollFork(bytes32 transaction)` cheatcode would do this + context + .journal_mut() + .method_that_constructs_inspector::<_, _, _, InstructionProviderT, PrecompileT>( + Env { block, tx, cfg }, + )?; + Ok(()) + } +} + +impl + Inspector> + for Cheatcodes +where + BlockT: Block + Clone, + TxT: Transaction + Clone, + CfgT: Cfg + Clone, + InstructionProviderT: InstructionProvider< + Context = Context, + InterpreterTypes = EthInterpreter, + > + Default, + PrecompileT: PrecompileProvider< + Context, + Output = InterpreterResult, + > + Default, +{ + /// Note that precompiles are no longer accessible via `EvmContext::precompiles`. + fn call( + &mut self, + context: &mut Context, + _inputs: &mut CallInputs, + ) -> Option { + self.call_count += 1; + // Don't apply cheatcodes recursively. + if self.call_count == 1 { + // Instead of calling unwrap here, we would want to return an appropriate call outcome based on the result + // in a real project. + self.apply_cheatcode(context).unwrap(); + } + None + } +} + +/// EVM environment +#[derive(Clone, Debug)] +struct Env { + block: BlockT, + tx: TxT, + cfg: CfgT, +} + +impl Env { + fn mainnet() -> Self { + // `CfgEnv` is non-exhaustive, so we need to set the field after construction. + let mut cfg = CfgEnv::default(); + cfg.disable_nonce_check = true; + + Self { + block: BlockEnv::default(), + tx: TxEnv::default(), + cfg, + } + } +} + +/// Executes a transaction and runs the inspector using the `Backend` as the state. +/// Mimics `commit_transaction` +fn commit_transaction( + backend: &mut Backend, + env: Env, + inspector: InspectorT, +) -> Result<(), EVMError> +where + InspectorT: Inspector, EthInterpreter>, + BlockT: Block, + TxT: Transaction + Clone, + CfgT: Cfg, + InstructionProviderT: InstructionProvider< + Context = Context, + InterpreterTypes = EthInterpreter, + > + Default, + PrecompileT: PrecompileProvider< + Context, + Output = InterpreterResult, + > + Default, +{ + // Create new journaled state and backend with the same DB and journaled state as the original for the transaction. + // This new backend and state will be discarded after the transaction is done and the changes are applied to the + // original backend. + // Mimics https://github.com/foundry-rs/foundry/blob/25cc1ac68b5f6977f23d713c01ec455ad7f03d21/crates/evm/core/src/backend/mod.rs#L1950-L1953 + let new_backend = backend.clone(); + let tx = env.tx.clone(); + + let context = Context { + tx: env.tx, + block: env.block, + cfg: env.cfg, + journaled_state: new_backend, + chain: (), + local: LocalContext::default(), + error: Ok(()), + }; + + let mut evm = Evm::new_with_inspector( + context, + inspector, + InstructionProviderT::default(), + PrecompileT::default(), + ); + + let state = evm.inspect_tx(tx)?.state; + + // Persist the changes to the original backend. + backend.journaled_state.database.commit(state); + update_state( + &mut backend.journaled_state.inner.state, + &mut backend.journaled_state.database, + )?; + + Ok(()) +} + +/// Mimics +/// Omits persistent accounts (accounts that should be kept persistent when switching forks) for simplicity. +fn update_state(state: &mut EvmState, db: &mut DB) -> Result<(), DB::Error> { + for (addr, acc) in state.iter_mut() { + acc.info = db.basic(*addr)?.unwrap_or_default(); + for (key, val) in acc.storage.iter_mut() { + val.present_value = db.storage(*addr, *key)?; + } + } + + Ok(()) +} + +fn main() -> anyhow::Result<()> { + let backend = Backend::new(SpecId::default(), InMemoryDB::default()); + let mut inspector = Cheatcodes::< + BlockEnv, + TxEnv, + CfgEnv, + EthInstructions>, + EthPrecompiles, + >::default(); + let env = Env::mainnet(); + let tx = env.tx.clone(); + + let context = Context { + tx: env.tx, + block: env.block, + cfg: env.cfg, + journaled_state: backend, + chain: (), + local: LocalContext::default(), + error: Ok(()), + }; + + let mut evm = Evm::new_with_inspector( + context, + &mut inspector, + EthInstructions::default(), + EthPrecompiles::default(), + ); + evm.inspect_tx(tx)?; + + // Sanity check + assert_eq!(evm.inspector.call_count, 2); + assert_eq!(evm.journaled_state.method_with_inspector_counter, 1); + assert_eq!(evm.journaled_state.method_without_inspector_counter, 1); + + Ok(()) +} diff --git a/examples/contract_deployment/Cargo.toml b/examples/contract_deployment/Cargo.toml new file mode 100644 index 0000000000..2586794344 --- /dev/null +++ b/examples/contract_deployment/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "example-contract-deployment" +version = "0.0.0" +publish = false +authors.workspace = true +edition.workspace = true +keywords.workspace = true +license.workspace = true +repository.workspace = true +readme.workspace = true + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] + +[lints] +workspace = true + +[dependencies] +revm = { workspace = true, features = ["std"] } + +# misc +anyhow = "1.0.89" diff --git a/examples/contract_deployment/src/main.rs b/examples/contract_deployment/src/main.rs new file mode 100644 index 0000000000..6e900b8cd9 --- /dev/null +++ b/examples/contract_deployment/src/main.rs @@ -0,0 +1,100 @@ +//! Example that deploys a contract by forging and executing a contract creation transaction. +#![cfg_attr(not(test), warn(unused_crate_dependencies))] + +use anyhow::{anyhow, bail}; +use revm::{ + bytecode::opcode, + context::{Context, TxEnv}, + context_interface::result::{ExecutionResult, Output}, + database::CacheDB, + database_interface::EmptyDB, + primitives::{hex, Bytes, StorageValue, TxKind}, + ExecuteCommitEvm, ExecuteEvm, MainBuilder, MainContext, +}; + +/// Load number parameter and set to storage with slot 0 +const INIT_CODE: &[u8] = &[ + opcode::PUSH1, + 0x01, + opcode::PUSH1, + 0x17, + opcode::PUSH1, + 0x1f, + opcode::CODECOPY, + opcode::PUSH0, + opcode::MLOAD, + opcode::PUSH0, + opcode::SSTORE, +]; + +/// Copy runtime bytecode to memory and return +const RET: &[u8] = &[ + opcode::PUSH1, + 0x02, + opcode::PUSH1, + 0x15, + opcode::PUSH0, + opcode::CODECOPY, + opcode::PUSH1, + 0x02, + opcode::PUSH0, + opcode::RETURN, +]; + +/// Load storage from slot zero to memory +const RUNTIME_BYTECODE: &[u8] = &[opcode::PUSH0, opcode::SLOAD]; + +fn main() -> anyhow::Result<()> { + let param = 0x42; + let bytecode: Bytes = [INIT_CODE, RET, RUNTIME_BYTECODE, &[param]].concat().into(); + let ctx = Context::mainnet().with_db(CacheDB::::default()); + + let mut evm = ctx.build_mainnet(); + + println!("bytecode: {}", hex::encode(&bytecode)); + let ref_tx = evm.transact_commit( + TxEnv::builder() + .kind(TxKind::Create) + .data(bytecode.clone()) + .build() + .unwrap(), + )?; + let ExecutionResult::Success { + output: Output::Create(_, Some(address)), + .. + } = ref_tx + else { + bail!("Failed to create contract: {ref_tx:#?}"); + }; + + println!("Created contract at {address}"); + let output = evm.transact( + TxEnv::builder() + .kind(TxKind::Call(address)) + .data(Default::default()) + .nonce(1) + .build() + .unwrap(), + )?; + let Some(storage0) = output + .state + .get(&address) + .ok_or_else(|| anyhow!("Contract not found"))? + .storage + .get::(&Default::default()) + else { + bail!( + "Failed to write storage in the init code: {:#?}", + output.result + ); + }; + + println!("storage U256(0) at {address}: {storage0:#?}"); + assert_eq!( + storage0.present_value(), + param.try_into()?, + "{:#?}", + output.result + ); + Ok(()) +} diff --git a/examples/custom_opcodes/Cargo.toml b/examples/custom_opcodes/Cargo.toml new file mode 100644 index 0000000000..8a269c1503 --- /dev/null +++ b/examples/custom_opcodes/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "example-custom-opcodes" +version = "0.0.0" +publish = false +authors.workspace = true +edition.workspace = true +keywords.workspace = true +license.workspace = true +repository.workspace = true +readme.workspace = true + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] + +[lints] +workspace = true + +[dependencies] +revm = {workspace = true, features = ["std", "tracer"]} diff --git a/examples/custom_opcodes/src/main.rs b/examples/custom_opcodes/src/main.rs new file mode 100644 index 0000000000..c08305de5f --- /dev/null +++ b/examples/custom_opcodes/src/main.rs @@ -0,0 +1,68 @@ +//! Custom opcodes example +#![cfg_attr(not(test), warn(unused_crate_dependencies))] + +use revm::{ + bytecode::opcode, + context::{Evm, TxEnv}, + database::{BenchmarkDB, BENCH_TARGET}, + handler::{instructions::EthInstructions, EthPrecompiles}, + inspector::inspectors::TracerEip3155, + interpreter::{ + interpreter::EthInterpreter, + interpreter_types::{Immediates, Jumps}, + InstructionContext, + }, + primitives::TxKind, + state::Bytecode, + Context, InspectEvm, MainContext, +}; + +/// Opcode hex value +const MY_STATIC_JUMP: u8 = 0x0C; + +/// Demonstrates how to implement and use custom opcodes in REVM. +/// This example shows how to create a custom static jump opcode that reads +/// a 16-bit offset from the bytecode and performs a relative jump. +pub fn main() { + let ctx = Context::mainnet().with_db(BenchmarkDB::new_bytecode(Bytecode::new_raw( + [ + MY_STATIC_JUMP, + 0x00, + 0x03, + opcode::STOP, + opcode::JUMPDEST, + opcode::STOP, + ] + .into(), + ))); + + // Create a new instruction set with our mainnet opcodes. + let mut instructions = EthInstructions::new_mainnet(); + // insert our custom opcode + instructions.insert_instruction( + MY_STATIC_JUMP, + |ctx: InstructionContext<'_, _, EthInterpreter>| { + let offset = ctx.interpreter.bytecode.read_i16(); + ctx.interpreter.bytecode.relative_jump(offset as isize); + }, + ); + + // Create a new EVM instance. + let mut evm = Evm::new(ctx, instructions, EthPrecompiles::default()) + .with_inspector(TracerEip3155::new_stdout().without_summary()); + + // inspect the transaction. + let _ = evm.inspect_one_tx( + TxEnv::builder() + .kind(TxKind::Call(BENCH_TARGET)) + .build() + .unwrap(), + ); + + // Expected output where we can see that JUMPDEST is called. + /* + "{"pc":0,"op":12,"gas":"0x1c97178","gasCost":"0x0","stack":[],"depth":1,"returnData":"0x","refund":"0x0","memSize":"0x0"} + {"pc":4,"op":91,"gas":"0x1c97178","gasCost":"0x1","stack":[],"depth":1,"returnData":"0x","refund":"0x0","memSize":"0x0","opName":"JUMPDEST"} + {"pc":5,"op":0,"gas":"0x1c97177","gasCost":"0x0","stack":[],"depth":1,"returnData":"0x","refund":"0x0","memSize":"0x0","opName":"STOP"} + */ +} diff --git a/examples/custom_precompile_journal/CHANGELOG.md b/examples/custom_precompile_journal/CHANGELOG.md new file mode 100644 index 0000000000..30d68f8f4e --- /dev/null +++ b/examples/custom_precompile_journal/CHANGELOG.md @@ -0,0 +1,14 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [0.1.0](https://github.com/bluealloy/revm/releases/tag/custom_precompile_journal-v0.1.0) - 2025-07-03 + +### Added + +- add custom precompile with journal access example ([#2677](https://github.com/bluealloy/revm/pull/2677)) diff --git a/examples/custom_precompile_journal/Cargo.toml b/examples/custom_precompile_journal/Cargo.toml new file mode 100644 index 0000000000..cc46f6f2f5 --- /dev/null +++ b/examples/custom_precompile_journal/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "custom_precompile_journal" +version = "0.1.0" +edition = "2021" + +[[bin]] +name = "custom_precompile_journal" +path = "src/main.rs" + +[dependencies] +revm = { path = "../../crates/revm", features = ["optional_eip3607"] } +anyhow = "1.0" diff --git a/examples/custom_precompile_journal/README.md b/examples/custom_precompile_journal/README.md new file mode 100644 index 0000000000..f4d11ac00c --- /dev/null +++ b/examples/custom_precompile_journal/README.md @@ -0,0 +1,124 @@ +# Custom Precompile with Journal Access Example + +This example demonstrates how to create a custom precompile for REVM that can access and modify the journal (state), integrated into a custom EVM implementation similar to MyEvm. + +## Overview + +The example shows: +1. How to create a custom precompile provider that extends the standard Ethereum precompiles +2. How to implement a precompile that can read from and write to the journaled state +3. How to modify account balances and storage from within a precompile +4. How to integrate custom precompiles into a custom EVM implementation +5. How to create handlers for transaction execution + +## Architecture + +### CustomPrecompileProvider + +A custom implementation of the `PrecompileProvider` trait that: +- Extends the standard Ethereum precompiles (`EthPrecompiles`) +- Adds a custom precompile at address `0x0000000000000000000000000000000000000100` +- Delegates to standard precompiles for all other addresses +- Implements journal access for storage and balance operations + +### CustomEvm + +A custom EVM implementation that: +- Wraps the standard REVM `Evm` struct with `CustomPrecompileProvider` +- Follows the same pattern as the MyEvm example +- Maintains full compatibility with REVM's execution model +- Supports both regular and inspector-based execution + +### CustomHandler + +A handler implementation that: +- Implements the `Handler` trait for transaction execution +- Supports both `Handler` and `InspectorHandler` traits +- Can be used with `handler.run(&mut evm)` for full transaction execution + +## Custom Precompile Functionality + +The precompile at `0x0100` supports two operations: + +1. **Read Storage** (empty input data): + - Reads a value from storage slot 0 + - Returns the value as output + - Gas cost: 2,100 + +2. **Write Storage** (32 bytes input): + - Stores the input value to storage slot 0 + - Transfers 1 wei from the precompile to the caller as a reward + - Gas cost: 41,000 (21,000 base + 20,000 for SSTORE) + +## Journal Access Patterns + +The example demonstrates how to access the journal from within a precompile: + +```rust +// Reading storage +let value = context + .journal_mut() + .sload(address, key) + .map_err(|e| PrecompileError::Other(format!("Storage read failed: {:?}", e)))? + .data; + +// Writing storage +context + .journal_mut() + .sstore(address, key, value) + .map_err(|e| PrecompileError::Other(format!("Storage write failed: {:?}", e)))?; + +// Transferring balance +context + .journal_mut() + .transfer(from, to, amount) + .map_err(|e| PrecompileError::Other(format!("Transfer failed: {:?}", e)))?; + +// Incrementing balance +context + .journal_mut() + .balance_incr(address, amount) + .map_err(|e| PrecompileError::Other(format!("Balance increment failed: {:?}", e)))?; +``` + +## Usage + +To use this custom EVM in your application: + +```rust +use custom_precompile_journal::{CustomEvm, CustomHandler}; +use revm::{context::Context, inspector::NoOpInspector, MainContext}; + +// Create the custom EVM +let context = Context::mainnet().with_db(db); +let mut evm = CustomEvm::new(context, NoOpInspector); + +// Create the handler +let handler = CustomHandler::>::default(); + +// Execute transactions +let result = handler.run(&mut evm); +``` + +## Safety Features + +- **Static call protection**: Prevents state modification in view calls +- **Gas accounting**: Proper gas cost calculation and out-of-gas protection +- **Error handling**: Comprehensive error types and result handling +- **Type safety**: Full Rust type safety with generic constraints + +## Running the Example + +```bash +cargo run -p custom_precompile_journal +``` + +The example will demonstrate the custom EVM architecture and show how the various components work together to provide journal access functionality within precompiles. + +## Integration with Existing Code + +This example extends the op-revm pattern and demonstrates how to: +- Create custom precompile providers that can access the journal +- Integrate custom precompiles into REVM's execution model +- Maintain compatibility with existing REVM patterns and interfaces +- Build custom EVM variants similar to MyEvm but with enhanced precompile capabilities \ No newline at end of file diff --git a/examples/custom_precompile_journal/src/custom_evm.rs b/examples/custom_precompile_journal/src/custom_evm.rs new file mode 100644 index 0000000000..02222c8fd2 --- /dev/null +++ b/examples/custom_precompile_journal/src/custom_evm.rs @@ -0,0 +1,151 @@ +//! Custom EVM implementation with journal-accessing precompiles. + +use crate::precompile_provider::CustomPrecompileProvider; +use revm::{ + context::{ContextError, ContextSetters, ContextTr, Evm, FrameStack}, + handler::{ + evm::FrameTr, instructions::EthInstructions, EthFrame, EvmTr, FrameInitOrResult, + ItemOrResult, + }, + inspector::{InspectorEvmTr, JournalExt}, + interpreter::interpreter::EthInterpreter, + primitives::hardfork::SpecId, + Database, Inspector, +}; + +/// Custom EVM variant with journal-accessing precompiles. +/// +/// This EVM extends the standard behavior by using a custom precompile provider +/// that includes journal access functionality. It follows the same pattern as MyEvm +/// but uses CustomPrecompileProvider instead of EthPrecompiles. +#[derive(Debug)] +pub struct CustomEvm( + pub Evm< + CTX, + INSP, + EthInstructions, + CustomPrecompileProvider, + EthFrame, + >, +); + +impl CustomEvm +where + CTX: ContextTr>, +{ + /// Creates a new instance of CustomEvm with the provided context and inspector. + /// + /// # Arguments + /// + /// * `ctx` - The execution context that manages state, environment, and journaling + /// * `inspector` - The inspector for debugging and tracing execution + /// + /// # Returns + /// + /// A new CustomEvm instance configured with: + /// - The provided context and inspector + /// - Mainnet instruction set + /// - Custom precompiles with journal access + /// - A fresh frame stack for execution + pub fn new(ctx: CTX, inspector: INSP) -> Self { + Self(Evm { + ctx, + inspector, + instruction: EthInstructions::new_mainnet(), + precompiles: CustomPrecompileProvider::new_with_spec(SpecId::CANCUN), + frame_stack: FrameStack::new(), + }) + } +} + +impl EvmTr for CustomEvm +where + CTX: ContextTr>, +{ + type Context = CTX; + type Instructions = EthInstructions; + type Precompiles = CustomPrecompileProvider; + type Frame = EthFrame; + + fn ctx(&mut self) -> &mut Self::Context { + &mut self.0.ctx + } + + fn ctx_ref(&self) -> &Self::Context { + self.0.ctx_ref() + } + + fn ctx_instructions(&mut self) -> (&mut Self::Context, &mut Self::Instructions) { + self.0.ctx_instructions() + } + + fn ctx_precompiles(&mut self) -> (&mut Self::Context, &mut Self::Precompiles) { + self.0.ctx_precompiles() + } + + fn frame_stack(&mut self) -> &mut FrameStack { + self.0.frame_stack() + } + + fn frame_init( + &mut self, + frame_input: ::FrameInit, + ) -> Result< + ItemOrResult<&mut Self::Frame, ::FrameResult>, + ContextError<<::Db as Database>::Error>, + > { + self.0.frame_init(frame_input) + } + + fn frame_run( + &mut self, + ) -> Result< + FrameInitOrResult, + ContextError<<::Db as Database>::Error>, + > { + self.0.frame_run() + } + + fn frame_return_result( + &mut self, + frame_result: ::FrameResult, + ) -> Result< + Option<::FrameResult>, + ContextError<<::Db as Database>::Error>, + > { + self.0.frame_return_result(frame_result) + } +} + +impl InspectorEvmTr for CustomEvm +where + CTX: ContextSetters, Journal: JournalExt>, + INSP: Inspector, +{ + type Inspector = INSP; + + fn inspector(&mut self) -> &mut Self::Inspector { + self.0.inspector() + } + + fn ctx_inspector(&mut self) -> (&mut Self::Context, &mut Self::Inspector) { + self.0.ctx_inspector() + } + + fn ctx_inspector_frame( + &mut self, + ) -> (&mut Self::Context, &mut Self::Inspector, &mut Self::Frame) { + self.0.ctx_inspector_frame() + } + + fn ctx_inspector_frame_instructions( + &mut self, + ) -> ( + &mut Self::Context, + &mut Self::Inspector, + &mut Self::Frame, + &mut Self::Instructions, + ) { + self.0.ctx_inspector_frame_instructions() + } +} diff --git a/examples/custom_precompile_journal/src/lib.rs b/examples/custom_precompile_journal/src/lib.rs new file mode 100644 index 0000000000..91e98b838f --- /dev/null +++ b/examples/custom_precompile_journal/src/lib.rs @@ -0,0 +1,7 @@ +//! Custom EVM implementation with journal-accessing precompiles. + +pub mod custom_evm; +pub mod precompile_provider; + +pub use custom_evm::CustomEvm; +pub use precompile_provider::CustomPrecompileProvider; diff --git a/examples/custom_precompile_journal/src/main.rs b/examples/custom_precompile_journal/src/main.rs new file mode 100644 index 0000000000..2aaf791a62 --- /dev/null +++ b/examples/custom_precompile_journal/src/main.rs @@ -0,0 +1,198 @@ +//! Example of a custom precompile that can access and modify the journal. +//! +//! This example demonstrates: +//! 1. Creating a custom precompile provider that extends the standard Ethereum precompiles +//! 2. Implementing a precompile that can read from and write to the journaled state +//! 3. Modifying account balances and storage from within a precompile +//! 4. Integrating the custom precompile into a custom EVM implementation + +use custom_precompile_journal::{precompile_provider::CUSTOM_PRECOMPILE_ADDRESS, CustomEvm}; +use revm::{ + context::{result::InvalidTransaction, Context, ContextSetters, ContextTr, TxEnv}, + context_interface::result::EVMError, + database::InMemoryDB, + handler::{Handler, MainnetHandler}, + inspector::NoOpInspector, + primitives::{address, TxKind, U256}, + state::AccountInfo, + Database, MainContext, +}; + +// Type alias for the error type +type MyError = EVMError; + +fn main() -> anyhow::Result<()> { + println!("=== Custom EVM with Journal-Accessing Precompiles ===\n"); + + // Setup initial accounts + let user_address = address!("0000000000000000000000000000000000000001"); + let mut db = InMemoryDB::default(); + + // Give the user some ETH for gas + let user_balance = U256::from(10).pow(U256::from(18)); // 1 ETH + db.insert_account_info( + user_address, + AccountInfo { + balance: user_balance, + nonce: 0, + code_hash: revm::primitives::KECCAK_EMPTY, + code: None, + }, + ); + + // Give the precompile some initial balance for transfers + db.insert_account_info( + CUSTOM_PRECOMPILE_ADDRESS, + AccountInfo { + balance: U256::from(1000), // 1000 wei + nonce: 0, + code_hash: revm::primitives::KECCAK_EMPTY, + code: None, + }, + ); + + println!("✅ Custom EVM with journal-accessing precompiles created successfully!"); + println!("🔧 Precompile available at address: {CUSTOM_PRECOMPILE_ADDRESS}"); + println!("📝 Precompile supports:"); + println!(" - Read storage (empty input): Returns value from storage slot 0"); + println!(" - Write storage (32-byte input): Stores value and transfers 1 wei to caller"); + + // Create our custom EVM with mainnet handler + let context = Context::mainnet().with_db(db); + let mut evm = CustomEvm::new(context, NoOpInspector); + println!("\n=== Testing Custom Precompile ==="); + + // Test 1: Read initial storage value (should be 0) + println!("1. Reading initial storage value from custom precompile..."); + evm.0.ctx.set_tx( + TxEnv::builder() + .caller(user_address) + .kind(TxKind::Call(CUSTOM_PRECOMPILE_ADDRESS)) + .data(revm::primitives::Bytes::new()) // Empty data for read operation + .gas_limit(100_000) + .build() + .unwrap(), + ); + let read_result: Result<_, MyError> = MainnetHandler::default().run(&mut evm); + + match read_result { + Ok(revm::context::result::ExecutionResult::Success { + output, gas_used, .. + }) => { + println!(" ✓ Success! Gas used: {gas_used}"); + let data = output.data(); + let value = U256::from_be_slice(data); + println!(" 📖 Initial storage value: {value}"); + } + Ok(revm::context::result::ExecutionResult::Revert { output, gas_used }) => { + println!(" ❌ Reverted! Gas used: {gas_used}, Output: {output:?}"); + } + Ok(revm::context::result::ExecutionResult::Halt { reason, gas_used }) => { + println!(" 🛑 Halted! Reason: {reason:?}, Gas used: {gas_used}"); + } + Err(e) => { + println!(" ❌ Error: {e:?}"); + } + } + + // Test 2: Write value 42 to storage + println!("\n2. Writing value 42 to storage via custom precompile..."); + let storage_value = U256::from(42); + evm.0.ctx.set_tx( + TxEnv::builder() + .caller(user_address) + .kind(TxKind::Call(CUSTOM_PRECOMPILE_ADDRESS)) + .data(storage_value.to_be_bytes_vec().into()) + .gas_limit(100_000) + .nonce(1) + .build() + .unwrap(), + ); + let write_result: Result<_, MyError> = MainnetHandler::default().run(&mut evm); + + match write_result { + Ok(revm::context::result::ExecutionResult::Success { gas_used, .. }) => { + println!(" ✓ Success! Gas used: {gas_used}"); + println!(" 📝 Value 42 written to storage"); + println!(" 💰 1 wei transferred from precompile to caller as reward"); + } + Ok(revm::context::result::ExecutionResult::Revert { output, gas_used }) => { + println!(" ❌ Reverted! Gas used: {gas_used}, Output: {output:?}"); + } + Ok(revm::context::result::ExecutionResult::Halt { reason, gas_used }) => { + println!(" 🛑 Halted! Reason: {reason:?}, Gas used: {gas_used}"); + } + Err(e) => { + println!(" ❌ Error: {e:?}"); + } + } + + // Test 3: Read storage value again to verify the write + println!("\n3. Reading storage value again to verify the write..."); + evm.0.ctx.set_tx( + TxEnv::builder() + .caller(user_address) + .kind(TxKind::Call(CUSTOM_PRECOMPILE_ADDRESS)) + .data(revm::primitives::Bytes::new()) // Empty data for read operation + .gas_limit(100_000) + .nonce(2) + .build() + .unwrap(), + ); + let verify_result: Result<_, MyError> = MainnetHandler::default().run(&mut evm); + + match verify_result { + Ok(revm::context::result::ExecutionResult::Success { + output, gas_used, .. + }) => { + println!(" ✓ Success! Gas used: {gas_used}"); + let data = output.data(); + let value = U256::from_be_slice(data); + println!(" 📖 Final storage value: {value}"); + if value == U256::from(42) { + println!(" 🎉 Storage write was successful!"); + } else { + println!(" ⚠️ Unexpected value in storage"); + } + } + Ok(revm::context::result::ExecutionResult::Revert { output, gas_used }) => { + println!(" ❌ Reverted! Gas used: {gas_used}, Output: {output:?}"); + } + Ok(revm::context::result::ExecutionResult::Halt { reason, gas_used }) => { + println!(" 🛑 Halted! Reason: {reason:?}, Gas used: {gas_used}"); + } + Err(e) => { + println!(" ❌ Error: {e:?}"); + } + } + + // Check final account states + println!("\n=== Final Account States ==="); + let final_context_mut = &mut evm.0.ctx; + + let user_info = final_context_mut.db_mut().basic(user_address).unwrap(); + if let Some(user_account) = user_info { + println!("👤 User balance: {} wei", user_account.balance); + println!(" Received 1 wei reward from precompile!"); + } + + let precompile_info = final_context_mut + .db_mut() + .basic(CUSTOM_PRECOMPILE_ADDRESS) + .unwrap(); + if let Some(precompile_account) = precompile_info { + println!("🔧 Precompile balance: {} wei", precompile_account.balance); + } + + // Check storage directly from the journal using the storage API + println!("📦 Note: Storage state has been modified via journal operations"); + + println!("\n=== Summary ==="); + println!("✅ Custom EVM with journal-accessing precompiles working correctly!"); + println!("📝 Precompile successfully read and wrote storage"); + println!("💸 Balance transfer from precompile to caller executed"); + println!("🔍 All operations properly recorded in the journal"); + println!("🎯 Used default mainnet handler for transaction execution"); + + Ok(()) +} diff --git a/examples/custom_precompile_journal/src/precompile_provider.rs b/examples/custom_precompile_journal/src/precompile_provider.rs new file mode 100644 index 0000000000..caab5682fd --- /dev/null +++ b/examples/custom_precompile_journal/src/precompile_provider.rs @@ -0,0 +1,216 @@ +//! Custom precompile provider implementation. + +use revm::{ + context::Cfg, + context_interface::{ContextTr, JournalTr, LocalContextTr, Transaction}, + handler::{EthPrecompiles, PrecompileProvider}, + interpreter::{Gas, InputsImpl, InstructionResult, InterpreterResult}, + precompile::{PrecompileError, PrecompileOutput, PrecompileResult}, + primitives::{address, hardfork::SpecId, Address, Bytes, U256}, +}; +use std::boxed::Box; +use std::string::String; + +// Define our custom precompile address +pub const CUSTOM_PRECOMPILE_ADDRESS: Address = address!("0000000000000000000000000000000000000100"); + +// Custom storage key for our example +const STORAGE_KEY: U256 = U256::ZERO; + +/// Custom precompile provider that includes journal access functionality +#[derive(Debug, Clone)] +pub struct CustomPrecompileProvider { + inner: EthPrecompiles, + spec: SpecId, +} + +impl CustomPrecompileProvider { + pub fn new_with_spec(spec: SpecId) -> Self { + Self { + inner: EthPrecompiles::default(), + spec, + } + } +} + +impl PrecompileProvider for CustomPrecompileProvider +where + CTX: ContextTr>, +{ + type Output = InterpreterResult; + + fn set_spec(&mut self, spec: ::Spec) -> bool { + if spec == self.spec { + return false; + } + self.spec = spec; + // Create a new inner provider with the new spec + self.inner = EthPrecompiles::default(); + true + } + + fn run( + &mut self, + context: &mut CTX, + address: &Address, + inputs: &InputsImpl, + is_static: bool, + gas_limit: u64, + ) -> Result, String> { + // Check if this is our custom precompile + if *address == CUSTOM_PRECOMPILE_ADDRESS { + return Ok(Some(run_custom_precompile( + context, inputs, is_static, gas_limit, + )?)); + } + + // Otherwise, delegate to standard Ethereum precompiles + self.inner + .run(context, address, inputs, is_static, gas_limit) + } + + fn warm_addresses(&self) -> Box> { + // Include our custom precompile address along with standard ones + let mut addresses = vec![CUSTOM_PRECOMPILE_ADDRESS]; + addresses.extend(self.inner.warm_addresses()); + Box::new(addresses.into_iter()) + } + + fn contains(&self, address: &Address) -> bool { + *address == CUSTOM_PRECOMPILE_ADDRESS || self.inner.contains(address) + } +} + +/// Runs our custom precompile +fn run_custom_precompile( + context: &mut CTX, + inputs: &InputsImpl, + is_static: bool, + gas_limit: u64, +) -> Result { + let input_bytes = match &inputs.input { + revm::interpreter::CallInput::SharedBuffer(range) => { + if let Some(slice) = context.local().shared_memory_buffer_slice(range.clone()) { + slice.to_vec() + } else { + vec![] + } + } + revm::interpreter::CallInput::Bytes(bytes) => bytes.0.to_vec(), + }; + + // For this example, we'll implement a simple precompile that: + // - If called with empty data: reads a storage value + // - If called with 32 bytes: writes that value to storage and transfers 1 wei to the caller + + let result = if input_bytes.is_empty() { + // Read storage operation + handle_read_storage(context, gas_limit) + } else if input_bytes.len() == 32 { + if is_static { + return Err("Cannot modify state in static context".to_string()); + } + // Write storage operation + handle_write_storage(context, &input_bytes, gas_limit) + } else { + Err(PrecompileError::Other("Invalid input length".to_string())) + }; + + match result { + Ok(output) => { + let mut interpreter_result = InterpreterResult { + result: if output.reverted { + InstructionResult::Revert + } else { + InstructionResult::Return + }, + gas: Gas::new(gas_limit), + output: output.bytes, + }; + let underflow = interpreter_result.gas.record_cost(output.gas_used); + if !underflow { + interpreter_result.result = InstructionResult::PrecompileOOG; + } + Ok(interpreter_result) + } + Err(e) => Ok(InterpreterResult { + result: if e.is_oog() { + InstructionResult::PrecompileOOG + } else { + InstructionResult::PrecompileError + }, + gas: Gas::new(gas_limit), + output: Bytes::new(), + }), + } +} + +/// Handles reading from storage +fn handle_read_storage(context: &mut CTX, gas_limit: u64) -> PrecompileResult { + // Base gas cost for reading storage + const BASE_GAS: u64 = 2_100; + + if gas_limit < BASE_GAS { + return Err(PrecompileError::OutOfGas); + } + + // Read from storage using the journal + let value = context + .journal_mut() + .sload(CUSTOM_PRECOMPILE_ADDRESS, STORAGE_KEY) + .map_err(|e| PrecompileError::Other(format!("Storage read failed: {e:?}")))? + .data; + + // Return the value as output + Ok(PrecompileOutput::new( + BASE_GAS, + value.to_be_bytes_vec().into(), + )) +} + +/// Handles writing to storage and transferring balance +fn handle_write_storage( + context: &mut CTX, + input: &[u8], + gas_limit: u64, +) -> PrecompileResult { + // Base gas cost for the operation + const BASE_GAS: u64 = 21_000; + const SSTORE_GAS: u64 = 20_000; + + if gas_limit < BASE_GAS + SSTORE_GAS { + return Err(PrecompileError::OutOfGas); + } + + // Parse the input as a U256 value + let value = U256::from_be_slice(input); + + // Store the value in the precompile's storage + context + .journal_mut() + .sstore(CUSTOM_PRECOMPILE_ADDRESS, STORAGE_KEY, value) + .map_err(|e| PrecompileError::Other(format!("Storage write failed: {e:?}")))?; + + // Get the caller address + let caller = context.tx().caller(); + + // Transfer 1 wei from the precompile to the caller as a reward + // First, ensure the precompile has balance + context + .journal_mut() + .balance_incr(CUSTOM_PRECOMPILE_ADDRESS, U256::from(1)) + .map_err(|e| PrecompileError::Other(format!("Balance increment failed: {e:?}")))?; + + // Then transfer to caller + let transfer_result = context + .journal_mut() + .transfer(CUSTOM_PRECOMPILE_ADDRESS, caller, U256::from(1)) + .map_err(|e| PrecompileError::Other(format!("Transfer failed: {e:?}")))?; + + if let Some(error) = transfer_result { + return Err(PrecompileError::Other(format!("Transfer error: {error:?}"))); + } + + // Return success with empty output + Ok(PrecompileOutput::new(BASE_GAS + SSTORE_GAS, Bytes::new())) +} diff --git a/examples/database_components/Cargo.toml b/examples/database_components/Cargo.toml new file mode 100644 index 0000000000..8aff4db8e7 --- /dev/null +++ b/examples/database_components/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "example-database-components" +version = "0.0.0" +publish = false +authors.workspace = true +edition.workspace = true +keywords.workspace = true +license.workspace = true +repository.workspace = true +readme.workspace = true + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] + +[lints] +workspace = true + +[dependencies] +# srevm +revm.workspace = true + +# misc +auto_impl.workspace = true +thiserror.workspace = true diff --git a/examples/database_components/src/block_hash.rs b/examples/database_components/src/block_hash.rs new file mode 100644 index 0000000000..449929d204 --- /dev/null +++ b/examples/database_components/src/block_hash.rs @@ -0,0 +1,52 @@ +//! BlockHash database component from [`revm::Database`] + +use auto_impl::auto_impl; +use core::{error::Error as StdError, ops::Deref}; +use revm::primitives::B256; +use std::sync::Arc; + +/// Trait for mutable access to block hash data. +/// This is typically used for database implementations that may cache or +/// lazily load block hashes. +#[auto_impl(&mut, Box)] +pub trait BlockHash { + /// Error type for block hash operations + type Error: StdError; + + /// Gets block hash by block number. + fn block_hash(&mut self, number: u64) -> Result; +} + +/// Trait for immutable access to block hash data. +/// This is typically used for read-only database implementations or +/// when block hash data is pre-loaded. +#[auto_impl(&, &mut, Box, Rc, Arc)] +pub trait BlockHashRef { + /// Error type for block hash operations + type Error: StdError; + + /// Gets block hash by block number. + fn block_hash(&self, number: u64) -> Result; +} + +impl BlockHash for &T +where + T: BlockHashRef, +{ + type Error = ::Error; + + fn block_hash(&mut self, number: u64) -> Result { + BlockHashRef::block_hash(*self, number) + } +} + +impl BlockHash for Arc +where + T: BlockHashRef, +{ + type Error = ::Error; + + fn block_hash(&mut self, number: u64) -> Result { + self.deref().block_hash(number) + } +} diff --git a/crates/primitives/src/db/components.rs b/examples/database_components/src/lib.rs similarity index 58% rename from crates/primitives/src/db/components.rs rename to examples/database_components/src/lib.rs index c6348b920a..c683d19f0e 100644 --- a/crates/primitives/src/db/components.rs +++ b/examples/database_components/src/lib.rs @@ -1,3 +1,6 @@ +//! Database component example. +#![cfg_attr(not(test), warn(unused_crate_dependencies))] + //! Database that is split on State and BlockHash traits. pub mod block_hash; pub mod state; @@ -5,25 +8,37 @@ pub mod state; pub use block_hash::{BlockHash, BlockHashRef}; pub use state::{State, StateRef}; -use crate::{ - db::{Database, DatabaseRef}, - Account, AccountInfo, Address, Bytecode, HashMap, B256, U256, +use revm::{ + database_interface::{DBErrorMarker, Database, DatabaseCommit, DatabaseRef}, + primitives::{Address, HashMap, StorageKey, StorageValue, B256}, + state::{Account, AccountInfo, Bytecode}, }; -use super::DatabaseCommit; - +/// A database implementation that separates state and block hash components. +/// This allows for modular database design where state and block hash +/// functionality can be implemented independently. #[derive(Debug)] pub struct DatabaseComponents { + /// State component for account and storage operations pub state: S, + /// Block hash component for retrieving historical block hashes pub block_hash: BH, } -#[derive(Debug)] +/// Error type for database component operations. +/// Wraps errors from both state and block hash components. +#[derive(Debug, thiserror::Error)] pub enum DatabaseComponentError { + /// Error from state component operations + #[error(transparent)] State(SE), + /// Error from block hash component operations + #[error(transparent)] BlockHash(BHE), } +impl DBErrorMarker for DatabaseComponentError {} + impl Database for DatabaseComponents { type Error = DatabaseComponentError; @@ -37,13 +52,17 @@ impl Database for DatabaseComponents { .map_err(Self::Error::State) } - fn storage(&mut self, address: Address, index: U256) -> Result { + fn storage( + &mut self, + address: Address, + index: StorageKey, + ) -> Result { self.state .storage(address, index) .map_err(Self::Error::State) } - fn block_hash(&mut self, number: U256) -> Result { + fn block_hash(&mut self, number: u64) -> Result { self.block_hash .block_hash(number) .map_err(Self::Error::BlockHash) @@ -63,13 +82,17 @@ impl DatabaseRef for DatabaseComponents { .map_err(Self::Error::State) } - fn storage_ref(&self, address: Address, index: U256) -> Result { + fn storage_ref( + &self, + address: Address, + index: StorageKey, + ) -> Result { self.state .storage(address, index) .map_err(Self::Error::State) } - fn block_hash_ref(&self, number: U256) -> Result { + fn block_hash_ref(&self, number: u64) -> Result { self.block_hash .block_hash(number) .map_err(Self::Error::BlockHash) diff --git a/examples/database_components/src/state.rs b/examples/database_components/src/state.rs new file mode 100644 index 0000000000..35f8d40ed8 --- /dev/null +++ b/examples/database_components/src/state.rs @@ -0,0 +1,92 @@ +//! State database component from [`crate::Database`] + +use auto_impl::auto_impl; +use core::ops::Deref; +use revm::{ + primitives::{Address, StorageKey, StorageValue, B256}, + state::{AccountInfo, Bytecode}, +}; +use std::{error::Error as StdError, sync::Arc}; + +/// Trait for mutable access to state data including accounts, code, and storage. +/// This is typically used for database implementations that may modify state +/// or need mutable access for caching purposes. +#[auto_impl(&mut, Box)] +pub trait State { + /// Error type for state operations + type Error: StdError; + + /// Gets basic account information. + fn basic(&mut self, address: Address) -> Result, Self::Error>; + + /// Gets account code by its hash. + fn code_by_hash(&mut self, code_hash: B256) -> Result; + + /// Gets storage value of address at index. + fn storage(&mut self, address: Address, index: StorageKey) + -> Result; +} + +/// Trait for immutable access to state data including accounts, code, and storage. +/// This is typically used for read-only database implementations or when +/// state data is pre-loaded and doesn't require modification. +#[auto_impl(&, &mut, Box, Rc, Arc)] +pub trait StateRef { + /// Error type for state operations + type Error: StdError; + + /// Gets basic account information. + fn basic(&self, address: Address) -> Result, Self::Error>; + + /// Gets account code by its hash. + fn code_by_hash(&self, code_hash: B256) -> Result; + + /// Gets storage value of address at index. + fn storage(&self, address: Address, index: StorageKey) -> Result; +} + +impl State for &T +where + T: StateRef, +{ + type Error = ::Error; + + fn basic(&mut self, address: Address) -> Result, Self::Error> { + StateRef::basic(*self, address) + } + + fn code_by_hash(&mut self, code_hash: B256) -> Result { + StateRef::code_by_hash(*self, code_hash) + } + + fn storage( + &mut self, + address: Address, + index: StorageKey, + ) -> Result { + StateRef::storage(*self, address, index) + } +} + +impl State for Arc +where + T: StateRef, +{ + type Error = ::Error; + + fn basic(&mut self, address: Address) -> Result, Self::Error> { + self.deref().basic(address) + } + + fn code_by_hash(&mut self, code_hash: B256) -> Result { + self.deref().code_by_hash(code_hash) + } + + fn storage( + &mut self, + address: Address, + index: StorageKey, + ) -> Result { + self.deref().storage(address, index) + } +} diff --git a/examples/db_by_ref.rs b/examples/db_by_ref.rs deleted file mode 100644 index 9e3615400c..0000000000 --- a/examples/db_by_ref.rs +++ /dev/null @@ -1,81 +0,0 @@ -use revm::{ - db::{CacheDB, EmptyDB, WrapDatabaseRef}, - handler::register::HandleRegister, - inspector_handle_register, - inspectors::{NoOpInspector, TracerEip3155}, - primitives::ResultAndState, - DatabaseCommit, DatabaseRef, Evm, -}; -use std::error::Error; - -trait DatabaseRefDebugError: DatabaseRef { - type DBError: std::fmt::Debug + Error + Send + Sync + 'static; -} - -impl DatabaseRefDebugError for DB -where - DB: DatabaseRef, - DBError: std::fmt::Debug + Error + Send + Sync + 'static, -{ - type DBError = DBError; -} - -fn run_transaction( - db: DB, - ext: EXT, - register_handles_fn: HandleRegister>, -) -> anyhow::Result<(ResultAndState, DB)> { - let mut evm = Evm::builder() - .with_ref_db(db) - .with_external_context(ext) - .append_handler_register(register_handles_fn) - .build(); - - let result = evm.transact()?; - Ok((result, evm.into_context().evm.inner.db.0)) -} - -fn run_transaction_and_commit_with_ext( - db: DB, - ext: EXT, - register_handles_fn: HandleRegister>, -) -> anyhow::Result<()> { - // To circumvent borrow checker issues, we need to move the database into the - // transaction and return it after the transaction is done. - let (ResultAndState { state: changes, .. }, mut db) = - { run_transaction(db, ext, register_handles_fn)? }; - - db.commit(changes); - - Ok(()) -} - -fn run_transaction_and_commit(db: &mut CacheDB) -> anyhow::Result<()> { - let ResultAndState { state: changes, .. } = { - let rdb = &*db; - - let mut evm = Evm::builder() - .with_ref_db(rdb) - .with_external_context(NoOpInspector) - .append_handler_register(inspector_handle_register) - .build(); - - evm.transact()? - }; - - // No compiler error because there is no lifetime parameter for the `HandleRegister` function - db.commit(changes); - - Ok(()) -} - -fn main() -> anyhow::Result<()> { - let mut cache_db = CacheDB::new(EmptyDB::default()); - - let mut tracer = TracerEip3155::new(Box::new(std::io::stdout())); - - run_transaction_and_commit_with_ext(&mut cache_db, &mut tracer, inspector_handle_register)?; - run_transaction_and_commit(&mut cache_db)?; - - Ok(()) -} diff --git a/examples/erc20_gas/Cargo.toml b/examples/erc20_gas/Cargo.toml new file mode 100644 index 0000000000..2101c4a4c0 --- /dev/null +++ b/examples/erc20_gas/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "example-erc20-gas" +version = "0.0.0" +publish = false +authors.workspace = true +edition.workspace = true +keywords.workspace = true +license.workspace = true +repository.workspace = true +readme.workspace = true + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] + +[lints] +workspace = true + +[dependencies] +revm = { workspace = true, features = ["std", "alloydb"] } + +# tokio +tokio = { workspace = true, features = ["rt-multi-thread", "macros"] } + +# alloy +alloy-sol-types = { workspace = true, features = ["std"] } +alloy-provider = { workspace = true, default-features = true } +anyhow.workspace = true diff --git a/examples/erc20_gas/src/exec.rs b/examples/erc20_gas/src/exec.rs new file mode 100644 index 0000000000..f9f5fd2f52 --- /dev/null +++ b/examples/erc20_gas/src/exec.rs @@ -0,0 +1,62 @@ +use crate::handler::Erc20MainnetHandler; +use revm::{ + context_interface::{ + result::{EVMError, ExecutionResult, HaltReason, InvalidTransaction}, + ContextTr, JournalTr, + }, + database_interface::DatabaseCommit, + handler::{ + instructions::InstructionProvider, ContextTrDbError, EthFrame, EvmTr, Handler, + PrecompileProvider, + }, + interpreter::{interpreter::EthInterpreter, InterpreterResult}, + state::EvmState, +}; + +type Erc20Error = EVMError, InvalidTransaction>; + +/// Executes a transaction using ERC20 tokens for gas payment. +/// Returns the execution result and the finalized state changes. +/// This function does not commit the state to the database. +pub fn transact_erc20evm( + evm: &mut EVM, +) -> Result<(ExecutionResult, EvmState), Erc20Error> +where + EVM: EvmTr< + Context: ContextTr>, + Precompiles: PrecompileProvider, + Instructions: InstructionProvider< + Context = EVM::Context, + InterpreterTypes = EthInterpreter, + >, + Frame = EthFrame, + >, +{ + Erc20MainnetHandler::new().run(evm).map(|r| { + let state = evm.ctx().journal_mut().finalize(); + (r, state) + }) +} + +/// Executes a transaction using ERC20 tokens for gas payment and commits the state. +/// This is a convenience function that runs the transaction and immediately +/// commits the resulting state changes to the database. +pub fn transact_erc20evm_commit( + evm: &mut EVM, +) -> Result, Erc20Error> +where + EVM: EvmTr< + Context: ContextTr, Db: DatabaseCommit>, + Precompiles: PrecompileProvider, + Instructions: InstructionProvider< + Context = EVM::Context, + InterpreterTypes = EthInterpreter, + >, + Frame = EthFrame, + >, +{ + transact_erc20evm(evm).map(|(result, state)| { + evm.ctx().db_mut().commit(state); + result + }) +} diff --git a/examples/erc20_gas/src/handler.rs b/examples/erc20_gas/src/handler.rs new file mode 100644 index 0000000000..c747319899 --- /dev/null +++ b/examples/erc20_gas/src/handler.rs @@ -0,0 +1,172 @@ +use revm::{ + context::Cfg, + context_interface::{ + result::{HaltReason, InvalidTransaction}, + Block, ContextTr, JournalTr, Transaction, + }, + handler::{ + pre_execution::validate_account_nonce_and_code, EvmTr, EvmTrError, FrameResult, FrameTr, + Handler, + }, + interpreter::interpreter_action::FrameInit, + primitives::{hardfork::SpecId, U256}, + state::EvmState, +}; + +use crate::{erc_address_storage, token_operation, TOKEN, TREASURY}; + +/// Custom handler that implements ERC20 token gas payment. +/// Instead of paying gas in ETH, transactions pay gas using ERC20 tokens. +/// The tokens are transferred from the transaction sender to a treasury address. +#[derive(Debug)] +pub struct Erc20MainnetHandler { + _phantom: core::marker::PhantomData<(EVM, ERROR, FRAME)>, +} + +impl Erc20MainnetHandler { + /// Creates a new ERC20 gas payment handler + pub fn new() -> Self { + Self { + _phantom: core::marker::PhantomData, + } + } +} + +impl Default for Erc20MainnetHandler { + fn default() -> Self { + Self::new() + } +} + +impl Handler for Erc20MainnetHandler +where + EVM: EvmTr>, Frame = FRAME>, + FRAME: FrameTr, + ERROR: EvmTrError, +{ + type Evm = EVM; + type Error = ERROR; + type HaltReason = HaltReason; + + fn validate_against_state_and_deduct_caller(&self, evm: &mut Self::Evm) -> Result<(), ERROR> { + let context = evm.ctx(); + let basefee = context.block().basefee() as u128; + let blob_price = context.block().blob_gasprice().unwrap_or_default(); + let is_balance_check_disabled = context.cfg().is_balance_check_disabled(); + let is_eip3607_disabled = context.cfg().is_eip3607_disabled(); + let is_nonce_check_disabled = context.cfg().is_nonce_check_disabled(); + let caller = context.tx().caller(); + let value = context.tx().value(); + + let (tx, journal) = context.tx_journal_mut(); + + // Load caller's account. + let caller_account = journal.load_account_code(tx.caller())?.data; + + validate_account_nonce_and_code( + &mut caller_account.info, + tx.nonce(), + is_eip3607_disabled, + is_nonce_check_disabled, + )?; + + if tx.kind().is_call() { + caller_account.info.nonce = caller_account.info.nonce.saturating_add(1); + } + + // Touch account so we know it is changed. + caller_account.mark_touch(); + + let max_balance_spending = tx.max_balance_spending()?; + let effective_balance_spending = tx + .effective_balance_spending(basefee, blob_price) + .expect("effective balance is always smaller than max balance so it can't overflow"); + + let account_balance_slot = erc_address_storage(tx.caller()); + let account_balance = context + .journal_mut() + .sload(TOKEN, account_balance_slot) + .map(|v| v.data) + .unwrap_or_default(); + + if account_balance < max_balance_spending && !is_balance_check_disabled { + return Err(InvalidTransaction::LackOfFundForMaxFee { + fee: Box::new(max_balance_spending), + balance: Box::new(account_balance), + } + .into()); + }; + + // Check if account has enough balance for `gas_limit * max_fee`` and value transfer. + // Transfer will be done inside `*_inner` functions. + if is_balance_check_disabled { + // ignore balance check. + // TODO add transfer value to the erc20 slot. + } else if max_balance_spending > account_balance { + return Err(InvalidTransaction::LackOfFundForMaxFee { + fee: Box::new(max_balance_spending), + balance: Box::new(account_balance), + } + .into()); + } else { + // subtracting max balance spending with value that is going to be deducted later in the call. + let gas_balance_spending = effective_balance_spending - value; + + token_operation::( + context, + caller, + TREASURY, + gas_balance_spending, + )?; + } + + Ok(()) + } + + fn reimburse_caller( + &self, + evm: &mut Self::Evm, + exec_result: &mut <::Frame as FrameTr>::FrameResult, + ) -> Result<(), Self::Error> { + let context = evm.ctx(); + let basefee = context.block().basefee() as u128; + let caller = context.tx().caller(); + let effective_gas_price = context.tx().effective_gas_price(basefee); + let gas = exec_result.gas(); + + let reimbursement = + effective_gas_price.saturating_mul((gas.remaining() + gas.refunded() as u64) as u128); + token_operation::( + context, + TREASURY, + caller, + U256::from(reimbursement), + )?; + + Ok(()) + } + + fn reward_beneficiary( + &self, + evm: &mut Self::Evm, + exec_result: &mut <::Frame as FrameTr>::FrameResult, + ) -> Result<(), Self::Error> { + let context = evm.ctx(); + let tx = context.tx(); + let beneficiary = context.block().beneficiary(); + let basefee = context.block().basefee() as u128; + let effective_gas_price = tx.effective_gas_price(basefee); + let gas = exec_result.gas(); + + let coinbase_gas_price = if context.cfg().spec().into().is_enabled_in(SpecId::LONDON) { + effective_gas_price.saturating_sub(basefee) + } else { + effective_gas_price + }; + + let reward = coinbase_gas_price.saturating_mul(gas.used() as u128); + token_operation::(context, TREASURY, beneficiary, U256::from(reward))?; + + Ok(()) + } +} diff --git a/examples/erc20_gas/src/main.rs b/examples/erc20_gas/src/main.rs new file mode 100644 index 0000000000..58e2187e7c --- /dev/null +++ b/examples/erc20_gas/src/main.rs @@ -0,0 +1,162 @@ +//! Example of a custom handler for ERC20 gas calculation. +//! +//! Gas is going to be deducted from ERC20 token. + +#![cfg_attr(not(test), warn(unused_crate_dependencies))] + +use alloy_provider::{network::Ethereum, DynProvider, Provider, ProviderBuilder}; +use alloy_sol_types::SolValue; +use anyhow::Result; +use exec::transact_erc20evm_commit; +use revm::{ + context::TxEnv, + context_interface::{ + result::{InvalidHeader, InvalidTransaction}, + ContextTr, JournalTr, + }, + database::{AlloyDB, BlockId, CacheDB}, + database_interface::WrapDatabaseAsync, + primitives::{ + address, hardfork::SpecId, keccak256, Address, StorageValue, TxKind, KECCAK_EMPTY, U256, + }, + state::AccountInfo, + Context, Database, MainBuilder, MainContext, +}; + +/// Execution utilities for ERC20 gas payment transactions +pub mod exec; +/// Custom handler implementation for ERC20 gas payment +pub mod handler; + +type AlloyCacheDB = CacheDB>>; + +// Constants +/// USDC token address on Ethereum mainnet +pub const TOKEN: Address = address!("a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"); +/// Treasury address that receives ERC20 gas payments +pub const TREASURY: Address = address!("0000000000000000000000000000000000000001"); + +#[tokio::main] +async fn main() -> Result<()> { + // Initialize the Alloy provider and database + let rpc_url = "https://mainnet.infura.io/v3/c60b0bb42f8a4c6481ecd229eddaca27"; + let provider = ProviderBuilder::new().connect(rpc_url).await?.erased(); + + let alloy_db = WrapDatabaseAsync::new(AlloyDB::new(provider, BlockId::latest())).unwrap(); + let mut cache_db = CacheDB::new(alloy_db); + + // Random empty account: From + let account = address!("18B06aaF27d44B756FCF16Ca20C1f183EB49111f"); + // Random empty account: To + let account_to = address!("21a4B6F62E51e59274b6Be1705c7c68781B87C77"); + + // USDC has 6 decimals + let hundred_tokens = U256::from(100_000_000_000_000_000u128); + + let balance_slot = erc_address_storage(account); + println!("Balance slot: {balance_slot}"); + cache_db + .insert_account_storage(TOKEN, balance_slot, hundred_tokens * StorageValue::from(2)) + .unwrap(); + cache_db.insert_account_info( + account, + AccountInfo { + nonce: 0, + balance: hundred_tokens * U256::from(2), + code_hash: KECCAK_EMPTY, + code: None, + }, + ); + + let balance_before = balance_of(account, &mut cache_db).unwrap(); + println!("Balance before: {balance_before}"); + + // Transfer 100 tokens from account to account_to + // Magic happens here with custom handlers + transfer(account, account_to, hundred_tokens, &mut cache_db)?; + + let balance_after = balance_of(account, &mut cache_db)?; + println!("Balance after: {balance_after}"); + + Ok(()) +} + +/// Helpers +pub fn token_operation( + context: &mut CTX, + sender: Address, + recipient: Address, + amount: U256, +) -> Result<(), ERROR> +where + CTX: ContextTr, + ERROR: From + From + From<::Error>, +{ + let sender_balance_slot = erc_address_storage(sender); + let sender_balance = context + .journal_mut() + .sload(TOKEN, sender_balance_slot)? + .data; + + if sender_balance < amount { + return Err(ERROR::from( + InvalidTransaction::MaxFeePerBlobGasNotSupported, + )); + } + // Subtract the amount from the sender's balance + let sender_new_balance = sender_balance.saturating_sub(amount); + context + .journal_mut() + .sstore(TOKEN, sender_balance_slot, sender_new_balance)?; + + // Add the amount to the recipient's balance + let recipient_balance_slot = erc_address_storage(recipient); + let recipient_balance = context + .journal_mut() + .sload(TOKEN, recipient_balance_slot)? + .data; + + let recipient_new_balance = recipient_balance.saturating_add(amount); + context + .journal_mut() + .sstore(TOKEN, recipient_balance_slot, recipient_new_balance)?; + + Ok(()) +} + +fn balance_of(address: Address, alloy_db: &mut AlloyCacheDB) -> Result { + let slot = erc_address_storage(address); + alloy_db.storage(TOKEN, slot).map_err(From::from) +} + +fn transfer(from: Address, to: Address, amount: U256, cache_db: &mut AlloyCacheDB) -> Result<()> { + let mut ctx = Context::mainnet() + .with_db(cache_db) + .modify_cfg_chained(|cfg| { + cfg.spec = SpecId::CANCUN; + }) + .with_tx( + TxEnv::builder() + .caller(from) + .kind(TxKind::Call(to)) + .value(amount) + .gas_price(2) + .build() + .unwrap(), + ) + .modify_block_chained(|b| { + b.basefee = 1; + }) + .build_mainnet(); + + transact_erc20evm_commit(&mut ctx).unwrap(); + + Ok(()) +} + +/// Calculates the storage slot for an ERC20 balance mapping. +/// This implements the standard Solidity mapping storage layout where +/// slot = keccak256(abi.encode(address, slot_number)) +pub fn erc_address_storage(address: Address) -> U256 { + keccak256((address, U256::from(4)).abi_encode()).into() +} diff --git a/examples/fork_ref_transact.rs b/examples/fork_ref_transact.rs deleted file mode 100644 index 6953fda2a0..0000000000 --- a/examples/fork_ref_transact.rs +++ /dev/null @@ -1,104 +0,0 @@ -use alloy_sol_types::sol; -use alloy_sol_types::SolCall; -use ethers_providers::{Http, Provider}; -use revm::{ - db::{CacheDB, EmptyDB, EthersDB}, - primitives::{address, ExecutionResult, Output, TransactTo, U256}, - Database, Evm, -}; -use std::sync::Arc; - -#[tokio::main] -async fn main() -> anyhow::Result<()> { - // create ethers client and wrap it in Arc - let client = Provider::::try_from( - "https://mainnet.infura.io/v3/c60b0bb42f8a4c6481ecd229eddaca27", - )?; - let client = Arc::new(client); - - // ----------------------------------------------------------- // - // Storage slots of UniV2Pair contract // - // =========================================================== // - // storage[5] = factory: address // - // storage[6] = token0: address // - // storage[7] = token1: address // - // storage[8] = (res0, res1, ts): (uint112, uint112, uint32) // - // storage[9] = price0CumulativeLast: uint256 // - // storage[10] = price1CumulativeLast: uint256 // - // storage[11] = kLast: uint256 // - // =========================================================== // - - // choose slot of storage that you would like to transact with - let slot = U256::from(8); - - // ETH/USDT pair on Uniswap V2 - let pool_address = address!("0d4a11d5EEaaC28EC3F61d100daF4d40471f1852"); - - // generate abi for the calldata from the human readable interface - sol! { - function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast); - } - - // encode abi into Bytes - let encoded = getReservesCall::new(()).abi_encode(); - - // initialize new EthersDB - let mut ethersdb = EthersDB::new(Arc::clone(&client), None).unwrap(); - - // query basic properties of an account incl bytecode - let acc_info = ethersdb.basic(pool_address).unwrap().unwrap(); - - // query value of storage slot at account address - let value = ethersdb.storage(pool_address, slot).unwrap(); - - // initialise empty in-memory-db - let mut cache_db = CacheDB::new(EmptyDB::default()); - - // insert basic account info which was generated via Web3DB with the corresponding address - cache_db.insert_account_info(pool_address, acc_info); - - // insert our pre-loaded storage slot to the corresponding contract key (address) in the DB - cache_db - .insert_account_storage(pool_address, slot, value) - .unwrap(); - - // initialise an empty (default) EVM - let mut evm = Evm::builder() - .with_db(cache_db) - .modify_tx_env(|tx| { - // fill in missing bits of env struct - // change that to whatever caller you want to be - tx.caller = address!("0000000000000000000000000000000000000000"); - // account you want to transact with - tx.transact_to = TransactTo::Call(pool_address); - // calldata formed via abigen - tx.data = encoded.into(); - // transaction value in wei - tx.value = U256::from(0); - }) - .build(); - - // execute transaction without writing to the DB - let ref_tx = evm.transact().unwrap(); - // select ExecutionResult struct - let result = ref_tx.result; - - // unpack output call enum into raw bytes - let value = match result { - ExecutionResult::Success { - output: Output::Call(value), - .. - } => value, - result => panic!("Execution failed: {result:?}"), - }; - - // decode bytes to reserves + ts via alloy's abi decode - let return_vals = getReservesCall::abi_decode_returns(&value, true)?; - - // Print emulated getReserves() call output - println!("Reserve0: {:#?}", return_vals.reserve0); - println!("Reserve1: {:#?}", return_vals.reserve1); - println!("Timestamp: {:#?}", return_vals.blockTimestampLast); - - Ok(()) -} diff --git a/examples/generate_block_traces.rs b/examples/generate_block_traces.rs deleted file mode 100644 index cfd8f030c1..0000000000 --- a/examples/generate_block_traces.rs +++ /dev/null @@ -1,188 +0,0 @@ -// Example Adapted From: https://github.com/bluealloy/revm/issues/672 - -use ethers_core::types::BlockId; -use ethers_providers::Middleware; -use ethers_providers::{Http, Provider}; -use indicatif::ProgressBar; -use revm::db::{CacheDB, EthersDB, StateBuilder}; -use revm::inspectors::TracerEip3155; -use revm::primitives::{Address, TransactTo, U256}; -use revm::{inspector_handle_register, Evm}; -use std::fs::OpenOptions; -use std::io::BufWriter; -use std::io::Write; -use std::sync::Arc; -use std::sync::Mutex; -use std::time::Instant; - -macro_rules! local_fill { - ($left:expr, $right:expr, $fun:expr) => { - if let Some(right) = $right { - $left = $fun(right.0) - } - }; - ($left:expr, $right:expr) => { - if let Some(right) = $right { - $left = Address::from(right.as_fixed_bytes()) - } - }; -} - -struct FlushWriter { - writer: Arc>>, -} - -impl FlushWriter { - fn new(writer: Arc>>) -> Self { - Self { writer } - } -} - -impl Write for FlushWriter { - fn write(&mut self, buf: &[u8]) -> std::io::Result { - self.writer.lock().unwrap().write(buf) - } - - fn flush(&mut self) -> std::io::Result<()> { - self.writer.lock().unwrap().flush() - } -} - -#[tokio::main] -async fn main() -> anyhow::Result<()> { - // Create ethers client and wrap it in Arc - let client = Provider::::try_from( - "https://mainnet.infura.io/v3/c60b0bb42f8a4c6481ecd229eddaca27", - )?; - let client = Arc::new(client); - - // Params - let chain_id: u64 = 1; - let block_number = 10889447; - - // Fetch the transaction-rich block - let block = match client.get_block_with_txs(block_number).await { - Ok(Some(block)) => block, - Ok(None) => anyhow::bail!("Block not found"), - Err(error) => anyhow::bail!("Error: {:?}", error), - }; - println!("Fetched block number: {}", block.number.unwrap().0[0]); - let previous_block_number = block_number - 1; - - // Use the previous block state as the db with caching - let prev_id: BlockId = previous_block_number.into(); - // SAFETY: This cannot fail since this is in the top-level tokio runtime - let state_db = EthersDB::new(Arc::clone(&client), Some(prev_id)).expect("panic"); - let cache_db: CacheDB>> = CacheDB::new(state_db); - let mut state = StateBuilder::new_with_database(cache_db).build(); - let mut evm = Evm::builder() - .with_db(&mut state) - .with_external_context(TracerEip3155::new(Box::new(std::io::stdout()))) - .modify_block_env(|b| { - if let Some(number) = block.number { - let nn = number.0[0]; - b.number = U256::from(nn); - } - local_fill!(b.coinbase, block.author); - local_fill!(b.timestamp, Some(block.timestamp), U256::from_limbs); - local_fill!(b.difficulty, Some(block.difficulty), U256::from_limbs); - local_fill!(b.gas_limit, Some(block.gas_limit), U256::from_limbs); - if let Some(base_fee) = block.base_fee_per_gas { - local_fill!(b.basefee, Some(base_fee), U256::from_limbs); - } - }) - .modify_cfg_env(|c| { - c.chain_id = chain_id; - }) - .append_handler_register(inspector_handle_register) - .build(); - - let txs = block.transactions.len(); - println!("Found {txs} transactions."); - - let console_bar = Arc::new(ProgressBar::new(txs as u64)); - let start = Instant::now(); - - // Create the traces directory if it doesn't exist - std::fs::create_dir_all("traces").expect("Failed to create traces directory"); - - // Fill in CfgEnv - for tx in block.transactions { - evm = evm - .modify() - .modify_tx_env(|etx| { - etx.caller = Address::from(tx.from.as_fixed_bytes()); - etx.gas_limit = tx.gas.as_u64(); - local_fill!(etx.gas_price, tx.gas_price, U256::from_limbs); - local_fill!(etx.value, Some(tx.value), U256::from_limbs); - etx.data = tx.input.0.into(); - let mut gas_priority_fee = U256::ZERO; - local_fill!( - gas_priority_fee, - tx.max_priority_fee_per_gas, - U256::from_limbs - ); - etx.gas_priority_fee = Some(gas_priority_fee); - etx.chain_id = Some(chain_id); - etx.nonce = Some(tx.nonce.as_u64()); - if let Some(access_list) = tx.access_list { - etx.access_list = access_list - .0 - .into_iter() - .map(|item| { - let new_keys: Vec = item - .storage_keys - .into_iter() - .map(|h256| U256::from_le_bytes(h256.0)) - .collect(); - (Address::from(item.address.as_fixed_bytes()), new_keys) - }) - .collect(); - } else { - etx.access_list = Default::default(); - } - - etx.transact_to = match tx.to { - Some(to_address) => { - TransactTo::Call(Address::from(to_address.as_fixed_bytes())) - } - None => TransactTo::create(), - }; - }) - .build(); - - // Construct the file writer to write the trace to - let tx_number = tx.transaction_index.unwrap().0[0]; - let file_name = format!("traces/{}.json", tx_number); - let write = OpenOptions::new() - .write(true) - .create(true) - .truncate(true) - .open(file_name); - let inner = Arc::new(Mutex::new(BufWriter::new( - write.expect("Failed to open file"), - ))); - let writer = FlushWriter::new(Arc::clone(&inner)); - - // Inspect and commit the transaction to the EVM - evm.context.external.set_writer(Box::new(writer)); - if let Err(error) = evm.transact_commit() { - println!("Got error: {:?}", error); - } - - // Flush the file writer - inner.lock().unwrap().flush().expect("Failed to flush file"); - - console_bar.inc(1); - } - - console_bar.finish_with_message("Finished all transactions."); - - let elapsed = start.elapsed(); - println!( - "Finished execution. Total CPU time: {:.6}s", - elapsed.as_secs_f64() - ); - - Ok(()) -} diff --git a/examples/my_evm/Cargo.toml b/examples/my_evm/Cargo.toml new file mode 100644 index 0000000000..9453097a42 --- /dev/null +++ b/examples/my_evm/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "example-my-evm" +version = "0.0.0" +publish = false +authors.workspace = true +edition.workspace = true +keywords.workspace = true +license.workspace = true +repository.workspace = true +readme.workspace = true + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] + +[lints] +workspace = true + +[dependencies] +revm = { workspace = true } diff --git a/examples/my_evm/README.md b/examples/my_evm/README.md new file mode 100644 index 0000000000..cc80132fc4 --- /dev/null +++ b/examples/my_evm/README.md @@ -0,0 +1,80 @@ +# Custom EVM Implementation Example: MyEvm + +This example demonstrates how to create a custom EVM variant that modifies core behavior, +specifically by disabling the beneficiary reward mechanism. + +## Core Components + +To implement a custom EVM variant, two key components are needed: + +1. A custom EVM struct ([`crate::MyEvm`] in [`crate::evm`]) that implements [`revm::handler::EvmTr`] +2. A custom handler ([`MyHandler`]) in [`crate::handler`] that controls execution behavior and implements [`revm::handler::Handler`] + +Basic usage after implementing these two components: +```rust,ignore +let mut my_evm = MyEvm::new(Context::mainnet(), ()); +let _res = MyHandler::default().run(&mut my_evm); +``` + +## Adding Inspector Support + +To enable transaction inspection capabilities, implement two additional traits: + +- [`revm::inspector::InspectorEvmTr`] on [`MyEvm`] +- [`revm::inspector::InspectorHandler`] on [`MyHandler`] + +This allows integration with [`revm::Inspector`] for transaction tracing: + +```rust,ignore +let mut my_evm = MyEvm::new(Context::mainnet(), revm::inspector::NoOpInspector); +let _res = MyHandler::default().inspect_run(&mut my_evm); +``` + +## High-Level Execution APIs + +The example includes several trait implementations in [`crate::api`] that provide +convenient high-level interfaces: + +### [`revm::ExecuteEvm`] +Provides a simplified interface that abstracts away handler complexity: + +```rust,ignore +let mut my_evm = MyEvm::new(Context::mainnet(), ()); +// Execute a new transaction +let _result_and_state = my_evm.transact(TxEnv::default()); +// Replay the last transaction +let _res_and_state = my_evm.replay(); +``` + +### [`revm::ExecuteCommitEvm`] +Extends [`revm::ExecuteEvm`] with database commit functionality. Requires the database +to implement [`revm::DatabaseCommit`]: + +```rust,ignore +let mut my_evm = MyEvm::new(Context::mainnet().with_db(InMemoryDB::default()), ()); +let _res = my_evm.transact_commit(TxEnv::default()); +``` + +### [`revm::InspectEvm`] +Extends [`revm::ExecuteEvm`] with inspection methods that allow monitoring execution +without committing changes: + +```rust,ignore +let mut my_evm = MyEvm::new(Context::mainnet(), revm::inspector::NoOpInspector); +// Inspect without committing +let _res = my_evm.inspect_replay(); +// Inspect and commit +let _res = my_evm.inspect_commit_replay(); +``` + +### [`revm::SystemCallEvm`] +Allows executing system transaction, only input needed is system contract add address and input +Validation and pre-execution and most of post execution phases of ordinary transact flow will be skipped. + +System calls are needed for inserting of fetching data on pre or post block state. + +```rust,ignore +let mut my_evm = MyEvm::new(Context::mainnet(), revm::inspector::NoOpInspector); +// System call with given input to system contract address. +let _res = my_evm.transact_system_call(bytes!("0x0001"), address!("f529c70db0800449ebd81fbc6e4221523a989f05")); +``` diff --git a/examples/my_evm/src/api.rs b/examples/my_evm/src/api.rs new file mode 100644 index 0000000000..466d507274 --- /dev/null +++ b/examples/my_evm/src/api.rs @@ -0,0 +1,94 @@ +use crate::{evm::MyEvm, handler::MyHandler}; +use revm::{ + context::{ + result::{ExecResultAndState, HaltReason, InvalidTransaction}, + ContextSetters, + }, + context_interface::{ + result::{EVMError, ExecutionResult}, + ContextTr, Database, JournalTr, + }, + handler::{EvmTr, Handler}, + inspector::{InspectCommitEvm, InspectEvm, Inspector, InspectorHandler, JournalExt}, + interpreter::interpreter::EthInterpreter, + state::EvmState, + DatabaseCommit, ExecuteCommitEvm, ExecuteEvm, +}; + +/// Type alias for the error type of the OpEvm. +type MyError = EVMError<<::Db as Database>::Error, InvalidTransaction>; + +// Trait that allows to replay and transact the transaction. +impl ExecuteEvm for MyEvm +where + CTX: ContextSetters>, +{ + type State = EvmState; + type ExecutionResult = ExecutionResult; + type Error = MyError; + + type Tx = ::Tx; + + type Block = ::Block; + + fn set_block(&mut self, block: Self::Block) { + self.0.ctx.set_block(block); + } + + fn transact_one(&mut self, tx: Self::Tx) -> Result { + self.0.ctx.set_tx(tx); + let mut handler = MyHandler::default(); + handler.run(self) + } + + fn finalize(&mut self) -> Self::State { + self.ctx().journal_mut().finalize() + } + + fn replay( + &mut self, + ) -> Result, Self::Error> { + let mut handler = MyHandler::default(); + handler.run(self).map(|result| { + let state = self.finalize(); + ExecResultAndState::new(result, state) + }) + } +} + +// Trait allows replay_commit and transact_commit functionality. +impl ExecuteCommitEvm for MyEvm +where + CTX: ContextSetters>, +{ + fn commit(&mut self, state: Self::State) { + self.ctx().db_mut().commit(state); + } +} + +// Inspection trait. +impl InspectEvm for MyEvm +where + CTX: ContextSetters + JournalExt>, + INSP: Inspector, +{ + type Inspector = INSP; + + fn set_inspector(&mut self, inspector: Self::Inspector) { + self.0.inspector = inspector; + } + + fn inspect_one_tx(&mut self, tx: Self::Tx) -> Result { + self.0.ctx.set_tx(tx); + let mut handler = MyHandler::default(); + handler.inspect_run(self) + } +} + +// Inspect +impl InspectCommitEvm for MyEvm +where + CTX: ContextSetters + JournalExt>, + INSP: Inspector, +{ +} diff --git a/examples/my_evm/src/evm.rs b/examples/my_evm/src/evm.rs new file mode 100644 index 0000000000..a5a11b34c1 --- /dev/null +++ b/examples/my_evm/src/evm.rs @@ -0,0 +1,146 @@ +use revm::{ + context::{ContextError, ContextSetters, ContextTr, Evm, FrameStack}, + handler::{ + evm::FrameTr, instructions::EthInstructions, EthFrame, EthPrecompiles, EvmTr, + FrameInitOrResult, ItemOrResult, + }, + inspector::{InspectorEvmTr, JournalExt}, + interpreter::interpreter::EthInterpreter, + Database, Inspector, +}; + +/// MyEvm variant of the EVM. +/// +/// This struct demonstrates how to create a custom EVM implementation by wrapping +/// the standard REVM components. It combines a context (CTX), an inspector (INSP), +/// and the standard Ethereum instructions, precompiles, and frame execution logic. +/// +/// The generic parameters allow for flexibility in the underlying database and +/// inspection capabilities while maintaining the standard Ethereum execution semantics. +#[derive(Debug)] +pub struct MyEvm( + pub Evm< + CTX, + INSP, + EthInstructions, + EthPrecompiles, + EthFrame, + >, +); + +impl MyEvm { + /// Creates a new instance of MyEvm with the provided context and inspector. + /// + /// # Arguments + /// + /// * `ctx` - The execution context that manages state, environment, and journaling + /// * `inspector` - The inspector for debugging and tracing execution + /// + /// # Returns + /// + /// A new MyEvm instance configured with: + /// - The provided context and inspector + /// - Mainnet instruction set + /// - Default Ethereum precompiles + /// - A fresh frame stack for execution + pub fn new(ctx: CTX, inspector: INSP) -> Self { + Self(Evm { + ctx, + inspector, + instruction: EthInstructions::new_mainnet(), + precompiles: EthPrecompiles::default(), + frame_stack: FrameStack::new(), + }) + } +} + +impl EvmTr for MyEvm +where + CTX: ContextTr, +{ + type Context = CTX; + type Instructions = EthInstructions; + type Precompiles = EthPrecompiles; + type Frame = EthFrame; + fn ctx(&mut self) -> &mut Self::Context { + &mut self.0.ctx + } + + fn ctx_ref(&self) -> &Self::Context { + self.0.ctx_ref() + } + + fn ctx_instructions(&mut self) -> (&mut Self::Context, &mut Self::Instructions) { + self.0.ctx_instructions() + } + + fn ctx_precompiles(&mut self) -> (&mut Self::Context, &mut Self::Precompiles) { + self.0.ctx_precompiles() + } + + fn frame_stack(&mut self) -> &mut FrameStack { + self.0.frame_stack() + } + + fn frame_init( + &mut self, + frame_input: ::FrameInit, + ) -> Result< + ItemOrResult<&mut Self::Frame, ::FrameResult>, + ContextError<<::Db as Database>::Error>, + > { + self.0.frame_init(frame_input) + } + + fn frame_run( + &mut self, + ) -> Result< + FrameInitOrResult, + ContextError<<::Db as Database>::Error>, + > { + self.0.frame_run() + } + + fn frame_return_result( + &mut self, + frame_result: ::FrameResult, + ) -> Result< + Option<::FrameResult>, + ContextError<<::Db as Database>::Error>, + > { + self.0.frame_return_result(frame_result) + } +} + +impl InspectorEvmTr for MyEvm +where + CTX: ContextSetters, + INSP: Inspector, +{ + type Inspector = INSP; + + fn inspector(&mut self) -> &mut Self::Inspector { + self.0.inspector() + } + + fn ctx_inspector(&mut self) -> (&mut Self::Context, &mut Self::Inspector) { + self.0.ctx_inspector() + } + + fn ctx_inspector_frame( + &mut self, + ) -> (&mut Self::Context, &mut Self::Inspector, &mut Self::Frame) { + self.0.ctx_inspector_frame() + } + + fn ctx_inspector_frame_instructions( + &mut self, + ) -> ( + &mut Self::Context, + &mut Self::Inspector, + &mut Self::Frame, + &mut Self::Instructions, + ) { + self.0.ctx_inspector_frame_instructions() + } +} diff --git a/examples/my_evm/src/handler.rs b/examples/my_evm/src/handler.rs new file mode 100644 index 0000000000..e499f87e28 --- /dev/null +++ b/examples/my_evm/src/handler.rs @@ -0,0 +1,75 @@ +use revm::{ + context::result::{EVMError, HaltReason, InvalidTransaction}, + context_interface::{ContextTr, JournalTr}, + handler::{ + evm::FrameTr, instructions::InstructionProvider, EvmTr, FrameResult, Handler, + PrecompileProvider, + }, + inspector::{Inspector, InspectorEvmTr, InspectorHandler}, + interpreter::{interpreter::EthInterpreter, interpreter_action::FrameInit, InterpreterResult}, + state::EvmState, + Database, +}; + +/// Custom handler for MyEvm that defines transaction execution behavior. +/// +/// This handler demonstrates how to customize EVM execution by implementing +/// the Handler trait. It can be extended to add custom validation, modify +/// gas calculations, or implement protocol-specific behavior while maintaining +/// compatibility with the standard EVM execution flow. +#[derive(Debug)] +pub struct MyHandler { + /// Phantom data to maintain the EVM type parameter. + /// This field exists solely to satisfy Rust's type system requirements + /// for generic parameters that aren't directly used in the struct fields. + pub _phantom: core::marker::PhantomData, +} + +impl Default for MyHandler { + fn default() -> Self { + Self { + _phantom: core::marker::PhantomData, + } + } +} + +impl Handler for MyHandler +where + EVM: EvmTr< + Context: ContextTr>, + Precompiles: PrecompileProvider, + Instructions: InstructionProvider< + Context = EVM::Context, + InterpreterTypes = EthInterpreter, + >, + Frame: FrameTr, + >, +{ + type Evm = EVM; + type Error = EVMError<<::Db as Database>::Error, InvalidTransaction>; + type HaltReason = HaltReason; + + fn reward_beneficiary( + &self, + _evm: &mut Self::Evm, + _exec_result: &mut FrameResult, + ) -> Result<(), Self::Error> { + // Skip beneficiary reward + Ok(()) + } +} + +impl InspectorHandler for MyHandler +where + EVM: InspectorEvmTr< + Inspector: Inspector<<::Evm as EvmTr>::Context, EthInterpreter>, + Context: ContextTr>, + Precompiles: PrecompileProvider, + Instructions: InstructionProvider< + Context = EVM::Context, + InterpreterTypes = EthInterpreter, + >, + >, +{ + type IT = EthInterpreter; +} diff --git a/examples/my_evm/src/lib.rs b/examples/my_evm/src/lib.rs new file mode 100644 index 0000000000..380e686fcd --- /dev/null +++ b/examples/my_evm/src/lib.rs @@ -0,0 +1,18 @@ +#![doc = include_str!("../README.md")] + +/// Public API for the custom EVM implementation. +/// This module provides the interface for external users to interact with MyEvm. +pub mod api; + +/// Custom EVM implementation module. +/// This module contains MyEvm, which is a custom variant of the REVM that demonstrates +/// how to create your own EVM implementation by wrapping the standard EVM components. +pub mod evm; + +/// Custom handler implementation for MyEvm. +/// This module contains MyHandler, which defines custom execution behavior for the EVM, +/// including how transactions are processed and how the EVM interacts with inspectors. +pub mod handler; + +pub use evm::*; +pub use handler::*; diff --git a/examples/my_evm/src/main.rs b/examples/my_evm/src/main.rs new file mode 100644 index 0000000000..e23f2342e3 --- /dev/null +++ b/examples/my_evm/src/main.rs @@ -0,0 +1,43 @@ +//! Example of a custom EVM variant. +#![doc = include_str!("../README.md")] +#![cfg_attr(not(test), warn(unused_crate_dependencies))] + +use example_my_evm::{evm::MyEvm, handler::MyHandler}; +use revm::{ + context::TxEnv, + database::InMemoryDB, + handler::{ExecuteCommitEvm, ExecuteEvm, Handler}, + inspector::InspectorHandler, + Context, MainContext, +}; + +/// Example demonstrating various ways to use a custom EVM implementation. +/// +/// This function showcases different usage patterns for MyEvm: +/// 1. Basic transaction execution without inspection +/// 2. Transaction execution with inspector support for debugging +/// 3. Single transaction execution with state finalization +/// 4. Transaction execution with automatic state commitment to the database +/// +/// Each example demonstrates a different aspect of EVM customization and usage, +/// from simple execution to more complex patterns involving state management +/// and transaction inspection. +pub fn main() { + // transact example + let mut my_evm = MyEvm::new(Context::mainnet(), ()); + let _res = MyHandler::default().run(&mut my_evm); + + // inspector example + let mut my_evm = MyEvm::new(Context::mainnet(), revm::inspector::NoOpInspector); + let _res = MyHandler::default().inspect_run(&mut my_evm); + + // Evm Execute example + let mut my_evm = MyEvm::new(Context::mainnet(), ()); + let _result = my_evm.transact_one(TxEnv::default()); + // or if you want to obtain the state by finalizing execution + let _state = my_evm.finalize(); + + // Evm Execute Commit example + let mut my_evm = MyEvm::new(Context::mainnet().with_db(InMemoryDB::default()), ()); + let _res = my_evm.transact_commit(TxEnv::default()); +} diff --git a/examples/uniswap_get_reserves/Cargo.toml b/examples/uniswap_get_reserves/Cargo.toml new file mode 100644 index 0000000000..d1d8d8df2d --- /dev/null +++ b/examples/uniswap_get_reserves/Cargo.toml @@ -0,0 +1,32 @@ +[package] +name = "example-uniswap-get-reserves" +version = "0.0.0" +publish = false +authors.workspace = true +edition.workspace = true +keywords.workspace = true +license.workspace = true +repository.workspace = true +readme.workspace = true + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] + +[lints] +workspace = true + +[dependencies] +# revm +revm = { workspace = true, features = ["std", "alloydb"] } + +# tokio +tokio = { workspace = true, features = ["rt-multi-thread", "macros"] } + +# alloy +alloy-sol-types = { workspace = true, features = ["std"] } +alloy-eips.workspace = true +alloy-provider = { workspace = true, default-features = true } + +# misc +anyhow.workspace = true diff --git a/examples/uniswap_get_reserves/src/main.rs b/examples/uniswap_get_reserves/src/main.rs new file mode 100644 index 0000000000..4b4f9f2a4c --- /dev/null +++ b/examples/uniswap_get_reserves/src/main.rs @@ -0,0 +1,107 @@ +//! Example of uniswap getReserves() call emulation. +#![cfg_attr(not(test), warn(unused_crate_dependencies))] + +use alloy_eips::BlockId; +use alloy_provider::ProviderBuilder; +use alloy_sol_types::{sol, SolCall}; +use revm::{ + context::TxEnv, + context_interface::result::{ExecutionResult, Output}, + database::{AlloyDB, CacheDB}, + database_interface::{DatabaseRef, EmptyDB, WrapDatabaseAsync}, + primitives::{address, StorageKey, TxKind, U256}, + Context, ExecuteEvm, MainBuilder, MainContext, +}; + +#[tokio::main] +async fn main() -> anyhow::Result<()> { + // Initialize the Alloy provider and database + let rpc_url = "https://mainnet.infura.io/v3/c60b0bb42f8a4c6481ecd229eddaca27"; + let provider = ProviderBuilder::new().connect(rpc_url).await?; + + let alloy_db = WrapDatabaseAsync::new(AlloyDB::new(provider, BlockId::latest())).unwrap(); + let cache_db = CacheDB::new(alloy_db); + + // ----------------------------------------------------------- // + // Storage slots of UniV2Pair contract // + // =========================================================== // + // storage[5] = factory: address // + // storage[6] = token0: address // + // storage[7] = token1: address // + // storage[8] = (res0, res1, ts): (uint112, uint112, uint32) // + // storage[9] = price0CumulativeLast: uint256 // + // storage[10] = price1CumulativeLast: uint256 // + // storage[11] = kLast: uint256 // + // =========================================================== // + + // Choose slot of storage that you would like to transact with + let slot = StorageKey::from(8); + + // ETH/USDT pair on Uniswap V2 + let pool_address = address!("0d4a11d5EEaaC28EC3F61d100daF4d40471f1852"); + + // Generate abi for the calldata from the human readable interface + sol! { + function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast); + } + + // Encode abi into Bytes + let encoded = getReservesCall::new(()).abi_encode(); + + // Query basic properties of an account incl bytecode + let acc_info = cache_db.basic_ref(pool_address).unwrap().unwrap(); + + // Query value of storage slot at account address + let value = cache_db.storage_ref(pool_address, slot).unwrap(); + + // Initialise empty in-memory-db + let mut cache_db = CacheDB::new(EmptyDB::default()); + + // Insert basic account info which was generated via Web3DB with the corresponding address + cache_db.insert_account_info(pool_address, acc_info); + + // Insert our pre-loaded storage slot to the corresponding contract key (address) in the DB + cache_db + .insert_account_storage(pool_address, slot, value) + .unwrap(); + + // Initialise an empty (default) EVM + let mut evm = Context::mainnet().with_db(cache_db).build_mainnet(); + + // Execute transaction without writing to the DB + let result = evm + .transact_one( + TxEnv::builder() + // fill in missing bits of env struct + // change that to whatever caller you want to be + .caller(address!("0000000000000000000000000000000000000000")) + // account you want to transact with + .kind(TxKind::Call(pool_address)) + // calldata formed via abigen + .data(encoded.into()) + // transaction value in wei + .value(U256::from(0)) + .build() + .unwrap(), + ) + .unwrap(); + + // Unpack output call enum into raw bytes + let value = match result { + ExecutionResult::Success { + output: Output::Call(value), + .. + } => value, + _ => panic!("Execution failed: {result:?}"), + }; + + // Decode bytes to reserves + ts via alloy's abi decode + let return_vals = getReservesCall::abi_decode_returns(&value)?; + + // Print emulated getReserves() call output + println!("Reserve0: {:#?}", return_vals.reserve0); + println!("Reserve1: {:#?}", return_vals.reserve1); + println!("Timestamp: {:#?}", return_vals.blockTimestampLast); + + Ok(()) +} diff --git a/examples/uniswap_v2_usdc_swap/Cargo.toml b/examples/uniswap_v2_usdc_swap/Cargo.toml new file mode 100644 index 0000000000..90fd3f1372 --- /dev/null +++ b/examples/uniswap_v2_usdc_swap/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "example-uniswap-v2-usdc-swap" +version = "0.0.0" +publish = false +authors.workspace = true +edition.workspace = true +keywords.workspace = true +license.workspace = true +repository.workspace = true +readme.workspace = true + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] + +[lints] +workspace = true + +[dependencies] +revm = { workspace = true, features = ["std", "alloydb"] } + +# tokio +tokio = { workspace = true, features = ["rt-multi-thread", "macros"] } + +# alloy +alloy-sol-types = { workspace = true, features = ["std"] } +alloy-eips.workspace = true +alloy-provider = { workspace = true, default-features = true } +anyhow.workspace = true diff --git a/examples/uniswap_v2_usdc_swap.rs b/examples/uniswap_v2_usdc_swap/src/main.rs similarity index 56% rename from examples/uniswap_v2_usdc_swap.rs rename to examples/uniswap_v2_usdc_swap/src/main.rs index a57a982642..4b374ab537 100644 --- a/examples/uniswap_v2_usdc_swap.rs +++ b/examples/uniswap_v2_usdc_swap/src/main.rs @@ -1,30 +1,31 @@ -use alloy_provider::{network::Ethereum, ProviderBuilder, RootProvider}; -use alloy_rpc_types::BlockId; +//! Example of uniswap getReserves() call emulation. +#![cfg_attr(not(test), warn(unused_crate_dependencies))] + +use alloy_eips::BlockId; +use alloy_provider::{network::Ethereum, DynProvider, Provider, ProviderBuilder}; use alloy_sol_types::{sol, SolCall, SolValue}; -use alloy_transport_http::Http; use anyhow::{anyhow, Result}; -use reqwest::Client; use revm::{ - db::{AlloyDB, CacheDB}, - primitives::{ - address, keccak256, AccountInfo, Address, Bytes, ExecutionResult, Output, TransactTo, U256, - }, - Evm, + context::TxEnv, + context_interface::result::{ExecutionResult, Output}, + database::{AlloyDB, CacheDB}, + database_interface::WrapDatabaseAsync, + primitives::{address, keccak256, Address, Bytes, StorageKey, TxKind, KECCAK_EMPTY, U256}, + state::AccountInfo, + Context, ExecuteCommitEvm, ExecuteEvm, MainBuilder, MainContext, }; use std::ops::Div; -use std::sync::Arc; -type AlloyCacheDB = CacheDB, Ethereum, Arc>>>>; +type AlloyCacheDB = CacheDB>>; #[tokio::main] async fn main() -> Result<()> { - let client = ProviderBuilder::new().on_http( - "https://mainnet.infura.io/v3/c60b0bb42f8a4c6481ecd229eddaca27" - .parse() - .unwrap(), - ); - let client = Arc::new(client); - let mut cache_db = CacheDB::new(AlloyDB::new(client, BlockId::default())); + // Initialize the Alloy provider and database + let rpc_url = "https://mainnet.infura.io/v3/c60b0bb42f8a4c6481ecd229eddaca27"; + let provider = ProviderBuilder::new().connect(rpc_url).await?.erased(); + + let alloy_db = WrapDatabaseAsync::new(AlloyDB::new(provider, BlockId::latest())).unwrap(); + let mut cache_db = CacheDB::new(alloy_db); // Random empty account let account = address!("18B06aaF27d44B756FCF16Ca20C1f183EB49111f"); @@ -33,9 +34,9 @@ async fn main() -> Result<()> { let usdc = address!("a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"); let usdc_weth_pair = address!("B4e16d0168e52d35CaCD2c6185b44281Ec28C9Dc"); - let weth_balance_slot = U256::from(3); + let weth_balance_slot = StorageKey::from(3); - // give our test account some fake WETH and ETH + // Give our test account some fake WETH and ETH let one_ether = U256::from(1_000_000_000_000_000_000u128); let hashed_acc_balance_slot = keccak256((account, weth_balance_slot).abi_encode()); cache_db @@ -45,27 +46,27 @@ async fn main() -> Result<()> { let acc_info = AccountInfo { nonce: 0_u64, balance: one_ether, - code_hash: keccak256(Bytes::new()), + code_hash: KECCAK_EMPTY, code: None, }; cache_db.insert_account_info(account, acc_info); let acc_weth_balance_before = balance_of(weth, account, &mut cache_db)?; - println!("WETH balance before swap: {}", acc_weth_balance_before); + println!("WETH balance before swap: {acc_weth_balance_before}"); let acc_usdc_balance_before = balance_of(usdc, account, &mut cache_db)?; - println!("USDC balance before swap: {}", acc_usdc_balance_before); + println!("USDC balance before swap: {acc_usdc_balance_before}"); let (reserve0, reserve1) = get_reserves(usdc_weth_pair, &mut cache_db)?; let amount_in = one_ether.div(U256::from(10)); - // calculate USDC amount out + // Calculate USDC amount out let amount_out = get_amount_out(amount_in, reserve1, reserve0, &mut cache_db).await?; - // transfer WETH to USDC-WETH pair + // Transfer WETH to USDC-WETH pair transfer(account, usdc_weth_pair, amount_in, weth, &mut cache_db)?; - // execute low-level swap without using UniswapV2 router + // Execute low-level swap without using UniswapV2 router swap( account, usdc_weth_pair, @@ -76,33 +77,34 @@ async fn main() -> Result<()> { )?; let acc_weth_balance_after = balance_of(weth, account, &mut cache_db)?; - println!("WETH balance after swap: {}", acc_weth_balance_after); + println!("WETH balance after swap: {acc_weth_balance_after}"); let acc_usdc_balance_after = balance_of(usdc, account, &mut cache_db)?; - println!("USDC balance after swap: {}", acc_usdc_balance_after); + println!("USDC balance after swap: {acc_usdc_balance_after}"); + println!("OK"); Ok(()) } -fn balance_of(token: Address, address: Address, cache_db: &mut AlloyCacheDB) -> Result { +fn balance_of(token: Address, address: Address, alloy_db: &mut AlloyCacheDB) -> Result { sol! { function balanceOf(address account) public returns (uint256); } let encoded = balanceOfCall { account: address }.abi_encode(); - let mut evm = Evm::builder() - .with_db(cache_db) - .modify_tx_env(|tx| { - // 0x1 because calling USDC proxy from zero address fails - tx.caller = address!("0000000000000000000000000000000000000001"); - tx.transact_to = TransactTo::Call(token); - tx.data = encoded.into(); - tx.value = U256::from(0); - }) - .build(); - - let ref_tx = evm.transact().unwrap(); - let result = ref_tx.result; + let mut evm = Context::mainnet().with_db(alloy_db).build_mainnet(); + + let result = evm + .transact_one( + TxEnv::builder() + .caller(address!("0000000000000000000000000000000000000001")) + .kind(TxKind::Call(token)) + .data(encoded.into()) + .value(U256::from(0)) + .build() + .unwrap(), + ) + .unwrap(); let value = match result { ExecutionResult::Success { @@ -112,7 +114,7 @@ fn balance_of(token: Address, address: Address, cache_db: &mut AlloyCacheDB) -> result => return Err(anyhow!("'balanceOf' execution failed: {result:?}")), }; - let balance = ::abi_decode(&value, false)?; + let balance = ::abi_decode(&value)?; Ok(balance) } @@ -135,18 +137,19 @@ async fn get_amount_out( } .abi_encode(); - let mut evm = Evm::builder() - .with_db(cache_db) - .modify_tx_env(|tx| { - tx.caller = address!("0000000000000000000000000000000000000000"); - tx.transact_to = TransactTo::Call(uniswap_v2_router); - tx.data = encoded.into(); - tx.value = U256::from(0); - }) - .build(); - - let ref_tx = evm.transact().unwrap(); - let result = ref_tx.result; + let mut evm = Context::mainnet().with_db(cache_db).build_mainnet(); + + let result = evm + .transact_one( + TxEnv::builder() + .caller(address!("0000000000000000000000000000000000000000")) + .kind(TxKind::Call(uniswap_v2_router)) + .data(encoded.into()) + .value(U256::from(0)) + .build() + .unwrap(), + ) + .unwrap(); let value = match result { ExecutionResult::Success { @@ -156,7 +159,7 @@ async fn get_amount_out( result => return Err(anyhow!("'getAmountOut' execution failed: {result:?}")), }; - let amount_out = ::abi_decode(&value, false)?; + let amount_out = ::abi_decode(&value)?; Ok(amount_out) } @@ -168,18 +171,19 @@ fn get_reserves(pair_address: Address, cache_db: &mut AlloyCacheDB) -> Result<(U let encoded = getReservesCall {}.abi_encode(); - let mut evm = Evm::builder() - .with_db(cache_db) - .modify_tx_env(|tx| { - tx.caller = address!("0000000000000000000000000000000000000000"); - tx.transact_to = TransactTo::Call(pair_address); - tx.data = encoded.into(); - tx.value = U256::from(0); - }) - .build(); - - let ref_tx = evm.transact().unwrap(); - let result = ref_tx.result; + let mut evm = Context::mainnet().with_db(cache_db).build_mainnet(); + + let result = evm + .transact_one( + TxEnv::builder() + .caller(address!("0000000000000000000000000000000000000000")) + .kind(TxKind::Call(pair_address)) + .data(encoded.into()) + .value(U256::from(0)) + .build() + .unwrap(), + ) + .unwrap(); let value = match result { ExecutionResult::Success { @@ -189,7 +193,7 @@ fn get_reserves(pair_address: Address, cache_db: &mut AlloyCacheDB) -> Result<(U result => return Err(anyhow!("'getReserves' execution failed: {result:?}")), }; - let (reserve0, reserve1, _) = <(U256, U256, u32)>::abi_decode(&value, false)?; + let (reserve0, reserve1, _) = <(U256, U256, u32)>::abi_decode(&value)?; Ok((reserve0, reserve1)) } @@ -217,17 +221,18 @@ fn swap( } .abi_encode(); - let mut evm = Evm::builder() - .with_db(cache_db) - .modify_tx_env(|tx| { - tx.caller = from; - tx.transact_to = TransactTo::Call(pool_address); - tx.data = encoded.into(); - tx.value = U256::from(0); - }) - .build(); + let mut evm = Context::mainnet().with_db(cache_db).build_mainnet(); + + let tx = TxEnv::builder() + .caller(from) + .kind(TxKind::Call(pool_address)) + .data(encoded.into()) + .value(U256::from(0)) + .nonce(1) + .build() + .unwrap(); - let ref_tx = evm.transact_commit().unwrap(); + let ref_tx = evm.transact_commit(tx).unwrap(); match ref_tx { ExecutionResult::Success { .. } => {} @@ -250,22 +255,22 @@ fn transfer( let encoded = transferCall { to, amount }.abi_encode(); - let mut evm = Evm::builder() - .with_db(cache_db) - .modify_tx_env(|tx| { - tx.caller = from; - tx.transact_to = TransactTo::Call(token); - tx.data = encoded.into(); - tx.value = U256::from(0); - }) - .build(); - - let ref_tx = evm.transact_commit().unwrap(); + let mut evm = Context::mainnet().with_db(cache_db).build_mainnet(); + + let tx = TxEnv::builder() + .caller(from) + .kind(TxKind::Call(token)) + .data(encoded.into()) + .value(U256::from(0)) + .build() + .unwrap(); + + let ref_tx = evm.transact_commit(tx).unwrap(); let success: bool = match ref_tx { ExecutionResult::Success { output: Output::Call(value), .. - } => ::abi_decode(&value, false)?, + } => ::abi_decode(&value)?, result => return Err(anyhow!("'transfer' execution failed: {result:?}")), }; diff --git a/funding.json b/funding.json new file mode 100644 index 0000000000..372ec73e9c --- /dev/null +++ b/funding.json @@ -0,0 +1,5 @@ +{ + "opRetro": { + "projectId": "0xb2d109759fe14e11ac5cc100ab6006321ebdd7ffdefbd2efac93a002105f8e92" + } +} diff --git a/publish.sh b/publish.sh deleted file mode 100755 index b6944ae0f1..0000000000 --- a/publish.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash - -# stop on error -set -e - -cargo publish --package revm-primitives -cargo publish --package revm-precompile -cargo publish --package revm-interpreter -cargo publish --package revm -cargo publish --package revme - -echo "All crates published" diff --git a/scripts/publish.sh b/scripts/publish.sh new file mode 100755 index 0000000000..d0ac3c4a24 --- /dev/null +++ b/scripts/publish.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +# stop on error +set -e + +cargo publish --package revm-primitives +cargo publish --package revm-bytecode +cargo publish --package revm-state +cargo publish --package revm-database-interface +cargo publish --package revm-context-interface +cargo publish --package revm-interpreter +cargo publish --package revm-precompile +cargo publish --package revm-database +cargo publish --package revm-context +cargo publish --package revm-handler +cargo publish --package revm-inspector +cargo publish --package revm +cargo publish --package revm-statetest-types +cargo publish --package revme +cargo publish --package op-revm diff --git a/scripts/run-tests.sh b/scripts/run-tests.sh new file mode 100755 index 0000000000..5826df605b --- /dev/null +++ b/scripts/run-tests.sh @@ -0,0 +1,199 @@ +# ./run-tests --help + +#!/bin/bash +set -e + +# Version for the execution spec tests +VERSION="v4.4.0" +DEVELOP_VERSION="fusaka-devnet-3@v1.0.0" + +# Directories +FIXTURES_DIR="test-fixtures" +STABLE_DIR="$FIXTURES_DIR/stable" +DEVELOP_DIR="$FIXTURES_DIR/develop" +LEGACY_DIR="$FIXTURES_DIR/legacytests" + +# URL and filenames +FIXTURES_URL="https://github.com/ethereum/execution-spec-tests/releases/download" +STABLE_TAR="fixtures_stable.tar.gz" +DEVELOP_TAR="fixtures_fusaka-devnet-3.tar.gz" +LEGACY_REPO_URL="https://github.com/ethereum/legacytests.git" + +# Print usage information and exit +usage() { + echo "Usage: $0 [clean] [runner] [profile] [target]" + echo "" + echo "Arguments (after optional 'clean'):" + echo " runner (Optional) Rust runner command. Must be either 'cargo' or 'cross'. Defaults to 'cargo'." + echo " profile (Optional) Rust profile to use. Defaults to 'debug' if not provided." + echo " target (Optional) Rust target. Only used if provided." + echo "" + echo "Examples:" + echo " $0" + echo " Uses runner 'cargo', profile 'debug', and no target." + echo "" + echo " $0 release" + echo " Uses runner 'cargo', profile 'release', and no target." + echo "" + echo " $0 release x86-win" + echo " Uses runner 'cargo', profile 'release', with target 'x86-win'." + echo "" + echo " $0 clean" + echo " Cleans fixtures then uses runner 'cargo', profile 'debug', and no target." + echo "" + echo " $0 clean cross release x86-win" + echo " Cleans fixtures then uses runner 'cross', profile 'release', and target 'x86-win'." + exit 1 +} + +# Check for help flag in any argument. +for arg in "$@"; do + if [ "$arg" = "-h" ] || [ "$arg" = "--help" ]; then + usage + fi +done + +# Deletes the test fixture directory +clean() { + echo "Cleaning test fixtures..." + rm -rf "$FIXTURES_DIR" + echo "Cleaned test fixtures directory." +} + +# Check if all required fixture directories exist +check_fixtures() { + if [ -d "$STABLE_DIR" ] && [ -d "$DEVELOP_DIR" ] && [ -d "$LEGACY_DIR" ]; then + return 0 + else + return 1 + fi +} + +# Download and extract a single fixture +# Arguments: target directory, tar file name, label for logging +download_and_extract() { + local target_dir="$1" + local tar_file="$2" + local label="$3" + local version="$4" + + echo "Downloading ${label} fixtures..." + curl -L "${FIXTURES_URL}/${version}/${tar_file}" -o "${FIXTURES_DIR}/${tar_file}" + echo "Extracting ${label} fixtures..." + # strip-components=1 removes the first top level directory from the flepath + # This is needed because when we extract the tar, it is placed under an + # unnecessary "fixtures/" directory. + tar -xzf "${FIXTURES_DIR}/${tar_file}" --strip-components=1 -C "$target_dir" +} + +# Download all fixtures +download_fixtures() { + echo "Creating fixtures directory structure..." + mkdir -p "$STABLE_DIR" "$DEVELOP_DIR" "$LEGACY_DIR" + + download_and_extract "$STABLE_DIR" "$STABLE_TAR" "stable" "$VERSION" + download_and_extract "$DEVELOP_DIR" "$DEVELOP_TAR" "develop" "$DEVELOP_VERSION" + + echo "Cleaning up tar files..." + rm "${FIXTURES_DIR}/${STABLE_TAR}" "${FIXTURES_DIR}/${DEVELOP_TAR}" + + # Clone legacytests repository + echo "Cloning legacytests repository..." + git clone --depth 1 "$LEGACY_REPO_URL" "$LEGACY_DIR" + + echo "Fixtures download and extraction complete." +} + +# Build Cargo options based on provided profile and target. +# For the profile: +# - "debug" is the default (no extra option needed) +# - "release" adds "--release" +# - Any other value adds "--profile " +# For the target: +# - If provided, add "--target " +build_cargo_options() { + CARGO_OPTS="" + + if [ "$RUST_PROFILE" = "release" ]; then + CARGO_OPTS="--release" + elif [ "$RUST_PROFILE" != "debug" ]; then + CARGO_OPTS="--profile $RUST_PROFILE" + fi + + if [ -n "$RUST_TARGET" ]; then + CARGO_OPTS="$CARGO_OPTS --target $RUST_TARGET" + fi +} + +# Run tests for each set of fixtures using the chosen runner. +run_tests() { + echo "Running stable statetests..." + $RUST_RUNNER run $CARGO_OPTS -p revme -- statetest "$STABLE_DIR/state_tests" + + echo "Running develop statetests..." + $RUST_RUNNER run $CARGO_OPTS -p revme -- statetest "$DEVELOP_DIR/state_tests" + + echo "Running legacy tests..." + $RUST_RUNNER run $CARGO_OPTS -p revme -- statetest "$LEGACY_DIR/Cancun/GeneralStateTests" +} + +############################## +# Main logic + +# If the first argument is "clean", perform cleaning and download fixtures. +if [ "$1" = "clean" ]; then + clean + download_fixtures + shift +else + if check_fixtures; then + echo "Using existing test fixtures." + else + echo "Test fixtures not found. Downloading..." + download_fixtures + fi +fi + +# Argument parsing for runner, profile, target. +# Expected order (after optional clean): [runner] [profile] [target] +# If the first argument is "cargo" or "cross", then it is the runner. +# Otherwise, runner defaults to "cargo", and the arguments are profile and target. +if [ "$#" -eq 0 ]; then + RUST_RUNNER="cargo" + RUST_PROFILE="debug" + RUST_TARGET="" +elif [ "$#" -eq 1 ]; then + if [ "$1" = "cargo" ] || [ "$1" = "cross" ]; then + RUST_RUNNER="$1" + RUST_PROFILE="debug" + RUST_TARGET="" + else + RUST_RUNNER="cargo" + RUST_PROFILE="$1" + RUST_TARGET="" + fi +elif [ "$#" -eq 2 ]; then + if [ "$1" = "cargo" ] || [ "$1" = "cross" ]; then + RUST_RUNNER="$1" + RUST_PROFILE="$2" + RUST_TARGET="" + else + RUST_RUNNER="cargo" + RUST_PROFILE="$1" + RUST_TARGET="$2" + fi +elif [ "$#" -eq 3 ]; then + if [ "$1" = "cargo" ] || [ "$1" = "cross" ]; then + RUST_RUNNER="$1" + RUST_PROFILE="$2" + RUST_TARGET="$3" + else + usage + fi +else + usage +fi + +build_cargo_options +run_tests + diff --git a/typos.toml b/typos.toml new file mode 100644 index 0000000000..db25dd86d7 --- /dev/null +++ b/typos.toml @@ -0,0 +1,5 @@ +[default] +extend-ignore-identifiers-re = ["[sS]imular", "ba"] + +[files] +extend-exclude = ["CHANGELOG.md", "tests"]