├── AUTHORS ├── cmake ├── cable │ ├── .gitignore │ ├── toolchains │ │ ├── default.cmake │ │ ├── cxx14.cmake │ │ ├── cxx17.cmake │ │ ├── cxx11.cmake │ │ ├── cxx14-pic.cmake │ │ ├── cxx17-pic.cmake │ │ ├── cxx11-pic.cmake │ │ ├── cxx14-32bit.cmake │ │ ├── cxx17-32bit.cmake │ │ ├── cxx11-32bit.cmake │ │ ├── cxx11-c99.cmake │ │ ├── cxx11-fpic.cmake │ │ ├── mips64.cmake │ │ └── powerpc64.cmake │ ├── buildinfo │ │ ├── buildinfo.sh.in │ │ ├── buildinfo.ps1.in │ │ ├── buildinfo.json.in │ │ ├── version.h.in │ │ ├── buildinfo.h.in │ │ ├── buildinfo.c.in │ │ └── gitinfo.cmake │ ├── defaults │ │ ├── HunterCacheServers-passwords.cmake │ │ └── HunterCacheServers.cmake │ ├── CableToolchains.cmake │ ├── CablePackage.cmake │ ├── CableBuildType.cmake │ ├── cable.cmake │ ├── bootstrap.cmake │ └── README.md ├── Hunter │ ├── config.cmake │ └── init.cmake ├── toolchains │ └── riscv32.cmake ├── LibraryTools.cmake └── blst.cmake ├── test ├── integration │ ├── statetest │ │ ├── tests1 │ │ │ ├── B │ │ │ │ └── T.json │ │ │ └── SuiteA │ │ │ │ ├── test1.json │ │ │ │ └── test2_multi.json │ │ ├── tests2 │ │ │ └── SuiteA │ │ │ │ └── test1.json │ │ ├── tx │ │ │ └── invalid_nonce.json │ │ └── eof │ │ │ └── invalid_eof_in_state.json │ ├── t8n │ │ ├── base_fee │ │ │ ├── alloc.json │ │ │ ├── txs.json │ │ │ └── env.json │ │ ├── prague_empty_requests │ │ │ ├── alloc.json │ │ │ ├── env.json │ │ │ └── txs.json │ │ └── cancun_create_tx │ │ │ ├── env.json │ │ │ ├── alloc.json │ │ │ └── txs.json │ ├── eofparse │ │ ├── two_errors.txt │ │ └── CMakeLists.txt │ ├── export │ │ └── CMakeLists.txt │ └── CMakeLists.txt ├── bench │ ├── .clang-tidy │ ├── synthetic_benchmarks.hpp │ └── CMakeLists.txt ├── eoftest │ ├── .clang-tidy │ ├── eoftest.hpp │ ├── CMakeLists.txt │ ├── eoftest.cpp │ └── eoftest_runner.cpp ├── internal_benchmarks │ ├── .clang-tidy │ ├── CMakeLists.txt │ ├── memory_allocation.cpp │ ├── realloc_behavior.cpp │ ├── build_complete_tree.py │ └── evmmax_bench.cpp ├── statetest │ ├── .clang-tidy │ ├── statetest_logs_hash.cpp │ ├── CMakeLists.txt │ ├── statetest_export.cpp │ └── statetest_runner.cpp ├── blockchaintest │ ├── .clang-tidy │ ├── CMakeLists.txt │ └── blockchaintest.hpp ├── .clang-tidy ├── eofparse │ ├── CMakeLists.txt │ └── eofparse.cpp ├── fuzzer │ ├── README.md │ └── CMakeLists.txt ├── utils │ ├── stdx │ │ └── utility.hpp │ ├── CMakeLists.txt │ ├── utils.cpp │ └── utils.hpp ├── state │ ├── ethash_difficulty.hpp │ ├── precompiles_stubs.hpp │ ├── hash_utils.hpp │ ├── mpt.hpp │ ├── mpt_hash.hpp │ ├── state_view.hpp │ ├── bloom_filter.hpp │ ├── system_contracts.hpp │ ├── precompiles_silkpre.hpp │ ├── block.cpp │ ├── mpt_hash.cpp │ ├── state_diff.hpp │ ├── requests.hpp │ ├── precompiles.hpp │ ├── bloom_filter.cpp │ ├── block.hpp │ ├── CMakeLists.txt │ ├── account.hpp │ └── system_contracts.cpp ├── unittests │ ├── exportable_fixture.hpp │ ├── statetest_logs_hash_test.cpp │ ├── state_transition_trace_test.cpp │ ├── evm_eip3198_basefee_test.cpp │ ├── state_block_test.cpp │ ├── evm_fixture.cpp │ ├── baseline_analysis_test.cpp │ ├── evm_eip3855_push0_test.cpp │ ├── evm_eip7516_blobbasefee_test.cpp │ ├── precompiles_sha256_test.cpp │ ├── exportable_fixture.cpp │ ├── state_transition_eip663_test.cpp │ ├── evmone_test.cpp │ ├── state_transition_call_test.cpp │ ├── evm_eip3860_initcode_test.cpp │ ├── eof_validation.hpp │ ├── state_precompiles_test.cpp │ ├── precompiles_kzg_test.cpp │ ├── state_transition_transient_storage_test.cpp │ ├── state_system_call_test.cpp │ ├── state_transition_block_test.cpp │ ├── state_transition_extcode_test.cpp │ ├── jumpdest_analysis_test.cpp │ └── precompiles_blake2b_test.cpp ├── t8n │ └── CMakeLists.txt ├── experimental │ ├── CMakeLists.txt │ ├── jumpdest_analysis.hpp │ └── jumpdest_analysis.cpp ├── eofparsefuzz │ ├── eofparsefuzz.cpp │ └── CMakeLists.txt ├── precompiles_bench │ └── CMakeLists.txt └── CMakeLists.txt ├── .gitignore ├── .dockerignore ├── codealike.json ├── codecov.yml ├── .gdbinit ├── .gitmodules ├── lib ├── CMakeLists.txt ├── evmone │ ├── baseline_instruction_table.hpp │ ├── constants.hpp │ ├── advanced_execution.hpp │ ├── cpu_check.cpp │ ├── baseline_instruction_table.cpp │ ├── vm.hpp │ ├── advanced_execution.cpp │ ├── CMakeLists.txt │ ├── tracing.hpp │ ├── vm.cpp │ └── baseline_analysis.cpp ├── evmone_precompiles │ ├── sha256.hpp │ ├── CMakeLists.txt │ ├── ripemd160.hpp │ ├── blake2b.hpp │ ├── kzg.hpp │ ├── bn254.hpp │ ├── expmod.tmpl │ └── secp256k1.hpp └── evmmax │ └── CMakeLists.txt ├── include └── evmone │ └── evmone.h ├── Dockerfile ├── .bumpversion.cfg ├── .clang-format ├── appveyor.yml └── .clang-tidy /AUTHORS: -------------------------------------------------------------------------------- 1 | Paweł Bylica 2 | -------------------------------------------------------------------------------- /cmake/cable/.gitignore: -------------------------------------------------------------------------------- 1 | /.idea 2 | -------------------------------------------------------------------------------- /test/integration/statetest/tests1/B/T.json: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/integration/t8n/base_fee/alloc.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /test/integration/t8n/base_fee/txs.json: -------------------------------------------------------------------------------- 1 | [] 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | /cmake-build-* 3 | /.idea 4 | -------------------------------------------------------------------------------- /test/integration/statetest/tests2/SuiteA/test1.json: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | /.git/ 2 | /.idea/ 3 | /build/ 4 | /.dockerignore 5 | /Dockerfile 6 | -------------------------------------------------------------------------------- /codealike.json: -------------------------------------------------------------------------------- 1 | {"projectId":"cb431fbb-c9ef-4e1a-a15c-47e63373c0df","projectName":"evmone"} -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | codecov: 2 | require_ci_to_pass: false 3 | 4 | comment: 5 | layout: "diff, flags, files" 6 | -------------------------------------------------------------------------------- /test/bench/.clang-tidy: -------------------------------------------------------------------------------- 1 | InheritParentConfig: true 2 | Checks: > 3 | -clang-analyzer-cplusplus.NewDeleteLeaks 4 | -------------------------------------------------------------------------------- /test/eoftest/.clang-tidy: -------------------------------------------------------------------------------- 1 | InheritParentConfig: true 2 | Checks: > 3 | -clang-analyzer-cplusplus.NewDeleteLeaks 4 | -------------------------------------------------------------------------------- /test/internal_benchmarks/.clang-tidy: -------------------------------------------------------------------------------- 1 | InheritParentConfig: true 2 | Checks: > 3 | -clang-analyzer-unix.Malloc 4 | -------------------------------------------------------------------------------- /test/statetest/.clang-tidy: -------------------------------------------------------------------------------- 1 | InheritParentConfig: true 2 | Checks: > 3 | -clang-analyzer-cplusplus.NewDeleteLeaks 4 | -------------------------------------------------------------------------------- /test/blockchaintest/.clang-tidy: -------------------------------------------------------------------------------- 1 | InheritParentConfig: true 2 | Checks: > 3 | -clang-analyzer-cplusplus.NewDeleteLeaks 4 | -------------------------------------------------------------------------------- /test/.clang-tidy: -------------------------------------------------------------------------------- 1 | InheritParentConfig: true 2 | CheckOptions: 3 | - key: readability-identifier-naming.ClassCase 4 | value: aNy_CasE 5 | -------------------------------------------------------------------------------- /cmake/cable/toolchains/default.cmake: -------------------------------------------------------------------------------- 1 | # Cable: CMake Bootstrap Library. 2 | # Copyright 2018 Pawel Bylica. 3 | # Licensed under the Apache License, Version 2.0. See the LICENSE file. 4 | -------------------------------------------------------------------------------- /.gdbinit: -------------------------------------------------------------------------------- 1 | # This file will not auto load by default because of the gdb policy. 2 | # Create ~/.config/gdb/gdbinit with 3 | # set auto-load safe-path 4 | 5 | source -v gdb_pretty_printers.py 6 | -------------------------------------------------------------------------------- /test/integration/t8n/prague_empty_requests/alloc.json: -------------------------------------------------------------------------------- 1 | { 2 | "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { 3 | "code": "", 4 | "nonce": "0x00", 5 | "balance": "0x02540be400" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "evmc"] 2 | path = evmc 3 | url = https://github.com/ethereum/evmc 4 | [submodule "evm-benchmarks"] 5 | path = test/evm-benchmarks 6 | url = https://github.com/ipsilon/evm-benchmarks 7 | -------------------------------------------------------------------------------- /test/integration/t8n/cancun_create_tx/env.json: -------------------------------------------------------------------------------- 1 | { 2 | "currentCoinbase": "0x8888f1f195afa192cfee860698584c030f4c9db1", 3 | "currentNumber": "0x01", 4 | "currentTimestamp": "0x54c99069", 5 | "currentGasLimit": "0x2fefd8" 6 | } 7 | -------------------------------------------------------------------------------- /cmake/cable/buildinfo/buildinfo.sh.in: -------------------------------------------------------------------------------- 1 | PROJECT_NAME='@PROJECT_NAME@' 2 | PROJECT_VERSION='@PROJECT_VERSION@' 3 | PROJECT_VERSION_IS_PRERELEASE='@PROJECT_VERSION_IS_PRERELEASE@' 4 | SYSTEM_NAME='@SYSTEM_NAME@' 5 | SYSTEM_PROCESSOR='@SYSTEM_PROCESSOR@' 6 | -------------------------------------------------------------------------------- /test/integration/t8n/prague_empty_requests/env.json: -------------------------------------------------------------------------------- 1 | { 2 | "currentCoinbase": "0x8888f1f195afa192cfee860698584c030f4c9db1", 3 | "currentNumber": "0x01", 4 | "currentTimestamp": "0x54c99069", 5 | "currentGasLimit": "0x2fefd8" 6 | } 7 | -------------------------------------------------------------------------------- /cmake/cable/toolchains/cxx14.cmake: -------------------------------------------------------------------------------- 1 | # Cable: CMake Bootstrap Library. 2 | # Copyright 2019 Pawel Bylica. 3 | # Licensed under the Apache License, Version 2.0. 4 | 5 | set(CMAKE_CXX_STANDARD 14) 6 | set(CMAKE_CXX_STANDARD_REQUIRED TRUE) 7 | set(CMAKE_CXX_EXTENSIONS OFF) 8 | -------------------------------------------------------------------------------- /cmake/cable/toolchains/cxx17.cmake: -------------------------------------------------------------------------------- 1 | # Cable: CMake Bootstrap Library. 2 | # Copyright 2019 Pawel Bylica. 3 | # Licensed under the Apache License, Version 2.0. 4 | 5 | set(CMAKE_CXX_STANDARD 17) 6 | set(CMAKE_CXX_STANDARD_REQUIRED TRUE) 7 | set(CMAKE_CXX_EXTENSIONS OFF) 8 | -------------------------------------------------------------------------------- /cmake/cable/buildinfo/buildinfo.ps1.in: -------------------------------------------------------------------------------- 1 | $env:project_name="@PROJECT_NAME@" 2 | $env:project_version="@PROJECT_VERSION@" 3 | $env:project_version_is_prerelease="@PROJECT_VERSION_IS_PRERELEASE@" 4 | $env:system_name='@SYSTEM_NAME@' 5 | $env:system_processor='@SYSTEM_PROCESSOR@' 6 | -------------------------------------------------------------------------------- /test/bench/synthetic_benchmarks.hpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2020 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | #pragma once 5 | 6 | namespace evmone::test 7 | { 8 | void register_synthetic_benchmarks(); 9 | } 10 | -------------------------------------------------------------------------------- /cmake/cable/toolchains/cxx11.cmake: -------------------------------------------------------------------------------- 1 | # Cable: CMake Bootstrap Library. 2 | # Copyright 2018 Pawel Bylica. 3 | # Licensed under the Apache License, Version 2.0. See the LICENSE file. 4 | 5 | set(CMAKE_CXX_STANDARD 11) 6 | set(CMAKE_CXX_STANDARD_REQUIRED TRUE) 7 | set(CMAKE_CXX_EXTENSIONS OFF) 8 | -------------------------------------------------------------------------------- /cmake/cable/toolchains/cxx14-pic.cmake: -------------------------------------------------------------------------------- 1 | # Cable: CMake Bootstrap Library. 2 | # Copyright 2019 Pawel Bylica. 3 | # Licensed under the Apache License, Version 2.0. 4 | 5 | set(CMAKE_CXX_STANDARD 14) 6 | set(CMAKE_CXX_STANDARD_REQUIRED TRUE) 7 | set(CMAKE_CXX_EXTENSIONS OFF) 8 | 9 | set(CMAKE_POSITION_INDEPENDENT_CODE ON) 10 | -------------------------------------------------------------------------------- /cmake/cable/toolchains/cxx17-pic.cmake: -------------------------------------------------------------------------------- 1 | # Cable: CMake Bootstrap Library. 2 | # Copyright 2019 Pawel Bylica. 3 | # Licensed under the Apache License, Version 2.0. 4 | 5 | set(CMAKE_CXX_STANDARD 17) 6 | set(CMAKE_CXX_STANDARD_REQUIRED TRUE) 7 | set(CMAKE_CXX_EXTENSIONS OFF) 8 | 9 | set(CMAKE_POSITION_INDEPENDENT_CODE ON) 10 | -------------------------------------------------------------------------------- /lib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # evmone: Fast Ethereum Virtual Machine implementation 2 | # Copyright 2018 The evmone Authors. 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | hunter_add_package(intx) 6 | find_package(intx CONFIG REQUIRED) 7 | 8 | add_subdirectory(evmmax) 9 | add_subdirectory(evmone) 10 | add_subdirectory(evmone_precompiles) 11 | -------------------------------------------------------------------------------- /test/eoftest/eoftest.hpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2023 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | #pragma once 5 | 6 | #include 7 | 8 | namespace evmone::test 9 | { 10 | 11 | void run_eof_test(std::istream& input); 12 | 13 | } // namespace evmone::test 14 | -------------------------------------------------------------------------------- /test/integration/t8n/base_fee/env.json: -------------------------------------------------------------------------------- 1 | { 2 | "currentCoinbase": "0x8888f1f195afa192cfee860698584c030f4c9db1", 3 | "currentNumber": "0x01", 4 | "currentTimestamp": "0x54c99069", 5 | "currentGasLimit": "15000000", 6 | "parentBaseFee": "7", 7 | "parentGasLimit": "5000000", 8 | "parentGasUsed": "5000000" 9 | } 10 | -------------------------------------------------------------------------------- /cmake/cable/toolchains/cxx11-pic.cmake: -------------------------------------------------------------------------------- 1 | # Cable: CMake Bootstrap Library. 2 | # Copyright 2018 Pawel Bylica. 3 | # Licensed under the Apache License, Version 2.0. See the LICENSE file. 4 | 5 | set(CMAKE_CXX_STANDARD 11) 6 | set(CMAKE_CXX_STANDARD_REQUIRED TRUE) 7 | set(CMAKE_CXX_EXTENSIONS OFF) 8 | 9 | set(CMAKE_POSITION_INDEPENDENT_CODE ON) 10 | -------------------------------------------------------------------------------- /cmake/cable/toolchains/cxx14-32bit.cmake: -------------------------------------------------------------------------------- 1 | # Cable: CMake Bootstrap Library. 2 | # Copyright 2019 Pawel Bylica. 3 | # Licensed under the Apache License, Version 2.0. 4 | 5 | set(CMAKE_CXX_STANDARD 14) 6 | set(CMAKE_CXX_STANDARD_REQUIRED TRUE) 7 | set(CMAKE_CXX_EXTENSIONS OFF) 8 | 9 | set(CMAKE_C_FLAGS_INIT -m32) 10 | set(CMAKE_CXX_FLAGS_INIT -m32) 11 | -------------------------------------------------------------------------------- /cmake/cable/toolchains/cxx17-32bit.cmake: -------------------------------------------------------------------------------- 1 | # Cable: CMake Bootstrap Library. 2 | # Copyright 2019 Pawel Bylica. 3 | # Licensed under the Apache License, Version 2.0. 4 | 5 | set(CMAKE_CXX_STANDARD 17) 6 | set(CMAKE_CXX_STANDARD_REQUIRED TRUE) 7 | set(CMAKE_CXX_EXTENSIONS OFF) 8 | 9 | set(CMAKE_C_FLAGS_INIT -m32) 10 | set(CMAKE_CXX_FLAGS_INIT -m32) 11 | -------------------------------------------------------------------------------- /cmake/cable/toolchains/cxx11-32bit.cmake: -------------------------------------------------------------------------------- 1 | # Cable: CMake Bootstrap Library. 2 | # Copyright 2018-2019 Pawel Bylica. 3 | # Licensed under the Apache License, Version 2.0. 4 | 5 | set(CMAKE_CXX_STANDARD 11) 6 | set(CMAKE_CXX_STANDARD_REQUIRED TRUE) 7 | set(CMAKE_CXX_EXTENSIONS OFF) 8 | 9 | set(CMAKE_C_FLAGS_INIT -m32) 10 | set(CMAKE_CXX_FLAGS_INIT -m32) 11 | -------------------------------------------------------------------------------- /test/eofparse/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # evmone: Fast Ethereum Virtual Machine implementation 2 | # Copyright 2023 The evmone Authors. 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | add_executable(evmone-eofparse eofparse.cpp) 6 | target_link_libraries(evmone-eofparse PRIVATE evmone) 7 | target_include_directories(evmone-eofparse PRIVATE ${evmone_private_include_dir}) 8 | -------------------------------------------------------------------------------- /cmake/cable/buildinfo/buildinfo.json.in: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@PROJECT_NAME@", 3 | "version": "@PROJECT_VERSION@", 4 | "is_prerelease": @PROJECT_VERSION_IS_PRERELEASE@, 5 | "commit": "@GIT_COMMIT_HASH@", 6 | "branch": "@GIT_BRANCH@", 7 | "repo": "@GIT_ORIGIN_URL@", 8 | "system_name": "@SYSTEM_NAME@", 9 | "system_processor": "@SYSTEM_PROCESSOR@" 10 | } 11 | -------------------------------------------------------------------------------- /cmake/cable/toolchains/cxx11-c99.cmake: -------------------------------------------------------------------------------- 1 | # Cable: CMake Bootstrap Library. 2 | # Copyright 2018 Pawel Bylica. 3 | # Licensed under the Apache License, Version 2.0. See the LICENSE file. 4 | 5 | set(CMAKE_CXX_STANDARD 11) 6 | set(CMAKE_CXX_STANDARD_REQUIRED TRUE) 7 | set(CMAKE_CXX_EXTENSIONS OFF) 8 | 9 | set(CMAKE_C_STANDARD 99) 10 | set(CMAKE_C_EXTENSIONS OFF) 11 | -------------------------------------------------------------------------------- /test/integration/eofparse/two_errors.txt: -------------------------------------------------------------------------------- 1 | # Example input file to eofparse tool. Two of the following lines contain EOF validation errors. 2 | 3 | # Minimal valid EOF container. 4 | EF0001 010004 0200010001 040000 00 00800000 00 5 | 6 | # Mandatory sections missing 7 | EF0001 00 8 | 9 | # Code section not terminated 10 | EF0001 010004 0200010001 040000 00 00800000 5b 11 | -------------------------------------------------------------------------------- /test/fuzzer/README.md: -------------------------------------------------------------------------------- 1 | # evmone-fuzzer 2 | 3 | > [LibFuzzer] powered testing tool for [EVMC]-compatible EVM implementations. 4 | 5 | ## License 6 | 7 | The evmone-fuzzer source code is licensed under the [Apache License, Version 2.0]. 8 | 9 | 10 | [Apache License, Version 2.0]: https://www.apache.org/licenses/LICENSE-2.0.txt 11 | [EVMC]: https://github.com/ethereum/evmc 12 | [LibFuzzer]: https://llvm.org/docs/LibFuzzer.html 13 | -------------------------------------------------------------------------------- /test/internal_benchmarks/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # evmone: Fast Ethereum Virtual Machine implementation 2 | # Copyright 2019-2020 The evmone Authors. 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | add_executable( 6 | evmone-bench-internal 7 | evmmax_bench.cpp 8 | find_jumpdest_bench.cpp 9 | memory_allocation.cpp 10 | ) 11 | 12 | target_link_libraries(evmone-bench-internal PRIVATE evmone::evmmax benchmark::benchmark) 13 | -------------------------------------------------------------------------------- /test/utils/stdx/utility.hpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2023 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | #pragma once 5 | #include 6 | 7 | namespace stdx 8 | { 9 | template 10 | inline constexpr auto to_underlying(EnumT e) noexcept 11 | { 12 | return static_cast>(e); 13 | } 14 | } // namespace stdx 15 | -------------------------------------------------------------------------------- /test/statetest/statetest_logs_hash.cpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2022 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | #include "../state/rlp.hpp" 6 | #include "statetest.hpp" 7 | 8 | namespace evmone::test 9 | { 10 | hash256 logs_hash(const std::vector& logs) 11 | { 12 | return keccak256(rlp::encode(logs)); 13 | } 14 | } // namespace evmone::test 15 | -------------------------------------------------------------------------------- /cmake/cable/buildinfo/version.h.in: -------------------------------------------------------------------------------- 1 | /* Cable: CMake Bootstrap Library. 2 | * Copyright 2019 Pawel Bylica. 3 | * Licensed under the Apache License, Version 2.0. 4 | */ 5 | 6 | /* Generated by Cable Build Info on @TIMESTAMP@. Do not modify directly. */ 7 | 8 | #pragma once 9 | 10 | #define @PROJECT_NAME_UPPERCASE@_VERSION "@PROJECT_VERSION@" 11 | 12 | #ifdef __cplusplus 13 | constexpr auto @PROJECT_NAME@_version = "@PROJECT_VERSION@"; 14 | #endif 15 | -------------------------------------------------------------------------------- /cmake/cable/toolchains/cxx11-fpic.cmake: -------------------------------------------------------------------------------- 1 | # Cable: CMake Bootstrap Library. 2 | # Copyright 2018 Pawel Bylica. 3 | # Licensed under the Apache License, Version 2.0. See the LICENSE file. 4 | 5 | set(CMAKE_CXX_STANDARD 11) 6 | set(CMAKE_CXX_STANDARD_REQUIRED TRUE) 7 | set(CMAKE_CXX_EXTENSIONS OFF) 8 | 9 | set(CMAKE_POSITION_INDEPENDENT_CODE ON) 10 | 11 | set(CMAKE_CXX_FLAGS_INIT "-fPIC" CACHE STRING "" FORCE) 12 | set(CMAKE_C_FLAGS_INIT "-fPIC" CACHE STRING "" FORCE) 13 | -------------------------------------------------------------------------------- /cmake/Hunter/config.cmake: -------------------------------------------------------------------------------- 1 | # evmone: Fast Ethereum Virtual Machine implementation 2 | # Copyright 2018 The evmone Authors. 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | include(hunter_cmake_args) 6 | 7 | hunter_cmake_args( 8 | ethash 9 | CMAKE_ARGS -DETHASH_BUILD_ETHASH=OFF 10 | ) 11 | 12 | hunter_config( 13 | intx 14 | VERSION 0.12.0 15 | URL https://github.com/chfast/intx/archive/v0.12.0.tar.gz 16 | SHA1 18a64e8e88c50d53325d906c9211daef905b97f4 17 | ) 18 | -------------------------------------------------------------------------------- /include/evmone/evmone.h: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2018-2019 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | #ifndef EVMONE_H 6 | #define EVMONE_H 7 | 8 | #include 9 | #include 10 | 11 | #if __cplusplus 12 | extern "C" { 13 | #endif 14 | 15 | EVMC_EXPORT struct evmc_vm* evmc_create_evmone(void) EVMC_NOEXCEPT; 16 | 17 | #if __cplusplus 18 | } 19 | #endif 20 | 21 | #endif // EVMONE_H 22 | -------------------------------------------------------------------------------- /test/integration/t8n/prague_empty_requests/txs.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "to": null, 4 | "input": "0x", 5 | "gas": "0x186a0", 6 | "nonce": "0x0", 7 | "value": "0x0", 8 | "gasPrice": "0x32", 9 | "chainId": "0x1", 10 | "sender": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", 11 | "v": "0x1b", 12 | "r": "0x468a915f087692bb9be503831a3dfef2cf9c8dee26deb40ff2ec99e8d22665ae", 13 | "s": "0x5cedae0810c3851ecd1004bfdbfe6ddc7753c2d665993bb01ce75af7857b13dc" 14 | } 15 | ] 16 | -------------------------------------------------------------------------------- /test/state/ethash_difficulty.hpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2023 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | #pragma once 5 | 6 | #include 7 | 8 | namespace evmone::state 9 | { 10 | int64_t calculate_difficulty(int64_t parent_difficulty, bool parent_has_ommers, 11 | int64_t parent_timestamp, int64_t current_timestamp, int64_t block_number, 12 | evmc_revision rev) noexcept; 13 | } // namespace evmone::state 14 | -------------------------------------------------------------------------------- /test/unittests/exportable_fixture.hpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2024 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | #pragma once 5 | 6 | #include 7 | 8 | namespace evmone::test 9 | { 10 | class ExportableFixture : public testing::Test 11 | { 12 | protected: 13 | std::string_view export_test_name; 14 | std::string export_file_path; 15 | 16 | ExportableFixture(); 17 | }; 18 | } // namespace evmone::test 19 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:testing as evmone 2 | 3 | RUN apt-get update -q && apt-get install -qy --no-install-recommends \ 4 | ca-certificates g++ cmake ninja-build \ 5 | && rm -rf /var/lib/apt/lists/* 6 | 7 | ADD . /src 8 | RUN mkdir /build \ 9 | && cmake -S /src -B /build -G Ninja -DEVMONE_TESTING=ON -DHUNTER_ROOT=/build \ 10 | && cmake --build /build --target install \ 11 | && ldconfig \ 12 | && rm /build -rf \ 13 | && adduser --disabled-password --no-create-home --gecos '' evmone 14 | USER evmone 15 | -------------------------------------------------------------------------------- /test/eoftest/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # evmone: Fast Ethereum Virtual Machine implementation 2 | # Copyright 2023 The evmone Authors. 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | add_executable(evmone-eoftest) 6 | target_link_libraries(evmone-eoftest PRIVATE evmone evmone::testutils nlohmann_json::nlohmann_json GTest::gtest) 7 | target_include_directories(evmone-eoftest PRIVATE ${evmone_private_include_dir}) 8 | target_sources( 9 | evmone-eoftest PRIVATE 10 | eoftest.cpp 11 | eoftest_runner.cpp 12 | ) 13 | -------------------------------------------------------------------------------- /test/t8n/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # evmone: Fast Ethereum Virtual Machine implementation 2 | # Copyright 2022 The evmone Authors. 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | include(CableBuildInfo) 6 | cable_add_buildinfo_library(PROJECT_NAME evmone) 7 | 8 | add_executable(evmone-t8n) 9 | target_link_libraries(evmone-t8n PRIVATE evmone::statetestutils nlohmann_json::nlohmann_json) 10 | target_link_libraries(evmone-t8n PRIVATE evmc::evmc evmone evmone-buildinfo) 11 | target_sources(evmone-t8n PRIVATE t8n.cpp) 12 | -------------------------------------------------------------------------------- /.bumpversion.cfg: -------------------------------------------------------------------------------- 1 | [bumpversion] 2 | current_version = 0.13.0 3 | tag = True 4 | sign_tags = True 5 | tag_message = evmone {new_version} 6 | commit = True 7 | message = evmone {new_version} 8 | 9 | Bump version: {current_version} -> {new_version} 10 | parse = (?P\d+)\.(?P\d+)\.(?P\d+)(?P-dev)? 11 | serialize = 12 | {major}.{minor}.{patch}{prerel} 13 | {major}.{minor}.{patch} 14 | 15 | [bumpversion:part:prerel] 16 | optional_value = rel 17 | values = 18 | -dev 19 | rel 20 | 21 | [bumpversion:file:CMakeLists.txt] 22 | -------------------------------------------------------------------------------- /cmake/Hunter/init.cmake: -------------------------------------------------------------------------------- 1 | # evmone: Fast Ethereum Virtual Machine implementation 2 | # Copyright 2018 The evmone Authors. 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | set(HUNTER_CONFIGURATION_TYPES Release CACHE STRING "Build type of Hunter packages") 6 | set(HUNTER_USE_CACHE_SERVERS NO CACHE STRING "Download binaries from Hunter cache servers") 7 | 8 | include(HunterGate) 9 | 10 | HunterGate( 11 | URL "https://github.com/cpp-pm/hunter/archive/v0.25.3.tar.gz" 12 | SHA1 "0dfbc2cb5c4cf7e83533733bdfd2125ff96680cb" 13 | LOCAL 14 | ) 15 | -------------------------------------------------------------------------------- /test/experimental/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # evmone: Fast Ethereum Virtual Machine implementation 2 | # Copyright 2020 The evmone Authors. 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | add_library(evmone-experimental STATIC) 6 | add_library(evmone::experimental ALIAS evmone-experimental) 7 | target_link_libraries(evmone-experimental PRIVATE evmone) 8 | target_include_directories(evmone-experimental PRIVATE ${evmone_private_include_dir}) 9 | target_sources( 10 | evmone-experimental PRIVATE 11 | jumpdest_analysis.hpp 12 | jumpdest_analysis.cpp 13 | ) 14 | -------------------------------------------------------------------------------- /lib/evmone/baseline_instruction_table.hpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2020 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | namespace evmone::baseline 10 | { 11 | using CostTable = std::array; 12 | 13 | const CostTable& get_baseline_cost_table(evmc_revision rev, uint8_t eof_version) noexcept; 14 | 15 | const CostTable& get_baseline_legacy_cost_table(evmc_revision rev) noexcept; 16 | } // namespace evmone::baseline 17 | -------------------------------------------------------------------------------- /test/blockchaintest/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # evmone: Fast Ethereum Virtual Machine implementation 2 | # Copyright 2023 The evmone Authors. 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | add_executable(evmone-blockchaintest) 6 | target_link_libraries(evmone-blockchaintest PRIVATE evmone evmone::statetestutils evmone-buildinfo GTest::gtest) 7 | target_include_directories(evmone-blockchaintest PRIVATE ${evmone_private_include_dir}) 8 | target_sources( 9 | evmone-blockchaintest PRIVATE 10 | blockchaintest.hpp 11 | blockchaintest.cpp 12 | blockchaintest_runner.cpp 13 | ) 14 | -------------------------------------------------------------------------------- /test/state/precompiles_stubs.hpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2024 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | #pragma once 5 | 6 | #include "precompiles_internal.hpp" 7 | 8 | namespace evmone::state 9 | { 10 | ExecutionResult expmod_stub( 11 | const uint8_t* input, size_t input_size, uint8_t* output, size_t max_output_size) noexcept; 12 | ExecutionResult ecpairing_stub( 13 | const uint8_t* input, size_t input_size, uint8_t* output, size_t max_output_size) noexcept; 14 | } // namespace evmone::state 15 | -------------------------------------------------------------------------------- /test/integration/t8n/cancun_create_tx/alloc.json: -------------------------------------------------------------------------------- 1 | { 2 | "0x000f3df6d732807ef1319fb7b8bb8522d0beac02": { 3 | "code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604d57602036146024575f5ffd5b5f35801560495762001fff810690815414603c575f5ffd5b62001fff01545f5260205ff35b5f5ffd5b62001fff42064281555f359062001fff015500", 4 | "nonce": "0x01", 5 | "balance": "0x00", 6 | "storage": { 7 | "0x12e2": "0x54c98c81" 8 | } 9 | }, 10 | "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { 11 | "code": "", 12 | "nonce": "0x00", 13 | "balance": "0x02540be400" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lib/evmone/constants.hpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2021 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | #pragma once 5 | 6 | namespace evmone 7 | { 8 | /// The limit of the size of created contract 9 | /// defined by [EIP-170](https://eips.ethereum.org/EIPS/eip-170) 10 | constexpr auto MAX_CODE_SIZE = 0x6000; 11 | 12 | /// The limit of the size of init codes for contract creation 13 | /// defined by [EIP-3860](https://eips.ethereum.org/EIPS/eip-3860) 14 | constexpr auto MAX_INITCODE_SIZE = 2 * MAX_CODE_SIZE; 15 | } // namespace evmone 16 | -------------------------------------------------------------------------------- /test/eofparsefuzz/eofparsefuzz.cpp: -------------------------------------------------------------------------------- 1 | // evmone-fuzzer: LibFuzzer based testing tool for EVMC-compatible EVM implementations. 2 | // Copyright 2023 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | #include 6 | 7 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t data_size) noexcept 8 | { 9 | const evmone::bytes_view eof{data, data_size}; 10 | if (evmone::validate_eof(EVMC_OSAKA, evmone::ContainerKind::runtime, eof) == 11 | evmone::EOFValidationError::success) 12 | (void)evmone::read_valid_eof1_header(eof); 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /cmake/cable/defaults/HunterCacheServers-passwords.cmake: -------------------------------------------------------------------------------- 1 | # Cable: CMake Bootstrap Library. 2 | # Copyright 2018 Pawel Bylica. 3 | # Licensed under the Apache License, Version 2.0. See the LICENSE file. 4 | 5 | # Hunter passwords file used by HunterCacheServers.cmake. 6 | # Do not include directly. 7 | 8 | hunter_upload_password( 9 | # REPO_OWNER + REPO = https://github.com/ethereum/hunter-cache 10 | REPO_OWNER ethereum 11 | REPO hunter-cache 12 | 13 | # USERNAME = https://github.com/hunter-cache-bot 14 | USERNAME hunter-cache-bot 15 | 16 | # PASSWORD = GitHub token saved as a secure environment variable 17 | PASSWORD "$ENV{HUNTER_CACHE_TOKEN}" 18 | ) 19 | -------------------------------------------------------------------------------- /test/utils/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # evmone: Fast Ethereum Virtual Machine implementation 2 | # Copyright 2019 The evmone Authors. 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | find_package(intx CONFIG REQUIRED) 6 | 7 | add_library(testutils STATIC) 8 | add_library(evmone::testutils ALIAS testutils) 9 | target_link_libraries(testutils PUBLIC evmc::evmc_cpp) 10 | target_include_directories(testutils INTERFACE ${PROJECT_SOURCE_DIR} ${evmone_private_include_dir}) 11 | 12 | if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.19) 13 | target_sources( 14 | testutils PRIVATE 15 | bytecode.hpp 16 | stdx/utility.hpp 17 | utils.hpp 18 | ) 19 | endif() 20 | target_sources(testutils PRIVATE utils.cpp) 21 | -------------------------------------------------------------------------------- /cmake/toolchains/riscv32.cmake: -------------------------------------------------------------------------------- 1 | # evmone: Ethereum Virtual Machine 2 | # Copyright 2023 Pawel Bylica. 3 | # Licensed under the Apache License, Version 2.0. See the LICENSE file. 4 | 5 | set(RISCV /usr/local/riscv) 6 | 7 | set(CMAKE_SYSTEM_PROCESSOR riscv32) 8 | set(CMAKE_SYSTEM_NAME Linux) 9 | set(CMAKE_C_COMPILER ${RISCV}/bin/clang) 10 | set(CMAKE_CXX_COMPILER ${RISCV}/bin/clang++) 11 | 12 | set(CMAKE_CXX_FLAGS_INIT -stdlib=libc++) 13 | 14 | set(CMAKE_FIND_ROOT_PATH ${RISCV}/sysroot) 15 | SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) 16 | SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) 17 | SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) 18 | 19 | set(CMAKE_CROSSCOMPILING_EMULATOR qemu-riscv32-static;-L;${CMAKE_FIND_ROOT_PATH}) 20 | -------------------------------------------------------------------------------- /test/fuzzer/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # evmone-fuzzer: LibFuzzer based testing tool for EVMC-compatible EVM implementations. 2 | # Copyright 2019 The evmone Authors. 3 | # SPDX-License-Identifier: Apache-2.0 4 | include(ExternalProject) 5 | 6 | get_target_property(type evmone TYPE) 7 | if(NOT type STREQUAL STATIC_LIBRARY) 8 | message(FATAL_ERROR "The evmone must be built as static library") 9 | endif() 10 | 11 | if(fuzzing_coverage) 12 | set(CMAKE_EXE_LINKER_FLAGS "-fsanitize=fuzzer") 13 | else() 14 | string(REPLACE fuzzer-no-link fuzzer CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS}) 15 | endif() 16 | 17 | add_executable(evmone-fuzzer fuzzer.cpp) 18 | target_link_libraries(evmone-fuzzer PRIVATE evmone evmone::testutils evmc::mocked_host) 19 | -------------------------------------------------------------------------------- /lib/evmone_precompiles/sha256.hpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2022 The Silkworm & evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | #pragma once 5 | 6 | #include 7 | 8 | namespace evmone::crypto 9 | { 10 | /// The size (32 bytes) of the SHA256 message digest. 11 | static constexpr std::size_t SHA256_HASH_SIZE = 256 / 8; 12 | 13 | /// Computes the SHA256 hash function. 14 | /// 15 | /// @param[out] hash The result message digest is written to the provided memory. 16 | /// @param data The input data. 17 | /// @param size The size of the input data. 18 | void sha256(std::byte hash[SHA256_HASH_SIZE], const std::byte* data, size_t size); 19 | } // namespace evmone::crypto 20 | -------------------------------------------------------------------------------- /lib/evmone_precompiles/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # evmone: Fast Ethereum Virtual Machine implementation 2 | # Copyright 2023 The evmone Authors. 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | include(blst) 6 | 7 | add_library(evmone_precompiles STATIC) 8 | add_library(evmone::precompiles ALIAS evmone_precompiles) 9 | target_link_libraries(evmone_precompiles PUBLIC evmc::evmc_cpp PRIVATE evmone::evmmax blst::blst) 10 | target_sources( 11 | evmone_precompiles PRIVATE 12 | blake2b.hpp 13 | blake2b.cpp 14 | bls.hpp 15 | bls.cpp 16 | bn254.hpp 17 | bn254.cpp 18 | ecc.hpp 19 | ripemd160.hpp 20 | ripemd160.cpp 21 | secp256k1.hpp 22 | secp256k1.cpp 23 | sha256.hpp 24 | sha256.cpp 25 | kzg.hpp 26 | kzg.cpp 27 | ) 28 | -------------------------------------------------------------------------------- /test/precompiles_bench/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # evmone: Fast Ethereum Virtual Machine implementation 2 | # Copyright 2024 The evmone Authors. 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | add_executable(evmone-precompiles-bench) 6 | target_compile_features(evmone-precompiles-bench PRIVATE cxx_std_20) 7 | target_include_directories(evmone-precompiles-bench PRIVATE ..) 8 | target_link_libraries(evmone-precompiles-bench PRIVATE evmone::state benchmark::benchmark) 9 | target_sources( 10 | evmone-precompiles-bench PRIVATE 11 | precompiles_bench.cpp 12 | ) 13 | 14 | add_test(NAME evmone/evmone-precompiles-bench COMMAND evmone-precompiles-bench --benchmark_min_time=1x) 15 | set_tests_properties(evmone/evmone-precompiles-bench PROPERTIES FAIL_REGULAR_EXPRESSION "ERROR") 16 | -------------------------------------------------------------------------------- /lib/evmmax/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # evmone: Fast Ethereum Virtual Machine implementation 2 | # Copyright 2023 The evmone Authors. 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | add_library(evmmax INTERFACE) 6 | add_library(evmone::evmmax ALIAS evmmax) 7 | target_compile_features(evmmax INTERFACE cxx_std_20) 8 | target_include_directories(evmmax INTERFACE ${PROJECT_SOURCE_DIR}/include) 9 | target_link_libraries(evmmax INTERFACE intx::intx) 10 | 11 | if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.19) 12 | # We want to add the header file to the library for IDEs. 13 | # However, cmake 3.18 does not support PRIVATE scope for INTERFACE libraries. 14 | target_sources( 15 | evmmax PRIVATE 16 | ${PROJECT_SOURCE_DIR}/include/evmmax/evmmax.hpp 17 | ) 18 | endif() 19 | -------------------------------------------------------------------------------- /lib/evmone_precompiles/ripemd160.hpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2024 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | #pragma once 6 | #include 7 | 8 | namespace evmone::crypto 9 | { 10 | /// The size (20 bytes) of the RIPEMD-160 message digest. 11 | static constexpr std::size_t RIPEMD160_HASH_SIZE = 160 / 8; 12 | 13 | /// Computes the RIPEMD-160 hash function. 14 | /// 15 | /// @param[out] hash The result message digest is written to the provided memory. 16 | /// @param data The input data. 17 | /// @param size The size of the input data. 18 | void ripemd160( 19 | std::byte hash[RIPEMD160_HASH_SIZE], const std::byte* data, std::size_t size) noexcept; 20 | 21 | } // namespace evmone::crypto 22 | -------------------------------------------------------------------------------- /test/eofparsefuzz/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # evmone-fuzzer: LibFuzzer based testing tool for EVMC-compatible EVM implementations. 2 | # Copyright 2023 The evmone Authors. 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | get_target_property(type evmone TYPE) 6 | if(NOT type STREQUAL STATIC_LIBRARY) 7 | message(FATAL_ERROR "The evmone must be built as static library") 8 | endif() 9 | 10 | if(fuzzing_coverage) 11 | set(CMAKE_EXE_LINKER_FLAGS "-fsanitize=fuzzer") 12 | else() 13 | string(REPLACE fuzzer-no-link fuzzer CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS}) 14 | endif() 15 | 16 | add_executable(evmone-eofparsefuzz eofparsefuzz.cpp) 17 | target_link_libraries(evmone-eofparsefuzz PRIVATE evmone) 18 | target_include_directories(evmone-eofparsefuzz PRIVATE ${evmone_private_include_dir}) 19 | -------------------------------------------------------------------------------- /test/unittests/statetest_logs_hash_test.cpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2023 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | #include 6 | #include 7 | 8 | using namespace evmone; 9 | using namespace evmone::state; 10 | 11 | TEST(statetest_logs_hash, empty_logs) 12 | { 13 | EXPECT_EQ(test::logs_hash({}), EmptyListHash); 14 | } 15 | 16 | TEST(statetest_logs_hash, example1) 17 | { 18 | const std::vector logs{ 19 | Log{0x00_address, bytes{0xb0, 0xb1}, {}}, 20 | Log{0xaa_address, {}, {0x01_bytes32, 0x02_bytes32}}, 21 | }; 22 | 23 | EXPECT_EQ(test::logs_hash(logs), 24 | 0xb27f856c430c0266d2925d442632401e63685677a4ea009f855dee23e74488aa_bytes32); 25 | } 26 | -------------------------------------------------------------------------------- /test/experimental/jumpdest_analysis.hpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2020 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | namespace evmone::exp::jda 10 | { 11 | using evmc::bytes_view; 12 | 13 | /// Bitset of valid jumpdest positions. 14 | class JumpdestBitset : std::vector 15 | { 16 | public: 17 | using std::vector::operator[]; 18 | 19 | JumpdestBitset(size_t size) : std::vector(size) {} 20 | 21 | bool check_jumpdest(size_t index) const noexcept { return index < size() && (*this)[index]; } 22 | }; 23 | 24 | JumpdestBitset reference(bytes_view code); 25 | JumpdestBitset speculate_push_data_size(bytes_view code); 26 | } // namespace evmone::exp::jda 27 | -------------------------------------------------------------------------------- /lib/evmone/advanced_execution.hpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2018 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | namespace evmone::advanced 10 | { 11 | struct AdvancedExecutionState; 12 | struct AdvancedCodeAnalysis; 13 | 14 | /// Execute the already analyzed code using the provided execution state. 15 | EVMC_EXPORT evmc_result execute( 16 | AdvancedExecutionState& state, const AdvancedCodeAnalysis& analysis) noexcept; 17 | 18 | /// EVMC-compatible execute() function. 19 | evmc_result execute(evmc_vm* vm, const evmc_host_interface* host, evmc_host_context* ctx, 20 | evmc_revision rev, const evmc_message* msg, const uint8_t* code, size_t code_size) noexcept; 21 | } // namespace evmone::advanced 22 | -------------------------------------------------------------------------------- /lib/evmone_precompiles/blake2b.hpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2024 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | #pragma once 5 | #include 6 | #include 7 | 8 | namespace evmone::crypto 9 | { 10 | /// BLAKE2b compress function F. 11 | /// https://datatracker.ietf.org/doc/html/rfc7693#section-3.2 12 | /// 13 | /// @param rounds the number of rounds to perform 14 | /// @param[in,out] h the state vector 15 | /// @param m the block vector 16 | /// @param t the 128-bit offset counter, {low word, high word} 17 | /// @param last the final block indicator flag "f" 18 | void blake2b_compress( 19 | uint32_t rounds, uint64_t h[8], const uint64_t m[16], const uint64_t t[2], bool last) noexcept; 20 | } // namespace evmone::crypto 21 | -------------------------------------------------------------------------------- /cmake/cable/buildinfo/buildinfo.h.in: -------------------------------------------------------------------------------- 1 | /* Cable: CMake Bootstrap Library. 2 | * Copyright 2018 Pawel Bylica. 3 | * Licensed under the Apache License, Version 2.0. See the LICENSE file. 4 | */ 5 | 6 | /* Generated by Cable Build Info on @TIMESTAMP@. Do not modify directly. */ 7 | 8 | #pragma once 9 | 10 | #ifdef __cplusplus 11 | extern "C" 12 | { 13 | #endif 14 | 15 | struct buildinfo 16 | { 17 | const char* project_name; 18 | const char* project_version; 19 | const char* project_name_with_version; 20 | const char* git_commit_hash; 21 | const char* git_branch; 22 | const char* system_name; 23 | const char* system_processor; 24 | const char* compiler_id; 25 | const char* compiler_version; 26 | const char* build_type; 27 | }; 28 | 29 | const struct buildinfo* @FUNCTION_NAME@(void); 30 | 31 | #ifdef __cplusplus 32 | } 33 | #endif 34 | -------------------------------------------------------------------------------- /test/unittests/state_transition_trace_test.cpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2023 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | #include "state_transition.hpp" 6 | #include 7 | 8 | using namespace evmc::literals; 9 | using namespace evmone::test; 10 | 11 | TEST_F(state_transition, trace_example) 12 | { 13 | tx.to = To; 14 | pre.insert(To, {.code = revert(0, 1)}); 15 | 16 | expect.status = EVMC_REVERT; 17 | expect.post[To].exists = true; 18 | 19 | expect.trace = R"( 20 | {"pc":0,"op":96,"gas":"0xef038","gasCost":"0x3","memSize":0,"stack":[],"depth":1,"refund":0,"opName":"PUSH1"} 21 | {"pc":2,"op":96,"gas":"0xef035","gasCost":"0x3","memSize":0,"stack":["0x1"],"depth":1,"refund":0,"opName":"PUSH1"} 22 | {"pc":4,"op":253,"gas":"0xef032","gasCost":"0x0","memSize":0,"stack":["0x1","0x0"],"depth":1,"refund":0,"opName":"REVERT"} 23 | )"; 24 | } 25 | -------------------------------------------------------------------------------- /cmake/cable/buildinfo/buildinfo.c.in: -------------------------------------------------------------------------------- 1 | /* Cable: CMake Bootstrap Library. 2 | * Copyright 2018 Pawel Bylica. 3 | * Licensed under the Apache License, Version 2.0. See the LICENSE file. 4 | */ 5 | 6 | /* Generated by Cable Build Info on @TIMESTAMP@. Do not modify directly. */ 7 | 8 | #include "buildinfo.h" 9 | 10 | const struct buildinfo* @FUNCTION_NAME@(void) 11 | { 12 | static const struct buildinfo buildinfo = { 13 | .project_name = "@PROJECT_NAME@", 14 | .project_version = "@PROJECT_VERSION@", 15 | .project_name_with_version = "@PROJECT_NAME@-@PROJECT_VERSION@", 16 | .git_commit_hash = "@GIT_COMMIT_HASH@", 17 | .git_branch = "@GIT_BRANCH@", 18 | .system_name = "@SYSTEM_NAME@", 19 | .system_processor = "@SYSTEM_PROCESSOR@", 20 | .compiler_id = "@COMPILER_ID@", 21 | .compiler_version = "@COMPILER_VERSION@", 22 | .build_type = "@BUILD_TYPE@", 23 | }; 24 | return &buildinfo; 25 | } 26 | -------------------------------------------------------------------------------- /lib/evmone/cpu_check.cpp: -------------------------------------------------------------------------------- 1 | 2 | #define STRINGIFY_HELPER(X) #X 3 | #define STRINGIFY(X) STRINGIFY_HELPER(X) 4 | 5 | #if defined(__GNUC__) && __GNUC__ >= 12 6 | #define CPU_FEATURE "x86-64-v" STRINGIFY(EVMONE_X86_64_ARCH_LEVEL) 7 | #else 8 | // TODO(clang-18): x86 architecture levels are supported in __builtin_cpu_supports() 9 | // since GCC 11 and Clang 18. Use approximations as fallback. 10 | #if EVMONE_X86_64_ARCH_LEVEL == 2 11 | #define CPU_FEATURE "sse4.2" 12 | #elif EVMONE_X86_64_ARCH_LEVEL == 3 13 | #define CPU_FEATURE "avx2" 14 | #endif 15 | #endif 16 | 17 | #ifndef CPU_FEATURE 18 | #error "EVMONE_X86_64_ARCH_LEVEL: Unsupported x86-64 architecture level" 19 | #endif 20 | 21 | #include 22 | #include 23 | 24 | static bool cpu_check = []() noexcept { 25 | if (!__builtin_cpu_supports(CPU_FEATURE)) 26 | { 27 | (void)std::fputs("CPU does not support " CPU_FEATURE "\n", stderr); 28 | std::abort(); 29 | } 30 | return false; 31 | }(); 32 | -------------------------------------------------------------------------------- /cmake/cable/toolchains/mips64.cmake: -------------------------------------------------------------------------------- 1 | # Cable: CMake Bootstrap Library. 2 | # Copyright 2018 Pawel Bylica. 3 | # Licensed under the Apache License, Version 2.0. See the LICENSE file. 4 | 5 | set(CMAKE_SYSTEM_PROCESSOR mips64) 6 | set(CMAKE_SYSTEM_NAME Linux) 7 | set(CMAKE_C_COMPILER mips64-linux-gnuabi64-gcc) 8 | set(CMAKE_CXX_COMPILER mips64-linux-gnuabi64-g++) 9 | 10 | set(CMAKE_FIND_ROOT_PATH /usr/mips64-linux-gnuabi64) 11 | SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) 12 | SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) 13 | SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) 14 | 15 | set(CMAKE_CXX_STANDARD 11) 16 | set(CMAKE_CXX_STANDARD_REQUIRED TRUE) 17 | set(CMAKE_CXX_EXTENSIONS Off) 18 | 19 | if(${CMAKE_VERSION} VERSION_LESS 3.10.0) 20 | # Until CMake 3.10 the FindThreads uses try_run() check of -pthread flag, 21 | # what causes CMake error in crosscompiling mode. Avoid the try_run() check 22 | # by specifying the result up front. 23 | set(THREADS_PTHREAD_ARG TRUE) 24 | endif() 25 | -------------------------------------------------------------------------------- /cmake/cable/toolchains/powerpc64.cmake: -------------------------------------------------------------------------------- 1 | # Cable: CMake Bootstrap Library. 2 | # Copyright 2018 Pawel Bylica. 3 | # Licensed under the Apache License, Version 2.0. See the LICENSE file. 4 | 5 | set(CMAKE_SYSTEM_PROCESSOR powerpc64) 6 | set(CMAKE_SYSTEM_NAME Linux) 7 | set(CMAKE_C_COMPILER powerpc64-linux-gnu-gcc) 8 | set(CMAKE_CXX_COMPILER powerpc64-linux-gnu-g++) 9 | 10 | set(CMAKE_FIND_ROOT_PATH /usr/powerpc64-linux-gnu) 11 | SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) 12 | SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) 13 | SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) 14 | 15 | set(CMAKE_CXX_STANDARD 11) 16 | set(CMAKE_CXX_STANDARD_REQUIRED TRUE) 17 | set(CMAKE_CXX_EXTENSIONS OFF) 18 | 19 | if(${CMAKE_VERSION} VERSION_LESS 3.10.0) 20 | # Until CMake 3.10 the FindThreads uses try_run() check of -pthread flag, 21 | # what causes CMake error in crosscompiling mode. Avoid the try_run() check 22 | # by specifying the result up front. 23 | set(THREADS_PTHREAD_ARG TRUE) 24 | endif() 25 | -------------------------------------------------------------------------------- /test/unittests/evm_eip3198_basefee_test.cpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2021 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | /// This file contains EVM unit tests for EIP-3198 "BASEFEE opcode" 6 | /// https://eips.ethereum.org/EIPS/eip-3198 7 | 8 | #include "evm_fixture.hpp" 9 | 10 | using namespace evmone::test; 11 | 12 | TEST_P(evm, basefee_pre_london) 13 | { 14 | rev = EVMC_BERLIN; 15 | const auto code = bytecode{OP_BASEFEE}; 16 | 17 | execute(code); 18 | EXPECT_STATUS(EVMC_UNDEFINED_INSTRUCTION); 19 | } 20 | 21 | TEST_P(evm, basefee_nominal_case) 22 | { 23 | // https://eips.ethereum.org/EIPS/eip-3198#nominal-case 24 | rev = EVMC_LONDON; 25 | host.tx_context.block_base_fee = evmc::bytes32{7}; 26 | 27 | execute(bytecode{} + OP_BASEFEE + OP_STOP); 28 | EXPECT_GAS_USED(EVMC_SUCCESS, 2); 29 | 30 | execute(bytecode{} + OP_BASEFEE + ret_top()); 31 | EXPECT_GAS_USED(EVMC_SUCCESS, 17); 32 | EXPECT_OUTPUT_INT(7); 33 | } 34 | -------------------------------------------------------------------------------- /test/unittests/state_block_test.cpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2023 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | #include 6 | #include 7 | 8 | using namespace evmone::state; 9 | using namespace intx::literals; 10 | 11 | TEST(state_block, blob_gas_price) 12 | { 13 | static constexpr uint64_t TARGET_BLOB_GAS_PER_BLOCK = 0x60000; 14 | 15 | EXPECT_EQ(compute_blob_gas_price(0), 1); 16 | EXPECT_EQ(compute_blob_gas_price(1), 1); 17 | EXPECT_EQ(compute_blob_gas_price(TARGET_BLOB_GAS_PER_BLOCK), 1); 18 | EXPECT_EQ(compute_blob_gas_price(TARGET_BLOB_GAS_PER_BLOCK * 2), 1); 19 | EXPECT_EQ(compute_blob_gas_price(TARGET_BLOB_GAS_PER_BLOCK * 7), 2); 20 | 21 | EXPECT_EQ(compute_blob_gas_price(10'000'000), 19); 22 | EXPECT_EQ(compute_blob_gas_price(100'000'000), 10203769476395); 23 | 24 | // Close to the computation overflowing: 25 | EXPECT_EQ(compute_blob_gas_price(400'000'000), 26 | 10840331274704280429132033759016842817414750029778539_u256); 27 | } 28 | -------------------------------------------------------------------------------- /test/state/hash_utils.hpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2022 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | namespace evmone 13 | { 14 | using evmc::address; 15 | using evmc::bytes; 16 | using evmc::bytes32; 17 | using evmc::bytes_view; 18 | using namespace evmc::literals; 19 | 20 | /// Default type for 256-bit hash. 21 | /// 22 | /// Better than ethash::hash256 because has some additional handy constructors. 23 | using hash256 = bytes32; 24 | 25 | /// The hash of the empty RLP list, i.e. keccak256({0xc0}). 26 | static constexpr auto EmptyListHash = 27 | 0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347_bytes32; 28 | 29 | /// Computes Keccak hash out of input bytes (wrapper of ethash::keccak256). 30 | inline hash256 keccak256(bytes_view data) noexcept 31 | { 32 | return std::bit_cast(ethash::keccak256(data.data(), data.size())); 33 | } 34 | } // namespace evmone 35 | -------------------------------------------------------------------------------- /test/unittests/evm_fixture.cpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2019-2020 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | #include "evm_fixture.hpp" 6 | #include 7 | 8 | namespace evmone::test 9 | { 10 | namespace 11 | { 12 | evmc::VM advanced_vm{evmc_create_evmone(), {{"advanced", ""}}}; 13 | evmc::VM baseline_vm{evmc_create_evmone()}; 14 | evmc::VM bnocgoto_vm{evmc_create_evmone(), {{"cgoto", "no"}}}; 15 | 16 | const char* print_vm_name(const testing::TestParamInfo& info) noexcept 17 | { 18 | if (info.param == &advanced_vm) 19 | return "advanced"; 20 | if (info.param == &baseline_vm) 21 | return "baseline"; 22 | if (info.param == &bnocgoto_vm) 23 | return "bnocgoto"; 24 | return "unknown"; 25 | } 26 | } // namespace 27 | 28 | INSTANTIATE_TEST_SUITE_P( 29 | evmone, evm, testing::Values(&advanced_vm, &baseline_vm, &bnocgoto_vm), print_vm_name); 30 | 31 | bool evm::is_advanced() noexcept 32 | { 33 | return GetParam() == &advanced_vm; 34 | } 35 | } // namespace evmone::test 36 | -------------------------------------------------------------------------------- /test/statetest/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # evmone: Fast Ethereum Virtual Machine implementation 2 | # Copyright 2022 The evmone Authors. 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | add_library(evmone-statetestutils STATIC) 6 | add_library(evmone::statetestutils ALIAS evmone-statetestutils) 7 | target_compile_features(evmone-statetestutils PUBLIC cxx_std_20) 8 | target_link_libraries(evmone-statetestutils PRIVATE evmone::state evmone::testutils nlohmann_json::nlohmann_json) 9 | target_include_directories(evmone-statetestutils PRIVATE ${evmone_private_include_dir}) 10 | target_sources( 11 | evmone-statetestutils PRIVATE 12 | ../blockchaintest/blockchaintest_loader.cpp 13 | statetest.hpp 14 | statetest_export.cpp 15 | statetest_loader.cpp 16 | statetest_logs_hash.cpp 17 | ) 18 | 19 | add_executable(evmone-statetest) 20 | target_link_libraries(evmone-statetest PRIVATE evmone::statetestutils evmone evmone-buildinfo GTest::gtest) 21 | target_include_directories(evmone-statetest PRIVATE ${evmone_private_include_dir}) 22 | target_sources( 23 | evmone-statetest PRIVATE 24 | statetest.cpp 25 | statetest_runner.cpp 26 | ) 27 | -------------------------------------------------------------------------------- /cmake/cable/defaults/HunterCacheServers.cmake: -------------------------------------------------------------------------------- 1 | # Cable: CMake Bootstrap Library. 2 | # Copyright 2018 Pawel Bylica. 3 | # Licensed under the Apache License, Version 2.0. See the LICENSE file. 4 | 5 | # This module, when included, sets default values for params related to 6 | # Hunter cache servers, including upload options. 7 | 8 | # Default Hunter cache servers. 9 | set(HUNTER_CACHE_SERVERS 10 | "https://github.com/ethereum/hunter-cache;https://github.com/ingenue/hunter-cache" 11 | CACHE STRING "Hunter cache servers") 12 | 13 | # Default path to Hunter passwords file containing information how to access 14 | # Ethereum's cache server. 15 | set(HUNTER_PASSWORDS_PATH 16 | ${CMAKE_CURRENT_LIST_DIR}/HunterCacheServers-passwords.cmake 17 | CACHE STRING "Hunter passwords file") 18 | 19 | # In CI builds upload the binaries if the HUNTER_CACHE_TOKEN was decrypted 20 | # (only for branches and internal PRs). 21 | if("$ENV{CI}" AND NOT "$ENV{HUNTER_CACHE_TOKEN}" STREQUAL "") 22 | set(run_upload YES) 23 | else() 24 | set(run_upload NO) 25 | endif() 26 | option(HUNTER_RUN_UPLOAD "Upload binaries to the Hunter cache server" ${run_upload}) 27 | unset(run_upload) 28 | -------------------------------------------------------------------------------- /test/state/mpt.hpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2022 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | #pragma once 5 | 6 | #include "hash_utils.hpp" 7 | #include 8 | 9 | namespace evmone::state 10 | { 11 | /// Insert-only Merkle Patricia Trie implementation for getting the root hash 12 | /// out of (key, value) pairs. 13 | /// 14 | /// Limitations: 15 | /// 1. A key must not be longer than 32 bytes. Protected by debug assert. 16 | /// 2. A key must not be a prefix of another key. Protected by debug assert. 17 | /// This comes from the spec (Yellow Paper Appendix D) - a branch node cannot store a value. 18 | /// 3. A key must be unique. Protected by debug assert. 19 | /// I.e. inserted values cannot be updated by inserting with the same key again. 20 | /// 4. Inserted values cannot be erased. There is no method for this. 21 | class MPT 22 | { 23 | std::unique_ptr m_root; 24 | 25 | public: 26 | MPT() noexcept; 27 | ~MPT() noexcept; 28 | 29 | void insert(bytes_view key, bytes&& value); 30 | 31 | [[nodiscard]] hash256 hash() const; 32 | }; 33 | 34 | } // namespace evmone::state 35 | -------------------------------------------------------------------------------- /cmake/cable/CableToolchains.cmake: -------------------------------------------------------------------------------- 1 | # Cable: CMake Bootstrap Library. 2 | # Copyright 2018 Pawel Bylica. 3 | # Licensed under the Apache License, Version 2.0. See the LICENSE file. 4 | 5 | set(cable_toolchain_dir ${CMAKE_CURRENT_LIST_DIR}/toolchains) 6 | 7 | function(cable_configure_toolchain) 8 | if(NOT PROJECT_IS_NESTED) 9 | # Do this configuration only in the top project. 10 | 11 | cmake_parse_arguments("" "" "DEFAULT" "" ${ARGN}) 12 | 13 | set(default_toolchain default) 14 | if(_DEFAULT) 15 | set(default_toolchain ${_DEFAULT}) 16 | endif() 17 | 18 | set(TOOLCHAIN ${default_toolchain} CACHE STRING "CMake toolchain") 19 | 20 | set(toolchain_file toolchains/${TOOLCHAIN}.cmake) 21 | foreach(path ${CMAKE_MODULE_PATH}) 22 | if(EXISTS "${path}/${toolchain_file}") 23 | set(toolchain_file "${path}/${toolchain_file}") 24 | break() 25 | endif() 26 | endforeach() 27 | 28 | cable_debug("Toolchain file: ${toolchain_file}") 29 | set(CMAKE_TOOLCHAIN_FILE ${toolchain_file} CACHE FILEPATH "CMake toolchain file") 30 | endif() 31 | endfunction() 32 | -------------------------------------------------------------------------------- /lib/evmone_precompiles/kzg.hpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2024 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | #pragma once 6 | #include "sha256.hpp" 7 | #include 8 | 9 | namespace evmone::crypto 10 | { 11 | using namespace intx::literals; 12 | 13 | /// Length (in bytes) of the versioned hash (based on SHA256). 14 | constexpr auto VERSIONED_HASH_SIZE = SHA256_HASH_SIZE; 15 | 16 | /// The KZG version number of the versioned hash. 17 | constexpr std::byte VERSIONED_HASH_VERSION_KZG{0x01}; 18 | 19 | /// An EIP-4844 parameter. 20 | constexpr auto FIELD_ELEMENTS_PER_BLOB = 4096_u256; 21 | 22 | /// Scalar field modulus of BLS12-381. 23 | constexpr auto BLS_MODULUS = 24 | 52435875175126190479447740508185965837690552500527637822603658699938581184513_u256; 25 | 26 | /// Number of significant bits of the BLS_MODULUS. 27 | constexpr size_t BLS_MODULUS_BITS = 255; 28 | static_assert((BLS_MODULUS >> BLS_MODULUS_BITS) == 0); 29 | 30 | bool kzg_verify_proof(const std::byte versioned_hash[VERSIONED_HASH_SIZE], const std::byte z[32], 31 | const std::byte y[32], const std::byte commitment[48], const std::byte proof[48]) noexcept; 32 | } // namespace evmone::crypto 33 | -------------------------------------------------------------------------------- /test/integration/statetest/tx/invalid_nonce.json: -------------------------------------------------------------------------------- 1 | { 2 | "invalid_nonce": { 3 | "env": { 4 | "currentBaseFee": "0x0a", 5 | "currentCoinbase": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", 6 | "currentDifficulty": "0x020000", 7 | "currentGasLimit": "0xff112233445566", 8 | "currentNumber": "0x01", 9 | "currentRandom": "0x0000000000000000000000000000000000000000000000000000000000020000", 10 | "currentTimestamp": "0x03e8" 11 | }, 12 | "post": { 13 | "Shanghai": [ 14 | { 15 | "hash": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", 16 | "indexes": { 17 | "data": 0, 18 | "gas": 0, 19 | "value": 0 20 | }, 21 | "logs": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" 22 | } 23 | ] 24 | }, 25 | "pre": {}, 26 | "transaction": { 27 | "data": [ 28 | "0x" 29 | ], 30 | "gasLimit": [ 31 | "0x00" 32 | ], 33 | "gasPrice": "0x0a", 34 | "nonce": "0x01", 35 | "sender": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", 36 | "to": "0x00", 37 | "value": [ 38 | "0x00" 39 | ] 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /cmake/cable/CablePackage.cmake: -------------------------------------------------------------------------------- 1 | # Cable: CMake Bootstrap Library 2 | # Copyright 2019-2020 Pawel Bylica. 3 | # Licensed under the Apache License, Version 2.0. 4 | 5 | # Cable Package, version 1.0.0 6 | # 7 | # This CMake module provides default configuration for CPack 8 | # 9 | # CHANGELOG 10 | # 11 | # 1.0.0 - 2020-05-06 12 | 13 | if(cable_package_included) 14 | return() 15 | endif() 16 | set(cable_package_included TRUE) 17 | 18 | # Configures CPack to build the archive package. 19 | macro(cable_add_archive_package) 20 | if(WIN32) 21 | set(CPACK_GENERATOR ZIP) 22 | set(CPACK_SOURCE_GENERATOR ZIP) 23 | else() 24 | set(CPACK_GENERATOR TGZ) 25 | set(CPACK_SOURCE_GENERATOR TGZ) 26 | endif() 27 | string(TOLOWER ${CMAKE_SYSTEM_NAME} system_name) 28 | string(TOLOWER ${CMAKE_SYSTEM_PROCESSOR} system_processor) 29 | set(CPACK_PACKAGE_FILE_NAME ${PROJECT_NAME}-${PROJECT_VERSION}-${system_name}-${system_processor}) 30 | set(CPACK_SOURCE_PACKAGE_FILE_NAME ${PROJECT_NAME}-${PROJECT_VERSION}-source) 31 | set(CPACK_PACKAGE_CHECKSUM SHA256) 32 | set(CPACK_INCLUDE_TOPLEVEL_DIRECTORY FALSE) 33 | unset(system_name) 34 | unset(system_processor) 35 | include(CPack) 36 | endmacro() 37 | -------------------------------------------------------------------------------- /test/state/mpt_hash.hpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2022 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | #pragma once 5 | 6 | #include "hash_utils.hpp" 7 | #include 8 | 9 | namespace evmone::test 10 | { 11 | class TestState; 12 | } 13 | 14 | namespace evmone::state 15 | { 16 | /// The hash of the empty Merkle Patricia Trie. 17 | /// 18 | /// Specifically, this is the value of keccak256(RLP("")), i.e. keccak256({0x80}). 19 | constexpr auto EMPTY_MPT_HASH = 20 | 0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421_bytes32; 21 | 22 | /// Computes Merkle Patricia Trie root hash for the given collection of state accounts. 23 | hash256 mpt_hash(const test::TestState& state); 24 | 25 | /// Computes Merkle Patricia Trie root hash for the given list of structures. 26 | template 27 | hash256 mpt_hash(std::span list); 28 | 29 | /// A helper to automatically convert collections (e.g. vector, array) to span. 30 | template 31 | inline hash256 mpt_hash(const T& list) 32 | requires std::is_convertible_v> 33 | { 34 | return mpt_hash(std::span{list}); 35 | } 36 | 37 | } // namespace evmone::state 38 | -------------------------------------------------------------------------------- /test/state/state_view.hpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2024 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | namespace evmone::state 11 | { 12 | using evmc::address; 13 | using evmc::bytes; 14 | using evmc::bytes32; 15 | using intx::uint256; 16 | 17 | class StateView 18 | { 19 | public: 20 | struct Account 21 | { 22 | uint64_t nonce = 0; 23 | uint256 balance; 24 | bytes32 code_hash; 25 | bool has_storage = false; 26 | }; 27 | 28 | virtual ~StateView() = default; 29 | virtual std::optional get_account(const address& addr) const noexcept = 0; 30 | virtual bytes get_account_code(const address& addr) const noexcept = 0; 31 | virtual bytes32 get_storage(const address& addr, const bytes32& key) const noexcept = 0; 32 | }; 33 | 34 | 35 | /// Interface to access hashes of known block headers. 36 | class BlockHashes 37 | { 38 | public: 39 | virtual ~BlockHashes() = default; 40 | 41 | /// Returns the hash of the block header of the given block number. 42 | virtual bytes32 get_block_hash(int64_t block_number) const noexcept = 0; 43 | }; 44 | } // namespace evmone::state 45 | -------------------------------------------------------------------------------- /test/state/bloom_filter.hpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2023 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | #pragma once 6 | #include "hash_utils.hpp" 7 | #include 8 | 9 | namespace evmone::state 10 | { 11 | struct Log; 12 | struct TransactionReceipt; 13 | 14 | /// The 2048-bit hash suitable for keeping an Ethereum bloom filter of transactions logs. 15 | struct BloomFilter 16 | { 17 | //// The 256 bytes of the bloom filter value. 18 | uint8_t bytes[256] = {}; 19 | 20 | /// Implicit operator converting to bytes_view. 21 | inline constexpr operator bytes_view() const noexcept { return {bytes, sizeof(bytes)}; } 22 | }; 23 | 24 | /// Computes combined bloom fitter for set of logs. 25 | /// It's used to compute bloom filter for single transaction. 26 | [[nodiscard]] BloomFilter compute_bloom_filter(std::span logs) noexcept; 27 | 28 | /// Computes combined bloom fitter for set of TransactionReceipts 29 | /// It's used to compute bloom filter for a block. 30 | [[nodiscard]] BloomFilter compute_bloom_filter( 31 | std::span receipts) noexcept; 32 | 33 | /// Loads BloomFilter from bytes_view 34 | BloomFilter bloom_filter_from_bytes(const bytes_view& data) noexcept; 35 | 36 | } // namespace evmone::state 37 | -------------------------------------------------------------------------------- /lib/evmone/baseline_instruction_table.cpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2020 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | #include "baseline_instruction_table.hpp" 6 | #include "instructions_traits.hpp" 7 | 8 | namespace evmone::baseline 9 | { 10 | namespace 11 | { 12 | consteval auto build_cost_tables(bool eof) noexcept 13 | { 14 | std::array tables{}; 15 | for (size_t r = EVMC_FRONTIER; r <= EVMC_MAX_REVISION; ++r) 16 | { 17 | auto& table = tables[r]; 18 | for (size_t op = 0; op < table.size(); ++op) 19 | { 20 | const auto& tr = instr::traits[op]; 21 | const auto since = eof ? tr.eof_since : tr.since; 22 | table[op] = (since && r >= *since) ? instr::gas_costs[r][op] : instr::undefined; 23 | } 24 | } 25 | return tables; 26 | } 27 | 28 | constexpr auto LEGACY_COST_TABLES = build_cost_tables(false); 29 | constexpr auto EOF_COST_TABLES = build_cost_tables(true); 30 | } // namespace 31 | 32 | const CostTable& get_baseline_cost_table(evmc_revision rev, uint8_t eof_version) noexcept 33 | { 34 | const auto& tables = (eof_version == 0) ? LEGACY_COST_TABLES : EOF_COST_TABLES; 35 | return tables[rev]; 36 | } 37 | } // namespace evmone::baseline 38 | -------------------------------------------------------------------------------- /test/unittests/baseline_analysis_test.cpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2024 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | using namespace evmone::test; 10 | 11 | TEST(baseline_analysis, legacy) 12 | { 13 | const auto code = push(1) + ret_top(); 14 | const auto analysis = evmone::baseline::analyze(code, false); 15 | 16 | EXPECT_EQ(analysis.eof_header().version, 0); 17 | EXPECT_EQ(analysis.executable_code(), code); 18 | EXPECT_EQ(analysis.raw_code(), code); 19 | EXPECT_NE(analysis.raw_code().data(), code.data()) << "copy should be made"; 20 | } 21 | 22 | TEST(baseline_analysis, eof1) 23 | { 24 | const auto code = push(1) + ret_top(); 25 | const bytecode container = eof_bytecode(code, 2).data("da4a"); 26 | const auto analysis = evmone::baseline::analyze(container, true); 27 | 28 | EXPECT_EQ(analysis.eof_header().version, 1); 29 | EXPECT_EQ(analysis.eof_header().code_sizes.size(), 1); 30 | EXPECT_EQ(analysis.eof_header().data_size, 2); 31 | EXPECT_EQ(analysis.executable_code(), code); 32 | EXPECT_EQ(analysis.raw_code(), container); 33 | EXPECT_EQ(analysis.raw_code().data(), container.data()) << "copy should not be made"; 34 | } 35 | -------------------------------------------------------------------------------- /test/state/system_contracts.hpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2023 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | #pragma once 5 | 6 | #include 7 | 8 | namespace evmone::state 9 | { 10 | using namespace evmc::literals; 11 | 12 | /// The address of the sender of the system calls (EIP-4788). 13 | constexpr auto SYSTEM_ADDRESS = 0xfffffffffffffffffffffffffffffffffffffffe_address; 14 | 15 | /// The address of the system contract storing the root hashes of beacon chain blocks (EIP-4788). 16 | constexpr auto BEACON_ROOTS_ADDRESS = 0x000F3df6D732807Ef1319fB7B8bB8522d0Beac02_address; 17 | 18 | /// The address of the system contract storing historical block hashes (EIP-2935). 19 | constexpr auto HISTORY_STORAGE_ADDRESS = 0x0aae40965e6800cd9b1f4b05ff21581047e3f91e_address; 20 | 21 | struct BlockInfo; 22 | struct StateDiff; 23 | class BlockHashes; 24 | class StateView; 25 | 26 | /// Performs the system call: invokes system contracts. 27 | /// 28 | /// Executes code of pre-defined accounts via pseudo-transaction from the system sender (0xff...fe). 29 | /// The sender's nonce is not increased. 30 | [[nodiscard]] StateDiff system_call(const StateView& state_view, const BlockInfo& block, 31 | const BlockHashes& block_hashes, evmc_revision rev, evmc::VM& vm); 32 | } // namespace evmone::state 33 | -------------------------------------------------------------------------------- /lib/evmone_precompiles/bn254.hpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2023 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | #pragma once 5 | 6 | #include "ecc.hpp" 7 | 8 | namespace evmmax::bn254 9 | { 10 | using namespace intx; 11 | 12 | /// The bn254 field prime number (P). 13 | inline constexpr auto FieldPrime = 14 | 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47_u256; 15 | 16 | using Point = ecc::Point; 17 | 18 | /// Validates that point is from the bn254 curve group 19 | /// 20 | /// Returns true if y^2 == x^3 + 3. Input is converted to the Montgomery form. 21 | bool validate(const Point& pt) noexcept; 22 | 23 | /// Modular inversion for bn254 prime field. 24 | /// 25 | /// Computes 1/x mod P modular inversion by computing modular exponentiation x^(P-2), 26 | /// where P is ::FieldPrime. 27 | uint256 field_inv(const ModArith& m, const uint256& x) noexcept; 28 | 29 | /// Addition in bn254 curve group. 30 | /// 31 | /// Computes P ⊕ Q for two points in affine coordinates on the bn254 curve, 32 | Point add(const Point& pt1, const Point& pt2) noexcept; 33 | 34 | /// Scalar multiplication in bn254 curve group. 35 | /// 36 | /// Computes [c]P for a point in affine coordinate on the bn254 curve, 37 | Point mul(const Point& pt, const uint256& c) noexcept; 38 | 39 | } // namespace evmmax::bn254 40 | -------------------------------------------------------------------------------- /test/unittests/evm_eip3855_push0_test.cpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2022 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | /// This file contains EVM unit tests for EIP-3855 "PUSH0 instruction" 6 | /// https://eips.ethereum.org/EIPS/eip-3855 7 | 8 | #include "evm_fixture.hpp" 9 | 10 | using namespace evmc::literals; 11 | using namespace evmone::test; 12 | 13 | TEST_P(evm, push0_pre_shanghai) 14 | { 15 | rev = EVMC_PARIS; 16 | const auto code = bytecode{OP_PUSH0}; 17 | 18 | execute(code); 19 | EXPECT_STATUS(EVMC_UNDEFINED_INSTRUCTION); 20 | } 21 | 22 | TEST_P(evm, push0) 23 | { 24 | rev = EVMC_SHANGHAI; 25 | execute(OP_PUSH0 + ret_top()); 26 | EXPECT_GAS_USED(EVMC_SUCCESS, 17); 27 | EXPECT_OUTPUT_INT(0); 28 | } 29 | 30 | TEST_P(evm, push0_return_empty) 31 | { 32 | rev = EVMC_SHANGHAI; 33 | execute(bytecode{} + OP_PUSH0 + OP_PUSH0 + OP_RETURN); 34 | EXPECT_GAS_USED(EVMC_SUCCESS, 4); 35 | EXPECT_EQ(result.output_size, 0); 36 | } 37 | 38 | TEST_P(evm, push0_full_stack) 39 | { 40 | rev = EVMC_SHANGHAI; 41 | execute(1024 * bytecode{OP_PUSH0}); 42 | EXPECT_GAS_USED(EVMC_SUCCESS, 1024 * 2); 43 | } 44 | 45 | TEST_P(evm, push0_stack_overflow) 46 | { 47 | rev = EVMC_SHANGHAI; 48 | execute(1025 * bytecode{OP_PUSH0}); 49 | EXPECT_STATUS(EVMC_STACK_OVERFLOW); 50 | } 51 | -------------------------------------------------------------------------------- /lib/evmone/vm.hpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2021 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | #pragma once 5 | 6 | #include "execution_state.hpp" 7 | #include "tracing.hpp" 8 | #include 9 | #include 10 | 11 | #if defined(_MSC_VER) && !defined(__clang__) 12 | #define EVMONE_CGOTO_SUPPORTED 0 13 | #else 14 | #define EVMONE_CGOTO_SUPPORTED 1 15 | #endif 16 | 17 | namespace evmone 18 | { 19 | /// The evmone EVMC instance. 20 | class VM : public evmc_vm 21 | { 22 | public: 23 | bool cgoto = EVMONE_CGOTO_SUPPORTED; 24 | bool validate_eof = false; 25 | 26 | private: 27 | std::vector m_execution_states; 28 | std::unique_ptr m_first_tracer; 29 | 30 | public: 31 | VM() noexcept; 32 | 33 | [[nodiscard]] ExecutionState& get_execution_state(size_t depth) noexcept; 34 | 35 | void add_tracer(std::unique_ptr tracer) noexcept 36 | { 37 | // Find the first empty unique_ptr and assign the new tracer to it. 38 | auto* end = &m_first_tracer; 39 | while (*end) 40 | end = &(*end)->m_next_tracer; 41 | *end = std::move(tracer); 42 | } 43 | 44 | void remove_tracers() noexcept { m_first_tracer.reset(); } 45 | 46 | [[nodiscard]] Tracer* get_tracer() const noexcept { return m_first_tracer.get(); } 47 | }; 48 | } // namespace evmone 49 | -------------------------------------------------------------------------------- /test/unittests/evm_eip7516_blobbasefee_test.cpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2023 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | /// This file contains EVM unit tests for EIP-7516: "BLOBBASEFEE opcode" 6 | /// https://eips.ethereum.org/EIPS/eip-7516 7 | 8 | #include "evm_fixture.hpp" 9 | 10 | using namespace evmc::literals; 11 | using namespace intx::literals; 12 | using namespace evmone::test; 13 | 14 | TEST_P(evm, blobbasefee_pre_cancun) 15 | { 16 | rev = EVMC_SHANGHAI; 17 | const auto code = bytecode{OP_BLOBBASEFEE}; 18 | 19 | execute(code); 20 | EXPECT_STATUS(EVMC_UNDEFINED_INSTRUCTION); 21 | } 22 | 23 | TEST_P(evm, blobbasefee_1) 24 | { 25 | rev = EVMC_CANCUN; 26 | host.tx_context.blob_base_fee = 0x01_bytes32; 27 | 28 | execute(bytecode{} + OP_BLOBBASEFEE); 29 | EXPECT_GAS_USED(EVMC_SUCCESS, 2); 30 | 31 | execute(bytecode{} + OP_BLOBBASEFEE + ret_top()); 32 | EXPECT_GAS_USED(EVMC_SUCCESS, 17); 33 | EXPECT_OUTPUT_INT(1); 34 | } 35 | 36 | TEST_P(evm, blobbasefee_dede) 37 | { 38 | rev = EVMC_CANCUN; 39 | host.tx_context.blob_base_fee = 40 | 0x8ededededededededededededededededededededededededededededededed1_bytes32; 41 | 42 | execute(bytecode{} + OP_BLOBBASEFEE + ret_top()); 43 | EXPECT_OUTPUT_INT(0x8ededededededededededededededededededededededededededededededed1_u256); 44 | } 45 | -------------------------------------------------------------------------------- /test/internal_benchmarks/memory_allocation.cpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2019 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | #include 6 | #include 7 | 8 | #if defined(__unix__) || defined(__APPLE__) 9 | #include 10 | #endif 11 | 12 | namespace 13 | { 14 | void malloc_(size_t size) noexcept 15 | { 16 | auto m = std::malloc(size); 17 | benchmark::DoNotOptimize(m); 18 | std::free(m); 19 | } 20 | 21 | void calloc_(size_t size) noexcept 22 | { 23 | auto m = std::calloc(1, size); 24 | benchmark::DoNotOptimize(m); 25 | std::free(m); 26 | } 27 | 28 | void os_specific(size_t size) noexcept 29 | { 30 | #if defined(__unix__) || defined(__APPLE__) 31 | auto m = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS, -1, 0); 32 | benchmark::DoNotOptimize(m); 33 | munmap(m, size); 34 | #else 35 | (void)size; 36 | #endif 37 | } 38 | 39 | 40 | template 41 | void allocate(benchmark::State& state) 42 | { 43 | const auto size = static_cast(state.range(0)) * 1024; 44 | 45 | for (auto _ : state) 46 | F(size); 47 | } 48 | 49 | #define ARGS ->RangeMultiplier(2)->Range(1, 128 * 1024) 50 | 51 | BENCHMARK_TEMPLATE(allocate, malloc_) ARGS; 52 | BENCHMARK_TEMPLATE(allocate, calloc_) ARGS; 53 | BENCHMARK_TEMPLATE(allocate, os_specific) ARGS; 54 | 55 | } // namespace 56 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | BasedOnStyle: Chromium 4 | AccessModifierOffset: -4 5 | AlignAfterOpenBracket: DontAlign 6 | BinPackParameters: true 7 | BraceWrapping: 8 | AfterCaseLabel: true 9 | AfterClass: true 10 | AfterControlStatement: true 11 | AfterEnum: true 12 | AfterFunction: true 13 | AfterNamespace: true 14 | AfterStruct: true 15 | AfterUnion: true 16 | # AfterExternBlock: true 17 | BeforeCatch: true 18 | BeforeElse: true 19 | # BeforeLambdaBody: true 20 | # BeforeWhile: true 21 | SplitEmptyFunction: false 22 | SplitEmptyRecord: false 23 | SplitEmptyNamespace: false 24 | BreakBeforeBraces: Custom 25 | BreakBeforeTernaryOperators: false 26 | ColumnLimit: 100 27 | ConstructorInitializerIndentWidth: 2 28 | IncludeBlocks: Preserve 29 | IncludeCategories: 30 | - Regex: '^".*' 31 | Priority: 1 32 | - Regex: '^' 35 | Priority: 2 36 | - Regex: '^<.*' 37 | Priority: 99 38 | - Regex: '.*' 39 | Priority: 4 40 | IncludeIsMainRegex: '(Test)?$' 41 | IndentCaseLabels: false 42 | # IndentExternBlock: NoIndent 43 | IndentWidth: 4 44 | MaxEmptyLinesToKeep: 2 45 | PenaltyBreakAssignment: 1 46 | PenaltyBreakComment: 50 47 | TabWidth: 4 48 | ... 49 | -------------------------------------------------------------------------------- /test/experimental/jumpdest_analysis.cpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2020 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | #include "jumpdest_analysis.hpp" 6 | #include 7 | 8 | namespace evmone::exp::jda 9 | { 10 | using enum Opcode; 11 | 12 | namespace 13 | { 14 | size_t get_push_data_size(uint8_t op) noexcept 15 | { 16 | return op - size_t{OP_PUSH1 - 1}; 17 | } 18 | } // namespace 19 | 20 | /// The reference implementation of the EVM jumpdest analysis. 21 | JumpdestBitset reference(bytes_view code) 22 | { 23 | JumpdestBitset m(code.size()); 24 | for (size_t i = 0; i < code.size(); ++i) 25 | { 26 | const auto op = code[i]; 27 | if (static_cast(op) >= OP_PUSH1) 28 | i += op - (OP_PUSH1 - 1); 29 | else if (op == OP_JUMPDEST) [[unlikely]] 30 | m[i] = true; 31 | } 32 | return m; 33 | } 34 | 35 | JumpdestBitset speculate_push_data_size(bytes_view code) 36 | { 37 | JumpdestBitset m(code.size()); 38 | for (size_t i = 0; i < code.size(); ++i) 39 | { 40 | const auto op = code[i]; 41 | const auto potential_push_data_len = get_push_data_size(op); 42 | if (potential_push_data_len <= 32) 43 | i += potential_push_data_len; 44 | else if (op == OP_JUMPDEST) [[unlikely]] 45 | m[i] = true; 46 | } 47 | return m; 48 | } 49 | 50 | } // namespace evmone::exp::jda 51 | -------------------------------------------------------------------------------- /test/unittests/precompiles_sha256_test.cpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2024 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | using evmone::crypto::sha256; 10 | 11 | TEST(sha256, test_vectors) 12 | { 13 | // Some test vectors from https://www.di-mgt.com.au/sha_testvectors.html. 14 | 15 | const std::pair test_cases[] = { 16 | {"", "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"}, 17 | {"abc", "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"}, 18 | {"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 19 | "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1"}, 20 | {"abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn" 21 | "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", 22 | "cf5b16a778af8380036ce59e7b0492370b249b11e8f07a51afac45037afee9d1"}, 23 | }; 24 | 25 | for (const auto& [input, expected_hash_hex] : test_cases) 26 | { 27 | std::byte hash[evmone::crypto::SHA256_HASH_SIZE]; 28 | sha256(hash, reinterpret_cast(input.data()), input.size()); 29 | const auto hash_hex = evmc::hex({reinterpret_cast(hash), std::size(hash)}); 30 | EXPECT_EQ(hash_hex, expected_hash_hex); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /lib/evmone_precompiles/expmod.tmpl: -------------------------------------------------------------------------------- 1 | {{- $exponent := "" -}} 2 | {{- range $exponent = $.Chain }}{{ end -}} 3 | 4 | uint256 expmod_(const ModArith& m, const uint256& x) noexcept 5 | { 6 | // Computes modular exponentiation 7 | // x^{{ printf "%#x" $exponent }} 8 | // Operations: {{ .Ops.Doubles }} squares {{ .Ops.Adds }} multiplies 9 | // Generated by {{ .Meta.Module }} {{ .Meta.ReleaseTag }}. 10 | // 11 | // Exponentiation computation is derived from the addition chain: 12 | // 13 | {{- range lines (format .Script) }} 14 | // {{ . }} 15 | {{- end }} 16 | 17 | // Allocate Temporaries. 18 | uint256 z; 19 | {{- range .Program.Temporaries }} 20 | uint256 {{ . }}; 21 | {{- end }} 22 | 23 | {{ range $i := .Program.Instructions }} 24 | // {{ printf "Step %d: %s = x^%#x" $i.Output.Index $i.Output (index $.Chain $i.Output.Index) }} 25 | {{- with add $i.Op }} 26 | {{ $i.Output }} = m.mul({{ .X }}, {{ .Y }}); 27 | {{ end -}} 28 | 29 | {{- with double $i.Op }} 30 | {{ $i.Output }} = m.mul({{ .X }}, {{ .X }}); 31 | {{ end -}} 32 | 33 | {{- with shift $i.Op -}} 34 | {{- $first := 0 -}} 35 | {{- if ne $i.Output.Identifier .X.Identifier }} 36 | {{ $i.Output }} = m.mul({{ .X }}, {{ .X }}); 37 | {{- $first = 1 -}} 38 | {{- end }} 39 | for (int i = {{ $first }}; i < {{ .S }}; ++i) 40 | {{ $i.Output }} = m.mul({{ $i.Output }}, {{ $i.Output }}); 41 | {{ end -}} 42 | {{- end }} 43 | return z; 44 | } 45 | -------------------------------------------------------------------------------- /test/state/precompiles_silkpre.hpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2022 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | #pragma once 5 | 6 | #include "precompiles_internal.hpp" 7 | 8 | namespace evmone::state 9 | { 10 | ExecutionResult silkpre_ecrecover_execute( 11 | const uint8_t* input, size_t input_size, uint8_t* output_buf, size_t max_output_size) noexcept; 12 | 13 | ExecutionResult silkpre_sha256_execute( 14 | const uint8_t* input, size_t input_size, uint8_t* output_buf, size_t max_output_size) noexcept; 15 | 16 | ExecutionResult silkpre_ripemd160_execute( 17 | const uint8_t* input, size_t input_size, uint8_t* output_buf, size_t max_output_size) noexcept; 18 | 19 | ExecutionResult silkpre_expmod_execute( 20 | const uint8_t* input, size_t input_size, uint8_t* output_buf, size_t max_output_size) noexcept; 21 | 22 | ExecutionResult silkpre_ecadd_execute( 23 | const uint8_t* input, size_t input_size, uint8_t* output_buf, size_t max_output_size) noexcept; 24 | 25 | ExecutionResult silkpre_ecmul_execute( 26 | const uint8_t* input, size_t input_size, uint8_t* output_buf, size_t max_output_size) noexcept; 27 | 28 | ExecutionResult silkpre_ecpairing_execute( 29 | const uint8_t* input, size_t input_size, uint8_t* output_buf, size_t max_output_size) noexcept; 30 | 31 | ExecutionResult silkpre_blake2bf_execute( 32 | const uint8_t* input, size_t input_size, uint8_t* output_buf, size_t max_output_size) noexcept; 33 | } // namespace evmone::state 34 | -------------------------------------------------------------------------------- /test/state/block.cpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2022 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | #include "block.hpp" 6 | #include "rlp.hpp" 7 | 8 | namespace evmone::state 9 | { 10 | intx::uint256 compute_blob_gas_price(uint64_t excess_blob_gas) noexcept 11 | { 12 | /// A helper function approximating `factor * e ** (numerator / denominator)`. 13 | /// https://eips.ethereum.org/EIPS/eip-4844#helpers 14 | static constexpr auto fake_exponential = [](uint64_t factor, uint64_t numerator, 15 | uint64_t denominator) noexcept { 16 | intx::uint256 i = 1; 17 | intx::uint256 output = 0; 18 | intx::uint256 numerator_accum = factor * denominator; 19 | while (numerator_accum > 0) 20 | { 21 | output += numerator_accum; 22 | numerator_accum = (numerator_accum * numerator) / (denominator * i); 23 | i += 1; 24 | } 25 | return output / denominator; 26 | }; 27 | 28 | static constexpr auto MIN_BLOB_GASPRICE = 1; 29 | static constexpr auto BLOB_GASPRICE_UPDATE_FRACTION = 3338477; 30 | return fake_exponential(MIN_BLOB_GASPRICE, excess_blob_gas, BLOB_GASPRICE_UPDATE_FRACTION); 31 | } 32 | 33 | [[nodiscard]] bytes rlp_encode(const Withdrawal& withdrawal) 34 | { 35 | return rlp::encode_tuple(withdrawal.index, withdrawal.validator_index, withdrawal.recipient, 36 | withdrawal.amount_in_gwei); 37 | } 38 | } // namespace evmone::state 39 | -------------------------------------------------------------------------------- /test/state/mpt_hash.cpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2022 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | #include "mpt_hash.hpp" 6 | #include "block.hpp" 7 | #include "mpt.hpp" 8 | #include "rlp.hpp" 9 | #include "test_state.hpp" 10 | #include "transaction.hpp" 11 | 12 | namespace evmone::state 13 | { 14 | namespace 15 | { 16 | hash256 mpt_hash(const std::map& storage) 17 | { 18 | MPT trie; 19 | for (const auto& [key, value] : storage) 20 | { 21 | if (!is_zero(value)) // Skip "deleted" values. 22 | trie.insert(keccak256(key), rlp::encode(rlp::trim(value))); 23 | } 24 | return trie.hash(); 25 | } 26 | } // namespace 27 | 28 | hash256 mpt_hash(const test::TestState& state) 29 | { 30 | MPT trie; 31 | for (const auto& [addr, acc] : state) 32 | { 33 | trie.insert(keccak256(addr), 34 | rlp::encode_tuple(acc.nonce, acc.balance, mpt_hash(acc.storage), keccak256(acc.code))); 35 | } 36 | return trie.hash(); 37 | } 38 | 39 | template 40 | hash256 mpt_hash(std::span list) 41 | { 42 | MPT trie; 43 | for (size_t i = 0; i < list.size(); ++i) 44 | trie.insert(rlp::encode(i), rlp::encode(list[i])); 45 | 46 | return trie.hash(); 47 | } 48 | 49 | template hash256 mpt_hash(std::span); 50 | template hash256 mpt_hash(std::span); 51 | template hash256 mpt_hash(std::span); 52 | 53 | } // namespace evmone::state 54 | -------------------------------------------------------------------------------- /test/internal_benchmarks/realloc_behavior.cpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2019 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace std::chrono; 11 | using timer = high_resolution_clock; 12 | 13 | struct result 14 | { 15 | size_t size; 16 | void* memory_ptr; 17 | decltype(timer::now() - timer::now()) duration; 18 | }; 19 | 20 | void benchmark_realloc() 21 | { 22 | constexpr int repeats = 6; 23 | constexpr size_t realloc_multiplier = 2; 24 | constexpr size_t size_start = 128 * 1024; 25 | constexpr size_t size_end = 8 * 1024 * 1024; 26 | 27 | auto results = std::vector{}; 28 | results.reserve(size_end / size_start); 29 | 30 | void* m = nullptr; 31 | 32 | for (int i = 0; i < repeats; ++i) 33 | { 34 | for (auto size = size_start; size <= size_end; size *= realloc_multiplier) 35 | { 36 | const auto start_time = timer::now(); 37 | m = std::realloc(m, size); 38 | const auto duration = timer::now() - start_time; 39 | results.push_back({size, m, duration}); 40 | } 41 | std::free(m); 42 | m = nullptr; 43 | } 44 | 45 | for (auto r : results) 46 | { 47 | std::cout << (r.size / 1024) << "k\t " << r.memory_ptr << "\t" 48 | << duration_cast(r.duration).count() << "\n"; 49 | } 50 | } 51 | 52 | int main() 53 | { 54 | benchmark_realloc(); 55 | return 0; 56 | } 57 | -------------------------------------------------------------------------------- /test/unittests/exportable_fixture.cpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2024 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | #ifdef _MSC_VER 6 | // Disable warning C4996: 'getenv': This function or variable may be unsafe. 7 | #define _CRT_SECURE_NO_WARNINGS 8 | #endif 9 | 10 | #include "exportable_fixture.hpp" 11 | #include 12 | #include 13 | 14 | namespace fs = std::filesystem; 15 | 16 | namespace evmone::test 17 | { 18 | namespace 19 | { 20 | /// Creates the file path for the exported test based on its name. 21 | fs::path get_export_test_path(const testing::TestInfo& test_info, std::string_view export_dir) 22 | { 23 | const std::string suite_name{test_info.test_suite_name()}; 24 | 25 | const auto stem = fs::path{test_info.file()}.stem().string(); 26 | const std::regex re{suite_name + "_(.*)_test"}; 27 | std::smatch m; 28 | const auto sub_suite_name = std::regex_match(stem, m, re) ? m[1] : std::string{}; 29 | 30 | const auto dir = fs::path{export_dir} / suite_name / sub_suite_name; 31 | 32 | fs::create_directories(dir); 33 | return dir / (std::string{test_info.name()} + ".json"); 34 | } 35 | } // namespace 36 | 37 | ExportableFixture::ExportableFixture() 38 | { 39 | if (const auto export_dir = std::getenv("EVMONE_EXPORT_TESTS"); export_dir != nullptr) 40 | { 41 | const auto& test_info = *testing::UnitTest::GetInstance()->current_test_info(); 42 | export_test_name = test_info.name(); 43 | export_file_path = get_export_test_path(test_info, export_dir).string(); 44 | } 45 | } 46 | } // namespace evmone::test 47 | -------------------------------------------------------------------------------- /test/integration/statetest/eof/invalid_eof_in_state.json: -------------------------------------------------------------------------------- 1 | { 2 | "invalid_eof_in_state": { 3 | "_info": {}, 4 | "env": { 5 | "currentBaseFee": "0x0a", 6 | "currentCoinbase": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", 7 | "currentDifficulty": "0x020000", 8 | "currentGasLimit": "0xff112233445566", 9 | "currentNumber": "0x01", 10 | "currentRandom": "0x0000000000000000000000000000000000000000000000000000000000020000", 11 | "currentTimestamp": "0x03e8" 12 | }, 13 | "post": { 14 | "Osaka": [ 15 | { 16 | "hash": "0xe8010ce590f401c9d61fef8ab05bea9bcec24281b795e5868809bc4e515aa530", 17 | "indexes": { 18 | "data": 0, 19 | "gas": 0, 20 | "value": 0 21 | }, 22 | "logs": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" 23 | } 24 | ] 25 | }, 26 | "pre": { 27 | "0xbadE0F": { 28 | "balance": "0x0", 29 | "code": "0xEF0001FE", 30 | "nonce": "0x00", 31 | "storage": {} 32 | }, 33 | "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { 34 | "balance": "0x0de0b6b3a7640000", 35 | "code": "0x", 36 | "nonce": "0x00", 37 | "storage": {} 38 | } 39 | }, 40 | "transaction": { 41 | "data": [ 42 | "0x" 43 | ], 44 | "gasLimit": [ 45 | "0x061a80" 46 | ], 47 | "gasPrice": "0x0a", 48 | "nonce": "0x00", 49 | "sender": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", 50 | "to": "0xbadE0F", 51 | "value": [ 52 | "0x0186a0" 53 | ] 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /test/integration/t8n/cancun_create_tx/txs.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "to": null, 4 | "input": "0x60015ff3", 5 | "gas": "0x186a0", 6 | "nonce": "0x0", 7 | "value": "0x0", 8 | "gasPrice": "0x32", 9 | "chainId": "0x1", 10 | "sender": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", 11 | "v": "0x1b", 12 | "r": "0x468a915f087692bb9be503831a3dfef2cf9c8dee26deb40ff2ec99e8d22665ae", 13 | "s": "0x5cedae0810c3851ecd1004bfdbfe6ddc7753c2d665993bb01ce75af7857b13dc" 14 | }, 15 | { 16 | "input": "0x00", 17 | "gas": "0x3d0900", 18 | "nonce": "0x0", 19 | "value": "0x186a0", 20 | "v": "0x0", 21 | "r": "0xfc12b67159a3567f8bdbc49e0be369a2e20e09d57a51c41310543a4128409464", 22 | "s": "0x2de0cfe5495c4f58ff60645ceda0afd67a4c90a70bc89fe207269435b35e5b67", 23 | "secretKey": "0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", 24 | "chainId": "0x1", 25 | "type": "0x3", 26 | "maxFeePerGas": "0x12a05f200", 27 | "maxPriorityFeePerGas": "0x2", 28 | "accessList": [ 29 | { 30 | "address": "0x095e7baea6a6c7c4c2dfeb977efac326af552d87", 31 | "storageKeys": [ 32 | "0x0000000000000000000000000000000000000000000000000000000000000000", 33 | "0x0000000000000000000000000000000000000000000000000000000000000001" 34 | ] 35 | } 36 | ], 37 | "maxFeePerBlobGas": "0xa", 38 | "blobVersionedHashes": [ 39 | "0x01a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8" 40 | ], 41 | "hash": "0xf564e770e59f0e74ea8d992ba407cabb2847ac66019911106e2ed97b330e26a8", 42 | "sender": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b" 43 | } 44 | ] 45 | -------------------------------------------------------------------------------- /test/state/state_diff.hpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2024 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | namespace evmone::state 11 | { 12 | using evmc::address; 13 | using evmc::bytes; 14 | using evmc::bytes32; 15 | using intx::uint256; 16 | 17 | /// Collection of changes to the State 18 | struct StateDiff 19 | { 20 | struct Entry 21 | { 22 | /// Address of the modified account. 23 | address addr; 24 | 25 | /// New nonce value. 26 | /// TODO: Currently it is not guaranteed the value is different from the initial one. 27 | uint64_t nonce; 28 | 29 | /// New balance value. 30 | /// TODO: Currently it is not guaranteed the value is different from the initial one. 31 | uint256 balance; 32 | 33 | /// New account code. If empty, it means the code has not changed. 34 | bytes code; 35 | 36 | /// The list of the account's storage modifications: key => new value. 37 | /// The value 0 means the storage entry is deleted. 38 | std::vector> modified_storage; 39 | }; 40 | 41 | /// List of modified or created accounts. 42 | std::vector modified_accounts; 43 | 44 | /// List of deleted accounts. 45 | /// 46 | /// This list doesn't have common addresses with modified_accounts. 47 | /// Note that from the Cancun revision (because of the modification to the SELFDESTRUCT) 48 | /// accounts cannot be deleted and this list is always empty. 49 | std::vector
deleted_accounts; 50 | }; 51 | } // namespace evmone::state 52 | -------------------------------------------------------------------------------- /test/state/requests.hpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2024 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | #pragma once 6 | 7 | #include "hash_utils.hpp" 8 | #include "transaction.hpp" 9 | #include 10 | #include 11 | #include 12 | 13 | namespace evmone::state 14 | { 15 | /// `requests` object. 16 | /// 17 | /// Defined by EIP-7685: General purpose execution layer requests. 18 | /// https://eips.ethereum.org/EIPS/eip-7685. 19 | struct Requests 20 | { 21 | /// The type of the requests. 22 | enum class Type : uint8_t 23 | { 24 | /// Deposit requests. 25 | /// Introduced by EIP-6110 https://eips.ethereum.org/EIPS/eip-6110. 26 | deposit = 0, 27 | 28 | /// Withdrawal requests. 29 | /// Introduced by EIP-7002 https://eips.ethereum.org/EIPS/eip-7002. 30 | withdrawal = 1, 31 | 32 | /// Consolidation requests. 33 | /// Introduced by EIP-7251 https://eips.ethereum.org/EIPS/eip-7251. 34 | consolidation = 2, 35 | }; 36 | 37 | /// Requests type. 38 | Type type = Type::deposit; 39 | /// Requests data - an opaque byte array, contains zero or more encoded request objects. 40 | evmc::bytes data; 41 | 42 | explicit Requests(Type _type, evmc::bytes _data = {}) noexcept 43 | : type(_type), data(std::move(_data)) 44 | {} 45 | }; 46 | 47 | /// Calculate commitment value of block requests list 48 | hash256 calculate_requests_hash(std::span requests_list); 49 | 50 | /// Construct requests object from logs of the deposit contract. 51 | Requests collect_deposit_requests(std::span receipts); 52 | } // namespace evmone::state 53 | -------------------------------------------------------------------------------- /test/unittests/state_transition_eip663_test.cpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2023 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | #include "../utils/bytecode.hpp" 6 | #include "state_transition.hpp" 7 | 8 | using namespace evmc::literals; 9 | using namespace evmone::test; 10 | 11 | TEST_F(state_transition, dupn) 12 | { 13 | rev = EVMC_OSAKA; 14 | tx.to = To; 15 | pre.insert(*tx.to, 16 | { 17 | .code = eof_bytecode( 18 | push(1) + 255 * push(2) + OP_DUPN + "ff" + sstore(0) + sstore(1) + OP_STOP, 258), 19 | }); 20 | expect.post[*tx.to].storage[0x00_bytes32] = 0x01_bytes32; 21 | expect.post[*tx.to].storage[0x01_bytes32] = 0x02_bytes32; 22 | } 23 | 24 | TEST_F(state_transition, swapn) 25 | { 26 | rev = EVMC_OSAKA; 27 | tx.to = To; 28 | pre.insert(*tx.to, 29 | { 30 | .code = eof_bytecode( 31 | push(1) + 256 * push(2) + OP_SWAPN + "ff" + sstore(0) + sstore(1) + OP_STOP, 258), 32 | }); 33 | expect.post[*tx.to].storage[0x00_bytes32] = 0x01_bytes32; 34 | expect.post[*tx.to].storage[0x01_bytes32] = 0x02_bytes32; 35 | } 36 | 37 | TEST_F(state_transition, exchange) 38 | { 39 | rev = EVMC_OSAKA; 40 | tx.to = To; 41 | pre.insert(*tx.to, { 42 | .code = eof_bytecode(push(1) + push(2) + push(3) + OP_EXCHANGE + "00" + 43 | sstore(0) + sstore(1) + sstore(2) + OP_STOP, 44 | 4), 45 | }); 46 | expect.post[*tx.to].storage[0x00_bytes32] = 0x03_bytes32; 47 | expect.post[*tx.to].storage[0x01_bytes32] = 0x01_bytes32; 48 | expect.post[*tx.to].storage[0x02_bytes32] = 0x02_bytes32; 49 | } 50 | -------------------------------------------------------------------------------- /test/utils/utils.cpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2023 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | #include "utils.hpp" 6 | 7 | namespace evmone::test 8 | { 9 | 10 | evmc_revision to_rev(std::string_view s) 11 | { 12 | if (s == "Frontier") 13 | return EVMC_FRONTIER; 14 | if (s == "Homestead") 15 | return EVMC_HOMESTEAD; 16 | if (s == "Tangerine Whistle" || s == "EIP150") 17 | return EVMC_TANGERINE_WHISTLE; 18 | if (s == "Spurious Dragon" || s == "EIP158") 19 | return EVMC_SPURIOUS_DRAGON; 20 | if (s == "Byzantium") 21 | return EVMC_BYZANTIUM; 22 | if (s == "Constantinople") 23 | return EVMC_CONSTANTINOPLE; 24 | if (s == "Petersburg" || s == "ConstantinopleFix") 25 | return EVMC_PETERSBURG; 26 | if (s == "Istanbul") 27 | return EVMC_ISTANBUL; 28 | if (s == "Berlin") 29 | return EVMC_BERLIN; 30 | if (s == "London" || s == "ArrowGlacier") 31 | return EVMC_LONDON; 32 | if (s == "Paris" || s == "Merge") 33 | return EVMC_PARIS; 34 | if (s == "Shanghai") 35 | return EVMC_SHANGHAI; 36 | if (s == "Cancun") 37 | return EVMC_CANCUN; 38 | if (s == "Prague") 39 | return EVMC_PRAGUE; 40 | if (s == "Osaka") 41 | return EVMC_OSAKA; 42 | throw std::invalid_argument{"unknown revision: " + std::string{s}}; 43 | } 44 | 45 | RevisionSchedule to_rev_schedule(std::string_view s) 46 | { 47 | if (s == "ShanghaiToCancunAtTime15k") 48 | return {EVMC_SHANGHAI, EVMC_CANCUN, 15'000}; 49 | if (s == "CancunToPragueAtTime15k") 50 | return {EVMC_CANCUN, EVMC_PRAGUE, 15'000}; 51 | 52 | const auto single_rev = to_rev(s); 53 | return {single_rev, single_rev, 0}; 54 | } 55 | 56 | } // namespace evmone::test 57 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: "{build}" 2 | image: Visual Studio 2019 3 | 4 | branches: 5 | only: 6 | - master 7 | - /release\/.*/ 8 | - appveyor 9 | - hunter 10 | - /v\d+\..+/ 11 | configuration: 12 | - Release 13 | - Debug 14 | environment: 15 | GITHUB_TOKEN: 16 | secure: OE3TGKRyt/hvk5Gt3DLXvs3Y+F1NLDQAL/bHplDffR+hY2aFg6HrapThKjYo/XX2 17 | matrix: 18 | - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 19 | GENERATOR: "Ninja" 20 | 21 | cache: 22 | - C:\.hunter\_Base\Cache -> cmake\Hunter\init.cmake 23 | 24 | install: 25 | - cmake --version 26 | - git submodule update --init --recursive 27 | 28 | before_build: 29 | - call "%ProgramFiles(x86)%\Microsoft Visual Studio\2019\Community\Common7\Tools\VsDevCmd" -arch=amd64 30 | - cmake -S . -B build -DEVMONE_TESTING=ON -Wno-dev -G "%GENERATOR%" -DCMAKE_BUILD_TYPE=%CONFIGURATION% -DHUNTER_CONFIGURATION_TYPES=%CONFIGURATION% -DCMAKE_INSTALL_PREFIX=C:\install 31 | 32 | build_script: 33 | - cmake --build build --target package 34 | - mkdir package 35 | - mv build/evmone-* package 36 | 37 | artifacts: 38 | - path: package/* 39 | name: package 40 | 41 | test_script: 42 | - cd build && ctest -j4 --output-on-failure --schedule-random 43 | 44 | deploy_script: 45 | - ps: >- 46 | if ($env:appveyor_repo_tag_name -match 'v\d+\..+') { 47 | 48 | $env:GO111MODULE = "on" 49 | go get github.com/tcnksm/ghr@v0.12.1 2>$null 50 | $env:PATH += ";$env:USERPROFILE\go\bin" 51 | 52 | cd $env:appveyor_build_folder 53 | $name = "evmone " + ($env:appveyor_repo_tag_name).Remove(0,1) 54 | if (($env:appveyor_repo_tag_name).Contains("-")) { 55 | $prerelease_flag = "-prerelease" 56 | } 57 | echo $name 58 | echo $prerelease_flag 59 | ghr -u ethereum -r evmone -n "$name" $prerelease_flag $env:appveyor_repo_tag_name package/ 60 | } 61 | -------------------------------------------------------------------------------- /test/internal_benchmarks/build_complete_tree.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | # The PoC of generating complete binary trees from sorted list 4 | # and packing the tree into an array. 5 | # This transformation can be used to speed up jumpdest search. 6 | 7 | import sys 8 | 9 | 10 | def hibit(n): 11 | n |= (n >> 1) 12 | n |= (n >> 2) 13 | n |= (n >> 4) 14 | n |= (n >> 8) 15 | n |= (n >> 16) 16 | return n - (n >> 1) 17 | 18 | 19 | def build_subtree(elems, arr, pos): 20 | # print(elems) 21 | size = len(elems) 22 | if size == 1: 23 | arr[pos] = elems[0] 24 | print("* {}".format(elems[0])) 25 | return 26 | 27 | perfect_tree_size = hibit(size + 1) - 1 28 | # print(perfect_tree_size) 29 | 30 | incomp_level_len = hibit(perfect_tree_size) * 2 31 | incomp_len = size - perfect_tree_size 32 | left_len = min(incomp_len, incomp_level_len // 2) 33 | right_len = max(incomp_len - incomp_level_len // 2, 0) 34 | balance = left_len - right_len 35 | # print("incomplete {}/{} of {}: {}".format(left_len, right_len, 36 | # incomp_level_len, balance)) 37 | 38 | middle = size // 2 + balance // 2 39 | arr[pos] = elems[middle] 40 | print("* {}".format(elems[middle])) 41 | 42 | left = elems[:middle] 43 | right = elems[middle + 1:] 44 | 45 | build_subtree(left, arr, 2 * pos + 1) 46 | build_subtree(right, arr, 2 * pos + 2) 47 | 48 | 49 | def build_tree(size): 50 | elems = list(range(size)) 51 | arr = [-1] * size 52 | build_subtree(elems, arr, 0) 53 | 54 | print(arr) 55 | 56 | l = 1 57 | q = 0 58 | for i in range(len(arr)): 59 | print("{} ".format(arr[i]), end='') 60 | q += 1 61 | if q == l: 62 | l *= 2 63 | q = 0 64 | print("") 65 | 66 | 67 | build_tree(int(sys.argv[1])) 68 | -------------------------------------------------------------------------------- /test/internal_benchmarks/evmmax_bench.cpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2023 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | #include 6 | #include 7 | 8 | using namespace intx; 9 | 10 | namespace 11 | { 12 | constexpr auto bn254 = 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47_u256; 13 | constexpr auto secp256k1 = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f_u256; 14 | 15 | template 16 | void evmmax_add(benchmark::State& state) 17 | { 18 | const evmmax::ModArith m{Mod}; 19 | auto a = Mod / 2; 20 | auto b = Mod / 3; 21 | 22 | while (state.KeepRunningBatch(2)) 23 | { 24 | a = m.add(a, b); 25 | b = m.add(b, a); 26 | } 27 | } 28 | 29 | template 30 | void evmmax_sub(benchmark::State& state) 31 | { 32 | const evmmax::ModArith m{Mod}; 33 | auto a = Mod / 2; 34 | auto b = Mod / 3; 35 | 36 | while (state.KeepRunningBatch(2)) 37 | { 38 | a = m.sub(a, b); 39 | b = m.sub(b, a); 40 | } 41 | } 42 | 43 | template 44 | void evmmax_mul(benchmark::State& state) 45 | { 46 | const evmmax::ModArith m{Mod}; 47 | auto a = m.to_mont(Mod / 2); 48 | auto b = m.to_mont(Mod / 3); 49 | 50 | while (state.KeepRunningBatch(2)) 51 | { 52 | a = m.mul(a, b); 53 | b = m.mul(b, a); 54 | } 55 | } 56 | } // namespace 57 | 58 | BENCHMARK_TEMPLATE(evmmax_add, uint256, bn254); 59 | BENCHMARK_TEMPLATE(evmmax_add, uint256, secp256k1); 60 | BENCHMARK_TEMPLATE(evmmax_sub, uint256, bn254); 61 | BENCHMARK_TEMPLATE(evmmax_sub, uint256, secp256k1); 62 | BENCHMARK_TEMPLATE(evmmax_mul, uint256, bn254); 63 | BENCHMARK_TEMPLATE(evmmax_mul, uint256, secp256k1); 64 | -------------------------------------------------------------------------------- /test/unittests/evmone_test.cpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2019-2020 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | TEST(evmone, info) 11 | { 12 | auto vm = evmc::VM{evmc_create_evmone()}; 13 | EXPECT_STREQ(vm.name(), "evmone"); 14 | EXPECT_STREQ(vm.version(), PROJECT_VERSION); 15 | EXPECT_TRUE(vm.is_abi_compatible()); 16 | } 17 | 18 | TEST(evmone, capabilities) 19 | { 20 | auto vm = evmc_create_evmone(); 21 | EXPECT_EQ(vm->get_capabilities(vm), evmc_capabilities_flagset{EVMC_CAPABILITY_EVM1}); 22 | vm->destroy(vm); 23 | } 24 | 25 | TEST(evmone, set_option_invalid) 26 | { 27 | auto vm = evmc_create_evmone(); 28 | ASSERT_NE(vm->set_option, nullptr); 29 | EXPECT_EQ(vm->set_option(vm, "", ""), EVMC_SET_OPTION_INVALID_NAME); 30 | EXPECT_EQ(vm->set_option(vm, "o", ""), EVMC_SET_OPTION_INVALID_NAME); 31 | EXPECT_EQ(vm->set_option(vm, "0", ""), EVMC_SET_OPTION_INVALID_NAME); 32 | vm->destroy(vm); 33 | } 34 | 35 | TEST(evmone, set_option_advanced) 36 | { 37 | auto vm = evmc::VM{evmc_create_evmone()}; 38 | EXPECT_EQ(vm.set_option("advanced", ""), EVMC_SET_OPTION_SUCCESS); 39 | 40 | // This will also enable Advanced. 41 | EXPECT_EQ(vm.set_option("advanced", "no"), EVMC_SET_OPTION_SUCCESS); 42 | } 43 | 44 | TEST(evmone, set_option_cgoto) 45 | { 46 | evmc::VM vm{evmc_create_evmone()}; 47 | 48 | #if EVMONE_CGOTO_SUPPORTED 49 | EXPECT_EQ(vm.set_option("cgoto", ""), EVMC_SET_OPTION_INVALID_VALUE); 50 | EXPECT_EQ(vm.set_option("cgoto", "yes"), EVMC_SET_OPTION_INVALID_VALUE); 51 | EXPECT_EQ(vm.set_option("cgoto", "no"), EVMC_SET_OPTION_SUCCESS); 52 | #else 53 | EXPECT_EQ(vm.set_option("cgoto", "no"), EVMC_SET_OPTION_INVALID_NAME); 54 | #endif 55 | } 56 | -------------------------------------------------------------------------------- /cmake/LibraryTools.cmake: -------------------------------------------------------------------------------- 1 | # evmone: Fast Ethereum Virtual Machine implementation 2 | # Copyright 2019 The evmone Authors. 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | # For given target of a static library creates a custom target with -standalone suffix 6 | # that merges the given target and all its static library dependencies 7 | # into a single static library. 8 | # 9 | # It silently ignores non-static library target and unsupported platforms. 10 | function(add_standalone_library TARGET) 11 | get_target_property(type ${TARGET} TYPE) 12 | if(NOT type STREQUAL STATIC_LIBRARY) 13 | return() 14 | endif() 15 | 16 | set(name ${TARGET}-standalone) 17 | 18 | if(CMAKE_AR) 19 | # Generate ar linker script. 20 | set(script_file ${name}.mri) 21 | set(script "CREATE $\n") 22 | string(APPEND script "ADDLIB $\n") 23 | 24 | get_target_property(link_libraries ${TARGET} LINK_LIBRARIES) 25 | foreach(lib ${link_libraries}) 26 | get_target_property(type ${lib} TYPE) 27 | if(NOT type STREQUAL INTERFACE_LIBRARY) 28 | string(APPEND script "ADDLIB $\n") 29 | endif() 30 | endforeach() 31 | 32 | string(APPEND script "SAVE\n") 33 | file(GENERATE OUTPUT ${script_file} CONTENT ${script}) 34 | 35 | # Add -standalone static library. 36 | add_library(${name} STATIC) 37 | target_sources(${name} PRIVATE ${script_file}) 38 | add_custom_command(TARGET ${name} POST_BUILD COMMAND ${CMAKE_AR} -M < ${script_file}) 39 | add_dependencies(${name} ${TARGET}) 40 | 41 | get_property(enabled_languages GLOBAL PROPERTY ENABLED_LANGUAGES) 42 | list(GET enabled_languages -1 lang) 43 | set_target_properties(${name} PROPERTIES LINKER_LANGUAGE ${lang}) 44 | endif() 45 | endfunction() 46 | -------------------------------------------------------------------------------- /test/integration/statetest/tests1/SuiteA/test1.json: -------------------------------------------------------------------------------- 1 | { 2 | "test1": { 3 | "_info": {}, 4 | "env": { 5 | "currentBaseFee": "0x0a", 6 | "currentCoinbase": "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", 7 | "currentDifficulty": "0x020000", 8 | "currentGasLimit": "0xff112233445566", 9 | "currentNumber": "0x01", 10 | "currentRandom": "0x0000000000000000000000000000000000000000000000000000000000020000", 11 | "currentTimestamp": "0x03e8" 12 | }, 13 | "post": { 14 | "London": [ 15 | { 16 | "hash": "0xe8010ce590f401c9d61fef8ab05bea9bcec24281b795e5868809bc4e515aa530", 17 | "indexes": { 18 | "data": 0, 19 | "gas": 0, 20 | "value": 0 21 | }, 22 | "logs": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" 23 | } 24 | ] 25 | }, 26 | "pre": { 27 | "0x095e7baea6a6c7c4c2dfeb977efac326af552d87": { 28 | "balance": "0x0de0b6b3a7640000", 29 | "code": "0x600160010160005500", 30 | "nonce": "0x00", 31 | "storage": {} 32 | }, 33 | "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba": { 34 | "balance": "0x00", 35 | "code": "0x", 36 | "nonce": "0x01", 37 | "storage": {} 38 | }, 39 | "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { 40 | "balance": "0x0de0b6b3a7640000", 41 | "code": "0x", 42 | "nonce": "0x00", 43 | "storage": {} 44 | } 45 | }, 46 | "transaction": { 47 | "data": [ 48 | "0x" 49 | ], 50 | "gasLimit": [ 51 | "0x061a80" 52 | ], 53 | "gasPrice": "0x0a", 54 | "nonce": "0x00", 55 | "sender": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", 56 | "to": "0x095e7baea6a6c7c4c2dfeb977efac326af552d87", 57 | "value": [ 58 | "0x0186a0" 59 | ] 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /cmake/blst.cmake: -------------------------------------------------------------------------------- 1 | include_guard() 2 | include(ExternalProject) 3 | 4 | if(MSVC) 5 | set(BLST_BUILD_SCRIPT build.bat) 6 | else() 7 | # Build CC compiler invocation. 8 | set(BLST_CC ${CMAKE_C_COMPILER}) 9 | if(CMAKE_OSX_SYSROOT) 10 | set(BLST_CC "${BLST_CC} ${CMAKE_C_SYSROOT_FLAG} ${CMAKE_OSX_SYSROOT}") 11 | endif() 12 | if(CMAKE_C_OSX_DEPLOYMENT_TARGET_FLAG AND CMAKE_OSX_DEPLOYMENT_TARGET) 13 | set(BLST_CC "${BLST_CC} ${CMAKE_C_OSX_DEPLOYMENT_TARGET_FLAG}${CMAKE_OSX_DEPLOYMENT_TARGET}") 14 | endif() 15 | if(CMAKE_C_FLAGS) 16 | # Pass CFLAGS as part of CC (e.g. to pass -m32). Using CFLAGS directly overwrites blst's default. 17 | set(BLST_CC "${BLST_CC} ${CMAKE_C_FLAGS}") 18 | endif() 19 | 20 | set(BLST_BUILD_SCRIPT ./build.sh CC='${BLST_CC}' AR='${CMAKE_AR}') 21 | endif() 22 | 23 | ExternalProject_Add( 24 | blst 25 | EXCLUDE_FROM_ALL TRUE 26 | PREFIX ${PROJECT_BINARY_DIR}/deps 27 | URL https://github.com/supranational/blst/archive/refs/tags/v0.3.13.tar.gz 28 | URL_HASH SHA256=89772cef338e93bc0348ae531462752906e8fa34738e38035308a7931dd2948f 29 | DOWNLOAD_NO_PROGRESS TRUE 30 | CONFIGURE_COMMAND "" 31 | BUILD_COMMAND ${BLST_BUILD_SCRIPT} 32 | BUILD_IN_SOURCE TRUE 33 | BUILD_BYPRODUCTS "/${CMAKE_STATIC_LIBRARY_PREFIX}blst${CMAKE_STATIC_LIBRARY_SUFFIX}" 34 | LOG_BUILD TRUE 35 | LOG_OUTPUT_ON_FAILURE TRUE 36 | INSTALL_COMMAND "" 37 | ) 38 | ExternalProject_Get_Property(blst SOURCE_DIR) 39 | 40 | set(BLST_INCLUDE_DIR ${SOURCE_DIR}/bindings) 41 | file(MAKE_DIRECTORY ${BLST_INCLUDE_DIR}) 42 | 43 | add_library(blst::blst STATIC IMPORTED GLOBAL) 44 | add_dependencies(blst::blst blst) 45 | set_target_properties( 46 | blst::blst PROPERTIES 47 | INTERFACE_INCLUDE_DIRECTORIES ${BLST_INCLUDE_DIR} 48 | IMPORTED_LOCATION ${SOURCE_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}blst${CMAKE_STATIC_LIBRARY_SUFFIX} 49 | ) 50 | 51 | -------------------------------------------------------------------------------- /test/unittests/state_transition_call_test.cpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2024 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | #include "../utils/bytecode.hpp" 6 | #include "state_transition.hpp" 7 | 8 | using namespace evmc::literals; 9 | using namespace evmone::test; 10 | 11 | TEST_F(state_transition, call_value_to_empty) 12 | { 13 | rev = EVMC_LONDON; 14 | static constexpr auto BENEFICIARY = 0xbe_address; 15 | tx.to = To; 16 | pre[To] = {.balance = 1, .code = call(BENEFICIARY).value(1)}; 17 | pre[BENEFICIARY] = {}; 18 | 19 | expect.post[To].balance = 0; 20 | expect.post[BENEFICIARY].balance = 1; 21 | } 22 | 23 | TEST_F(state_transition, delegatecall_static_legacy) 24 | { 25 | rev = EVMC_OSAKA; 26 | // Checks if DELEGATECALL forwards the "static" flag. 27 | static constexpr auto CALLEE1 = 0xca11ee01_address; 28 | static constexpr auto CALLEE2 = 0xca11ee02_address; 29 | pre[CALLEE2] = { 30 | .storage = {{0x01_bytes32, 0xdd_bytes32}}, 31 | .code = sstore(1, 0xcc_bytes32), 32 | }; 33 | pre[CALLEE1] = { 34 | .storage = {{0x01_bytes32, 0xdd_bytes32}}, 35 | .code = ret(delegatecall(CALLEE2).gas(100'000)), 36 | }; 37 | tx.to = To; 38 | pre[To] = { 39 | .storage = {{0x01_bytes32, 0xdd_bytes32}, {0x02_bytes32, 0xdd_bytes32}}, 40 | .code = sstore(1, staticcall(CALLEE1).gas(200'000)) + 41 | sstore(2, returndatacopy(0, 0, returndatasize()) + mload(0)), 42 | }; 43 | 44 | expect.gas_used = 131480; 45 | // Outer call - success. 46 | expect.post[To].storage[0x01_bytes32] = 0x01_bytes32; 47 | // Inner call - no success. 48 | expect.post[To].storage[0x02_bytes32] = 0x00_bytes32; 49 | // SSTORE failed. 50 | expect.post[CALLEE1].storage[0x01_bytes32] = 0xdd_bytes32; 51 | expect.post[CALLEE2].storage[0x01_bytes32] = 0xdd_bytes32; 52 | } 53 | -------------------------------------------------------------------------------- /test/integration/eofparse/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # evmone: Fast Ethereum Virtual Machine implementation 2 | # Copyright 2024 The evmone Authors. 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | set(PREFIX ${PROJECT_NAME}/integration/eofparse) 6 | 7 | string(REPLACE ";" " " CROSSCOMPILING_EMULATOR "${CMAKE_CROSSCOMPILING_EMULATOR}") 8 | 9 | add_test(NAME ${PREFIX}/minimal_eof COMMAND sh -c "echo EF0001.010004 0200010001 040000 00,00800000 FE | ${CROSSCOMPILING_EMULATOR} $") 10 | set_tests_properties(${PREFIX}/minimal_eof PROPERTIES PASS_REGULAR_EXPRESSION "OK fe") 11 | 12 | add_test(NAME ${PREFIX}/two_code_sections COMMAND sh -c "echo EF0001 010008 02000200030001 040000 00 00800000,00800000 E50001,00 | ${CROSSCOMPILING_EMULATOR} $") 13 | set_tests_properties(${PREFIX}/two_code_sections PROPERTIES PASS_REGULAR_EXPRESSION "OK e50001,00") 14 | 15 | add_test(NAME ${PREFIX}/eof_version_unknown COMMAND sh -c "echo EF00.FF | ${CROSSCOMPILING_EMULATOR} $") 16 | set_tests_properties(${PREFIX}/eof_version_unknown PROPERTIES PASS_REGULAR_EXPRESSION "err: eof_version_unknown") 17 | 18 | add_test(NAME ${PREFIX}/invalid_hex COMMAND sh -c "echo gaga | ${CROSSCOMPILING_EMULATOR} $") 19 | set_tests_properties(${PREFIX}/invalid_hex PROPERTIES PASS_REGULAR_EXPRESSION "err: invalid hex") 20 | 21 | add_test(NAME ${PREFIX}/example_input_file COMMAND sh -c "${CROSSCOMPILING_EMULATOR} $ <${CMAKE_CURRENT_SOURCE_DIR}/two_errors.txt") 22 | set_tests_properties(${PREFIX}/example_input_file PROPERTIES PASS_REGULAR_EXPRESSION "OK 00\nerr: type_section_missing\nerr: no_terminating_instruction") 23 | 24 | add_test(NAME ${PREFIX}/exit_code COMMAND sh -c "${CROSSCOMPILING_EMULATOR} $ <${CMAKE_CURRENT_SOURCE_DIR}/two_errors.txt >/dev/null; echo $?") 25 | set_tests_properties(${PREFIX}/exit_code PROPERTIES PASS_REGULAR_EXPRESSION "2") 26 | -------------------------------------------------------------------------------- /cmake/cable/buildinfo/gitinfo.cmake: -------------------------------------------------------------------------------- 1 | # Cable: CMake Bootstrap Library. 2 | # Copyright 2018 Pawel Bylica. 3 | # Licensed under the Apache License, Version 2.0. See the LICENSE file. 4 | 5 | # Execute git only if the tool is available. 6 | if(GIT) 7 | execute_process( 8 | COMMAND ${GIT} describe --always --long --tags --first-parent --match=v* --abbrev=40 --dirty 9 | WORKING_DIRECTORY ${SOURCE_DIR} 10 | OUTPUT_VARIABLE gitinfo 11 | OUTPUT_STRIP_TRAILING_WHITESPACE 12 | ERROR_VARIABLE error 13 | ERROR_STRIP_TRAILING_WHITESPACE 14 | ) 15 | if(error) 16 | message(WARNING "Git ${error}") 17 | endif() 18 | 19 | execute_process( 20 | COMMAND ${GIT} rev-parse --abbrev-ref HEAD 21 | WORKING_DIRECTORY ${SOURCE_DIR} 22 | OUTPUT_VARIABLE gitbranch 23 | OUTPUT_STRIP_TRAILING_WHITESPACE 24 | ERROR_VARIABLE error 25 | ERROR_STRIP_TRAILING_WHITESPACE 26 | ) 27 | if(error) 28 | message(WARNING "Git ${error}") 29 | else() 30 | set(gitinfo "${gitinfo}\n${gitbranch}") 31 | endif() 32 | 33 | execute_process( 34 | COMMAND ${GIT} config --get remote.origin.url 35 | WORKING_DIRECTORY ${SOURCE_DIR} 36 | OUTPUT_VARIABLE gitorigin 37 | OUTPUT_STRIP_TRAILING_WHITESPACE 38 | ERROR_VARIABLE error 39 | ERROR_STRIP_TRAILING_WHITESPACE 40 | ) 41 | if(error) 42 | message(WARNING "Git ${error}") 43 | else() 44 | set(gitinfo "${gitinfo}\n${gitorigin}\n") 45 | endif() 46 | endif() 47 | 48 | set(gitinfo_file ${OUTPUT_DIR}/gitinfo.txt) 49 | 50 | if(EXISTS ${gitinfo_file}) 51 | file(READ ${gitinfo_file} prev_gitinfo) 52 | else() 53 | # Create empty file, because other targets expect it to exist. 54 | file(WRITE ${gitinfo_file} "") 55 | endif() 56 | 57 | if(NOT "${gitinfo}" STREQUAL "${prev_gitinfo}") 58 | file(WRITE ${gitinfo_file} ${gitinfo}) 59 | endif() 60 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # evmone: Fast Ethereum Virtual Machine implementation 2 | # Copyright 2019-2020 The evmone Authors. 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | include(GoogleTest) 6 | include(${PROJECT_SOURCE_DIR}/evmc/cmake/EVMC.cmake) 7 | 8 | set(evmone_private_include_dir ${PROJECT_SOURCE_DIR}/lib) 9 | 10 | hunter_add_package(GTest) 11 | find_package(GTest CONFIG REQUIRED) 12 | 13 | hunter_add_package(benchmark) 14 | find_package(benchmark CONFIG REQUIRED) 15 | 16 | hunter_add_package(nlohmann_json) 17 | find_package(nlohmann_json CONFIG REQUIRED) 18 | 19 | add_subdirectory(utils) 20 | add_subdirectory(bench) 21 | add_subdirectory(blockchaintest) 22 | add_subdirectory(eofparse) 23 | add_subdirectory(experimental) 24 | add_subdirectory(integration) 25 | add_subdirectory(internal_benchmarks) 26 | add_subdirectory(precompiles_bench) 27 | add_subdirectory(state) 28 | add_subdirectory(statetest) 29 | add_subdirectory(eoftest) 30 | add_subdirectory(t8n) 31 | add_subdirectory(unittests) 32 | 33 | set(targets evmone-bench evmone-bench-internal evmone-eofparse evmone-blockchaintest evmone-precompiles-bench evmone-state evmone-statetest evmone-eoftest evmone-t8n evmone-unittests) 34 | 35 | if(EVMONE_FUZZING) 36 | add_subdirectory(eofparsefuzz) 37 | add_subdirectory(fuzzer) 38 | list(APPEND targets evmone-eofparsefuzz evmone-fuzzer) 39 | endif() 40 | 41 | set_target_properties( 42 | ${targets} PROPERTIES 43 | ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR} 44 | LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR} 45 | RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_BINDIR} 46 | ) 47 | 48 | get_target_property(type evmone TYPE) 49 | if(type STREQUAL SHARED_LIBRARY) 50 | evmc_add_vm_test(NAME ${PROJECT_NAME}/evmc-vmtester TARGET evmone) 51 | 52 | if(TARGET evm-test) 53 | add_test(NAME ${PROJECT_NAME}/evm-test COMMAND evm-test $) 54 | endif() 55 | endif() 56 | -------------------------------------------------------------------------------- /test/integration/export/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # evmone: Fast Ethereum Virtual Machine implementation 2 | # Copyright 2023 The evmone Authors. 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | # Commands and tests for exporting evmone's tests to JSON formats 6 | 7 | set(PREFIX ${PREFIX}/export) 8 | set(EXPORT_DIR fixtures) 9 | 10 | add_test( 11 | # Clean the export directory before exporting to delete potentially outdated tests. 12 | NAME ${PREFIX}/clean_export_dir 13 | COMMAND ${CMAKE_COMMAND} -E rm -rf ${EXPORT_DIR} 14 | ) 15 | set_tests_properties( 16 | ${PREFIX}/clean_export_dir PROPERTIES 17 | FIXTURES_SETUP EXPORT_PREPARATION 18 | ) 19 | 20 | add_test( 21 | NAME ${PREFIX}/export_state_tests 22 | COMMAND evmone-unittests --gtest_filter=state_transition.* 23 | ) 24 | set_tests_properties( 25 | ${PREFIX}/export_state_tests PROPERTIES 26 | ENVIRONMENT EVMONE_EXPORT_TESTS=${EXPORT_DIR}/state_tests 27 | FIXTURES_SETUP EXPORT_STATE_TESTS 28 | FIXTURES_REQUIRED EXPORT_PREPARATION 29 | ) 30 | 31 | add_test( 32 | NAME ${PREFIX}/execute_exported_state_tests 33 | # TODO: Broken exported tests are filtered out. 34 | COMMAND evmone-statetest ${EXPORT_DIR}/state_tests --gtest_filter=-*block.* 35 | ) 36 | set_tests_properties( 37 | ${PREFIX}/execute_exported_state_tests PROPERTIES 38 | FIXTURES_REQUIRED EXPORT_STATE_TESTS 39 | ) 40 | 41 | add_test( 42 | NAME ${PREFIX}/export_eof_tests 43 | COMMAND evmone-unittests --gtest_filter=eof_validation.* 44 | ) 45 | set_tests_properties( 46 | ${PREFIX}/export_eof_tests PROPERTIES 47 | ENVIRONMENT EVMONE_EXPORT_TESTS=${EXPORT_DIR}/eof_tests 48 | FIXTURES_SETUP EXPORT_EOF_TESTS 49 | FIXTURES_REQUIRED EXPORT_PREPARATION 50 | ) 51 | 52 | add_test( 53 | NAME ${PREFIX}/execute_exported_eof_tests 54 | COMMAND evmone-eoftest ${EXPORT_DIR}/eof_tests 55 | ) 56 | set_tests_properties( 57 | ${PREFIX}/execute_exported_eof_tests PROPERTIES 58 | FIXTURES_REQUIRED EXPORT_EOF_TESTS 59 | ) 60 | -------------------------------------------------------------------------------- /test/state/precompiles.hpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2022 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | #pragma once 5 | 6 | #include "../utils/stdx/utility.hpp" 7 | #include 8 | #include 9 | 10 | namespace evmone::state 11 | { 12 | /// The precompile identifiers and their corresponding addresses. 13 | enum class PrecompileId : uint8_t 14 | { 15 | ecrecover = 0x01, 16 | sha256 = 0x02, 17 | ripemd160 = 0x03, 18 | identity = 0x04, 19 | expmod = 0x05, 20 | ecadd = 0x06, 21 | ecmul = 0x07, 22 | ecpairing = 0x08, 23 | blake2bf = 0x09, 24 | point_evaluation = 0x0a, 25 | bls12_g1add = 0x0b, 26 | bls12_g1mul = 0x0c, 27 | bls12_g1msm = 0x0d, 28 | bls12_g2add = 0x0e, 29 | bls12_g2mul = 0x0f, 30 | bls12_g2msm = 0x10, 31 | bls12_pairing_check = 0x11, 32 | bls12_map_fp_to_g1 = 0x12, 33 | bls12_map_fp2_to_g2 = 0x13, 34 | 35 | since_byzantium = expmod, ///< The first precompile introduced in Byzantium. 36 | since_istanbul = blake2bf, ///< The first precompile introduced in Istanbul. 37 | since_cancun = point_evaluation, ///< The first precompile introduced in Cancun. 38 | since_prague = bls12_g1add, ///< The first precompile introduced in Prague. 39 | latest = bls12_map_fp2_to_g2 ///< The latest introduced precompile (highest address). 40 | }; 41 | 42 | /// The total number of known precompiles ids, including 0. 43 | inline constexpr std::size_t NumPrecompiles = stdx::to_underlying(PrecompileId::latest) + 1; 44 | 45 | /// Checks if the address @p addr is considered a precompiled contract in the revision @p rev. 46 | bool is_precompile(evmc_revision rev, const evmc::address& addr) noexcept; 47 | 48 | /// Executes the message to a precompiled contract (msg.code_address must be a precompile). 49 | evmc::Result call_precompile(evmc_revision rev, const evmc_message& msg) noexcept; 50 | } // namespace evmone::state 51 | -------------------------------------------------------------------------------- /test/state/bloom_filter.cpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2023 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | #include "bloom_filter.hpp" 6 | #include "transaction.hpp" 7 | 8 | namespace evmone::state 9 | { 10 | 11 | namespace 12 | { 13 | /// Adds an entry to the bloom filter. 14 | /// based on 15 | /// https://ethereum.github.io/execution-specs/autoapi/ethereum/shanghai/bloom/index.html#add-to-bloom 16 | inline void add_to(BloomFilter& bf, const bytes_view& entry) 17 | { 18 | const auto hash = keccak256(entry); 19 | 20 | // take the least significant 11-bits of the first three 16-bit values 21 | for (const auto i : {0, 2, 4}) 22 | { 23 | const auto bit_to_set = ((hash.bytes[i] & 0x07) << 8) | hash.bytes[i + 1]; 24 | const auto bit_index = 0x07FF - bit_to_set; 25 | const auto byte_index = bit_index / 8; 26 | const auto bit_pos = static_cast(1 << (7 - (bit_index % 8))); 27 | bf.bytes[byte_index] |= bit_pos; 28 | } 29 | } 30 | 31 | } // namespace 32 | 33 | BloomFilter compute_bloom_filter(std::span logs) noexcept 34 | { 35 | BloomFilter res; 36 | for (const auto& log : logs) 37 | { 38 | add_to(res, log.addr); 39 | for (const auto& topic : log.topics) 40 | add_to(res, topic); 41 | } 42 | 43 | return res; 44 | } 45 | 46 | BloomFilter compute_bloom_filter(std::span receipts) noexcept 47 | { 48 | BloomFilter res; 49 | 50 | for (const auto& r : receipts) 51 | std::transform( 52 | res.bytes, std::end(res.bytes), r.logs_bloom_filter.bytes, res.bytes, std::bit_or<>()); 53 | 54 | return res; 55 | } 56 | 57 | BloomFilter bloom_filter_from_bytes(const bytes_view& data) noexcept 58 | { 59 | assert(data.size() == 256); 60 | BloomFilter res; 61 | std::copy(std::begin(data), std::end(data), std::begin(res.bytes)); 62 | return res; 63 | } 64 | 65 | } // namespace evmone::state 66 | -------------------------------------------------------------------------------- /cmake/cable/CableBuildType.cmake: -------------------------------------------------------------------------------- 1 | # Cable: CMake Bootstrap Library 2 | # Copyright 2018 Pawel Bylica. 3 | # Licensed under the Apache License, Version 2.0. 4 | 5 | # Cable Build Type, version 1.0.1 6 | # 7 | # This CMake module helps with setting default build type 8 | # and build configurations for multi-configuration generators. 9 | # Use cable_set_build_type(). 10 | # 11 | # CHANGELOG 12 | # 13 | # 1.0.1 - 2021-05-20 14 | # - Fix usage in CMake sub-project. 15 | # 16 | # 1.0.0 - 2020-01-02 17 | 18 | 19 | if(cable_build_type_included) 20 | return() 21 | endif() 22 | set(cable_build_type_included TRUE) 23 | 24 | macro(cable_set_build_type) 25 | if(NOT PROJECT_SOURCE_DIR) # Before the main project(). 26 | cmake_parse_arguments(build_type "" DEFAULT CONFIGURATION_TYPES ${ARGN}) 27 | 28 | if(CMAKE_CONFIGURATION_TYPES) 29 | if(build_type_CONFIGURATION_TYPES) 30 | set( 31 | CMAKE_CONFIGURATION_TYPES 32 | ${build_type_CONFIGURATION_TYPES} 33 | CACHE 34 | STRING 35 | "Available configurations for multi-configuration generators" 36 | FORCE 37 | ) 38 | endif() 39 | message(STATUS "Configurations: ${CMAKE_CONFIGURATION_TYPES}") 40 | else() 41 | if(build_type_DEFAULT AND NOT CMAKE_BUILD_TYPE) 42 | set( 43 | CMAKE_BUILD_TYPE 44 | ${build_type_DEFAULT} 45 | CACHE STRING 46 | "Build type for single-configuration generators" 47 | FORCE 48 | ) 49 | endif() 50 | message(STATUS "Build type: ${CMAKE_BUILD_TYPE}") 51 | endif() 52 | elseif(PROJECT_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) # After the main project(). 53 | message(FATAL_ERROR "cable_set_build_type() must be used before project()") 54 | endif() # Sub-project - silently ignore. 55 | endmacro() 56 | -------------------------------------------------------------------------------- /test/blockchaintest/blockchaintest.hpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2023 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | #pragma once 5 | 6 | #include "../state/block.hpp" 7 | #include "../state/bloom_filter.hpp" 8 | #include "../state/test_state.hpp" 9 | #include "../state/transaction.hpp" 10 | #include "../utils/utils.hpp" 11 | #include 12 | #include 13 | #include 14 | 15 | namespace evmone::test 16 | { 17 | struct UnsupportedTestFeature : std::runtime_error 18 | { 19 | using runtime_error::runtime_error; 20 | }; 21 | 22 | // https://ethereum.org/en/developers/docs/blocks/ 23 | struct BlockHeader 24 | { 25 | hash256 parent_hash; 26 | address coinbase; 27 | hash256 state_root; 28 | hash256 receipts_root; 29 | state::BloomFilter logs_bloom; 30 | int64_t difficulty; 31 | bytes32 prev_randao; 32 | int64_t block_number; 33 | int64_t gas_limit; 34 | int64_t gas_used; 35 | int64_t timestamp; 36 | bytes extra_data; 37 | uint64_t base_fee_per_gas; 38 | hash256 hash; 39 | hash256 transactions_root; 40 | hash256 withdrawal_root; 41 | hash256 parent_beacon_block_root; 42 | uint64_t excess_blob_gas; 43 | hash256 requests_hash; 44 | }; 45 | 46 | struct TestBlock 47 | { 48 | state::BlockInfo block_info; 49 | std::vector transactions; 50 | 51 | BlockHeader expected_block_header; 52 | }; 53 | 54 | struct BlockchainTest 55 | { 56 | struct Expectation 57 | { 58 | hash256 last_block_hash; 59 | std::variant post_state; 60 | }; 61 | 62 | std::string name; 63 | 64 | std::vector test_blocks; 65 | BlockHeader genesis_block_header; 66 | TestState pre_state; 67 | RevisionSchedule rev; 68 | 69 | Expectation expectation; 70 | }; 71 | 72 | std::vector load_blockchain_tests(std::istream& input); 73 | 74 | void run_blockchain_tests(std::span tests, evmc::VM& vm); 75 | 76 | } // namespace evmone::test 77 | -------------------------------------------------------------------------------- /test/unittests/evm_eip3860_initcode_test.cpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2022 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | /// This file contains EVM unit tests for EIP-3860 "Limit and meter initcode" 6 | /// https://eips.ethereum.org/EIPS/eip-3860 7 | 8 | #include "evm_fixture.hpp" 9 | 10 | using namespace evmc::literals; 11 | using namespace evmone::test; 12 | 13 | inline constexpr size_t initcode_size_limit = 0xc000; 14 | 15 | TEST_P(evm, create_initcode_limit) 16 | { 17 | host.call_result.create_address = 0x02_address; 18 | for (const auto& c : {create().input(0, calldataload(0)) + ret_top(), 19 | create2().input(0, calldataload(0)) + ret_top()}) 20 | { 21 | for (const auto r : {EVMC_PARIS, EVMC_SHANGHAI}) 22 | { 23 | rev = r; 24 | for (const auto s : {initcode_size_limit, initcode_size_limit + 1}) 25 | { 26 | execute(c, evmc::uint256be{s}); 27 | if (rev >= EVMC_SHANGHAI && s > initcode_size_limit) 28 | { 29 | EXPECT_STATUS(EVMC_OUT_OF_GAS); 30 | } 31 | else 32 | { 33 | EXPECT_OUTPUT_INT(2); 34 | } 35 | } 36 | } 37 | } 38 | } 39 | 40 | TEST_P(evm, create_initcode_gas_cost) 41 | { 42 | rev = EVMC_SHANGHAI; 43 | const auto code = create().input(0, calldataload(0)); 44 | execute(44300, code, evmc::uint256be{initcode_size_limit}); 45 | EXPECT_GAS_USED(EVMC_SUCCESS, 44300); 46 | execute(44299, code, evmc::uint256be{initcode_size_limit}); 47 | EXPECT_STATUS(EVMC_OUT_OF_GAS); 48 | } 49 | 50 | TEST_P(evm, create2_initcode_gas_cost) 51 | { 52 | rev = EVMC_SHANGHAI; 53 | const auto code = create2().input(0, calldataload(0)); 54 | execute(53519, code, evmc::uint256be{initcode_size_limit}); 55 | EXPECT_GAS_USED(EVMC_SUCCESS, 53519); 56 | execute(53518, code, evmc::uint256be{initcode_size_limit}); 57 | EXPECT_STATUS(EVMC_OUT_OF_GAS); 58 | } 59 | -------------------------------------------------------------------------------- /test/utils/utils.hpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2018 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | namespace evmone::test 11 | { 12 | using evmc::bytes; 13 | using evmc::bytes_view; 14 | using evmc::from_hex; 15 | using evmc::from_spaced_hex; 16 | using evmc::hex; 17 | 18 | /// The EVM revision schedule based on timestamps. 19 | struct RevisionSchedule 20 | { 21 | /// The revision of the first block. 22 | evmc_revision genesis_rev = EVMC_FRONTIER; 23 | 24 | /// The final revision to transition to. 25 | evmc_revision final_rev = genesis_rev; 26 | 27 | /// The timestamp of the transition to the final revision. 28 | int64_t transition_time = 0; 29 | 30 | /// Returns the specific revision for the given timestamp. 31 | [[nodiscard]] evmc_revision get_revision(int64_t timestamp) const noexcept 32 | { 33 | return timestamp >= transition_time ? final_rev : genesis_rev; 34 | } 35 | }; 36 | 37 | /// Translates tests fork name to EVM revision 38 | evmc_revision to_rev(std::string_view s); 39 | 40 | /// Translates tests fork name to the EVM revision schedule. 41 | RevisionSchedule to_rev_schedule(std::string_view s); 42 | 43 | /// Converts a string to bytes by casting individual characters. 44 | inline bytes to_bytes(std::string_view s) 45 | { 46 | return {s.begin(), s.end()}; 47 | } 48 | 49 | /// Convert address to 32-byte value left-padding with 0s. 50 | inline evmc::bytes32 to_bytes32(const evmc::address& addr) 51 | { 52 | evmc::bytes32 addr32; 53 | std::copy_n(addr.bytes, sizeof(addr), &addr32.bytes[sizeof(addr32) - sizeof(addr)]); 54 | return addr32; 55 | } 56 | 57 | /// Produces bytes out of string literal. 58 | inline bytes operator""_b(const char* data, size_t size) 59 | { 60 | return to_bytes({data, size}); 61 | } 62 | 63 | inline bytes operator""_hex(const char* s, size_t size) 64 | { 65 | return from_spaced_hex({s, size}).value(); 66 | } 67 | 68 | } // namespace evmone::test 69 | -------------------------------------------------------------------------------- /test/bench/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # evmone: Fast Ethereum Virtual Machine implementation 2 | # Copyright 2019 The evmone Authors. 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | add_executable(evmone-bench) 6 | target_include_directories(evmone-bench PRIVATE ${evmone_private_include_dir}) 7 | target_link_libraries(evmone-bench PRIVATE evmone evmone::testutils evmone::statetestutils evmc::loader benchmark::benchmark) 8 | target_sources( 9 | evmone-bench PRIVATE 10 | bench.cpp 11 | helpers.hpp 12 | synthetic_benchmarks.cpp synthetic_benchmarks.hpp 13 | ) 14 | 15 | # Tests 16 | 17 | set(PREFIX evmone/bench) 18 | set(BENCHMARK_SUITE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../evm-benchmarks/benchmarks) 19 | 20 | # Check if DIR argument works. 21 | add_test(NAME ${PREFIX}/dir COMMAND evmone-bench ${BENCHMARK_SUITE_DIR} --benchmark_list_tests) 22 | set_tests_properties(${PREFIX}/dir PROPERTIES PASS_REGULAR_EXPRESSION "total/synth") 23 | 24 | # Omitting DIR is fine. 25 | add_test(NAME ${PREFIX}/no_dir COMMAND evmone-bench --benchmark_list_tests) 26 | set_tests_properties(${PREFIX}/no_dir PROPERTIES PASS_REGULAR_EXPRESSION "total/synth") 27 | 28 | # Empty DIR name should list only built-in benchmarks. 29 | add_test(NAME ${PREFIX}/dirname_empty COMMAND evmone-bench "" --benchmark_list_tests) 30 | set_tests_properties(${PREFIX}/dirname_empty PROPERTIES PASS_REGULAR_EXPRESSION "total/synth") 31 | 32 | # Run all benchmark cases split into groups to check if none of them crashes. 33 | add_test(NAME ${PREFIX}/synth COMMAND evmone-bench --benchmark_min_time=1x --benchmark_filter=synth) 34 | add_test(NAME ${PREFIX}/micro COMMAND evmone-bench --benchmark_min_time=1x --benchmark_filter=micro ${BENCHMARK_SUITE_DIR}) 35 | add_test(NAME ${PREFIX}/main/b COMMAND evmone-bench --benchmark_min_time=1x --benchmark_filter=main/[b] ${BENCHMARK_SUITE_DIR}) 36 | add_test(NAME ${PREFIX}/main/s COMMAND evmone-bench --benchmark_min_time=1x --benchmark_filter=main/[s] ${BENCHMARK_SUITE_DIR}) 37 | add_test(NAME ${PREFIX}/main/w COMMAND evmone-bench --benchmark_min_time=1x --benchmark_filter=main/[w] ${BENCHMARK_SUITE_DIR}) 38 | add_test(NAME ${PREFIX}/main/_ COMMAND evmone-bench --benchmark_min_time=1x --benchmark_filter=main/[^bsw] ${BENCHMARK_SUITE_DIR}) 39 | -------------------------------------------------------------------------------- /lib/evmone/advanced_execution.cpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2019 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | #include "advanced_execution.hpp" 6 | #include "advanced_analysis.hpp" 7 | #include "eof.hpp" 8 | #include 9 | 10 | namespace evmone::advanced 11 | { 12 | evmc_result execute(AdvancedExecutionState& state, const AdvancedCodeAnalysis& analysis) noexcept 13 | { 14 | state.analysis.advanced = &analysis; // Allow accessing the analysis by instructions. 15 | 16 | const auto* instr = state.analysis.advanced->instrs.data(); // Get the first instruction. 17 | while (instr != nullptr) 18 | instr = instr->fn(instr, state); 19 | 20 | const auto gas_left = 21 | (state.status == EVMC_SUCCESS || state.status == EVMC_REVERT) ? state.gas_left : 0; 22 | const auto gas_refund = (state.status == EVMC_SUCCESS) ? state.gas_refund : 0; 23 | 24 | assert(state.output_size != 0 || state.output_offset == 0); 25 | return evmc::make_result(state.status, gas_left, gas_refund, 26 | state.memory.data() + state.output_offset, state.output_size); 27 | } 28 | 29 | evmc_result execute(evmc_vm* /*unused*/, const evmc_host_interface* host, evmc_host_context* ctx, 30 | evmc_revision rev, const evmc_message* msg, const uint8_t* code, size_t code_size) noexcept 31 | { 32 | AdvancedCodeAnalysis analysis; 33 | const bytes_view container = {code, code_size}; 34 | if (is_eof_container(container)) 35 | { 36 | if (rev >= EVMC_OSAKA) 37 | { 38 | const auto eof1_header = read_valid_eof1_header(container); 39 | analysis = analyze(rev, eof1_header.get_code(container, 0)); 40 | } 41 | else 42 | // Skip analysis, because it will recognize 01 section id as OP_ADD and return 43 | // EVMC_STACKUNDERFLOW. 44 | return evmc::make_result(EVMC_UNDEFINED_INSTRUCTION, 0, 0, nullptr, 0); 45 | } 46 | else 47 | analysis = analyze(rev, container); 48 | auto state = std::make_unique(*msg, rev, *host, ctx, container); 49 | return execute(*state, analysis); 50 | } 51 | } // namespace evmone::advanced 52 | -------------------------------------------------------------------------------- /cmake/cable/cable.cmake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env -S cmake -P 2 | 3 | # Cable: CMake Bootstrap Library 4 | # Copyright 2019-2020 Pawel Bylica. 5 | # Licensed under the Apache License, Version 2.0. 6 | 7 | # The cable command-line tool, version 1.0.0 8 | # 9 | # This CMake script allows installing or updating Cable modules. 10 | # Commands: 11 | # - list 12 | # - install 13 | # - update 14 | # 15 | # You can also include it from CMakeLists.txt to add Cable modules to 16 | # CMAKE_MODULE_PATH. 17 | 18 | if(NOT CMAKE_SCRIPT_MODE_FILE) 19 | # Setup Cable modules when included as include(cable.cmake). 20 | list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}) 21 | return() 22 | endif() 23 | 24 | set(repo_url https://github.com/ethereum/cable) 25 | set(download_url ${repo_url}/raw/master) 26 | set(cable_dir ${CMAKE_CURRENT_LIST_DIR}) 27 | 28 | function(get_modules_list OUTPUT_LIST) 29 | file(GLOB modules_files RELATIVE ${cable_dir} "${cable_dir}/Cable*.cmake") 30 | string(REPLACE ".cmake" "" modules "${modules_files}") 31 | set(${OUTPUT_LIST} "${modules}" PARENT_SCOPE) 32 | endfunction() 33 | 34 | function(download MODULE_NAME) 35 | set(module_file ${MODULE_NAME}.cmake) 36 | set(src "${download_url}/${module_file}") 37 | set(dst "${cable_dir}/${module_file}") 38 | file(DOWNLOAD "${src}" "${dst}" STATUS status) 39 | list(GET status 0 status_code) 40 | list(GET status 1 error_msg) 41 | if(status EQUAL 0) 42 | set(msg DONE) 43 | else() 44 | file(REMOVE "${dst}") 45 | set(msg "${status_code} ${error_msg}\n ${src}") 46 | endif() 47 | message("Downloading ${MODULE_NAME}: ${msg}") 48 | endfunction() 49 | 50 | set(cmd ${CMAKE_ARGV3}) # cmake -P cable.cmake ARGV3 ARGV4 ... 51 | if(NOT cmd) 52 | set(cmd list) 53 | endif() 54 | 55 | if(cmd STREQUAL list) 56 | get_modules_list(modules) 57 | string(REPLACE ";" "\n " modules "${modules}") 58 | message("Installed modules:\n ${modules}") 59 | elseif(cmd STREQUAL update) 60 | get_modules_list(modules) 61 | foreach(module ${modules}) 62 | download(${module}) 63 | endforeach() 64 | elseif(cmd STREQUAL install) 65 | download(${CMAKE_ARGV4}) 66 | else() 67 | message(FATAL_ERROR "Unknown command '${cmd}'") 68 | endif() 69 | -------------------------------------------------------------------------------- /test/state/block.hpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2022 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | #pragma once 6 | 7 | #include "hash_utils.hpp" 8 | #include 9 | #include 10 | 11 | namespace evmone::state 12 | { 13 | struct Ommer 14 | { 15 | address beneficiary; ///< Ommer block beneficiary address. 16 | uint32_t delta = 0; ///< Difference between current and ommer block number. 17 | }; 18 | 19 | struct Withdrawal 20 | { 21 | uint64_t index = 0; 22 | uint64_t validator_index = 0; 23 | address recipient; 24 | uint64_t amount_in_gwei = 0; ///< The amount is denominated in gwei. 25 | 26 | /// Returns withdrawal amount in wei. 27 | [[nodiscard]] intx::uint256 get_amount() const noexcept 28 | { 29 | return intx::uint256{amount_in_gwei} * 1'000'000'000; 30 | } 31 | }; 32 | 33 | struct BlockInfo 34 | { 35 | /// Max amount of blob gas allowed in block. It's constant now but can be dynamic in the future. 36 | static constexpr int64_t MAX_BLOB_GAS_PER_BLOCK = 786432; 37 | 38 | int64_t number = 0; 39 | int64_t timestamp = 0; 40 | int64_t parent_timestamp = 0; 41 | int64_t gas_limit = 0; 42 | address coinbase; 43 | int64_t difficulty = 0; 44 | int64_t parent_difficulty = 0; 45 | hash256 parent_ommers_hash; 46 | bytes32 prev_randao; 47 | hash256 parent_beacon_block_root; 48 | 49 | /// The EIP-1559 base fee, since London. 50 | uint64_t base_fee = 0; 51 | 52 | /// The "excess blob gas" parameter from EIP-4844 53 | /// for computing the blob gas price in the current block. 54 | uint64_t excess_blob_gas = 0; 55 | 56 | /// The blob gas price parameter from EIP-4844. 57 | /// This value is not stored in block headers directly but computed from excess_blob_gas. 58 | intx::uint256 blob_base_fee = 0; 59 | 60 | std::vector ommers; 61 | std::vector withdrawals; 62 | }; 63 | 64 | /// Computes the current blob gas price based on the excess blob gas. 65 | intx::uint256 compute_blob_gas_price(uint64_t excess_blob_gas) noexcept; 66 | 67 | /// Defines how to RLP-encode a Withdrawal. 68 | [[nodiscard]] bytes rlp_encode(const Withdrawal& withdrawal); 69 | } // namespace evmone::state 70 | -------------------------------------------------------------------------------- /test/state/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # evmone: Fast Ethereum Virtual Machine implementation 2 | # Copyright 2022 The evmone Authors. 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | add_library(evmone-state STATIC) 6 | add_library(evmone::state ALIAS evmone-state) 7 | target_link_libraries(evmone-state PUBLIC evmc::evmc_cpp PRIVATE evmone evmone::precompiles ethash::keccak) 8 | target_include_directories(evmone-state PRIVATE ${evmone_private_include_dir}) 9 | target_sources( 10 | evmone-state PRIVATE 11 | account.hpp 12 | block.hpp 13 | block.cpp 14 | bloom_filter.hpp 15 | bloom_filter.cpp 16 | errors.hpp 17 | ethash_difficulty.hpp 18 | ethash_difficulty.cpp 19 | hash_utils.hpp 20 | host.hpp 21 | host.cpp 22 | mpt.hpp 23 | mpt.cpp 24 | mpt_hash.hpp 25 | mpt_hash.cpp 26 | precompiles.hpp 27 | precompiles.cpp 28 | precompiles_internal.hpp 29 | precompiles_stubs.hpp 30 | precompiles_stubs.cpp 31 | requests.hpp 32 | requests.cpp 33 | rlp.hpp 34 | state.hpp 35 | state.cpp 36 | state_diff.hpp 37 | state_view.hpp 38 | system_contracts.hpp 39 | system_contracts.cpp 40 | test_state.hpp 41 | test_state.cpp 42 | transaction.hpp 43 | transaction.cpp 44 | ) 45 | 46 | option(EVMONE_PRECOMPILES_SILKPRE "Enable precompiles support via silkpre library" OFF) 47 | if(EVMONE_PRECOMPILES_SILKPRE) 48 | include(FetchContent) 49 | FetchContent_Declare( 50 | silkpre 51 | GIT_REPOSITORY https://github.com/torquem-ch/silkpre 52 | GIT_TAG 3322bb898ac9528fc2cf9a8df1e48360420d0c1a 53 | GIT_SHALLOW TRUE 54 | ) 55 | set(BUILD_SHARED_LIBS_ORIG ${BUILD_SHARED_LIBS}) 56 | set(BUILD_SHARED_LIBS OFF) 57 | FetchContent_MakeAvailable(silkpre) 58 | set(BUILD_SHARED_LIBS ${BUILD_SHARED_LIBS_ORIG}) 59 | 60 | set_target_properties( 61 | silkpre secp256k1 ff 62 | PROPERTIES 63 | COMPILE_OPTIONS -w # Disable warnings. 64 | CXX_CLANG_TIDY "" 65 | ) 66 | 67 | target_link_libraries(evmone-state PRIVATE silkpre) 68 | target_compile_definitions(evmone-state PUBLIC EVMONE_PRECOMPILES_SILKPRE=1) 69 | target_sources( 70 | evmone-state PRIVATE 71 | precompiles_silkpre.hpp 72 | precompiles_silkpre.cpp 73 | ) 74 | endif() 75 | -------------------------------------------------------------------------------- /test/unittests/eof_validation.hpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2024 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | #pragma once 5 | 6 | #include "exportable_fixture.hpp" 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | namespace evmone::test 14 | { 15 | using evmc::bytes; 16 | 17 | /// Fixture for defining test cases for EOF validation. 18 | /// 19 | /// Each test contains multiple cases, which are validated during test teardown. 20 | class eof_validation : public ExportableFixture 21 | { 22 | protected: 23 | /// EOF validation test case. 24 | struct TestCase 25 | { 26 | /// Container to be validated. 27 | bytes container; 28 | /// Expected container kind 29 | ContainerKind kind = ContainerKind::runtime; 30 | /// Expected error if container is expected to be invalid, 31 | /// or EOFValidationError::success if it is expected to be valid. 32 | EOFValidationError error = EOFValidationError::success; 33 | /// (Optional) Test case description. 34 | /// In non-empty, exported test file will use it for test case name. 35 | std::string name; 36 | }; 37 | 38 | evmc_revision rev = EVMC_OSAKA; 39 | std::vector test_cases; 40 | 41 | /// Adds the case to test cases. 42 | /// 43 | /// Can be called as add_test_case(string_view hex, error, name) 44 | /// or add_test_case(bytes_view cont, error, name). 45 | void add_test_case(bytecode container, EOFValidationError error, std::string name = {}) 46 | { 47 | test_cases.push_back( 48 | {std::move(container), ContainerKind::runtime, error, std::move(name)}); 49 | } 50 | 51 | void add_test_case( 52 | bytecode container, ContainerKind kind, EOFValidationError error, std::string name = {}) 53 | { 54 | test_cases.push_back({std::move(container), kind, error, std::move(name)}); 55 | } 56 | 57 | /// The test runner. 58 | void TearDown() override; 59 | 60 | /// Exports the test in the JSON EOF Test format in the given directory. 61 | void export_eof_validation_test(); 62 | }; 63 | 64 | } // namespace evmone::test 65 | -------------------------------------------------------------------------------- /test/unittests/state_precompiles_test.cpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2023 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | #include 6 | #include 7 | 8 | using namespace evmc; 9 | using namespace evmone::state; 10 | 11 | TEST(state_precompiles, is_precompile) 12 | { 13 | for (int r = 0; r <= EVMC_MAX_REVISION; ++r) 14 | { 15 | const auto rev = static_cast(r); 16 | 17 | EXPECT_FALSE(is_precompile(rev, 0x00_address)); 18 | 19 | // Frontier: 20 | EXPECT_TRUE(is_precompile(rev, 0x01_address)); 21 | EXPECT_TRUE(is_precompile(rev, 0x02_address)); 22 | EXPECT_TRUE(is_precompile(rev, 0x03_address)); 23 | EXPECT_TRUE(is_precompile(rev, 0x04_address)); 24 | 25 | // Byzantium: 26 | EXPECT_EQ(is_precompile(rev, 0x05_address), rev >= EVMC_BYZANTIUM); 27 | EXPECT_EQ(is_precompile(rev, 0x06_address), rev >= EVMC_BYZANTIUM); 28 | EXPECT_EQ(is_precompile(rev, 0x07_address), rev >= EVMC_BYZANTIUM); 29 | EXPECT_EQ(is_precompile(rev, 0x08_address), rev >= EVMC_BYZANTIUM); 30 | 31 | // Istanbul: 32 | EXPECT_EQ(is_precompile(rev, 0x09_address), rev >= EVMC_ISTANBUL); 33 | 34 | // Cancun: 35 | EXPECT_EQ(is_precompile(rev, 0x0a_address), rev >= EVMC_CANCUN); 36 | 37 | // Prague: 38 | EXPECT_EQ(is_precompile(rev, 0x0b_address), rev >= EVMC_PRAGUE); 39 | EXPECT_EQ(is_precompile(rev, 0x0c_address), rev >= EVMC_PRAGUE); 40 | EXPECT_EQ(is_precompile(rev, 0x0d_address), rev >= EVMC_PRAGUE); 41 | EXPECT_EQ(is_precompile(rev, 0x0e_address), rev >= EVMC_PRAGUE); 42 | EXPECT_EQ(is_precompile(rev, 0x0f_address), rev >= EVMC_PRAGUE); 43 | EXPECT_EQ(is_precompile(rev, 0x10_address), rev >= EVMC_PRAGUE); 44 | EXPECT_EQ(is_precompile(rev, 0x11_address), rev >= EVMC_PRAGUE); 45 | EXPECT_EQ(is_precompile(rev, 0x12_address), rev >= EVMC_PRAGUE); 46 | EXPECT_EQ(is_precompile(rev, 0x13_address), rev >= EVMC_PRAGUE); 47 | 48 | // Future? 49 | EXPECT_FALSE(is_precompile(rev, 0x14_address)); 50 | EXPECT_FALSE(is_precompile(rev, 0x15_address)); 51 | EXPECT_FALSE(is_precompile(rev, 0x16_address)); 52 | EXPECT_FALSE(is_precompile(rev, 0x17_address)); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /test/unittests/precompiles_kzg_test.cpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2024 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace evmc::literals; 13 | using namespace evmone::crypto; 14 | 15 | namespace 16 | { 17 | // TODO(intx): Add ""_u384. 18 | consteval auto operator""_u384(const char* s) 19 | { 20 | return intx::from_string(s); 21 | } 22 | 23 | constexpr auto G1_GENERATOR_X = 24 | 0x17F1D3A73197D7942695638C4FA9AC0FC3688C4F9774B905A14E3A3F171BAC586C55E83FF97A1AEFFB3AF00ADB22C6BB_u384; 25 | constexpr std::byte ZERO32[32]{}; 26 | constexpr std::byte POINT_AT_INFINITY[48]{std::byte{0xC0}}; 27 | 28 | auto versioned_hash(std::span input) noexcept 29 | { 30 | std::array hash{}; 31 | sha256(hash.data(), input.data(), input.size()); 32 | hash[0] = VERSIONED_HASH_VERSION_KZG; 33 | return hash; 34 | } 35 | } // namespace 36 | 37 | TEST(kzg, verify_proof_hash_invalid) 38 | { 39 | const auto r = kzg_verify_proof(ZERO32, ZERO32, ZERO32, POINT_AT_INFINITY, POINT_AT_INFINITY); 40 | EXPECT_FALSE(r); 41 | } 42 | 43 | TEST(kzg, verify_proof_zero) 44 | { 45 | // Commit and prove polynomial f(x) = 0. 46 | std::byte z[32]{}; 47 | z[13] = std::byte{17}; // can be any value because f(z) is always 0. 48 | const auto hash = versioned_hash(POINT_AT_INFINITY); 49 | const auto r = kzg_verify_proof(hash.data(), z, ZERO32, POINT_AT_INFINITY, POINT_AT_INFINITY); 50 | EXPECT_TRUE(r); 51 | } 52 | 53 | TEST(kzg, verify_proof_constant) 54 | { 55 | // Commit and prove polynomial f(x) = 1. 56 | std::byte z[32]{}; 57 | z[13] = std::byte{17}; // can be any value because f(z) is always 0. 58 | std::byte y[32]{}; 59 | y[31] = std::byte{1}; 60 | 61 | // Commitment for f(x) = 1 is [1]₁, i.e. the G1 generator point. 62 | std::byte c[48]{}; 63 | intx::be::store(reinterpret_cast(c), G1_GENERATOR_X); 64 | c[0] |= std::byte{0x80}; // flag of the point compressed form. 65 | 66 | const auto hash = versioned_hash(c); 67 | const auto r = kzg_verify_proof(hash.data(), z, y, c, POINT_AT_INFINITY); 68 | EXPECT_TRUE(r); 69 | } 70 | -------------------------------------------------------------------------------- /lib/evmone/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # evmone: Fast Ethereum Virtual Machine implementation 2 | # Copyright 2019 The evmone Authors. 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | include(LibraryTools) 6 | 7 | add_library(evmone 8 | ${include_dir}/evmone/evmone.h 9 | advanced_analysis.cpp 10 | advanced_analysis.hpp 11 | advanced_execution.cpp 12 | advanced_execution.hpp 13 | advanced_instructions.cpp 14 | baseline.hpp 15 | baseline_analysis.cpp 16 | baseline_execution.cpp 17 | baseline_instruction_table.cpp 18 | baseline_instruction_table.hpp 19 | constants.hpp 20 | eof.cpp 21 | eof.hpp 22 | instructions.hpp 23 | instructions_calls.cpp 24 | instructions_opcodes.hpp 25 | instructions_storage.cpp 26 | instructions_traits.hpp 27 | instructions_xmacro.hpp 28 | tracing.cpp 29 | tracing.hpp 30 | vm.cpp 31 | vm.hpp 32 | ) 33 | target_compile_features(evmone PUBLIC cxx_std_20) 34 | target_link_libraries(evmone PUBLIC evmc::evmc intx::intx PRIVATE ethash::keccak) 35 | target_include_directories(evmone PUBLIC 36 | $$ 37 | ) 38 | 39 | if(EVMONE_X86_64_ARCH_LEVEL GREATER_EQUAL 2) 40 | # Add CPU architecture runtime check. The EVMONE_X86_64_ARCH_LEVEL has a valid value. 41 | target_sources(evmone PRIVATE cpu_check.cpp) 42 | set_source_files_properties(cpu_check.cpp PROPERTIES COMPILE_DEFINITIONS EVMONE_X86_64_ARCH_LEVEL=${EVMONE_X86_64_ARCH_LEVEL}) 43 | endif() 44 | 45 | if(CABLE_COMPILER_GNULIKE) 46 | target_compile_options( 47 | evmone PRIVATE 48 | -fno-exceptions 49 | $<$:-Wstack-usage=2900> 50 | ) 51 | if(NOT SANITIZE MATCHES undefined) 52 | # RTTI can be disabled except for UBSan which checks vptr integrity. 53 | target_compile_options(evmone PRIVATE -fno-rtti) 54 | endif() 55 | endif() 56 | set_target_properties( 57 | evmone 58 | PROPERTIES 59 | VERSION ${PROJECT_VERSION} 60 | SOVERSION ${PROJECT_SOVERSION} 61 | ) 62 | 63 | if(NOT SANITIZE) 64 | # On Linux, check if all symbols in evmone are resolved during linking. 65 | target_link_options(evmone PRIVATE $<$:LINKER:--no-undefined>) 66 | endif() 67 | 68 | set_source_files_properties(vm.cpp PROPERTIES COMPILE_DEFINITIONS PROJECT_VERSION="${PROJECT_VERSION}") 69 | 70 | add_standalone_library(evmone) 71 | -------------------------------------------------------------------------------- /test/statetest/statetest_export.cpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2023 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | #include "statetest.hpp" 6 | 7 | namespace evmone::test 8 | { 9 | [[nodiscard]] std::string get_invalid_tx_message(state::ErrorCode errc) noexcept 10 | { 11 | using namespace state; 12 | switch (errc) 13 | { 14 | case SUCCESS: 15 | return ""; 16 | case INTRINSIC_GAS_TOO_LOW: 17 | return "TR_IntrinsicGas"; 18 | case TX_TYPE_NOT_SUPPORTED: 19 | return "TR_TypeNotSupported"; 20 | case INSUFFICIENT_FUNDS: 21 | return "TR_NoFunds"; 22 | case NONCE_HAS_MAX_VALUE: 23 | return "TR_NonceHasMaxValue:"; 24 | case NONCE_TOO_HIGH: 25 | return "TR_NonceTooHigh"; 26 | case NONCE_TOO_LOW: 27 | return "TR_NonceTooLow"; 28 | case TIP_GT_FEE_CAP: 29 | return "TR_TipGtFeeCap"; 30 | case FEE_CAP_LESS_THEN_BLOCKS: 31 | return "TR_FeeCapLessThanBlocks"; 32 | case GAS_LIMIT_REACHED: 33 | return "TR_GasLimitReached"; 34 | case SENDER_NOT_EOA: 35 | return "SenderNotEOA"; 36 | case INIT_CODE_SIZE_LIMIT_EXCEEDED: 37 | return "TR_InitCodeLimitExceeded"; 38 | case CREATE_BLOB_TX: 39 | return "TR_BLOBCREATE"; 40 | case EMPTY_BLOB_HASHES_LIST: 41 | return "TR_EMPTYBLOB"; 42 | case INVALID_BLOB_HASH_VERSION: 43 | return "TR_BLOBVERSION_INVALID"; 44 | case BLOB_GAS_LIMIT_EXCEEDED: 45 | return "TR_BLOBLIST_OVERSIZE"; 46 | case UNKNOWN_ERROR: 47 | return "Unknown error"; 48 | default: 49 | assert(false); 50 | return "Wrong error code"; 51 | } 52 | } 53 | 54 | 55 | json::json to_json(const TestState& state) 56 | { 57 | json::json j = json::json::object(); 58 | for (const auto& [addr, acc] : state) 59 | { 60 | auto& j_acc = j[hex0x(addr)]; 61 | j_acc["nonce"] = hex0x(acc.nonce); 62 | j_acc["balance"] = hex0x(acc.balance); 63 | j_acc["code"] = hex0x(bytes_view(acc.code.data(), acc.code.size())); 64 | 65 | auto& j_storage = j_acc["storage"] = json::json::object(); 66 | for (const auto& [key, val] : acc.storage) 67 | { 68 | if (!is_zero(val)) 69 | j_storage[hex0x(key)] = hex0x(val); 70 | } 71 | } 72 | return j; 73 | } 74 | } // namespace evmone::test 75 | -------------------------------------------------------------------------------- /cmake/cable/bootstrap.cmake: -------------------------------------------------------------------------------- 1 | # Cable: CMake Bootstrap Library 2 | # Copyright 2019-2020 Pawel Bylica. 3 | # Licensed under the Apache License, Version 2.0. 4 | 5 | # Bootstrap the Cable - CMake Bootstrap Library by including this file. 6 | # e.g. include(cmake/cable/bootstrap.cmake). 7 | 8 | 9 | # Cable version. 10 | # 11 | # This is internal variable automatically updated with external tools. 12 | # Use CABLE_VERSION variable if you need this information. 13 | set(version 0.5.0) 14 | 15 | # For convenience, add the project CMake module dir to module path. 16 | set(module_dir ${CMAKE_CURRENT_SOURCE_DIR}/cmake) 17 | if(EXISTS ${module_dir}) 18 | list(APPEND CMAKE_MODULE_PATH ${module_dir}) 19 | endif() 20 | 21 | # Always add this Cable instance modules to the CMake module path. 22 | list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}) 23 | 24 | if(CABLE_VERSION) 25 | # Some other instance of Cable has been initialized in the top project. 26 | 27 | # Mark this project as nested. 28 | set(PROJECT_IS_NESTED TRUE) 29 | 30 | # Compare versions of the top project and this instances. 31 | if(CABLE_VERSION VERSION_LESS version) 32 | set(comment " (version older than ${version})") 33 | elseif(CABLE_VERSION VERSION_GREATER version) 34 | set(comment " (version newer than ${version})") 35 | endif() 36 | 37 | # Log information about initialization in the top project. 38 | file(RELATIVE_PATH subproject_dir ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}) 39 | cable_debug("${subproject_dir}: Cable ${CABLE_VERSION}${comment} already initialized in the top project") 40 | cable_debug("Project CMake modules directory: ${module_dir}") 41 | 42 | unset(version) 43 | unset(module_dir) 44 | unset(comment) 45 | return() 46 | endif() 47 | 48 | 49 | option(CABLE_DEBUG "Enable Cable debug logs" OFF) 50 | 51 | function(cable_log) 52 | message(STATUS "[cable ] ${ARGN}") 53 | endfunction() 54 | 55 | function(cable_debug) 56 | if(CABLE_DEBUG) 57 | message(STATUS "[cable*] ${ARGN}") 58 | endif() 59 | endfunction() 60 | 61 | # Export Cable version. 62 | set(CABLE_VERSION ${version}) 63 | 64 | # Mark this project as non-nested. 65 | set(PROJECT_IS_NESTED FALSE) 66 | 67 | cable_log("Cable ${CABLE_VERSION} initialized") 68 | cable_debug("Project CMake modules directory: ${module_dir}") 69 | 70 | unset(version) 71 | unset(module_dir) 72 | -------------------------------------------------------------------------------- /lib/evmone/tracing.hpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2021 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | namespace evmone 15 | { 16 | using evmc::bytes_view; 17 | class ExecutionState; 18 | 19 | class Tracer 20 | { 21 | friend class VM; // Has access the m_next_tracer to traverse the list forward. 22 | std::unique_ptr m_next_tracer; 23 | 24 | public: 25 | virtual ~Tracer() = default; 26 | 27 | void notify_execution_start( // NOLINT(misc-no-recursion) 28 | evmc_revision rev, const evmc_message& msg, bytes_view code) noexcept 29 | { 30 | on_execution_start(rev, msg, code); 31 | if (m_next_tracer) 32 | m_next_tracer->notify_execution_start(rev, msg, code); 33 | } 34 | 35 | void notify_execution_end(const evmc_result& result) noexcept // NOLINT(misc-no-recursion) 36 | { 37 | on_execution_end(result); 38 | if (m_next_tracer) 39 | m_next_tracer->notify_execution_end(result); 40 | } 41 | 42 | void notify_instruction_start( // NOLINT(misc-no-recursion) 43 | uint32_t pc, intx::uint256* stack_top, int stack_height, int64_t gas, 44 | const ExecutionState& state) noexcept 45 | { 46 | on_instruction_start(pc, stack_top, stack_height, gas, state); 47 | if (m_next_tracer) 48 | m_next_tracer->notify_instruction_start(pc, stack_top, stack_height, gas, state); 49 | } 50 | 51 | private: 52 | virtual void on_execution_start( 53 | evmc_revision rev, const evmc_message& msg, bytes_view code) noexcept = 0; 54 | virtual void on_instruction_start(uint32_t pc, const intx::uint256* stack_top, int stack_height, 55 | int64_t gas, const ExecutionState& state) noexcept = 0; 56 | virtual void on_execution_end(const evmc_result& result) noexcept = 0; 57 | }; 58 | 59 | /// Creates the "histogram" tracer which counts occurrences of individual opcodes during execution 60 | /// and reports this data in CSV format. 61 | /// 62 | /// @param out Report output stream. 63 | /// @return Histogram tracer object. 64 | EVMC_EXPORT std::unique_ptr create_histogram_tracer(std::ostream& out); 65 | 66 | EVMC_EXPORT std::unique_ptr create_instruction_tracer(std::ostream& out); 67 | 68 | } // namespace evmone 69 | -------------------------------------------------------------------------------- /test/eoftest/eoftest.cpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2023 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | 6 | #include "eoftest.hpp" 7 | #include 8 | #include 9 | #include 10 | 11 | namespace fs = std::filesystem; 12 | 13 | namespace 14 | { 15 | 16 | class EOFTest : public testing::Test 17 | { 18 | fs::path m_json_test_file; 19 | 20 | public: 21 | explicit EOFTest(fs::path json_test_file) noexcept : m_json_test_file{std::move(json_test_file)} 22 | {} 23 | 24 | void TestBody() final 25 | { 26 | std::ifstream f{m_json_test_file}; 27 | evmone::test::run_eof_test(f); 28 | } 29 | }; 30 | 31 | void register_test(const std::string& suite_name, const fs::path& file) 32 | { 33 | testing::RegisterTest(suite_name.c_str(), file.stem().string().c_str(), nullptr, nullptr, 34 | file.string().c_str(), 0, [file]() -> testing::Test* { return new EOFTest(file); }); 35 | } 36 | 37 | void register_test_files(const fs::path& root) 38 | { 39 | if (is_directory(root)) 40 | { 41 | std::vector test_files; 42 | std::copy_if(fs::recursive_directory_iterator{root}, fs::recursive_directory_iterator{}, 43 | std::back_inserter(test_files), [](const fs::directory_entry& entry) { 44 | return entry.is_regular_file() && entry.path().extension() == ".json"; 45 | }); 46 | std::sort(test_files.begin(), test_files.end()); 47 | 48 | for (const auto& p : test_files) 49 | register_test(fs::relative(p, root).parent_path().string(), p); 50 | } 51 | else // Treat as a file. 52 | { 53 | register_test(root.parent_path().string(), root); 54 | } 55 | } 56 | 57 | } // namespace 58 | 59 | 60 | int main(int argc, char* argv[]) 61 | { 62 | try 63 | { 64 | testing::InitGoogleTest(&argc, argv); 65 | CLI::App app{"evmone eof test runner"}; 66 | 67 | std::vector paths; 68 | app.add_option("path", paths, "Path to test file or directory") 69 | ->required() 70 | ->check(CLI::ExistingPath); 71 | 72 | CLI11_PARSE(app, argc, argv); 73 | 74 | for (const auto& p : paths) 75 | { 76 | register_test_files(p); 77 | } 78 | 79 | return RUN_ALL_TESTS(); 80 | } 81 | catch (const std::exception& ex) 82 | { 83 | std::cerr << ex.what() << "\n"; 84 | return -1; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /test/unittests/state_transition_transient_storage_test.cpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2023 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | #include "../utils/bytecode.hpp" 6 | #include "state_transition.hpp" 7 | 8 | using namespace evmc::literals; 9 | using namespace evmone::test; 10 | 11 | TEST_F(state_transition, transient_storage) 12 | { 13 | rev = EVMC_CANCUN; 14 | const auto tbump = 0xb0_address; 15 | 16 | tx.to = To; 17 | pre.insert(tbump, {.code = tstore(0, add(tload(0), 1)) + sstore(0, tload(0))}); 18 | pre.insert(*tx.to, {.code = call(tbump).gas(0xffff) + call(tbump).gas(0xffff)}); 19 | 20 | expect.post[To].exists = true; 21 | expect.post[tbump].storage[0x00_bytes32] = 0x02_bytes32; 22 | } 23 | 24 | TEST_F(state_transition, transient_storage_revert) 25 | { 26 | rev = EVMC_CANCUN; 27 | const auto tbump = 0xb0_address; 28 | 29 | tx.to = To; 30 | pre.insert(tbump, {.code = tstore(0, add(tload(0), 1)) + sstore(0, tload(0))}); 31 | pre.insert(*tx.to, 32 | {.code = call(tbump).gas(0xffff) + call(tbump).gas(0x1ff) + call(tbump).gas(0xffff)}); 33 | 34 | expect.post[To].exists = true; 35 | expect.post[tbump].storage[0x00_bytes32] = 0x02_bytes32; 36 | } 37 | 38 | TEST_F(state_transition, transient_storage_static) 39 | { 40 | rev = EVMC_CANCUN; 41 | const auto db = 0xdb_address; 42 | 43 | tx.to = To; 44 | pre.insert(db, {.code = tload(1) + jumpi(17, calldataload(0)) + ret_top() + OP_JUMPDEST + 45 | tstore(1, add(7))}); 46 | pre.insert(*tx.to, {.code = mstore(0, 1) + 47 | // bump db.tstore[1] += 7 48 | sstore(0xc1, call(db).gas(0xffff).input(0, 32)) + 49 | // get db.tstore[1] 50 | sstore(0xc2, staticcall(db).gas(0xffff).output(0, 32)) + 51 | // sstore[0xd1] = db.tstore[1] 52 | sstore(0xd1, mload(0)) + 53 | // static call to bump db.tstore[1] fails 54 | sstore(0xc3, staticcall(db).gas(0xffff).input(0, 32))}); 55 | 56 | expect.post[db].exists = true; 57 | expect.post[To].exists = true; 58 | expect.post[To].storage[0xc1_bytes32] = 0x01_bytes32; 59 | expect.post[To].storage[0xc2_bytes32] = 0x01_bytes32; 60 | expect.post[To].storage[0xc3_bytes32] = 0x00_bytes32; 61 | expect.post[To].storage[0xd1_bytes32] = 0x07_bytes32; 62 | } 63 | -------------------------------------------------------------------------------- /lib/evmone_precompiles/secp256k1.hpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2023 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | #pragma once 5 | 6 | #include "ecc.hpp" 7 | #include 8 | #include 9 | #include 10 | 11 | namespace evmmax::secp256k1 12 | { 13 | using namespace intx; 14 | 15 | /// The secp256k1 field prime number (P). 16 | inline constexpr auto FieldPrime = 17 | 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f_u256; 18 | 19 | /// The secp256k1 curve group order (N). 20 | inline constexpr auto Order = 21 | 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141_u256; 22 | 23 | using Point = ecc::Point; 24 | 25 | 26 | /// Modular inversion for secp256k1 prime field. 27 | /// 28 | /// Computes 1/x mod P modular inversion by computing modular exponentiation x^(P-2), 29 | /// where P is ::FieldPrime. 30 | uint256 field_inv(const ModArith& m, const uint256& x) noexcept; 31 | 32 | /// Square root for secp256k1 prime field. 33 | /// 34 | /// Computes √x mod P by computing modular exponentiation x^((P+1)/4), 35 | /// where P is ::FieldPrime. 36 | /// 37 | /// @return Square root of x if it exists, std::nullopt otherwise. 38 | std::optional field_sqrt(const ModArith& m, const uint256& x) noexcept; 39 | 40 | /// Inversion modulo order of secp256k1. 41 | /// 42 | /// Computes 1/x mod N modular inversion by computing modular exponentiation x^(N-2), 43 | /// where N is ::Order. 44 | uint256 scalar_inv(const ModArith& m, const uint256& x) noexcept; 45 | 46 | /// Calculate y coordinate of a point having x coordinate and y parity. 47 | std::optional calculate_y( 48 | const ModArith& m, const uint256& x, bool y_parity) noexcept; 49 | 50 | /// Addition in secp256k1. 51 | /// 52 | /// Computes P ⊕ Q for two points in affine coordinates on the secp256k1 curve, 53 | Point add(const Point& p, const Point& q) noexcept; 54 | 55 | /// Scalar multiplication in secp256k1. 56 | /// 57 | /// Computes [c]P for a point in affine coordinate on the secp256k1 curve, 58 | Point mul(const Point& p, const uint256& c) noexcept; 59 | 60 | /// Convert the secp256k1 point (uncompressed public key) to Ethereum address. 61 | evmc::address to_address(const Point& pt) noexcept; 62 | 63 | std::optional secp256k1_ecdsa_recover( 64 | const ethash::hash256& e, const uint256& r, const uint256& s, bool v) noexcept; 65 | 66 | std::optional ecrecover( 67 | const ethash::hash256& e, const uint256& r, const uint256& s, bool v) noexcept; 68 | 69 | } // namespace evmmax::secp256k1 70 | -------------------------------------------------------------------------------- /test/unittests/state_system_call_test.cpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2023 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace evmc::literals; 13 | using namespace evmone::state; 14 | using namespace evmone::test; 15 | 16 | class state_system_call : public testing::Test 17 | { 18 | protected: 19 | evmc::VM vm{evmc_create_evmone()}; 20 | TestState state; 21 | TestBlockHashes block_hashes; 22 | }; 23 | 24 | TEST_F(state_system_call, non_existient) 25 | { 26 | // Use MAX revision to invoke all activate system contracts. 27 | system_call(state, {}, block_hashes, EVMC_MAX_REVISION, vm); 28 | 29 | EXPECT_EQ(state.size(), 0) << "State must remain unchanged"; 30 | } 31 | 32 | TEST_F(state_system_call, beacon_roots) 33 | { 34 | const BlockInfo block{.number = 1, .parent_beacon_block_root = 0xbeac04004a54_bytes32}; 35 | state.insert( 36 | BEACON_ROOTS_ADDRESS, {.code = sstore(OP_NUMBER, calldataload(0)) + sstore(0, OP_CALLER)}); 37 | 38 | system_call(state, block, block_hashes, EVMC_CANCUN, vm); 39 | 40 | ASSERT_EQ(state.size(), 1); 41 | EXPECT_FALSE(state.contains(SYSTEM_ADDRESS)); 42 | EXPECT_EQ(state.at(BEACON_ROOTS_ADDRESS).nonce, 0); 43 | EXPECT_EQ(state.at(BEACON_ROOTS_ADDRESS).balance, 0); 44 | const auto& storage = state.at(BEACON_ROOTS_ADDRESS).storage; 45 | ASSERT_EQ(storage.size(), 2); 46 | EXPECT_EQ(storage.at(0x01_bytes32), block.parent_beacon_block_root); 47 | EXPECT_EQ(storage.at(0x00_bytes32), to_bytes32(SYSTEM_ADDRESS)); 48 | } 49 | 50 | TEST_F(state_system_call, history_storage) 51 | { 52 | static constexpr auto NUMBER = 123456789; 53 | static constexpr auto PREV_BLOCKHASH = 0xbbbb_bytes32; 54 | const BlockInfo block{.number = NUMBER}; 55 | block_hashes = {{NUMBER - 1, PREV_BLOCKHASH}}; 56 | state.insert(HISTORY_STORAGE_ADDRESS, 57 | {.code = sstore(OP_NUMBER, calldataload(0)) + sstore(0, OP_CALLER)}); 58 | 59 | system_call(state, block, block_hashes, EVMC_PRAGUE, vm); 60 | 61 | ASSERT_EQ(state.size(), 1); 62 | EXPECT_FALSE(state.contains(SYSTEM_ADDRESS)); 63 | EXPECT_EQ(state.at(HISTORY_STORAGE_ADDRESS).nonce, 0); 64 | EXPECT_EQ(state.at(HISTORY_STORAGE_ADDRESS).balance, 0); 65 | const auto& storage = state.at(HISTORY_STORAGE_ADDRESS).storage; 66 | ASSERT_EQ(storage.size(), 2); 67 | EXPECT_EQ(storage.at(bytes32{NUMBER}), PREV_BLOCKHASH); 68 | EXPECT_EQ(storage.at(0x00_bytes32), to_bytes32(SYSTEM_ADDRESS)); 69 | } 70 | -------------------------------------------------------------------------------- /test/state/account.hpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2021 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | namespace evmone::state 11 | { 12 | using evmc::address; 13 | using evmc::bytes; 14 | using evmc::bytes32; 15 | using namespace evmc::literals; 16 | 17 | /// The representation of the account storage value. 18 | struct StorageValue 19 | { 20 | /// The current value. 21 | bytes32 current; 22 | 23 | /// The original value. 24 | bytes32 original; 25 | 26 | evmc_access_status access_status = EVMC_ACCESS_COLD; 27 | }; 28 | 29 | /// The state account. 30 | struct Account 31 | { 32 | /// The maximum allowed nonce value. 33 | static constexpr auto NonceMax = std::numeric_limits::max(); 34 | 35 | /// The keccak256 hash of the empty input. Used to identify empty account's code. 36 | static constexpr auto EMPTY_CODE_HASH = 37 | 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470_bytes32; 38 | 39 | /// The account nonce. 40 | uint64_t nonce = 0; 41 | 42 | /// The account balance. 43 | intx::uint256 balance; 44 | 45 | bytes32 code_hash = EMPTY_CODE_HASH; 46 | 47 | /// If the account has non-empty initial storage (when accessing the cold account). 48 | bool has_initial_storage = false; 49 | 50 | /// The cached and modified account storage entries. 51 | std::unordered_map storage; 52 | 53 | /// The EIP-1153 transient (transaction-level lifetime) storage. 54 | std::unordered_map transient_storage; 55 | 56 | /// The cache of the account code. 57 | /// 58 | /// Check code_hash to know if an account code is empty. 59 | /// Empty here only means it has not been loaded from the initial storage. 60 | bytes code; 61 | 62 | /// The account has been destructed and should be erased at the end of a transaction. 63 | bool destructed = false; 64 | 65 | /// The account should be erased if it is empty at the end of a transaction. 66 | /// This flag means the account has been "touched" as defined in EIP-161, 67 | /// or it is a newly created temporary account. 68 | /// 69 | /// Yellow Paper uses term "delete" but it is a keyword in C++ while 70 | /// the term "erase" is used for deleting objects from C++ collections. 71 | bool erase_if_empty = false; 72 | 73 | /// The account has been created in the current transaction. 74 | bool just_created = false; 75 | 76 | evmc_access_status access_status = EVMC_ACCESS_COLD; 77 | 78 | [[nodiscard]] bool is_empty() const noexcept 79 | { 80 | return nonce == 0 && balance == 0 && code_hash == EMPTY_CODE_HASH; 81 | } 82 | }; 83 | } // namespace evmone::state 84 | -------------------------------------------------------------------------------- /test/unittests/state_transition_block_test.cpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2023 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | #include "../utils/bytecode.hpp" 6 | #include "state_transition.hpp" 7 | 8 | using namespace evmc::literals; 9 | using namespace evmone::test; 10 | 11 | TEST_F(state_transition, block_apply_withdrawal) 12 | { 13 | static constexpr auto withdrawal_address = 0x8888_address; 14 | 15 | block.withdrawals = {{0, 0, withdrawal_address, 3}}; 16 | tx.to = To; 17 | expect.post[withdrawal_address].balance = intx::uint256{3} * 1'000'000'000; 18 | } 19 | 20 | TEST_F(state_transition, known_block_hash) 21 | { 22 | block_hashes = { 23 | {1, 0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421_bytes32}, 24 | {2, 0x0000000000000000000000000000000000000000000000000000000000000111_bytes32}, 25 | }; 26 | block.number = 5; 27 | 28 | tx.to = To; 29 | pre.insert(*tx.to, {.nonce = 1, .code = sstore(0, blockhash(1)) + sstore(1, blockhash(2))}); 30 | expect.post[To].storage[0x00_bytes32] = 31 | 0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421_bytes32; 32 | expect.post[To].storage[0x01_bytes32] = 33 | 0x0000000000000000000000000000000000000000000000000000000000000111_bytes32; 34 | } 35 | 36 | TEST_F(state_transition, known_block_hash_fake) 37 | { 38 | block.number = 2; 39 | tx.to = To; 40 | pre.insert(*tx.to, {.nonce = 1, .code = sstore(0, blockhash(0)) + sstore(1, blockhash(1))}); 41 | expect.post[To].storage[0x00_bytes32] = 42 | 0x044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d_bytes32; 43 | expect.post[To].storage[0x01_bytes32] = 44 | 0xc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6_bytes32; 45 | } 46 | 47 | TEST_F(state_transition, block_apply_ommers_reward) 48 | { 49 | rev = EVMC_LONDON; 50 | 51 | static constexpr auto o1 = Ommer{0x0eeee1_address, 1}; 52 | static constexpr auto o2 = Ommer{0x0eeee2_address, 3}; 53 | 54 | // Use high value 5 ETH to catch potential uint64 overflows. 55 | block_reward = 5'000'000'000'000'000'000; 56 | block.ommers = {o1, o2}; 57 | tx.to = To; 58 | expect.post[o1.beneficiary].balance = intx::uint256{block_reward} * (8 - o1.delta) / 8; 59 | expect.post[o2.beneficiary].balance = intx::uint256{block_reward} * (8 - o2.delta) / 8; 60 | 61 | // Two ommers +1/32 * block_reward for each. +21000 cost of the tx goes to coinbase. 62 | expect.post[Coinbase].balance = 21000 + intx::uint256{block_reward} + block_reward / 16; 63 | } 64 | 65 | TEST_F(state_transition, eip7516_blob_base_fee) 66 | { 67 | rev = EVMC_CANCUN; 68 | 69 | block.blob_base_fee = 0xabcd; 70 | tx.to = To; 71 | pre.insert(*tx.to, {.code = sstore(0x4a, OP_BLOBBASEFEE)}); 72 | 73 | expect.post[To].storage[0x4a_bytes32] = 0xabcd_bytes32; 74 | } 75 | -------------------------------------------------------------------------------- /.clang-tidy: -------------------------------------------------------------------------------- 1 | FormatStyle: file 2 | HeaderFilterRegex: 'lib/evmone/|test/state/' 3 | WarningsAsErrors: '*' 4 | Checks: 5 | - "bugprone-*" 6 | - "-bugprone-assignment-in-if-condition" 7 | - "-bugprone-easily-swappable-parameters" 8 | - "-bugprone-implicit-widening-of-multiplication-result" 9 | - "-bugprone-unchecked-optional-access" 10 | - "cert-dcl21-cpp" 11 | - "cert-dcl50-cpp" 12 | - "cert-dcl58-cpp" 13 | - "cert-env33-c" 14 | - "cert-err33-c" 15 | - "cert-err34-c" 16 | - "cert-err52-cpp" 17 | - "cert-err60-cpp" 18 | - "cert-flp30-c" 19 | - "cert-mem57-cpp" 20 | - "cert-msc50-cpp" 21 | - "cert-msc51-cpp" 22 | - "cert-oop57-cpp" 23 | - "cert-oop58-cpp" 24 | - "clang-analyzer-*" 25 | - "cppcoreguidelines-*" 26 | - "-cppcoreguidelines-avoid-c-arrays" 27 | - "-cppcoreguidelines-avoid-const-or-ref-data-members" 28 | - "-cppcoreguidelines-avoid-goto" 29 | - "-cppcoreguidelines-avoid-magic-numbers" 30 | - "-cppcoreguidelines-avoid-non-const-global-variables" 31 | - "-cppcoreguidelines-macro-usage" 32 | - "-cppcoreguidelines-no-malloc" 33 | - "-cppcoreguidelines-non-private-member-variables-in-classes" 34 | - "-cppcoreguidelines-owning-memory" 35 | - "-cppcoreguidelines-pro-bounds-array-to-pointer-decay" 36 | - "-cppcoreguidelines-pro-bounds-constant-array-index" 37 | - "-cppcoreguidelines-pro-bounds-pointer-arithmetic" 38 | - "-cppcoreguidelines-pro-type-reinterpret-cast" 39 | - "-cppcoreguidelines-pro-type-static-cast-downcast" 40 | - "-cppcoreguidelines-pro-type-union-access" 41 | - "-cppcoreguidelines-pro-type-vararg" 42 | - "-cppcoreguidelines-special-member-functions" 43 | - "google-global-names-in-headers" 44 | - "google-runtime-int" 45 | - "hicpp-exception-baseclass" 46 | - "hicpp-multiway-paths-covered" 47 | - "hicpp-no-assembler" 48 | - "misc-*" 49 | - "-misc-include-cleaner" 50 | - "-misc-non-private-member-variables-in-classes" 51 | - "-misc-use-anonymous-namespace" 52 | - "modernize-*" 53 | - "-modernize-avoid-c-arrays" 54 | - "-modernize-use-nodiscard" 55 | - "-modernize-use-trailing-return-type" 56 | - "performance-*" 57 | - "-performance-enum-size" 58 | - "portability-*" 59 | - "readability-*" 60 | - "-readability-braces-around-statements" 61 | # Sometimes we actually want to take the address of the first element. 62 | - "-readability-container-data-pointer" 63 | - "-readability-else-after-return" 64 | - "-readability-function-cognitive-complexity" 65 | - "-readability-function-size" 66 | - "-readability-identifier-length" 67 | - "-readability-magic-numbers" 68 | - "-readability-named-parameter" 69 | - "-readability-qualified-auto" 70 | # TODO: Check if removing inline affects clang optimized builds. 71 | - "-readability-redundant-inline-specifier" 72 | - "-readability-uppercase-literal-suffix" 73 | 74 | CheckOptions: 75 | readability-identifier-naming.ClassCase: CamelCase 76 | readability-identifier-naming.UnionCase: CamelCase 77 | -------------------------------------------------------------------------------- /test/integration/statetest/tests1/SuiteA/test2_multi.json: -------------------------------------------------------------------------------- 1 | { 2 | "test_case_1": { 3 | "env": { 4 | "currentBaseFee": "0x0a", 5 | "currentCoinbase": "0x0000000000000000000000000000000000000000", 6 | "currentDifficulty": "0x020000", 7 | "currentGasLimit": "0xff112233445566", 8 | "currentNumber": "0x01", 9 | "currentRandom": "0x0000000000000000000000000000000000000000000000000000000000020000", 10 | "currentTimestamp": "0x03e8" 11 | }, 12 | "post": { 13 | "London": [ 14 | { 15 | "hash": "0x0000000000000000000000000000000000000000000000000000000000000000", 16 | "indexes": { 17 | "data": 0, 18 | "gas": 0, 19 | "value": 0 20 | }, 21 | "logs": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" 22 | } 23 | ] 24 | }, 25 | "pre": { 26 | "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { 27 | "balance": "0x0de0b6b3a7640000", 28 | "code": "0x", 29 | "nonce": "0x00", 30 | "storage": {} 31 | } 32 | }, 33 | "transaction": { 34 | "data": [ 35 | "0x" 36 | ], 37 | "gasLimit": [ 38 | "0x061a80" 39 | ], 40 | "gasPrice": "0x0a", 41 | "nonce": "0x00", 42 | "sender": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", 43 | "to": "0x0000000000000000000000000000000000000000", 44 | "value": [ 45 | "0x1" 46 | ] 47 | } 48 | }, 49 | "test_case_2": { 50 | "env": { 51 | "currentBaseFee": "0x0a", 52 | "currentCoinbase": "0x0000000000000000000000000000000000000000", 53 | "currentDifficulty": "0x020000", 54 | "currentGasLimit": "0xff112233445566", 55 | "currentNumber": "0x01", 56 | "currentRandom": "0x0000000000000000000000000000000000000000000000000000000000020000", 57 | "currentTimestamp": "0x03e8" 58 | }, 59 | "post": { 60 | "London": [ 61 | { 62 | "hash": "0x0000000000000000000000000000000000000000000000000000000000000000", 63 | "indexes": { 64 | "data": 0, 65 | "gas": 0, 66 | "value": 0 67 | }, 68 | "logs": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" 69 | } 70 | ] 71 | }, 72 | "pre": { 73 | "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { 74 | "balance": "0x0de0b6b3a7640000", 75 | "code": "0x", 76 | "nonce": "0x00", 77 | "storage": {} 78 | } 79 | }, 80 | "transaction": { 81 | "data": [ 82 | "0x" 83 | ], 84 | "gasLimit": [ 85 | "0x061a80" 86 | ], 87 | "gasPrice": "0x0a", 88 | "nonce": "0x00", 89 | "sender": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", 90 | "to": "0x0000000000000000000000000000000000000000", 91 | "value": [ 92 | "0x2" 93 | ] 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /test/statetest/statetest_runner.cpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2022 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | #include "../state/mpt_hash.hpp" 6 | #include "../state/rlp.hpp" 7 | #include "statetest.hpp" 8 | #include 9 | 10 | namespace evmone::test 11 | { 12 | void run_state_test(const StateTransitionTest& test, evmc::VM& vm, bool trace_summary) 13 | { 14 | SCOPED_TRACE(test.name); 15 | for (const auto& [rev, cases] : test.cases) 16 | { 17 | validate_state(test.pre_state, rev); 18 | for (size_t case_index = 0; case_index != cases.size(); ++case_index) 19 | { 20 | SCOPED_TRACE(std::string{evmc::to_string(rev)} + '/' + std::to_string(case_index)); 21 | // if (rev != EVMC_FRONTIER) 22 | // continue; 23 | // if (case_index != 3) 24 | // continue; 25 | 26 | const auto& expected = cases[case_index]; 27 | const auto tx = test.multi_tx.get(expected.indexes); 28 | auto state = test.pre_state; 29 | 30 | const auto res = test::transition(state, test.block, test.block_hashes, tx, rev, vm, 31 | test.block.gas_limit, state::BlockInfo::MAX_BLOB_GAS_PER_BLOCK); 32 | 33 | // Finalize block with reward 0. 34 | test::finalize(state, rev, test.block.coinbase, 0, {}, {}); 35 | 36 | const auto state_root = state::mpt_hash(state); 37 | 38 | if (trace_summary) 39 | { 40 | std::clog << '{'; 41 | if (holds_alternative(res)) // if tx valid 42 | { 43 | const auto& r = get(res); 44 | if (r.status == EVMC_SUCCESS) 45 | std::clog << R"("pass":true)"; 46 | else 47 | std::clog << R"("pass":false,"error":")" << r.status << '"'; 48 | std::clog << R"(,"gasUsed":"0x)" << std::hex << r.gas_used << R"(",)"; 49 | } 50 | std::clog << R"("stateRoot":"0x)" << hex(state_root) << "\"}\n"; 51 | } 52 | 53 | if (expected.exception) 54 | { 55 | ASSERT_FALSE(holds_alternative(res)) 56 | << "unexpected valid transaction"; 57 | EXPECT_EQ(logs_hash(std::vector()), expected.logs_hash); 58 | } 59 | else 60 | { 61 | ASSERT_TRUE(holds_alternative(res)) 62 | << "unexpected invalid transaction: " << get(res).message(); 63 | EXPECT_EQ(logs_hash(get(res).logs), expected.logs_hash); 64 | } 65 | 66 | EXPECT_EQ(state_root, expected.state_hash); 67 | } 68 | } 69 | } 70 | } // namespace evmone::test 71 | -------------------------------------------------------------------------------- /test/state/system_contracts.cpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2023 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | #include "system_contracts.hpp" 6 | #include "host.hpp" 7 | #include "state_view.hpp" 8 | 9 | namespace evmone::state 10 | { 11 | namespace 12 | { 13 | /// Information about a registered system contract. 14 | struct SystemContract 15 | { 16 | using GetInputFn = bytes32(const BlockInfo&, const BlockHashes&) noexcept; 17 | 18 | evmc_revision since = EVMC_MAX_REVISION; ///< EVM revision in which added. 19 | address addr; ///< Address of the system contract. 20 | GetInputFn* get_input = nullptr; ///< How to get the input for the system call. 21 | }; 22 | 23 | /// Registered system contracts. 24 | constexpr std::array SYSTEM_CONTRACTS{ 25 | SystemContract{EVMC_CANCUN, BEACON_ROOTS_ADDRESS, 26 | [](const BlockInfo& block, const BlockHashes&) noexcept { 27 | return block.parent_beacon_block_root; 28 | }}, 29 | SystemContract{EVMC_PRAGUE, HISTORY_STORAGE_ADDRESS, 30 | [](const BlockInfo& block, const BlockHashes& block_hashes) noexcept { 31 | return block_hashes.get_block_hash(block.number - 1); 32 | }}, 33 | }; 34 | 35 | static_assert(std::ranges::is_sorted(SYSTEM_CONTRACTS, 36 | [](const auto& a, const auto& b) noexcept { return a.since < b.since; }), 37 | "system contract entries must be ordered by revision"); 38 | 39 | } // namespace 40 | 41 | StateDiff system_call(const StateView& state_view, const BlockInfo& block, 42 | const BlockHashes& block_hashes, evmc_revision rev, evmc::VM& vm) 43 | { 44 | State state{state_view}; 45 | for (const auto& [since, addr, get_input] : SYSTEM_CONTRACTS) 46 | { 47 | if (rev < since) 48 | break; // Because entries are ordered, there are no other contracts for this revision. 49 | 50 | // Skip the call if the target account doesn't exist. This is by EIP-4788 spec. 51 | // > if no code exists at [address], the call must fail silently. 52 | const auto code = state_view.get_account_code(addr); 53 | if (code.empty()) 54 | continue; 55 | 56 | const auto input = get_input(block, block_hashes); 57 | 58 | const evmc_message msg{ 59 | .kind = EVMC_CALL, 60 | .gas = 30'000'000, 61 | .recipient = addr, 62 | .sender = SYSTEM_ADDRESS, 63 | .input_data = input.bytes, 64 | .input_size = std::size(input.bytes), 65 | }; 66 | 67 | const Transaction empty_tx{}; 68 | Host host{rev, vm, state, block, block_hashes, empty_tx}; 69 | [[maybe_unused]] const auto res = vm.execute(host, rev, msg, code.data(), code.size()); 70 | assert(res.status_code == EVMC_SUCCESS); 71 | } 72 | // TODO: Should we return empty diff if no system contracts? 73 | return state.build_diff(rev); 74 | } 75 | } // namespace evmone::state 76 | -------------------------------------------------------------------------------- /test/unittests/state_transition_extcode_test.cpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2023 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | #include "../utils/bytecode.hpp" 6 | #include "state_transition.hpp" 7 | 8 | using namespace evmc::literals; 9 | using namespace evmone::test; 10 | 11 | TEST_F(state_transition, extcodehash_existent) 12 | { 13 | rev = EVMC_ISTANBUL; // before account access 14 | block.base_fee = 0; 15 | 16 | static constexpr auto EXT = 0xe4_address; 17 | tx.type = Transaction::Type::legacy; 18 | tx.to = To; 19 | pre.insert(To, {.code = sstore(0, push(EXT) + OP_EXTCODEHASH)}); 20 | pre.insert(EXT, {.code = bytecode{"1234"}}); 21 | 22 | expect.post[EXT].exists = true; 23 | expect.post[To].storage[0x00_bytes32] = keccak256(pre.get(EXT).code); 24 | } 25 | 26 | TEST_F(state_transition, extcodesize_existent) 27 | { 28 | rev = EVMC_ISTANBUL; // before account access 29 | block.base_fee = 0; 30 | 31 | static constexpr auto EXT = 0xe4_address; 32 | tx.type = Transaction::Type::legacy; 33 | tx.to = To; 34 | pre.insert(To, {.code = sstore(0, push(EXT) + OP_EXTCODESIZE)}); 35 | pre.insert(EXT, {.code = bytes(3, 0)}); 36 | 37 | expect.post[EXT].exists = true; 38 | expect.post[To].storage[0x00_bytes32] = 0x03_bytes32; 39 | } 40 | 41 | constexpr auto target = 0xfffffffffffffffffffffffffffffffffffffffe_address; 42 | 43 | TEST_F(state_transition, legacy_extcodesize_eof) 44 | { 45 | pre.insert(target, {.code = eof_bytecode("FE")}); 46 | 47 | rev = EVMC_OSAKA; 48 | tx.to = To; 49 | pre.insert(*tx.to, { 50 | .code = bytecode(push(target) + sstore(1, OP_EXTCODESIZE)), 51 | }); 52 | expect.post[*tx.to].storage[0x01_bytes32] = 0x02_bytes32; 53 | expect.post[target].exists = true; 54 | } 55 | 56 | TEST_F(state_transition, legacy_extcodehash_eof) 57 | { 58 | pre.insert(target, {.code = eof_bytecode("FE")}); 59 | 60 | rev = EVMC_OSAKA; 61 | tx.to = To; 62 | pre.insert(*tx.to, { 63 | .code = bytecode(push(target) + sstore(1, OP_EXTCODEHASH)), 64 | }); 65 | expect.post[*tx.to].storage[0x01_bytes32] = keccak256(bytecode("EF00")); 66 | expect.post[target].exists = true; 67 | } 68 | 69 | TEST_F(state_transition, legacy_extcodecopy_eof) 70 | { 71 | constexpr auto ones = 72 | 0x1111111111111111111111111111111111111111111111111111111111111111_bytes32; 73 | pre.insert(target, {.code = eof_bytecode("FE")}); 74 | 75 | rev = EVMC_OSAKA; 76 | tx.to = To; 77 | pre.insert(*tx.to, { 78 | .code = bytecode(mstore(0, ones) + push(20) + push0() + push0() + 79 | push(target) + OP_EXTCODECOPY + sstore(1, mload(0))), 80 | }); 81 | expect.post[*tx.to].storage[0x01_bytes32] = 82 | 0xef00000000000000000000000000000000000000111111111111111111111111_bytes32; 83 | expect.post[target].exists = true; 84 | } 85 | -------------------------------------------------------------------------------- /test/eofparse/eofparse.cpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2023 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | namespace 12 | { 13 | inline constexpr bool isalnum(char ch) noexcept 14 | { 15 | return (ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z'); 16 | } 17 | 18 | template 19 | struct skip_nonalnum_iterator : evmc::filter_iterator 20 | { 21 | using evmc::filter_iterator::filter_iterator; 22 | }; 23 | 24 | template 25 | skip_nonalnum_iterator(BaseIterator, BaseIterator) -> skip_nonalnum_iterator; 26 | 27 | template 28 | std::optional from_hex_skip_nonalnum(InputIterator begin, InputIterator end) noexcept 29 | { 30 | evmc::bytes bs; 31 | if (!from_hex(skip_nonalnum_iterator{begin, end}, skip_nonalnum_iterator{end, end}, 32 | std::back_inserter(bs))) 33 | return {}; 34 | return bs; 35 | } 36 | 37 | } // namespace 38 | 39 | int main(int argc, char* argv[]) 40 | { 41 | try 42 | { 43 | CLI::App app{"evmone eofparse tool"}; 44 | const auto& initcode_flag = 45 | *app.add_flag("--initcode", "Validate code as initcode containers"); 46 | 47 | app.parse(argc, argv); 48 | const auto container_kind = 49 | initcode_flag ? evmone::ContainerKind::initcode : evmone::ContainerKind::runtime; 50 | 51 | int num_errors = 0; 52 | for (std::string line; std::getline(std::cin, line);) 53 | { 54 | if (line.empty() || line.starts_with('#')) 55 | continue; 56 | 57 | auto o = from_hex_skip_nonalnum(line.begin(), line.end()); 58 | if (!o) 59 | { 60 | std::cout << "err: invalid hex\n"; 61 | ++num_errors; 62 | continue; 63 | } 64 | 65 | const auto& eof = *o; 66 | const auto err = evmone::validate_eof(EVMC_OSAKA, container_kind, eof); 67 | if (err != evmone::EOFValidationError::success) 68 | { 69 | std::cout << "err: " << evmone::get_error_message(err) << "\n"; 70 | ++num_errors; 71 | continue; 72 | } 73 | 74 | const auto header = evmone::read_valid_eof1_header(eof); 75 | std::cout << "OK "; 76 | for (size_t i = 0; i < header.code_sizes.size(); ++i) 77 | { 78 | if (i != 0) 79 | std::cout << ","; 80 | std::cout << evmc::hex(header.get_code(eof, i)); 81 | } 82 | std::cout << "\n"; 83 | } 84 | return num_errors; 85 | } 86 | catch (const std::exception& ex) 87 | { 88 | std::cerr << ex.what() << "\n"; 89 | return -1; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /test/unittests/jumpdest_analysis_test.cpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2020 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | #include "test/experimental/jumpdest_analysis.hpp" 6 | #include "test/utils/bytecode.hpp" 7 | #include 8 | #include 9 | 10 | using namespace evmone; 11 | using namespace evmone::exp::jda; 12 | using namespace evmone::test; 13 | 14 | namespace 15 | { 16 | constexpr auto CODE_PADDING_CHECK_SIZE = 100; 17 | 18 | auto baseline_analyze(bytes_view code) 19 | { 20 | return baseline::analyze(code, false); 21 | } 22 | 23 | /// The set of test cases for jumpdest analysis. 24 | /// They come from inspecting various implementations and from issues found by fuzzers. 25 | const bytecode bytecode_test_cases[]{ 26 | {}, 27 | push(0x5b), 28 | OP_JUMPDEST, 29 | 2 * OP_JUMPDEST, 30 | push(0), 31 | push(0x5b) + OP_JUMPDEST, 32 | push(0x60) + OP_JUMPDEST, 33 | bytecode{"00"} + OP_JUMPDEST, 34 | bytecode{"80"} + OP_JUMPDEST, 35 | bytecode{"5f"} + OP_JUMPDEST, 36 | bytecode{"ff"} + OP_JUMPDEST, 37 | bytecode{OP_STOP} + OP_JUMPDEST, 38 | push(0x5b) + OP_STOP + push(0x5b), 39 | OP_JUMPDEST + 30 * bytecode{0x00} + OP_PUSH1, 40 | 30 * bytecode{0x00} + OP_PUSH32 + OP_JUMPDEST, 41 | OP_STOP + push(0x5b) + 27 * bytecode{0x00} + push(0x5b), 42 | OP_STOP + 3 * OP_JUMPDEST, 43 | 32 * OP_STOP + push("00000000000000005b000000000000005b") + OP_JUMPDEST, 44 | "5b14000000000000005badadad0000000000000000000000606060606060ff5b", 45 | }; 46 | } // namespace 47 | 48 | /// Wrapper for jumpdest analysis implementations suitable for typed tests. 49 | template 50 | struct I 51 | { 52 | static constexpr auto analyze = Fn; 53 | }; 54 | 55 | template 56 | class jumpdest_analysis_test : public testing::Test 57 | {}; 58 | using test_types = testing::Types< // 59 | I, // 60 | I // 61 | >; 62 | TYPED_TEST_SUITE(jumpdest_analysis_test, test_types); 63 | 64 | TYPED_TEST(jumpdest_analysis_test, validate) 65 | { 66 | // Compare a jumpdest analysis implementation against the reference implementation. 67 | for (size_t test_idx = 0; test_idx < std::size(bytecode_test_cases); ++test_idx) 68 | { 69 | for (const auto extended : {true, false}) 70 | { 71 | auto code = bytecode_test_cases[test_idx]; 72 | if (extended) // Extend size to multiply of 32 to force bulk-based implementations. 73 | code.resize(code.size() / 32 * 32); 74 | const auto expected = reference(code); 75 | const auto analysis = TypeParam::analyze(code); 76 | 77 | for (size_t i = 0; i < code.size() + CODE_PADDING_CHECK_SIZE; ++i) 78 | { 79 | EXPECT_EQ(analysis.check_jumpdest(i), expected.check_jumpdest(i)) 80 | << "case " << test_idx << (extended ? " extended" : "") << " [" << i << "]"; 81 | } 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /cmake/cable/README.md: -------------------------------------------------------------------------------- 1 | # Cable 2 | 3 | [![readme style: standard][readme style standard badge]][standard readme] 4 | 5 | > Cable: CMake Bootstrap Library 6 | 7 | Cable is a set of CMake modules and scripts containing common patterns used 8 | in CMake-based C++ projects. The design goal is to be pragmatic rather than 9 | generic so the number of provided options is minimal. The Cable modules are 10 | independent and it is easy to use them individually. 11 | 12 | 13 | ## Table of Contents 14 | 15 | - [Install](#install) 16 | - [Usage](#usage) 17 | - [Maintainer](#maintainer) 18 | - [License](#license) 19 | 20 | 21 | ## Install 22 | 23 | The suggested Cable location is `cmake/cable` relative to your project root directory. 24 | 25 | 26 | ### With cable.cmake script 27 | 28 | Copy [cable.cmake](cable.cmake) script to your project. 29 | Then use it to download individual Cable CMake modules. 30 | 31 | ```bash 32 | ./cable.cmake install CableBuildType 33 | ``` 34 | 35 | 36 | ### As git subtree 37 | 38 | Adding a dependency project as a [git subtree] is just a copy of the source code 39 | done in a bit more systematic way. 40 | 41 | If you are not familiar with managing dependencies with git subtree read the 42 | [Git subtree: the alternative to Git submodule][git subtree tutorial]. 43 | 44 | #### To install 45 | 46 | ```sh 47 | git remote add cable https://github.com/ethereum/cable 48 | git subtree add --prefix cmake/cable cable master --squash 49 | ``` 50 | 51 | #### To update 52 | 53 | ```sh 54 | git subtree pull --prefix cmake/cable cable master --squash 55 | ``` 56 | 57 | ### As git submodule 58 | 59 | Include the Cable library as [git submodule] in your project. 60 | 61 | ```sh 62 | git submodule add https://github.com/ethereum/cable cmake/cable 63 | ``` 64 | 65 | ## Usage 66 | 67 | Cable contains the `bootstrap.cmake` file that initializes the library. 68 | Start by including this file in your main `CMakeLists.txt` from the Cable 69 | submodule/subtree or any other location. The `bootstrap.cmake` must be included 70 | before the `project()` command. After that, you can include and use other 71 | Cable modules. 72 | 73 | ### Example 74 | 75 | ```cmake 76 | cmake_minimum_required(VERSION 3.5) 77 | 78 | include(cmake/cable/bootstrap.cmake) 79 | include(CableBuildType) 80 | 81 | project(tothemoon) 82 | 83 | cable_set_build_type(DEFAULT RelWithDebInfo CONFIGURATION_TYPES Debug Release RelWithDebInfo) 84 | ``` 85 | 86 | 87 | ## Maintainer 88 | 89 | Paweł Bylica [@chfast] 90 | 91 | ## License 92 | 93 | Licensed under the [Apache License, Version 2.0]. 94 | 95 | 96 | [@chfast]: https://github.com/chfast 97 | [Apache License, Version 2.0]: LICENSE 98 | [git submodule]: https://git-scm.com/book/en/v2/Git-Tools-Submodules 99 | [git subtree]: https://github.com/git/git/blob/master/contrib/subtree/git-subtree.txt 100 | [git subtree tutorial]: https://www.atlassian.com/blog/git/alternatives-to-git-submodule-git-subtree 101 | [standard readme]: https://github.com/RichardLitt/standard-readme 102 | 103 | [readme style standard badge]: https://img.shields.io/badge/readme%20style-standard-brightgreen.svg?style=flat-square 104 | -------------------------------------------------------------------------------- /lib/evmone/vm.cpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2018 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | /// @file 6 | /// EVMC instance (class VM) and entry point of evmone is defined here. 7 | 8 | #include "vm.hpp" 9 | #include "advanced_execution.hpp" 10 | #include "baseline.hpp" 11 | #include 12 | #include 13 | #include 14 | 15 | namespace evmone 16 | { 17 | namespace 18 | { 19 | void destroy(evmc_vm* vm) noexcept 20 | { 21 | assert(vm != nullptr); 22 | delete static_cast(vm); 23 | } 24 | 25 | constexpr evmc_capabilities_flagset get_capabilities(evmc_vm* /*vm*/) noexcept 26 | { 27 | return EVMC_CAPABILITY_EVM1; 28 | } 29 | 30 | evmc_set_option_result set_option(evmc_vm* c_vm, char const* c_name, char const* c_value) noexcept 31 | { 32 | const auto name = (c_name != nullptr) ? std::string_view{c_name} : std::string_view{}; 33 | const auto value = (c_value != nullptr) ? std::string_view{c_value} : std::string_view{}; 34 | auto& vm = *static_cast(c_vm); 35 | 36 | if (name == "advanced") 37 | { 38 | c_vm->execute = evmone::advanced::execute; 39 | return EVMC_SET_OPTION_SUCCESS; 40 | } 41 | else if (name == "cgoto") 42 | { 43 | #if EVMONE_CGOTO_SUPPORTED 44 | if (value == "no") 45 | { 46 | vm.cgoto = false; 47 | return EVMC_SET_OPTION_SUCCESS; 48 | } 49 | return EVMC_SET_OPTION_INVALID_VALUE; 50 | #else 51 | return EVMC_SET_OPTION_INVALID_NAME; 52 | #endif 53 | } 54 | else if (name == "trace") 55 | { 56 | vm.add_tracer(create_instruction_tracer(std::clog)); 57 | return EVMC_SET_OPTION_SUCCESS; 58 | } 59 | else if (name == "histogram") 60 | { 61 | vm.add_tracer(create_histogram_tracer(std::clog)); 62 | return EVMC_SET_OPTION_SUCCESS; 63 | } 64 | else if (name == "validate_eof") 65 | { 66 | vm.validate_eof = true; 67 | return EVMC_SET_OPTION_SUCCESS; 68 | } 69 | return EVMC_SET_OPTION_INVALID_NAME; 70 | } 71 | 72 | } // namespace 73 | 74 | 75 | VM::VM() noexcept 76 | : evmc_vm{ 77 | EVMC_ABI_VERSION, 78 | "evmone", 79 | PROJECT_VERSION, 80 | evmone::destroy, 81 | evmone::baseline::execute, 82 | evmone::get_capabilities, 83 | evmone::set_option, 84 | } 85 | { 86 | m_execution_states.reserve(1025); 87 | } 88 | 89 | ExecutionState& VM::get_execution_state(size_t depth) noexcept 90 | { 91 | // Vector already has the capacity for all possible depths, 92 | // so reallocation never happens (therefore: noexcept). 93 | // The ExecutionStates are lazily created because they pre-allocate EVM memory and stack. 94 | assert(depth < m_execution_states.capacity()); 95 | if (m_execution_states.size() <= depth) 96 | m_execution_states.resize(depth + 1); 97 | return m_execution_states[depth]; 98 | } 99 | 100 | } // namespace evmone 101 | 102 | extern "C" { 103 | EVMC_EXPORT evmc_vm* evmc_create_evmone() noexcept 104 | { 105 | return new evmone::VM{}; 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /test/unittests/precompiles_blake2b_test.cpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2024 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | using evmone::crypto::blake2b_compress; 12 | 13 | // Initialization Vector. 14 | // https://datatracker.ietf.org/doc/html/rfc7693#appendix-C.2 15 | constexpr std::array blake2b_iv{ 16 | 0x6a09e667f3bcc908, 17 | 0xbb67ae8584caa73b, 18 | 0x3c6ef372fe94f82b, 19 | 0xa54ff53a5f1d36f1, 20 | 0x510e527fade682d1, 21 | 0x9b05688c2b3e6c1f, 22 | 0x1f83d9abfb41bd6b, 23 | 0x5be0cd19137e2179, 24 | }; 25 | 26 | TEST(blake2b_compress, reference_test) 27 | { 28 | // The reference test from the RFC. 29 | // https://datatracker.ietf.org/doc/html/rfc7693#appendix-A 30 | // with some extensions by modifying the "rounds" and "last" values. 31 | 32 | using evmone::test::hex; 33 | 34 | auto h_init = blake2b_iv; 35 | h_init[0] ^= 0x01010000 ^ /*outlen = */ 64; 36 | 37 | const std::string_view data = "abc"; 38 | uint64_t m[16]{}; 39 | std::memcpy(m, data.data(), data.size()); 40 | 41 | const uint64_t t[2]{data.size(), 0}; 42 | 43 | auto h = h_init; 44 | blake2b_compress(12, h.data(), m, t, true); 45 | EXPECT_EQ(hex({reinterpret_cast(h.data()), sizeof(h)}), 46 | "ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d1" 47 | "7d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923"); 48 | 49 | // https://github.com/ethereum/tests/blob/v13.2/src/GeneralStateTestsFiller/stPreCompiledContracts/blake2BFiller.yml#L301-L302 50 | h = h_init; 51 | blake2b_compress(12, h.data(), m, t, false); 52 | EXPECT_EQ(hex({reinterpret_cast(h.data()), sizeof(h)}), 53 | "75ab69d3190a562c51aef8d88f1c2775876944407270c42c9844252c26d28752" 54 | "98743e7f6d5ea2f2d3e8d226039cd31b4e426ac4f2d3d666a610c2116fde4735"); 55 | 56 | // https://github.com/ethereum/tests/blob/v13.2/src/GeneralStateTestsFiller/stPreCompiledContracts/blake2BFiller.yml#L268-L269 57 | h = h_init; 58 | blake2b_compress(0, h.data(), m, t, true); 59 | EXPECT_EQ(hex({reinterpret_cast(h.data()), sizeof(h)}), 60 | "08c9bcf367e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5" 61 | "d282e6ad7f520e511f6c3e2b8c68059b9442be0454267ce079217e1319cde05b"); 62 | 63 | // this gives the same result because the xor zeros out the "last" flag 64 | h = h_init; 65 | blake2b_compress(0, h.data(), m, t, false); 66 | EXPECT_EQ(hex({reinterpret_cast(h.data()), sizeof(h)}), 67 | "08c9bcf367e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5" 68 | "d282e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b"); 69 | } 70 | 71 | TEST(blake2b_compress, null_input) 72 | { 73 | std::array h{}; 74 | const uint64_t t[2]{}; 75 | 76 | // the data block is unused so be pass nullptr. 77 | blake2b_compress(0, h.data(), nullptr, t, false); 78 | 79 | // For null input you get the IV as the result. 80 | EXPECT_EQ(h, blake2b_iv); 81 | } 82 | -------------------------------------------------------------------------------- /test/integration/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # evmone: Fast Ethereum Virtual Machine implementation 2 | # Copyright 2021 The evmone Authors. 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | set(PREFIX ${PROJECT_NAME}/integration) 6 | 7 | get_target_property(EVMONE_LIB_TYPE evmone TYPE) 8 | if(EVMONE_LIB_TYPE STREQUAL SHARED_LIBRARY) 9 | 10 | add_test(NAME ${PREFIX}/histogram COMMAND evmc::tool --vm $,histogram run 6000808080800101010200) 11 | set_tests_properties( 12 | ${PREFIX}/histogram PROPERTIES PASS_REGULAR_EXPRESSION 13 | "--- # HISTOGRAM depth=0 14 | opcode,count 15 | STOP,1 16 | ADD,3 17 | MUL,1 18 | PUSH1,1 19 | DUP1,4 20 | ") 21 | 22 | add_test(NAME ${PREFIX}/trace COMMAND evmc::tool --vm $,trace run 60006002800103) 23 | set_tests_properties( 24 | ${PREFIX}/trace PROPERTIES PASS_REGULAR_EXPRESSION 25 | "\"pc\":0,\"op\":96,\"gas\":\"0xf4240\",\"gasCost\":\"0x3\",\"memSize\":0,\"stack\":\\[\\],\"depth\":1,\"refund\":0,\"opName\":\"PUSH1\"} 26 | {\"pc\":2,\"op\":96,\"gas\":\"0xf423d\",\"gasCost\":\"0x3\",\"memSize\":0,\"stack\":\\[\"0x0\"\\],\"depth\":1,\"refund\":0,\"opName\":\"PUSH1\"} 27 | {\"pc\":4,\"op\":128,\"gas\":\"0xf423a\",\"gasCost\":\"0x3\",\"memSize\":0,\"stack\":\\[\"0x0\",\"0x2\"\\],\"depth\":1,\"refund\":0,\"opName\":\"DUP1\"} 28 | {\"pc\":5,\"op\":1,\"gas\":\"0xf4237\",\"gasCost\":\"0x3\",\"memSize\":0,\"stack\":\\[\"0x0\",\"0x2\",\"0x2\"\\],\"depth\":1,\"refund\":0,\"opName\":\"ADD\"} 29 | {\"pc\":6,\"op\":3,\"gas\":\"0xf4234\",\"gasCost\":\"0x3\",\"memSize\":0,\"stack\":\\[\"0x0\",\"0x4\"\\],\"depth\":1,\"refund\":0,\"opName\":\"SUB\"} 30 | ") 31 | 32 | add_test(NAME ${PREFIX}/validate_eof COMMAND evmc::tool --vm $,validate_eof run --rev 14 EF0001) 33 | set_tests_properties( 34 | ${PREFIX}/validate_eof PROPERTIES PASS_REGULAR_EXPRESSION 35 | "contract validation failure") 36 | 37 | add_test(NAME ${PREFIX}/validate_eof_success COMMAND evmc::tool --vm $,validate_eof run --rev 14 EF00010100040200010001040000000080000000) 38 | set_tests_properties( 39 | ${PREFIX}/validate_eof_success PROPERTIES PASS_REGULAR_EXPRESSION 40 | "Result: success") 41 | 42 | add_test(NAME ${PREFIX}/validate_eof_create COMMAND evmc::tool --vm $,validate_eof run --rev 14 --create EF00010100040200010001040000000080000000) 43 | set_tests_properties( 44 | ${PREFIX}/validate_eof_create PROPERTIES PASS_REGULAR_EXPRESSION 45 | "contract validation failure") 46 | 47 | add_test(NAME ${PREFIX}/validate_eof_create_success COMMAND evmc::tool --vm $,validate_eof run --rev 14 --create EF00010100040200010004030001001404000000008000025F5FEE00EF00010100040200010001040000000080000000) 48 | set_tests_properties( 49 | ${PREFIX}/validate_eof_create_success PROPERTIES PASS_REGULAR_EXPRESSION 50 | "Result: success") 51 | 52 | endif() 53 | 54 | add_subdirectory(eofparse) 55 | add_subdirectory(export) 56 | add_subdirectory(statetest) 57 | add_subdirectory(t8n) 58 | 59 | get_property(ALL_TESTS DIRECTORY PROPERTY TESTS) 60 | set_tests_properties(${ALL_TESTS} PROPERTIES ENVIRONMENT LLVM_PROFILE_FILE=${CMAKE_BINARY_DIR}/integration-%p.profraw) 61 | 62 | -------------------------------------------------------------------------------- /lib/evmone/baseline_analysis.cpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2020 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | #include "baseline.hpp" 6 | #include "eof.hpp" 7 | #include "instructions.hpp" 8 | #include 9 | 10 | namespace evmone::baseline 11 | { 12 | static_assert(std::is_move_constructible_v); 13 | static_assert(std::is_move_assignable_v); 14 | static_assert(!std::is_copy_constructible_v); 15 | static_assert(!std::is_copy_assignable_v); 16 | 17 | namespace 18 | { 19 | CodeAnalysis::JumpdestMap analyze_jumpdests(bytes_view code) 20 | { 21 | // To find if op is any PUSH opcode (OP_PUSH1 <= op <= OP_PUSH32) 22 | // it can be noticed that OP_PUSH32 is INT8_MAX (0x7f) therefore 23 | // static_cast(op) <= OP_PUSH32 is always true and can be skipped. 24 | static_assert(OP_PUSH32 == std::numeric_limits::max()); 25 | 26 | CodeAnalysis::JumpdestMap map(code.size()); // Allocate and init bitmap with zeros. 27 | for (size_t i = 0; i < code.size(); ++i) 28 | { 29 | const auto op = code[i]; 30 | if (static_cast(op) >= OP_PUSH1) // If any PUSH opcode (see explanation above). 31 | i += op - size_t{OP_PUSH1 - 1}; // Skip PUSH data. 32 | else if (INTX_UNLIKELY(op == OP_JUMPDEST)) 33 | map[i] = true; 34 | } 35 | 36 | return map; 37 | } 38 | 39 | std::unique_ptr pad_code(bytes_view code) 40 | { 41 | // We need at most 33 bytes of code padding: 32 for possible missing all data bytes of PUSH32 42 | // at the very end of the code; and one more byte for STOP to guarantee there is a terminating 43 | // instruction at the code end. 44 | constexpr auto padding = 32 + 1; 45 | 46 | auto padded_code = std::make_unique_for_overwrite(code.size() + padding); 47 | std::copy(std::begin(code), std::end(code), padded_code.get()); 48 | std::fill_n(&padded_code[code.size()], padding, uint8_t{OP_STOP}); 49 | return padded_code; 50 | } 51 | 52 | 53 | CodeAnalysis analyze_legacy(bytes_view code) 54 | { 55 | // TODO: The padded code buffer and jumpdest bitmap can be created with single allocation. 56 | return {pad_code(code), code.size(), analyze_jumpdests(code)}; 57 | } 58 | 59 | CodeAnalysis analyze_eof1(bytes_view container) 60 | { 61 | auto header = read_valid_eof1_header(container); 62 | 63 | // Extract all code sections as single buffer reference. 64 | // TODO: It would be much easier if header had code_sections_offset and data_section_offset 65 | // with code_offsets[] being relative to code_sections_offset. 66 | const auto code_sections_offset = header.code_offsets[0]; 67 | const auto code_sections_end = size_t{header.code_offsets.back()} + header.code_sizes.back(); 68 | const auto executable_code = 69 | container.substr(code_sections_offset, code_sections_end - code_sections_offset); 70 | 71 | return CodeAnalysis{container, executable_code, std::move(header)}; 72 | } 73 | } // namespace 74 | 75 | CodeAnalysis analyze(bytes_view code, bool eof_enabled) 76 | { 77 | if (eof_enabled && is_eof_container(code)) 78 | return analyze_eof1(code); 79 | return analyze_legacy(code); 80 | } 81 | } // namespace evmone::baseline 82 | -------------------------------------------------------------------------------- /test/eoftest/eoftest_runner.cpp: -------------------------------------------------------------------------------- 1 | // evmone: Fast Ethereum Virtual Machine implementation 2 | // Copyright 2023 The evmone Authors. 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | #include "../utils/utils.hpp" 6 | #include "eoftest.hpp" 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | namespace json = nlohmann; 13 | 14 | namespace evmone::test 15 | { 16 | 17 | namespace 18 | { 19 | struct EOFValidationTest 20 | { 21 | struct Case 22 | { 23 | struct Expectation 24 | { 25 | evmc_revision rev = EVMC_OSAKA; 26 | bool result = false; 27 | }; 28 | std::string name; 29 | evmc::bytes code; 30 | ContainerKind kind = ContainerKind::runtime; 31 | std::vector expectations; 32 | }; 33 | std::string name; 34 | std::unordered_map cases; 35 | }; 36 | 37 | void from_json(const json::json& j, EOFValidationTest::Case& o) 38 | { 39 | const auto op_code = evmc::from_hex(j.at("code").get()); 40 | if (!op_code) 41 | throw std::invalid_argument{"code is invalid hex string"}; 42 | o.code = *op_code; 43 | 44 | if (const auto it_kind = j.find("containerKind"); it_kind != j.end()) 45 | { 46 | if (it_kind->get() == "INITCODE") 47 | o.kind = ContainerKind::initcode; 48 | } 49 | 50 | for (const auto& [rev, result] : j.at("results").items()) 51 | { 52 | o.expectations.push_back({to_rev(rev), result.at("result").get()}); 53 | } 54 | } 55 | 56 | void from_json(const json::json& j, EOFValidationTest& o) 57 | { 58 | if (!j.is_object() || j.empty()) 59 | throw std::invalid_argument{"JSON test must be an object with single key of the test name"}; 60 | 61 | for (const auto& [name, test] : j.at("vectors").items()) 62 | { 63 | o.cases.emplace(name, test.get()); 64 | } 65 | } 66 | 67 | void from_json(const json::json& j, std::vector& o) 68 | { 69 | for (const auto& elem_it : j.items()) 70 | { 71 | auto test = elem_it.value().get(); 72 | test.name = elem_it.key(); 73 | o.emplace_back(std::move(test)); 74 | } 75 | } 76 | 77 | std::vector load_eof_tests(std::istream& input) 78 | { 79 | return json::json::parse(input).get>(); 80 | } 81 | 82 | } // namespace 83 | 84 | void run_eof_test(std::istream& input) 85 | { 86 | const auto tests = evmone::test::load_eof_tests(input); 87 | for (const auto& test : tests) 88 | { 89 | for (const auto& [name, cases] : test.cases) 90 | { 91 | for (const auto& expectation : cases.expectations) 92 | { 93 | const auto result = evmone::validate_eof(expectation.rev, cases.kind, cases.code); 94 | const bool b_result = (result == EOFValidationError::success); 95 | EXPECT_EQ(b_result, expectation.result) 96 | << name << " " << expectation.rev << " " << hex(cases.code); 97 | } 98 | } 99 | } 100 | } 101 | 102 | } // namespace evmone::test 103 | --------------------------------------------------------------------------------