diff --git a/CMakeLists.txt b/CMakeLists.txt index 140c63dac..3d9797fb8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,8 +15,8 @@ HunterGate( ) list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") -project(retesteth VERSION 0.2.3) -set(VERSION_SUFFIX "postmerge") +project(retesteth VERSION 0.3.0) +set(VERSION_SUFFIX "shanghai") set(Boost_USE_STATIC_LIBS ON) set(Boost_USE_MULTITHREADED ON) @@ -40,22 +40,6 @@ message(STATUS "[retesteth] Boost include: `${Boost_INCLUDE_DIR}`") hunter_add_package(yaml-cpp) find_package(yaml-cpp CONFIG REQUIRED) -IF (NOT LOCALDEPS MATCHES ".*CRYPTOPP") - hunter_add_package(cryptopp) - find_package(cryptopp CONFIG REQUIRED) - set(CRYPTOPP_LINK "cryptopp-static") -ELSE() - message(STATUS "[retesteth] LOCALDEPS=CRYPTOPP looking for locally installed version") - find_package(cryptopp MODULE REQUIRED) - message(STATUS "[retesteth] cryptopp libdir: `${CRYPTOPP_LIBRARIES}`") - message(STATUS "[retesteth] cryptopp include: `${CRYPTOPP_INCLUDE_DIRS}`") - set(CRYPTOPP_LINK ${CRYPTOPP_LIBRARIES}) -ENDIF() - - -hunter_add_package(libscrypt) -find_package(libscrypt CONFIG REQUIRED) - # Silence cmake warnings on newer versions if (POLICY CMP0074) cmake_policy(SET CMP0074 NEW) # Use download timestamp for remote objects @@ -76,7 +60,6 @@ include(EthDependencies) include(EthCompilerSettings) include(ProjectSecp256k1) -include(ProjectLibFF) configure_project() if(JSONCPP) diff --git a/Dockerfile b/Dockerfile index 90ca96508..11239f501 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,8 +3,9 @@ FROM ubuntu:20.04 as retesteth ENV TZ=Etc/UTC RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone +# Get necessary packages RUN apt-get update \ - && apt-get install --yes git cmake g++ make perl psmisc curl python3 \ + && apt-get install --yes git cmake g++ make perl psmisc curl python3 wget libboost-all-dev \ && rm -rf /var/lib/apt/lists/* # Retesteth @@ -21,8 +22,6 @@ RUN mkdir /build && cd /build \ # Solidity LLLC RUN git clone --depth 1 -b master https://github.com/winsvega/solidity.git /solidity RUN mkdir /build && cd /build \ - && apt-get update \ - && apt-get install --yes libboost-all-dev \ && cmake /solidity -DCMAKE_BUILD_TYPE=Release -DLLL=1 && make lllc \ && cp /build/lllc/lllc /bin/lllc \ && rm -rf /build /solidity /var/cache/* /root/.hunter/* @@ -33,13 +32,13 @@ RUN mkdir /build && cd /build \ # && cmake /solidity -DCMAKE_BUILD_TYPE=Release && make solc \ # && cp /build/solc/solc /bin/solc \ # && rm -rf /build /solidity /var/cache/* /root/.hunter/* -RUN apt-get install wget && wget https://github.com/ethereum/solidity/releases/download/v0.8.5/solc-static-linux \ +RUN wget https://github.com/ethereum/solidity/releases/download/v0.8.17/solc-static-linux \ && cp solc-static-linux /bin/solc \ && chmod +x /bin/solc # Geth RUN git clone --depth 1 -b master https://github.com/ethereum/go-ethereum.git /geth -RUN cd /geth && apt-get install wget \ +RUN cd /geth \ && wget https://dl.google.com/go/go1.19.linux-amd64.tar.gz \ && tar -xvf go1.19.linux-amd64.tar.gz \ && mv go /usr/local && ln -s /usr/local/go/bin/go /bin/go \ diff --git a/README.md b/README.md index 95a050b12..ee6ea6a8e 100644 --- a/README.md +++ b/README.md @@ -64,7 +64,7 @@ If one of the following dependecies is failing to autoinstall, some times due to ``` rm -r /root/.hunter rm CMakeCache.txt -cmake .. -DLOCALDEPS="BOOST,MPIR,CRYPTOPP" +cmake .. -DLOCALDEPS="BOOST" ``` Try building instruction for beginners: [retesteth + solidity build](https://github.com/ethereum/retesteth#building-instructions-for-beginners) diff --git a/circle.yml b/circle.yml index 1a098c908..33b9f4956 100644 --- a/circle.yml +++ b/circle.yml @@ -44,8 +44,8 @@ defaults: name: "LinuxInstallGO and Tests" working_directory: ~/project command: | - curl -L --output go1.18.linux-amd64.tar.gz "https://dl.google.com/go/go1.18.linux-amd64.tar.gz" - tar -xf go1.18.linux-amd64.tar.gz + curl -L --output go1.19.linux-amd64.tar.gz "https://dl.google.com/go/go1.19.linux-amd64.tar.gz" + tar -xf go1.19.linux-amd64.tar.gz sudo mv go /usr/local sudo ln -s /usr/local/go/bin/go /usr/local/bin/go git clone --depth 1 https://github.com/ethereum/go-ethereum.git diff --git a/cmake/EthCompilerSettings.cmake b/cmake/EthCompilerSettings.cmake index e330c2834..58ce7c2a4 100644 --- a/cmake/EthCompilerSettings.cmake +++ b/cmake/EthCompilerSettings.cmake @@ -55,12 +55,6 @@ if (("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") OR ("${CMAKE_CXX_COMPILER_ID}" MA if("${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS 4.8) message(FATAL_ERROR "This compiler ${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION} is not supported. GCC 4.8 or newer is required.") endif() - - # Stop if buggy clang compiler detected. - elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES AppleClang) - if("${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS 8.4) - message(FATAL_ERROR "This compiler ${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION} is not able to compile required libff. Install clang 4+ from Homebrew or XCode 9.") - endif() endif() # The major alternative compiler to GCC/Clang is Microsoft's Visual C++ compiler, only available on Windows. diff --git a/cmake/Findcryptopp.cmake b/cmake/Findcryptopp.cmake deleted file mode 100644 index 0c85202d5..000000000 --- a/cmake/Findcryptopp.cmake +++ /dev/null @@ -1,114 +0,0 @@ -# Module for locating the Crypto++ encryption library. -# -# Customizable variables: -# CRYPTOPP_ROOT_DIR -# This variable points to the CryptoPP root directory. On Windows the -# library location typically will have to be provided explicitly using the -# -D command-line option. The directory should include the include/cryptopp, -# lib and/or bin sub-directories. -# -# Read-only variables: -# CRYPTOPP_FOUND -# Indicates whether the library has been found. -# -# CRYPTOPP_INCLUDE_DIRS -# Points to the CryptoPP include directory. -# -# CRYPTOPP_LIBRARIES -# Points to the CryptoPP libraries that should be passed to -# target_link_libararies. -# -# -# Copyright (c) 2012 Sergiu Dotenco -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - -# Set this for a custom location of cryptopp -#SET(ADDPATH "/home/wins/Ethereum") - -INCLUDE (FindPackageHandleStandardArgs) - -FIND_PATH (CRYPTOPP_ROOT_DIR - NAMES cryptopp/cryptlib.h include/cryptopp/cryptlib.h - PATHS ${ADDPATH} - DOC "cryptopp root directory") - -# Re-use the previous path: -FIND_PATH (CRYPTOPP_INCLUDE_DIR - NAMES cryptopp/cryptlib.h - HINTS ${CRYPTOPP_ROOT_DIR} - PATH_SUFFIXES include - PATHS ${ADDPATH} - DOC "cryptopp include directory") - -FIND_LIBRARY (CRYPTOPP_LIBRARY_DEBUG - NAMES cryptlibd cryptoppd - HINTS ${CRYPTOPP_ROOT_DIR} - PATH_SUFFIXES lib - PATHS ${ADDPATH} - DOC "cryptopp debug library") - -FIND_LIBRARY (CRYPTOPP_LIBRARY_RELEASE - NAMES cryptlib cryptopp - HINTS ${CRYPTOPP_ROOT_DIR} - PATH_SUFFIXES lib - PATHS ${ADDPATH} - DOC "cryptopp release library") - -IF (CRYPTOPP_LIBRARY_DEBUG AND CRYPTOPP_LIBRARY_RELEASE) - SET (CRYPTOPP_LIBRARY - optimized ${CRYPTOPP_LIBRARY_RELEASE} - debug ${CRYPTOPP_LIBRARY_DEBUG} CACHE DOC "cryptopp library") -ELSEIF (CRYPTOPP_LIBRARY_RELEASE) - SET (CRYPTOPP_LIBRARY ${CRYPTOPP_LIBRARY_RELEASE} CACHE DOC "cryptopp library") -ENDIF (CRYPTOPP_LIBRARY_DEBUG AND CRYPTOPP_LIBRARY_RELEASE) - -IF (CRYPTOPP_INCLUDE_DIR) - SET (_CRYPTOPP_VERSION_HEADER ${CRYPTOPP_INCLUDE_DIR}/cryptopp/config.h) - -# This part does not work with newer version of cryptopp -# IF (EXISTS ${_CRYPTOPP_VERSION_HEADER}) -# FILE (STRINGS ${_CRYPTOPP_VERSION_HEADER} _CRYPTOPP_VERSION_TMP REGEX -# "^#define CRYPTOPP_VERSION[ \t]+[0-9]+$") - -# STRING (REGEX REPLACE -# "^#define CRYPTOPP_VERSION[ \t]+([0-9]+)" "\\1" _CRYPTOPP_VERSION_TMP -# ${_CRYPTOPP_VERSION_TMP}) - -# STRING (REGEX REPLACE "([0-9]+)[0-9][0-9]" "\\1" CRYPTOPP_VERSION_MAJOR -# ${_CRYPTOPP_VERSION_TMP}) -# STRING (REGEX REPLACE "[0-9]([0-9])[0-9]" "\\1" CRYPTOPP_VERSION_MINOR -# ${_CRYPTOPP_VERSION_TMP}) -# STRING (REGEX REPLACE "[0-9][0-9]([0-9])" "\\1" CRYPTOPP_VERSION_PATCH -# ${_CRYPTOPP_VERSION_TMP}) - -# SET (CRYPTOPP_VERSION_COUNT 3) -# SET (CRYPTOPP_VERSION -# ${CRYPTOPP_VERSION_MAJOR}.${CRYPTOPP_VERSION_MINOR}.${CRYPTOPP_VERSION_PATCH}) -# ENDIF (EXISTS ${_CRYPTOPP_VERSION_HEADER}) -ENDIF (CRYPTOPP_INCLUDE_DIR) - -SET (CRYPTOPP_INCLUDE_DIRS ${CRYPTOPP_INCLUDE_DIR}) -SET (CRYPTOPP_LIBRARIES ${CRYPTOPP_LIBRARY}) - -MARK_AS_ADVANCED (CRYPTOPP_INCLUDE_DIR CRYPTOPP_LIBRARY CRYPTOPP_LIBRARY_DEBUG - CRYPTOPP_LIBRARY_RELEASE) - -FIND_PACKAGE_HANDLE_STANDARD_ARGS (cryptopp REQUIRED_VARS CRYPTOPP_ROOT_DIR - CRYPTOPP_INCLUDE_DIR CRYPTOPP_LIBRARY VERSION_VAR CRYPTOPP_VERSION) diff --git a/cmake/Findmpir.cmake b/cmake/Findmpir.cmake deleted file mode 100644 index 4e101c94c..000000000 --- a/cmake/Findmpir.cmake +++ /dev/null @@ -1,75 +0,0 @@ -# Find mpir with API version ?.? -# -# Usage: -# find_package(mpir [REQUIRED] [QUIET]) -# -# Sets the following variables: -# - MPIR_FOUND .. true if library is found -# - MPIR_LIBRARY .. full path to library -# - MPIR_INCLUDE_DIR .. full path to include directory -# -# Honors the following optional variables: -# - MPIR_INCLUDE_LOC .. include directory path, to be searched before defaults -# - MPIR_LIBRARY_LOC .. the library's directory path, to be searched before defaults -# - MPIR_STATIC_LIBRARY .. if true, find the static library version -# -# Copyright 2015 Joachim Coenen, Forschungszentrum Jülich. -# Redistribution permitted. - -# find the mpir include directory -find_path(MPIR_INCLUDE_DIR mpir.h - PATH_SUFFIXES include mpir/include mpir - PATHS - ${MPIR_INCLUDE_LOC} - "C:/Program Files/mpir/" - ~/Library/Frameworks/ - /Library/Frameworks/ - /usr/local/ - /usr/ - /sw/ # Fink - /opt/local/ # DarwinPorts - /opt/csw/ # Blastwave - /opt/ - ) - - -set(CMAKE_REQUIRED_INCLUDES ${MPIR_INCLUDE_DIR}) -set(CMAKE_REQUIRED_QUIET False) - -# attempt to find static library first if this is set -if(MPIR_STATIC_LIBRARY) - set(MPIR_STATIC mpir.a) - #set(MPIR_STATIC mpir.lib) -endif() - -# find the mpir library -find_library(MPIR_LIBRARY - NAMES - #${MPIR_STATIC} - mpir - PATH_SUFFIXES lib64 lib - PATHS - ${MPIR_LIBRARY_LOC} - "C:/Program Files/mpir/" - ~/Library/Frameworks - /Library/Frameworks - /usr/local - /usr - /sw - /opt/local - /opt/csw - /opt - ) - -if ( MPIR_LIBRARY ) - set(MPIR_FOUND TRUE) -else() - message(FATAL_ERROR "[mpir] Locally installed MPIR not found!") -endif() - -message(STATUS "[mpir] FOUND=${MPIR_FOUND}, VERSION=${MPIR_VERSION}, LIB=${MPIR_LIBRARY}") -message(STATUS "[mpir] Found FindMPIR: ${MPIR_LIBRARY}") - - -mark_as_advanced(MPIR_INCLUDE_DIR MPIR_LIBRARY) - diff --git a/cmake/Hunter/config.cmake b/cmake/Hunter/config.cmake index aa9c393fa..ebaefde14 100644 --- a/cmake/Hunter/config.cmake +++ b/cmake/Hunter/config.cmake @@ -1,8 +1,3 @@ -# cryptopp has very bad CMakeLists.txt config. -# We have to enforce "cross compiling mode" there by setting CMAKE_SYSTEM_VERSION=NO -# to any "false" value. -hunter_config(cryptopp VERSION ${HUNTER_cryptopp_VERSION} CMAKE_ARGS CMAKE_SYSTEM_VERSION=NO) - hunter_config( libjson-rpc-cpp VERSION ${HUNTER_libjson-rpc-cpp_VERSION} diff --git a/cmake/ProjectLibFF.cmake b/cmake/ProjectLibFF.cmake deleted file mode 100644 index 7f0e2e0e4..000000000 --- a/cmake/ProjectLibFF.cmake +++ /dev/null @@ -1,44 +0,0 @@ -include(ProjectMPIR) - -set(prefix "${CMAKE_BINARY_DIR}/deps") -set(libff_library "${prefix}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}ff${CMAKE_STATIC_LIBRARY_SUFFIX}") -set(libff_inlcude_dir "${prefix}/include/libff") - -ExternalProject_Add(libff - PREFIX "${prefix}" - DOWNLOAD_NAME libff-03b719a7.tar.gz - DOWNLOAD_NO_PROGRESS TRUE - URL https://github.com/scipr-lab/libff/archive/03b719a7c81757071f99fc60be1f7f7694e51390.tar.gz - URL_HASH SHA256=81b476089af43025c8f253cb1a9b5038a1c375baccffea402fa82042e608ab02 - CMAKE_ARGS - -DCMAKE_BUILD_TYPE=Release - -DCMAKE_INSTALL_PREFIX= - -DGMP_INCLUDE_DIR=${MPIR_INCLUDE_DIR} - -DGMP_LIBRARY=${MPIR_LIBRARY} - -DCURVE=ALT_BN128 -DPERFORMANCE=Off -DWITH_PROCPS=Off - -DUSE_PT_COMPRESSION=Off - -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} - -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} - BUILD_COMMAND ${CMAKE_COMMAND} --build --config Release - LOG_BUILD 1 - INSTALL_COMMAND ${CMAKE_COMMAND} --build --config Release --target install - BUILD_BYPRODUCTS "${libff_library}" -) - -IF( NOT MPIR_FOUND ) - add_dependencies(libff mpir) -ENDIF() - -# Create snark imported library -add_library(libff::ff STATIC IMPORTED) -file(MAKE_DIRECTORY ${libff_inlcude_dir}) -set_property(TARGET libff::ff PROPERTY IMPORTED_CONFIGURATIONS Release) -set_property(TARGET libff::ff PROPERTY IMPORTED_LOCATION_RELEASE ${libff_library}) -set_property(TARGET libff::ff PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${libff_inlcude_dir}) -IF( NOT MPIR_FOUND ) - set_property(TARGET libff::ff PROPERTY INTERFACE_LINK_LIBRARIES MPIR::mpir) -ELSE() - set_property(TARGET libff::ff PROPERTY INTERFACE_LINK_LIBRARIES ${MPIR_LIBRARY}) -ENDIF() - -add_dependencies(libff::ff libff) diff --git a/cmake/ProjectMPIR.cmake b/cmake/ProjectMPIR.cmake deleted file mode 100644 index 0a419e3e5..000000000 --- a/cmake/ProjectMPIR.cmake +++ /dev/null @@ -1,30 +0,0 @@ -IF (NOT LOCALDEPS MATCHES ".*MPIR") - message(STATUS "[retesteth] Will add mpir dependency as external project to compile") - include(ExternalProject) - include(GNUInstallDirs) - - set(prefix "${CMAKE_BINARY_DIR}/deps") - set(MPIR_LIBRARY "${prefix}/${CMAKE_INSTALL_LIBDIR}/${CMAKE_STATIC_LIBRARY_PREFIX}mpir${CMAKE_STATIC_LIBRARY_SUFFIX}") - set(MPIR_INCLUDE_DIR "${prefix}/include") - - ExternalProject_Add(mpir - PREFIX "${prefix}" - DOWNLOAD_NAME mpir-cmake.tar.gz - DOWNLOAD_NO_PROGRESS TRUE - URL https://github.com/chfast/mpir/archive/cmake.tar.gz - URL_HASH SHA256=d32ea73cb2d8115a8e59b244f96f29bad7ff03367162b660bae6495826811e06 - CMAKE_ARGS -DCMAKE_INSTALL_PREFIX= - -DCMAKE_BUILD_TYPE=Release - -DMPIR_GMP=On - BUILD_BYPRODUCTS "${MPIR_LIBRARY}" - ) - - add_library(MPIR::mpir STATIC IMPORTED) - set_property(TARGET MPIR::mpir PROPERTY IMPORTED_CONFIGURATIONS Release) - set_property(TARGET MPIR::mpir PROPERTY IMPORTED_LOCATION_RELEASE ${MPIR_LIBRARY}) - set_property(TARGET MPIR::mpir PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${MPIR_INCLUDE_DIR}) - add_dependencies(MPIR::mpir mpir) -ELSE() - find_package(mpir REQUIRED) -ENDIF() - diff --git a/dretesteth.sh b/dretesteth.sh index 08ffc22f8..8b2ff3a65 100755 --- a/dretesteth.sh +++ b/dretesteth.sh @@ -16,6 +16,7 @@ testpaths=0 testpath="notfound" argstring="" clientsopt=0 +helpversion=0 for var in "$@" do if [ "$var" = "--" ]; then @@ -23,9 +24,10 @@ do argstring=$argstring" "$var continue fi - if [ "$var" = "--help" ]; then + if [ "$var" = "--help" ] || [ "$var" = "--version" ]; then argstring=$argstring" "$var testpath="" + helpversion=1 break; fi if [ "$var" = "--testpath" ] && [ "$separator" -eq "1" ]; then @@ -53,4 +55,8 @@ if [ "$testpath" = "notfound" ]; then exit 1 fi -docker run -v $testpath:/tests retesteth $argstring --testpath /tests $defaultclient +if [ "$helpversion" -eq 1 ]; then + docker run retesteth $argstring +else + docker run -v $testpath:/tests retesteth $argstring --testpath /tests $defaultclient +fi diff --git a/libdataobj/ConvertYaml.cpp b/libdataobj/ConvertYaml.cpp index d03f956a3..27225511a 100644 --- a/libdataobj/ConvertYaml.cpp +++ b/libdataobj/ConvertYaml.cpp @@ -2,6 +2,11 @@ #include using namespace std; +namespace { + string const YML_INT_TAG = "tag:yaml.org,2002:int"; + string const YML_BOOL_TAG = "tag:yaml.org,2002:bool"; +} + namespace dataobject { @@ -33,8 +38,10 @@ spDataObject ConvertYamlToData(YAML::Node const& _node, bool _sort) if (_node.IsScalar()) { - if (_node.Tag() == "tag:yaml.org,2002:int") + if (_node.Tag() == YML_INT_TAG) return spDataObject(new DataObject(_node.as())); + else if (_node.Tag() == YML_BOOL_TAG) + return spDataObject(new DataObject(DataType::Bool, _node.as())); else return spDataObject(new DataObject(_node.as())); } diff --git a/libdataobj/DataObject.cpp b/libdataobj/DataObject.cpp index e5731a1a2..74938d65e 100644 --- a/libdataobj/DataObject.cpp +++ b/libdataobj/DataObject.cpp @@ -13,12 +13,12 @@ DataObject::DataObject() { m_type = DataType::NotInitialized; } DataObject::DataObject(DataType _type) { m_type = _type; } /// Define dataobject of string -DataObject::DataObject(std::string&& _str) : m_strVal(_str) { m_type = DataType::String; } +DataObject::DataObject(std::string&& _str) : m_strVal(std::move(_str)) { m_type = DataType::String; } DataObject::DataObject(std::string const& _str) : m_strVal(_str) { m_type = DataType::String; } /// Define dataobject[_key] = string DataObject::DataObject(std::string&& _key, std::string&& _str) - : m_strKey(_key), m_strVal(_str) + : m_strKey(std::move(_key)), m_strVal(std::move(_str)) { m_type = DataType::String; } @@ -29,7 +29,7 @@ DataObject::DataObject(std::string const& _key, std::string const& _str) } DataObject::DataObject(std::string&& _key, int _val) - : m_strKey(_key), m_intVal(_val) + : m_strKey(std::move(_key)), m_intVal(_val) { m_type = DataType::Integer; } @@ -52,7 +52,7 @@ DataObject::DataObject(DataType type, bool _bool) DataType DataObject::type() const { return m_type; } /// Set key of the dataobject -void DataObject::setKey(std::string&& _key) { m_strKey = _key; } +void DataObject::setKey(std::string&& _key) { m_strKey = std::move(_key); } void DataObject::setKey(std::string const& _key) { m_strKey = _key; } /// Get key of the dataobject @@ -86,7 +86,7 @@ DataObject& DataObject::addSubObject(spDataObject const& _obj) /// Add new subobject and set it's key DataObject& DataObject::addSubObject(std::string&& _key, spDataObject const& _obj) { - return _addSubObject(_obj, std::move(_key)); + return _addSubObject(_obj, std::forward(_key)); } DataObject& DataObject::addSubObject(std::string const& _key, spDataObject const& _obj) { @@ -98,7 +98,7 @@ void DataObject::setSubObjectKey(size_t _index, std::string&& _key) { _assert(_index < m_subObjects.size(), "_index < m_subObjects.size() (DataObject::setSubObjectKey)"); if (m_subObjects.size() > _index) - m_subObjects.at(_index).getContent().setKey(std::move(_key)); + m_subObjects.at(_index).getContent().setKey(std::forward(_key)); } @@ -279,7 +279,7 @@ void DataObject::renameKey(std::string const& _currentKey, std::string&& _newKey { spDataObject data = m_subObjectKeys.at(_currentKey); m_subObjectKeys.erase(_currentKey); - data.getContent().setKey(std::move(_newKey)); + data.getContent().setKey(_newKey); m_subObjectKeys.emplace(_newKey, data); } @@ -352,11 +352,17 @@ void DataObject::performModifier(void (*f)(DataObject&), ModifierOption _opt, st } } -void DataObject::performVerifier(void (*f)(DataObject const&)) const +bool DataObject::performSearch(bool (*f)(DataObject const&)) const { + bool res = true; for (auto const& el : m_subObjects) - el->performVerifier(f); - f(*this); + { + res = res && !el->performSearch(f); + if (false) + break; + } + res = res && !f(*this); + return !res; } std::string DataObject::asJsonNoFirstKey() const @@ -599,13 +605,13 @@ DataObject& DataObject::_addSubObject(spDataObject const& _obj, string&& _keyOve m_type = DataType::Object; size_t pos; - string const* key = _keyOverwrite.empty() ? &_obj->getKey() : &_keyOverwrite; - if (key->empty() || !m_autosort) + string const key = _keyOverwrite.empty() ? _obj->getKey() : _keyOverwrite; + if (key.empty() || !m_autosort) { m_subObjects.push_back(_obj); pos = m_subObjects.size() - 1; if (!_keyOverwrite.empty()) - setSubObjectKey(pos, std::move(_keyOverwrite)); + setSubObjectKey(pos, std::forward(_keyOverwrite)); else setSubObjectKey(pos, string(_obj->getKey())); m_subObjects.at(pos).getContent().setOverwrite(m_allowOverwrite); @@ -615,7 +621,7 @@ DataObject& DataObject::_addSubObject(spDataObject const& _obj, string&& _keyOve { // find ordered position to insert key // better use it only when export as ordered json !!! - pos = findOrderedKeyPosition(*key, m_subObjects); + pos = findOrderedKeyPosition(key, m_subObjects); if (pos == m_subObjects.size()) m_subObjects.push_back(_obj); else @@ -626,14 +632,14 @@ DataObject& DataObject::_addSubObject(spDataObject const& _obj, string&& _keyOve } if (!_keyOverwrite.empty()) - m_subObjects.at(pos).getContent().setKey(std::move(_keyOverwrite)); + m_subObjects.at(pos).getContent().setKey(std::forward(_keyOverwrite)); else m_subObjects.at(pos).getContent().setKey(string(_obj->getKey())); m_subObjects.at(pos).getContent().setOverwrite(true); m_subObjects.at(pos).getContent().setAutosort(m_autosort); } - if (!key->empty()) - m_subObjectKeys.emplace(*key, m_subObjects.at(pos)); + if (!key.empty()) + m_subObjectKeys.emplace(key, m_subObjects.at(pos)); return m_subObjects.at(pos).getContent(); } @@ -656,7 +662,7 @@ void DataObject::setString(string&& _value) _assert(m_type == DataType::String || m_type == DataType::NotInitialized, "In DataObject=(string) DataObject must be string or NotInitialized!"); m_type = DataType::String; - m_strVal = _value; + m_strVal = std::move(_value); } void DataObject::setInt(int _value) @@ -846,7 +852,7 @@ DataObject& DataObject::operator[](std::string&& _key) return m_subObjectKeys.at(_key).getContent(); spDataObject newObj(new DataObject(DataType::NotInitialized)); - newObj.getContent().setKey(std::move(_key)); + newObj.getContent().setKey(std::forward(_key)); return _addSubObject(newObj); // !could change the item order! } @@ -855,7 +861,7 @@ DataObject& DataObject::operator=(std::string&& _value) _assert(m_type == DataType::String || m_type == DataType::NotInitialized, "In DataObject=(string) DataObject must be string or NotInitialized!"); m_type = DataType::String; - m_strVal = _value; + m_strVal = std::move(_value); return *this; } diff --git a/libdataobj/DataObject.h b/libdataobj/DataObject.h index ef0d9f0b5..f936055fd 100644 --- a/libdataobj/DataObject.h +++ b/libdataobj/DataObject.h @@ -105,7 +105,7 @@ class DataObject : public GCP_SPointerBase }; void performModifier(void (*f)(DataObject&), ModifierOption _opt = ModifierOption::RECURSIVE, std::set const& _exceptionKeys = {}); - void performVerifier(void (*f)(DataObject const&)) const; + bool performSearch(bool (*f)(DataObject const&)) const; void clear(DataType _type = DataType::NotInitialized); diff --git a/libdevcrypto/AES.cpp b/libdevcrypto/AES.cpp deleted file mode 100644 index c4320ff2d..000000000 --- a/libdevcrypto/AES.cpp +++ /dev/null @@ -1,60 +0,0 @@ -/* - This file is part of cpp-ethereum. - - cpp-ethereum is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - cpp-ethereum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with cpp-ethereum. If not, see . - */ -/** @file AES.cpp - * @author Alex Leverington - * @date 2014 - */ - -#include "AES.h" -#include -#include -#include -#include -#include - -using namespace dev; -using namespace dev::crypto; - -bytes dev::aesDecrypt(bytesConstRef _ivCipher, std::string const& _password, unsigned _rounds, bytesConstRef _salt) -{ - bytes pw = asBytes(_password); - - if (!_salt.size()) - _salt = &pw; - - bytes target(64); - CryptoPP::PKCS5_PBKDF2_HMAC().DeriveKey(target.data(), target.size(), 0, pw.data(), pw.size(), _salt.data(), _salt.size(), _rounds); - - try - { - CryptoPP::AES::Decryption aesDecryption(target.data(), 16); - auto cipher = _ivCipher.cropped(16); - auto iv = _ivCipher.cropped(0, 16); - CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcDecryption(aesDecryption, iv.data()); - std::string decrypted; - CryptoPP::StreamTransformationFilter stfDecryptor(cbcDecryption, new CryptoPP::StringSink(decrypted)); - stfDecryptor.Put(cipher.data(), cipher.size()); - stfDecryptor.MessageEnd(); - return asBytes(decrypted); - } - catch (std::exception const& e) - { - // FIXME: Handle this error better. - std::cerr << e.what() << '\n'; - return bytes(); - } -} diff --git a/libdevcrypto/AES.h b/libdevcrypto/AES.h deleted file mode 100644 index 6f72369f6..000000000 --- a/libdevcrypto/AES.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - This file is part of cpp-ethereum. - - cpp-ethereum is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - cpp-ethereum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with cpp-ethereum. If not, see . - */ -/** @file AES.h - * @author Alex Leverington - * @date 2014 - * - * AES - * todo: use openssl - */ - -#pragma once - -#include "Common.h" - -namespace dev -{ - -bytes aesDecrypt(bytesConstRef _cipher, std::string const& _password, unsigned _rounds = 2000, bytesConstRef _salt = bytesConstRef()); - -} diff --git a/libdevcrypto/CMakeLists.txt b/libdevcrypto/CMakeLists.txt index f22e6f917..a1dc73c07 100644 --- a/libdevcrypto/CMakeLists.txt +++ b/libdevcrypto/CMakeLists.txt @@ -4,5 +4,5 @@ file(GLOB HEADERS "*.h") add_library(devcrypto ${SOURCES} ${HEADERS}) target_include_directories(devcrypto SYSTEM PRIVATE "../") -target_include_directories(devcrypto SYSTEM PUBLIC ${CRYPTOPP_INCLUDE_DIRS}) -target_link_libraries(devcrypto PUBLIC devcore Secp256k1 PRIVATE libff::ff ${CRYPTOPP_LINK} libscrypt::scrypt) +target_link_libraries(devcrypto PUBLIC devcore Secp256k1) + diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index 1f416e7f0..acbebbc44 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -23,22 +23,11 @@ #include // conflicts with #include "Common.h" #include -#include #include -#include -#include -#include -#include -#include -#include #include #include -#include "AES.h" -#include "CryptoPP.h" -#include "Exceptions.h" using namespace std; using namespace dev; -using namespace dev::crypto; namespace { @@ -94,107 +83,6 @@ Address dev::toAddress(Address const& _from, u256 const& _nonce) return right160(sha3(rlpList(_from, _nonce))); } -void dev::encrypt(Public const& _k, bytesConstRef _plain, bytes& o_cipher) -{ - bytes io = _plain.toBytes(); - Secp256k1PP::get()->encrypt(_k, io); - o_cipher = std::move(io); -} - -bool dev::decrypt(Secret const& _k, bytesConstRef _cipher, bytes& o_plaintext) -{ - bytes io = _cipher.toBytes(); - Secp256k1PP::get()->decrypt(_k, io); - if (io.empty()) - return false; - o_plaintext = std::move(io); - return true; -} - -void dev::encryptECIES(Public const& _k, bytesConstRef _plain, bytes& o_cipher) -{ - encryptECIES(_k, bytesConstRef(), _plain, o_cipher); -} - -void dev::encryptECIES(Public const& _k, bytesConstRef _sharedMacData, bytesConstRef _plain, bytes& o_cipher) -{ - bytes io = _plain.toBytes(); - Secp256k1PP::get()->encryptECIES(_k, _sharedMacData, io); - o_cipher = std::move(io); -} - -bool dev::decryptECIES(Secret const& _k, bytesConstRef _cipher, bytes& o_plaintext) -{ - return decryptECIES(_k, bytesConstRef(), _cipher, o_plaintext); -} - -bool dev::decryptECIES(Secret const& _k, bytesConstRef _sharedMacData, bytesConstRef _cipher, bytes& o_plaintext) -{ - bytes io = _cipher.toBytes(); - if (!Secp256k1PP::get()->decryptECIES(_k, _sharedMacData, io)) - return false; - o_plaintext = std::move(io); - return true; -} - -void dev::encryptSym(Secret const& _k, bytesConstRef _plain, bytes& o_cipher) -{ - // TODO: @alex @subtly do this properly. - encrypt(KeyPair(_k).pub(), _plain, o_cipher); -} - -bool dev::decryptSym(Secret const& _k, bytesConstRef _cipher, bytes& o_plain) -{ - // TODO: @alex @subtly do this properly. - return decrypt(_k, _cipher, o_plain); -} - -std::pair dev::encryptSymNoAuth(SecureFixedHash<16> const& _k, bytesConstRef _plain) -{ - h128 iv(Nonce::get().makeInsecure()); - return make_pair(encryptSymNoAuth(_k, iv, _plain), iv); -} - -bytes dev::encryptAES128CTR(bytesConstRef _k, h128 const& _iv, bytesConstRef _plain) -{ - if (_k.size() != 16 && _k.size() != 24 && _k.size() != 32) - return bytes(); - CryptoPP::SecByteBlock key(_k.data(), _k.size()); - try - { - CryptoPP::CTR_Mode::Encryption e; - e.SetKeyWithIV(key, key.size(), _iv.data()); - bytes ret(_plain.size()); - e.ProcessData(ret.data(), _plain.data(), _plain.size()); - return ret; - } - catch (CryptoPP::Exception& _e) - { - cerr << _e.what() << endl; - return bytes(); - } -} - -bytesSec dev::decryptAES128CTR(bytesConstRef _k, h128 const& _iv, bytesConstRef _cipher) -{ - if (_k.size() != 16 && _k.size() != 24 && _k.size() != 32) - return bytesSec(); - CryptoPP::SecByteBlock key(_k.data(), _k.size()); - try - { - CryptoPP::CTR_Mode::Decryption d; - d.SetKeyWithIV(key, key.size(), _iv.data()); - bytesSec ret(_cipher.size()); - d.ProcessData(ret.writable().data(), _cipher.data(), _cipher.size()); - return ret; - } - catch (CryptoPP::Exception& _e) - { - cerr << _e.what() << endl; - return bytesSec(); - } -} - Public dev::recover(Signature const& _sig, h256 const& _message) { int v = _sig[64]; @@ -252,119 +140,3 @@ bool dev::verify(Public const& _p, Signature const& _s, h256 const& _hash) return false; return _p == recover(_s, _hash); } - -bytesSec dev::pbkdf2(string const& _pass, bytes const& _salt, unsigned _iterations, unsigned _dkLen) -{ - bytesSec ret(_dkLen); - if (CryptoPP::PKCS5_PBKDF2_HMAC().DeriveKey(ret.writable().data(), _dkLen, 0, - reinterpret_cast(_pass.data()), _pass.size(), _salt.data(), _salt.size(), - _iterations) != _iterations) - BOOST_THROW_EXCEPTION(CryptoException() << errinfo_comment("Key derivation failed.")); - return ret; -} - -bytesSec dev::scrypt(std::string const& _pass, bytes const& _salt, uint64_t _n, uint32_t _r, uint32_t _p, unsigned _dkLen) -{ - bytesSec ret(_dkLen); - if (libscrypt_scrypt(reinterpret_cast(_pass.data()), _pass.size(), _salt.data(), - _salt.size(), _n, _r, _p, ret.writable().data(), _dkLen) != 0) - BOOST_THROW_EXCEPTION(CryptoException() << errinfo_comment("Key derivation failed.")); - return ret; -} - -KeyPair::KeyPair(Secret const& _sec) : m_secret(_sec), m_public(toPublic(_sec)) -{ - // Assign address only if the secret key is valid. - if (m_public) - m_address = toAddress(m_public); -} - -KeyPair KeyPair::create() -{ - while (true) - { - KeyPair keyPair(Secret::random()); - if (keyPair.address()) - return keyPair; - } -} - -KeyPair KeyPair::fromEncryptedSeed(bytesConstRef _seed, std::string const& _password) -{ - return KeyPair(Secret(sha3(aesDecrypt(_seed, _password)))); -} - -h256 crypto::kdf(Secret const& _priv, h256 const& _hash) -{ - // H(H(r||k)^h) - h256 s; - sha3mac(Secret::random().ref(), _priv.ref(), s.ref()); - s ^= _hash; - sha3(s.ref(), s.ref()); - - if (!s || !_hash || !_priv) - BOOST_THROW_EXCEPTION(InvalidState()); - return s; -} - -Secret Nonce::next() -{ - Guard l(x_value); - if (!m_value) - { - m_value = Secret::random(); - if (!m_value) - BOOST_THROW_EXCEPTION(InvalidState()); - } - m_value = sha3Secure(m_value.ref()); - return sha3(~m_value); -} - -bool ecdh::agree(Secret const& _s, Public const& _r, Secret& o_s) noexcept -{ - auto* ctx = getCtx(); - static_assert(sizeof(Secret) == 32, "Invalid Secret type size"); - secp256k1_pubkey rawPubkey; - std::array serializedPubKey{{0x04}}; - std::copy(_r.asArray().begin(), _r.asArray().end(), serializedPubKey.begin() + 1); - if (!secp256k1_ec_pubkey_parse( - ctx, &rawPubkey, serializedPubKey.data(), serializedPubKey.size())) - return false; // Invalid public key. - // FIXME: We should verify the public key when constructed, maybe even keep - // secp256k1_pubkey as the internal data of Public. - std::array compressedPoint; - if (!secp256k1_ecdh_raw(ctx, compressedPoint.data(), &rawPubkey, _s.data())) - return false; // Invalid secret key. - std::copy(compressedPoint.begin() + 1, compressedPoint.end(), o_s.writable().data()); - return true; -} - -bytes ecies::kdf(Secret const& _z, bytes const& _s1, unsigned kdByteLen) -{ - auto reps = ((kdByteLen + 7) * 8) / 512; - // SEC/ISO/Shoup specify counter size SHOULD be equivalent - // to size of hash output, however, it also notes that - // the 4 bytes is okay. NIST specifies 4 bytes. - std::array ctr{{0, 0, 0, 1}}; - bytes k; - secp256k1_sha256_t ctx; - for (unsigned i = 0; i <= reps; i++) - { - secp256k1_sha256_initialize(&ctx); - secp256k1_sha256_write(&ctx, ctr.data(), ctr.size()); - secp256k1_sha256_write(&ctx, _z.data(), Secret::size); - secp256k1_sha256_write(&ctx, _s1.data(), _s1.size()); - // append hash to k - std::array digest; - secp256k1_sha256_finalize(&ctx, digest.data()); - - k.reserve(k.size() + h256::size); - move(digest.begin(), digest.end(), back_inserter(k)); - - if (++ctr[3] || ++ctr[2] || ++ctr[1] || ++ctr[0]) - continue; - } - - k.resize(kdByteLen); - return k; -} diff --git a/libdevcrypto/Common.h b/libdevcrypto/Common.h index bd1c54598..265b58e9b 100644 --- a/libdevcrypto/Common.h +++ b/libdevcrypto/Common.h @@ -24,10 +24,8 @@ #pragma once -#include #include #include -#include #include namespace dev @@ -58,9 +56,6 @@ struct SignatureStruct byte v = 0; }; -/// A vector of secrets. -using Secrets = std::vector; - /// Convert a secret key into the public key equivalent. Public toPublic(Secret const& _secret); @@ -74,49 +69,6 @@ Address toAddress(Secret const& _secret); // Convert transaction from and nonce to address. Address toAddress(Address const& _from, u256 const& _nonce); -/// Encrypts plain text using Public key. -void encrypt(Public const& _k, bytesConstRef _plain, bytes& o_cipher); - -/// Decrypts cipher using Secret key. -bool decrypt(Secret const& _k, bytesConstRef _cipher, bytes& o_plaintext); - -/// Symmetric encryption. -void encryptSym(Secret const& _k, bytesConstRef _plain, bytes& o_cipher); - -/// Symmetric decryption. -bool decryptSym(Secret const& _k, bytesConstRef _cipher, bytes& o_plaintext); - -/// Encrypt payload using ECIES standard with AES128-CTR. -void encryptECIES(Public const& _k, bytesConstRef _plain, bytes& o_cipher); - -/// Encrypt payload using ECIES standard with AES128-CTR. -/// @a _sharedMacData is shared authenticated data. -void encryptECIES(Public const& _k, bytesConstRef _sharedMacData, bytesConstRef _plain, bytes& o_cipher); - -/// Decrypt payload using ECIES standard with AES128-CTR. -bool decryptECIES(Secret const& _k, bytesConstRef _cipher, bytes& o_plaintext); - -/// Decrypt payload using ECIES standard with AES128-CTR. -/// @a _sharedMacData is shared authenticated data. -bool decryptECIES(Secret const& _k, bytesConstRef _sharedMacData, bytesConstRef _cipher, bytes& o_plaintext); - -/// Encrypts payload with random IV/ctr using AES128-CTR. -std::pair encryptSymNoAuth(SecureFixedHash<16> const& _k, bytesConstRef _plain); - -/// Encrypts payload with specified IV/ctr using AES128-CTR. -bytes encryptAES128CTR(bytesConstRef _k, h128 const& _iv, bytesConstRef _plain); - -/// Decrypts payload with specified IV/ctr using AES128-CTR. -bytesSec decryptAES128CTR(bytesConstRef _k, h128 const& _iv, bytesConstRef _cipher); - -/// Encrypts payload with specified IV/ctr using AES128-CTR. -inline bytes encryptSymNoAuth(SecureFixedHash<16> const& _k, h128 const& _iv, bytesConstRef _plain) { return encryptAES128CTR(_k.ref(), _iv, _plain); } -inline bytes encryptSymNoAuth(SecureFixedHash<32> const& _k, h128 const& _iv, bytesConstRef _plain) { return encryptAES128CTR(_k.ref(), _iv, _plain); } - -/// Decrypts payload with specified IV/ctr using AES128-CTR. -inline bytesSec decryptSymNoAuth(SecureFixedHash<16> const& _k, h128 const& _iv, bytesConstRef _cipher) { return decryptAES128CTR(_k.ref(), _iv, _cipher); } -inline bytesSec decryptSymNoAuth(SecureFixedHash<32> const& _k, h128 const& _iv, bytesConstRef _cipher) { return decryptAES128CTR(_k.ref(), _iv, _cipher); } - /// Recovers Public key from signed message hash. Public recover(Signature const& _sig, h256 const& _hash); @@ -125,92 +77,4 @@ Signature sign(Secret const& _k, h256 const& _hash); /// Verify signature. bool verify(Public const& _k, Signature const& _s, h256 const& _hash); - -/// Derive key via PBKDF2. -bytesSec pbkdf2(std::string const& _pass, bytes const& _salt, unsigned _iterations, unsigned _dkLen = 32); - -/// Derive key via Scrypt. -bytesSec scrypt(std::string const& _pass, bytes const& _salt, uint64_t _n, uint32_t _r, uint32_t _p, unsigned _dkLen); - -/// Simple class that represents a "key pair". -/// All of the data of the class can be regenerated from the secret key (m_secret) alone. -/// Actually stores a tuplet of secret, public and address (the right 160-bits of the public). -class KeyPair -{ -public: - /// Normal constructor - populates object from the given secret key. - /// If the secret key is invalid the constructor succeeds, but public key - /// and address stay "null". - KeyPair(Secret const& _sec); - - /// Create a new, randomly generated object. - static KeyPair create(); - - /// Create from an encrypted seed. - static KeyPair fromEncryptedSeed(bytesConstRef _seed, std::string const& _password); - - Secret const& secret() const { return m_secret; } - - /// Retrieve the public key. - Public const& pub() const { return m_public; } - - /// Retrieve the associated address of the public key. - Address const& address() const { return m_address; } - - bool operator==(KeyPair const& _c) const { return m_public == _c.m_public; } - bool operator!=(KeyPair const& _c) const { return m_public != _c.m_public; } - -private: - Secret m_secret; - Public m_public; - Address m_address; -}; - -namespace crypto -{ - -DEV_SIMPLE_EXCEPTION(InvalidState); - -/// Key derivation -h256 kdf(Secret const& _priv, h256 const& _hash); - -/** - * @brief Generator for non-repeating nonce material. - * The Nonce class should only be used when a non-repeating nonce - * is required and, in its current form, not recommended for signatures. - * This is primarily because the key-material for signatures is - * encrypted on disk whereas the seed for Nonce is not. - * Thus, Nonce's primary intended use at this time is for networking - * where the key is also stored in plaintext. - */ -class Nonce -{ -public: - /// Returns the next nonce (might be read from a file). - static Secret get() { static Nonce s; return s.next(); } - -private: - Nonce() = default; - - /// @returns the next nonce. - Secret next(); - - std::mutex x_value; - Secret m_value; -}; - -namespace ecdh -{ - -bool agree(Secret const& _s, Public const& _r, Secret& o_s) noexcept; - -} - -namespace ecies -{ - -bytes kdf(Secret const& _z, bytes const& _s1, unsigned kdByteLen); - -} -} } diff --git a/libdevcrypto/CryptoPP.cpp b/libdevcrypto/CryptoPP.cpp deleted file mode 100644 index 0b5f6e87d..000000000 --- a/libdevcrypto/CryptoPP.cpp +++ /dev/null @@ -1,251 +0,0 @@ -/* - This file is part of cpp-ethereum. - - cpp-ethereum is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - cpp-ethereum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with cpp-ethereum. If not, see . - */ -/** @file CryptoPP.cpp - * @author Alex Leverington - * @date 2014 - */ - -#include // conflicts with -#include "CryptoPP.h" -#include -#include -#include -#include -#include - -static_assert(CRYPTOPP_VERSION >= 820, "Wrong Crypto++ version"); - -using namespace dev; -using namespace dev::crypto; - -static_assert(dev::Secret::size == 32, "Secret key must be 32 bytes."); -static_assert(dev::Public::size == 64, "Public key must be 64 bytes."); -static_assert(dev::Signature::size == 65, "Signature must be 65 bytes."); - -namespace -{ -class Secp256k1PPCtx -{ -public: - CryptoPP::OID m_oid; - - std::mutex x_rng; - CryptoPP::AutoSeededRandomPool m_rng; - - std::mutex x_params; - CryptoPP::DL_GroupParameters_EC m_params; - - CryptoPP::DL_GroupParameters_EC::EllipticCurve m_curve; - - CryptoPP::Integer m_q; - CryptoPP::Integer m_qs; - - static Secp256k1PPCtx& get() - { - static Secp256k1PPCtx ctx; - return ctx; - } - -private: - Secp256k1PPCtx(): - m_oid(CryptoPP::ASN1::secp256k1()), m_params(m_oid), m_curve(m_params.GetCurve()), - m_q(m_params.GetGroupOrder()), m_qs(m_params.GetSubgroupOrder()) - {} -}; - -inline CryptoPP::ECP::Point publicToPoint(Public const& _p) { CryptoPP::Integer x(_p.data(), 32); CryptoPP::Integer y(_p.data() + 32, 32); return CryptoPP::ECP::Point(x,y); } - -inline CryptoPP::Integer secretToExponent(Secret const& _s) { return CryptoPP::Integer(_s.data(), Secret::size); } - -} - -Secp256k1PP* Secp256k1PP::get() -{ - static Secp256k1PP s_this; - return &s_this; -} - -void Secp256k1PP::encryptECIES(Public const& _k, bytes& io_cipher) -{ - encryptECIES(_k, bytesConstRef(), io_cipher); -} - -void Secp256k1PP::encryptECIES(Public const& _k, bytesConstRef _sharedMacData, bytes& io_cipher) -{ - // interop w/go ecies implementation - auto r = KeyPair::create(); - Secret z; - ecdh::agree(r.secret(), _k, z); - auto key = ecies::kdf(z, bytes(), 32); - bytesConstRef eKey = bytesConstRef(&key).cropped(0, 16); - bytesRef mKeyMaterial = bytesRef(&key).cropped(16, 16); - CryptoPP::SHA256 ctx; - ctx.Update(mKeyMaterial.data(), mKeyMaterial.size()); - bytes mKey(32); - ctx.Final(mKey.data()); - - auto iv = h128::random(); - bytes cipherText = encryptSymNoAuth(SecureFixedHash<16>(eKey), iv, bytesConstRef(&io_cipher)); - if (cipherText.empty()) - return; - - bytes msg(1 + Public::size + h128::size + cipherText.size() + 32); - msg[0] = 0x04; - r.pub().ref().copyTo(bytesRef(&msg).cropped(1, Public::size)); - iv.ref().copyTo(bytesRef(&msg).cropped(1 + Public::size, h128::size)); - bytesRef msgCipherRef = bytesRef(&msg).cropped(1 + Public::size + h128::size, cipherText.size()); - bytesConstRef(&cipherText).copyTo(msgCipherRef); - - // tag message - CryptoPP::HMAC hmacctx(mKey.data(), mKey.size()); - bytesConstRef cipherWithIV = bytesRef(&msg).cropped(1 + Public::size, h128::size + cipherText.size()); - hmacctx.Update(cipherWithIV.data(), cipherWithIV.size()); - hmacctx.Update(_sharedMacData.data(), _sharedMacData.size()); - hmacctx.Final(msg.data() + 1 + Public::size + cipherWithIV.size()); - - io_cipher.resize(msg.size()); - io_cipher.swap(msg); -} - -bool Secp256k1PP::decryptECIES(Secret const& _k, bytes& io_text) -{ - return decryptECIES(_k, bytesConstRef(), io_text); -} - -bool Secp256k1PP::decryptECIES(Secret const& _k, bytesConstRef _sharedMacData, bytes& io_text) -{ - - // interop w/go ecies implementation - - // io_cipher[0] must be 2, 3, or 4, else invalidpublickey - if (io_text.empty() || io_text[0] < 2 || io_text[0] > 4) - // invalid message: publickey - return false; - - if (io_text.size() < (1 + Public::size + h128::size + 1 + h256::size)) - // invalid message: length - return false; - - Secret z; - if (!ecdh::agree(_k, *(Public*)(io_text.data() + 1), z)) - return false; // Invalid pubkey or seckey. - auto key = ecies::kdf(z, bytes(), 64); - bytesConstRef eKey = bytesConstRef(&key).cropped(0, 16); - bytesRef mKeyMaterial = bytesRef(&key).cropped(16, 16); - bytes mKey(32); - CryptoPP::SHA256 ctx; - ctx.Update(mKeyMaterial.data(), mKeyMaterial.size()); - ctx.Final(mKey.data()); - - bytes plain; - size_t cipherLen = io_text.size() - 1 - Public::size - h128::size - h256::size; - bytesConstRef cipherWithIV(io_text.data() + 1 + Public::size, h128::size + cipherLen); - bytesConstRef cipherIV = cipherWithIV.cropped(0, h128::size); - bytesConstRef cipherNoIV = cipherWithIV.cropped(h128::size, cipherLen); - bytesConstRef msgMac(cipherNoIV.data() + cipherLen, h256::size); - h128 iv(cipherIV.toBytes()); - - // verify tag - CryptoPP::HMAC hmacctx(mKey.data(), mKey.size()); - hmacctx.Update(cipherWithIV.data(), cipherWithIV.size()); - hmacctx.Update(_sharedMacData.data(), _sharedMacData.size()); - h256 mac; - hmacctx.Final(mac.data()); - for (unsigned i = 0; i < h256::size; i++) - if (mac[i] != msgMac[i]) - return false; - - plain = decryptSymNoAuth(SecureFixedHash<16>(eKey), iv, cipherNoIV).makeInsecure(); - io_text.resize(plain.size()); - io_text.swap(plain); - - return true; -} - -void Secp256k1PP::encrypt(Public const& _k, bytes& io_cipher) -{ - auto& ctx = Secp256k1PPCtx::get(); - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - CryptoPP::ECIES::Encryptor e; -#pragma GCC diagnostic pop -#pragma clang diagnostic pop - - { - Guard l(ctx.x_params); - e.AccessKey().Initialize(ctx.m_params, publicToPoint(_k)); - } - - - size_t plen = io_cipher.size(); - bytes ciphertext; - ciphertext.resize(e.CiphertextLength(plen)); - - { - Guard l(ctx.x_rng); - e.Encrypt(ctx.m_rng, io_cipher.data(), plen, ciphertext.data()); - } - - memset(io_cipher.data(), 0, io_cipher.size()); - io_cipher = std::move(ciphertext); -} - -void Secp256k1PP::decrypt(Secret const& _k, bytes& io_text) -{ - auto& ctx = Secp256k1PPCtx::get(); - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - CryptoPP::ECIES::Decryptor d; -#pragma GCC diagnostic pop -#pragma clang diagnostic pop - - { - Guard l(ctx.x_params); - d.AccessKey().Initialize(ctx.m_params, secretToExponent(_k)); - } - - if (!io_text.size()) - { - io_text.resize(1); - io_text[0] = 0; - } - - size_t clen = io_text.size(); - bytes plain; - plain.resize(d.MaxPlaintextLength(io_text.size())); - - CryptoPP::DecodingResult r; - { - Guard l(ctx.x_rng); - r = d.Decrypt(ctx.m_rng, io_text.data(), clen, plain.data()); - } - - if (!r.isValidCoding) - { - io_text.clear(); - return; - } - - io_text.resize(r.messageLength); - io_text = std::move(plain); -} diff --git a/libdevcrypto/CryptoPP.h b/libdevcrypto/CryptoPP.h deleted file mode 100644 index f5affa715..000000000 --- a/libdevcrypto/CryptoPP.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - This file is part of cpp-ethereum. - - cpp-ethereum is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - cpp-ethereum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with cpp-ethereum. If not, see . - */ -/** @file CryptoPP.h - * @author Alex Leverington - * @date 2014 - * - * CryptoPP headers and primitive helper methods - */ - -#pragma once - -#include "Common.h" - -namespace dev -{ -namespace crypto -{ -/// Amount of bytes added when encrypting with encryptECIES. -static const unsigned c_eciesOverhead = 113; - -/** - * CryptoPP secp256k1 algorithms. - * @todo Collect ECIES methods into class. - */ -class Secp256k1PP -{ -public: - static Secp256k1PP* get(); - - /// Encrypts text (replace input). (ECIES w/XOR-SHA1) - void encrypt(Public const& _k, bytes& io_cipher); - - /// Decrypts text (replace input). (ECIES w/XOR-SHA1) - void decrypt(Secret const& _k, bytes& io_text); - - /// Encrypts text (replace input). (ECIES w/AES128-CTR-SHA256) - void encryptECIES(Public const& _k, bytes& io_cipher); - - /// Encrypts text (replace input). (ECIES w/AES128-CTR-SHA256) - void encryptECIES(Public const& _k, bytesConstRef _sharedMacData, bytes& io_cipher); - - /// Decrypts text (replace input). (ECIES w/AES128-CTR-SHA256) - bool decryptECIES(Secret const& _k, bytes& io_text); - - /// Decrypts text (replace input). (ECIES w/AES128-CTR-SHA256) - bool decryptECIES(Secret const& _k, bytesConstRef _sharedMacData, bytes& io_text); - -private: - Secp256k1PP() = default; -}; - -} -} - diff --git a/libdevcrypto/Exceptions.h b/libdevcrypto/Exceptions.h deleted file mode 100644 index 858374bda..000000000 --- a/libdevcrypto/Exceptions.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - This file is part of cpp-ethereum. - - cpp-ethereum is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - cpp-ethereum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with cpp-ethereum. If not, see . -*/ -/** @file Exceptions.h - * @author Christian - * @date 2016 - */ - -#pragma once - -#include - -namespace dev -{ -namespace crypto -{ - -/// Rare malfunction of cryptographic functions. -DEV_SIMPLE_EXCEPTION(CryptoException); - -} -} diff --git a/libdevcrypto/Hash.cpp b/libdevcrypto/Hash.cpp deleted file mode 100644 index c4c6cab38..000000000 --- a/libdevcrypto/Hash.cpp +++ /dev/null @@ -1,440 +0,0 @@ -/* - This file is part of cpp-ethereum. - - cpp-ethereum is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - cpp-ethereum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with cpp-ethereum. If not, see . -*/ -/** @file Hash.cpp - * @author Gav Wood - * @date 2014 - */ - -#include "Hash.h" -#include - -using namespace dev; - -namespace dev -{ - -h256 sha256(bytesConstRef _input) noexcept -{ - secp256k1_sha256_t ctx; - secp256k1_sha256_initialize(&ctx); - secp256k1_sha256_write(&ctx, _input.data(), _input.size()); - h256 hash; - secp256k1_sha256_finalize(&ctx, hash.data()); - return hash; -} - -namespace rmd160 -{ - -/********************************************************************\ - * - * FILE: rmd160.h - * FILE: rmd160.c - * - * CONTENTS: Header file for a sample C-implementation of the - * RIPEMD-160 hash-function. - * TARGET: any computer with an ANSI C compiler - * - * AUTHOR: Antoon Bosselaers, ESAT-COSIC - * DATE: 1 March 1996 - * VERSION: 1.0 - * - * Copyright (c) Katholieke Universiteit Leuven - * 1996, All Rights Reserved - * - \********************************************************************/ - -// Adapted into "header-only" format by Gav Wood. - -/* macro definitions */ - -#define RMDsize 160 - -/* collect four bytes into one word: */ -#define BYTES_TO_DWORD(strptr) \ -(((uint32_t) *((strptr)+3) << 24) | \ -((uint32_t) *((strptr)+2) << 16) | \ -((uint32_t) *((strptr)+1) << 8) | \ -((uint32_t) *(strptr))) - -/* ROL(x, n) cyclically rotates x over n bits to the left */ -/* x must be of an unsigned 32 bits type and 0 <= n < 32. */ -#define ROL(x, n) (((x) << (n)) | ((x) >> (32-(n)))) - -/* the five basic functions F(), G() and H() */ -#define F(x, y, z) ((x) ^ (y) ^ (z)) -#define G(x, y, z) (((x) & (y)) | (~(x) & (z))) -#define H(x, y, z) (((x) | ~(y)) ^ (z)) -#define I(x, y, z) (((x) & (z)) | ((y) & ~(z))) -#define J(x, y, z) ((x) ^ ((y) | ~(z))) - -/* the ten basic operations FF() through III() */ -#define FF(a, b, c, d, e, x, s) {\ -(a) += F((b), (c), (d)) + (x);\ -(a) = ROL((a), (s)) + (e);\ -(c) = ROL((c), 10);\ -} -#define GG(a, b, c, d, e, x, s) {\ -(a) += G((b), (c), (d)) + (x) + 0x5a827999UL;\ -(a) = ROL((a), (s)) + (e);\ -(c) = ROL((c), 10);\ -} -#define HH(a, b, c, d, e, x, s) {\ -(a) += H((b), (c), (d)) + (x) + 0x6ed9eba1UL;\ -(a) = ROL((a), (s)) + (e);\ -(c) = ROL((c), 10);\ -} -#define II(a, b, c, d, e, x, s) {\ -(a) += I((b), (c), (d)) + (x) + 0x8f1bbcdcUL;\ -(a) = ROL((a), (s)) + (e);\ -(c) = ROL((c), 10);\ -} -#define JJ(a, b, c, d, e, x, s) {\ -(a) += J((b), (c), (d)) + (x) + 0xa953fd4eUL;\ -(a) = ROL((a), (s)) + (e);\ -(c) = ROL((c), 10);\ -} -#define FFF(a, b, c, d, e, x, s) {\ -(a) += F((b), (c), (d)) + (x);\ -(a) = ROL((a), (s)) + (e);\ -(c) = ROL((c), 10);\ -} -#define GGG(a, b, c, d, e, x, s) {\ -(a) += G((b), (c), (d)) + (x) + 0x7a6d76e9UL;\ -(a) = ROL((a), (s)) + (e);\ -(c) = ROL((c), 10);\ -} -#define HHH(a, b, c, d, e, x, s) {\ -(a) += H((b), (c), (d)) + (x) + 0x6d703ef3UL;\ -(a) = ROL((a), (s)) + (e);\ -(c) = ROL((c), 10);\ -} -#define III(a, b, c, d, e, x, s) {\ -(a) += I((b), (c), (d)) + (x) + 0x5c4dd124UL;\ -(a) = ROL((a), (s)) + (e);\ -(c) = ROL((c), 10);\ -} -#define JJJ(a, b, c, d, e, x, s) {\ -(a) += J((b), (c), (d)) + (x) + 0x50a28be6UL;\ -(a) = ROL((a), (s)) + (e);\ -(c) = ROL((c), 10);\ -} - -void MDinit(uint32_t *MDbuf) -{ - MDbuf[0] = 0x67452301UL; - MDbuf[1] = 0xefcdab89UL; - MDbuf[2] = 0x98badcfeUL; - MDbuf[3] = 0x10325476UL; - MDbuf[4] = 0xc3d2e1f0UL; - - return; -} - -/********************************************************************/ - -void MDcompress(uint32_t *MDbuf, uint32_t *X) -{ - uint32_t aa = MDbuf[0], bb = MDbuf[1], cc = MDbuf[2], - dd = MDbuf[3], ee = MDbuf[4]; - uint32_t aaa = MDbuf[0], bbb = MDbuf[1], ccc = MDbuf[2], - ddd = MDbuf[3], eee = MDbuf[4]; - - /* round 1 */ - FF(aa, bb, cc, dd, ee, X[ 0], 11); - FF(ee, aa, bb, cc, dd, X[ 1], 14); - FF(dd, ee, aa, bb, cc, X[ 2], 15); - FF(cc, dd, ee, aa, bb, X[ 3], 12); - FF(bb, cc, dd, ee, aa, X[ 4], 5); - FF(aa, bb, cc, dd, ee, X[ 5], 8); - FF(ee, aa, bb, cc, dd, X[ 6], 7); - FF(dd, ee, aa, bb, cc, X[ 7], 9); - FF(cc, dd, ee, aa, bb, X[ 8], 11); - FF(bb, cc, dd, ee, aa, X[ 9], 13); - FF(aa, bb, cc, dd, ee, X[10], 14); - FF(ee, aa, bb, cc, dd, X[11], 15); - FF(dd, ee, aa, bb, cc, X[12], 6); - FF(cc, dd, ee, aa, bb, X[13], 7); - FF(bb, cc, dd, ee, aa, X[14], 9); - FF(aa, bb, cc, dd, ee, X[15], 8); - - /* round 2 */ - GG(ee, aa, bb, cc, dd, X[ 7], 7); - GG(dd, ee, aa, bb, cc, X[ 4], 6); - GG(cc, dd, ee, aa, bb, X[13], 8); - GG(bb, cc, dd, ee, aa, X[ 1], 13); - GG(aa, bb, cc, dd, ee, X[10], 11); - GG(ee, aa, bb, cc, dd, X[ 6], 9); - GG(dd, ee, aa, bb, cc, X[15], 7); - GG(cc, dd, ee, aa, bb, X[ 3], 15); - GG(bb, cc, dd, ee, aa, X[12], 7); - GG(aa, bb, cc, dd, ee, X[ 0], 12); - GG(ee, aa, bb, cc, dd, X[ 9], 15); - GG(dd, ee, aa, bb, cc, X[ 5], 9); - GG(cc, dd, ee, aa, bb, X[ 2], 11); - GG(bb, cc, dd, ee, aa, X[14], 7); - GG(aa, bb, cc, dd, ee, X[11], 13); - GG(ee, aa, bb, cc, dd, X[ 8], 12); - - /* round 3 */ - HH(dd, ee, aa, bb, cc, X[ 3], 11); - HH(cc, dd, ee, aa, bb, X[10], 13); - HH(bb, cc, dd, ee, aa, X[14], 6); - HH(aa, bb, cc, dd, ee, X[ 4], 7); - HH(ee, aa, bb, cc, dd, X[ 9], 14); - HH(dd, ee, aa, bb, cc, X[15], 9); - HH(cc, dd, ee, aa, bb, X[ 8], 13); - HH(bb, cc, dd, ee, aa, X[ 1], 15); - HH(aa, bb, cc, dd, ee, X[ 2], 14); - HH(ee, aa, bb, cc, dd, X[ 7], 8); - HH(dd, ee, aa, bb, cc, X[ 0], 13); - HH(cc, dd, ee, aa, bb, X[ 6], 6); - HH(bb, cc, dd, ee, aa, X[13], 5); - HH(aa, bb, cc, dd, ee, X[11], 12); - HH(ee, aa, bb, cc, dd, X[ 5], 7); - HH(dd, ee, aa, bb, cc, X[12], 5); - - /* round 4 */ - II(cc, dd, ee, aa, bb, X[ 1], 11); - II(bb, cc, dd, ee, aa, X[ 9], 12); - II(aa, bb, cc, dd, ee, X[11], 14); - II(ee, aa, bb, cc, dd, X[10], 15); - II(dd, ee, aa, bb, cc, X[ 0], 14); - II(cc, dd, ee, aa, bb, X[ 8], 15); - II(bb, cc, dd, ee, aa, X[12], 9); - II(aa, bb, cc, dd, ee, X[ 4], 8); - II(ee, aa, bb, cc, dd, X[13], 9); - II(dd, ee, aa, bb, cc, X[ 3], 14); - II(cc, dd, ee, aa, bb, X[ 7], 5); - II(bb, cc, dd, ee, aa, X[15], 6); - II(aa, bb, cc, dd, ee, X[14], 8); - II(ee, aa, bb, cc, dd, X[ 5], 6); - II(dd, ee, aa, bb, cc, X[ 6], 5); - II(cc, dd, ee, aa, bb, X[ 2], 12); - - /* round 5 */ - JJ(bb, cc, dd, ee, aa, X[ 4], 9); - JJ(aa, bb, cc, dd, ee, X[ 0], 15); - JJ(ee, aa, bb, cc, dd, X[ 5], 5); - JJ(dd, ee, aa, bb, cc, X[ 9], 11); - JJ(cc, dd, ee, aa, bb, X[ 7], 6); - JJ(bb, cc, dd, ee, aa, X[12], 8); - JJ(aa, bb, cc, dd, ee, X[ 2], 13); - JJ(ee, aa, bb, cc, dd, X[10], 12); - JJ(dd, ee, aa, bb, cc, X[14], 5); - JJ(cc, dd, ee, aa, bb, X[ 1], 12); - JJ(bb, cc, dd, ee, aa, X[ 3], 13); - JJ(aa, bb, cc, dd, ee, X[ 8], 14); - JJ(ee, aa, bb, cc, dd, X[11], 11); - JJ(dd, ee, aa, bb, cc, X[ 6], 8); - JJ(cc, dd, ee, aa, bb, X[15], 5); - JJ(bb, cc, dd, ee, aa, X[13], 6); - - /* parallel round 1 */ - JJJ(aaa, bbb, ccc, ddd, eee, X[ 5], 8); - JJJ(eee, aaa, bbb, ccc, ddd, X[14], 9); - JJJ(ddd, eee, aaa, bbb, ccc, X[ 7], 9); - JJJ(ccc, ddd, eee, aaa, bbb, X[ 0], 11); - JJJ(bbb, ccc, ddd, eee, aaa, X[ 9], 13); - JJJ(aaa, bbb, ccc, ddd, eee, X[ 2], 15); - JJJ(eee, aaa, bbb, ccc, ddd, X[11], 15); - JJJ(ddd, eee, aaa, bbb, ccc, X[ 4], 5); - JJJ(ccc, ddd, eee, aaa, bbb, X[13], 7); - JJJ(bbb, ccc, ddd, eee, aaa, X[ 6], 7); - JJJ(aaa, bbb, ccc, ddd, eee, X[15], 8); - JJJ(eee, aaa, bbb, ccc, ddd, X[ 8], 11); - JJJ(ddd, eee, aaa, bbb, ccc, X[ 1], 14); - JJJ(ccc, ddd, eee, aaa, bbb, X[10], 14); - JJJ(bbb, ccc, ddd, eee, aaa, X[ 3], 12); - JJJ(aaa, bbb, ccc, ddd, eee, X[12], 6); - - /* parallel round 2 */ - III(eee, aaa, bbb, ccc, ddd, X[ 6], 9); - III(ddd, eee, aaa, bbb, ccc, X[11], 13); - III(ccc, ddd, eee, aaa, bbb, X[ 3], 15); - III(bbb, ccc, ddd, eee, aaa, X[ 7], 7); - III(aaa, bbb, ccc, ddd, eee, X[ 0], 12); - III(eee, aaa, bbb, ccc, ddd, X[13], 8); - III(ddd, eee, aaa, bbb, ccc, X[ 5], 9); - III(ccc, ddd, eee, aaa, bbb, X[10], 11); - III(bbb, ccc, ddd, eee, aaa, X[14], 7); - III(aaa, bbb, ccc, ddd, eee, X[15], 7); - III(eee, aaa, bbb, ccc, ddd, X[ 8], 12); - III(ddd, eee, aaa, bbb, ccc, X[12], 7); - III(ccc, ddd, eee, aaa, bbb, X[ 4], 6); - III(bbb, ccc, ddd, eee, aaa, X[ 9], 15); - III(aaa, bbb, ccc, ddd, eee, X[ 1], 13); - III(eee, aaa, bbb, ccc, ddd, X[ 2], 11); - - /* parallel round 3 */ - HHH(ddd, eee, aaa, bbb, ccc, X[15], 9); - HHH(ccc, ddd, eee, aaa, bbb, X[ 5], 7); - HHH(bbb, ccc, ddd, eee, aaa, X[ 1], 15); - HHH(aaa, bbb, ccc, ddd, eee, X[ 3], 11); - HHH(eee, aaa, bbb, ccc, ddd, X[ 7], 8); - HHH(ddd, eee, aaa, bbb, ccc, X[14], 6); - HHH(ccc, ddd, eee, aaa, bbb, X[ 6], 6); - HHH(bbb, ccc, ddd, eee, aaa, X[ 9], 14); - HHH(aaa, bbb, ccc, ddd, eee, X[11], 12); - HHH(eee, aaa, bbb, ccc, ddd, X[ 8], 13); - HHH(ddd, eee, aaa, bbb, ccc, X[12], 5); - HHH(ccc, ddd, eee, aaa, bbb, X[ 2], 14); - HHH(bbb, ccc, ddd, eee, aaa, X[10], 13); - HHH(aaa, bbb, ccc, ddd, eee, X[ 0], 13); - HHH(eee, aaa, bbb, ccc, ddd, X[ 4], 7); - HHH(ddd, eee, aaa, bbb, ccc, X[13], 5); - - /* parallel round 4 */ - GGG(ccc, ddd, eee, aaa, bbb, X[ 8], 15); - GGG(bbb, ccc, ddd, eee, aaa, X[ 6], 5); - GGG(aaa, bbb, ccc, ddd, eee, X[ 4], 8); - GGG(eee, aaa, bbb, ccc, ddd, X[ 1], 11); - GGG(ddd, eee, aaa, bbb, ccc, X[ 3], 14); - GGG(ccc, ddd, eee, aaa, bbb, X[11], 14); - GGG(bbb, ccc, ddd, eee, aaa, X[15], 6); - GGG(aaa, bbb, ccc, ddd, eee, X[ 0], 14); - GGG(eee, aaa, bbb, ccc, ddd, X[ 5], 6); - GGG(ddd, eee, aaa, bbb, ccc, X[12], 9); - GGG(ccc, ddd, eee, aaa, bbb, X[ 2], 12); - GGG(bbb, ccc, ddd, eee, aaa, X[13], 9); - GGG(aaa, bbb, ccc, ddd, eee, X[ 9], 12); - GGG(eee, aaa, bbb, ccc, ddd, X[ 7], 5); - GGG(ddd, eee, aaa, bbb, ccc, X[10], 15); - GGG(ccc, ddd, eee, aaa, bbb, X[14], 8); - - /* parallel round 5 */ - FFF(bbb, ccc, ddd, eee, aaa, X[12] , 8); - FFF(aaa, bbb, ccc, ddd, eee, X[15] , 5); - FFF(eee, aaa, bbb, ccc, ddd, X[10] , 12); - FFF(ddd, eee, aaa, bbb, ccc, X[ 4] , 9); - FFF(ccc, ddd, eee, aaa, bbb, X[ 1] , 12); - FFF(bbb, ccc, ddd, eee, aaa, X[ 5] , 5); - FFF(aaa, bbb, ccc, ddd, eee, X[ 8] , 14); - FFF(eee, aaa, bbb, ccc, ddd, X[ 7] , 6); - FFF(ddd, eee, aaa, bbb, ccc, X[ 6] , 8); - FFF(ccc, ddd, eee, aaa, bbb, X[ 2] , 13); - FFF(bbb, ccc, ddd, eee, aaa, X[13] , 6); - FFF(aaa, bbb, ccc, ddd, eee, X[14] , 5); - FFF(eee, aaa, bbb, ccc, ddd, X[ 0] , 15); - FFF(ddd, eee, aaa, bbb, ccc, X[ 3] , 13); - FFF(ccc, ddd, eee, aaa, bbb, X[ 9] , 11); - FFF(bbb, ccc, ddd, eee, aaa, X[11] , 11); - - /* combine results */ - ddd += cc + MDbuf[1]; /* final result for MDbuf[0] */ - MDbuf[1] = MDbuf[2] + dd + eee; - MDbuf[2] = MDbuf[3] + ee + aaa; - MDbuf[3] = MDbuf[4] + aa + bbb; - MDbuf[4] = MDbuf[0] + bb + ccc; - MDbuf[0] = ddd; - - return; -} - -void MDfinish(uint32_t *MDbuf, byte const *strptr, uint32_t lswlen, uint32_t mswlen) -{ - unsigned int i; /* counter */ - uint32_t X[16]; /* message words */ - - memset(X, 0, 16*sizeof(uint32_t)); - - /* put bytes from strptr into X */ - for (i=0; i<(lswlen&63); i++) { - /* byte i goes into word X[i div 4] at pos. 8*(i mod 4) */ - X[i>>2] ^= (uint32_t) *strptr++ << (8 * (i&3)); - } - - /* append the bit m_n == 1 */ - X[(lswlen>>2)&15] ^= (uint32_t)1 << (8*(lswlen&3) + 7); - - if ((lswlen & 63) > 55) { - /* length goes to next block */ - MDcompress(MDbuf, X); - memset(X, 0, 16*sizeof(uint32_t)); - } - - /* append length in bits*/ - X[14] = lswlen << 3; - X[15] = (lswlen >> 29) | (mswlen << 3); - MDcompress(MDbuf, X); - - return; -} - -#undef ROL -#undef F -#undef G -#undef H -#undef I -#undef J -#undef FF -#undef GG -#undef HH -#undef II -#undef JJ -#undef FFF -#undef GGG -#undef HHH -#undef III -#undef JJJ - -} - -/* - * @returns RMD(_input) - */ -h160 ripemd160(bytesConstRef _input) -{ - h160 hashcode; - uint32_t buffer[RMDsize / 32]; // contains (A, B, C, D(, E)) - uint32_t current[16]; // current 16-word chunk - - // initialize - rmd160::MDinit(buffer); - byte const* message = _input.data(); - uint32_t remaining = _input.size(); // # of bytes not yet processed - - // process message in 16x 4-byte chunks - for (; remaining >= 64; remaining -= 64) - { - for (unsigned i = 0; i < 16; i++) - { - current[i] = BYTES_TO_DWORD(message); - message += 4; - } - rmd160::MDcompress(buffer, current); - } - // length mod 64 bytes left - - // finish: - rmd160::MDfinish(buffer, message, _input.size(), 0); - - for (unsigned i = 0; i < RMDsize / 8; i += 4) - { - hashcode[i] = buffer[i >> 2]; // implicit cast to byte - hashcode[i + 1] = (buffer[i >> 2] >> 8); //extracts the 8 least - hashcode[i + 2] = (buffer[i >> 2] >> 16); // significant bits. - hashcode[i + 3] = (buffer[i >> 2] >> 24); - } - - return hashcode; -} - -#undef BYTES_TO_DWORD -#undef RMDsize - -} diff --git a/libdevcrypto/Hash.h b/libdevcrypto/Hash.h deleted file mode 100644 index af185eca8..000000000 --- a/libdevcrypto/Hash.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - This file is part of cpp-ethereum. - - cpp-ethereum is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - cpp-ethereum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with cpp-ethereum. If not, see . -*/ -/** @file Hash.h - * @author Gav Wood - * @date 2014 - * - * The FixedHash fixed-size "hash" container type. - */ - -#pragma once - -#include "libdevcore/FixedHash.h" -#include "libdevcore/vector_ref.h" - -namespace dev -{ - -h256 sha256(bytesConstRef _input) noexcept; - -h160 ripemd160(bytesConstRef _input); - -} diff --git a/libdevcrypto/LibSnark.cpp b/libdevcrypto/LibSnark.cpp deleted file mode 100644 index 522969a9c..000000000 --- a/libdevcrypto/LibSnark.cpp +++ /dev/null @@ -1,200 +0,0 @@ -/* - This file is part of cpp-ethereum. - - cpp-ethereum is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - cpp-ethereum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with cpp-ethereum. If not, see . - */ - -#include - -#include -#include -#include -#include -#include - -#include - -using namespace std; -using namespace dev; -using namespace dev::crypto; - -namespace -{ - -DEV_SIMPLE_EXCEPTION(InvalidEncoding); - -void initLibSnark() noexcept -{ - static bool s_initialized = []() noexcept - { - libff::inhibit_profiling_info = true; - libff::inhibit_profiling_counters = true; - libff::alt_bn128_pp::init_public_params(); - return true; - }(); - (void)s_initialized; -} - -libff::bigint toLibsnarkBigint(h256 const& _x) -{ - libff::bigint b; - auto const N = b.N; - constexpr size_t L = sizeof(b.data[0]); - static_assert(sizeof(mp_limb_t) == L, "Unexpected limb size in libff::bigint."); - for (size_t i = 0; i < N; i++) - for (size_t j = 0; j < L; j++) - b.data[N - 1 - i] |= mp_limb_t(_x[i * L + j]) << (8 * (L - 1 - j)); - return b; -} - -h256 fromLibsnarkBigint(libff::bigint const& _b) -{ - static size_t const N = static_cast(_b.N); - static size_t const L = sizeof(_b.data[0]); - static_assert(sizeof(mp_limb_t) == L, "Unexpected limb size in libff::bigint."); - h256 x; - for (size_t i = 0; i < N; i++) - for (size_t j = 0; j < L; j++) - x[i * L + j] = uint8_t(_b.data[N - 1 - i] >> (8 * (L - 1 - j))); - return x; -} - -libff::alt_bn128_Fq decodeFqElement(dev::bytesConstRef _data) -{ - // h256::AlignLeft ensures that the h256 is zero-filled on the right if _data - // is too short. - h256 xbin(_data, h256::AlignLeft); - // TODO: Consider using a compiler time constant for comparison. - if (u256(xbin) >= u256(fromLibsnarkBigint(libff::alt_bn128_Fq::mod))) - BOOST_THROW_EXCEPTION(InvalidEncoding()); - return toLibsnarkBigint(xbin); -} - -libff::alt_bn128_G1 decodePointG1(dev::bytesConstRef _data) -{ - libff::alt_bn128_Fq x = decodeFqElement(_data.cropped(0)); - libff::alt_bn128_Fq y = decodeFqElement(_data.cropped(32)); - if (x == libff::alt_bn128_Fq::zero() && y == libff::alt_bn128_Fq::zero()) - return libff::alt_bn128_G1::zero(); - libff::alt_bn128_G1 p(x, y, libff::alt_bn128_Fq::one()); - if (!p.is_well_formed()) - BOOST_THROW_EXCEPTION(InvalidEncoding()); - return p; -} - -bytes encodePointG1(libff::alt_bn128_G1 _p) -{ - if (_p.is_zero()) - return bytes(64, 0); - _p.to_affine_coordinates(); - return - fromLibsnarkBigint(_p.X.as_bigint()).asBytes() + - fromLibsnarkBigint(_p.Y.as_bigint()).asBytes(); -} - -libff::alt_bn128_Fq2 decodeFq2Element(dev::bytesConstRef _data) -{ - // Encoding: c1 (256 bits) c0 (256 bits) - // "Big endian", just like the numbers - return libff::alt_bn128_Fq2( - decodeFqElement(_data.cropped(32)), - decodeFqElement(_data.cropped(0)) - ); -} - -libff::alt_bn128_G2 decodePointG2(dev::bytesConstRef _data) -{ - libff::alt_bn128_Fq2 const x = decodeFq2Element(_data); - libff::alt_bn128_Fq2 const y = decodeFq2Element(_data.cropped(64)); - if (x == libff::alt_bn128_Fq2::zero() && y == libff::alt_bn128_Fq2::zero()) - return libff::alt_bn128_G2::zero(); - libff::alt_bn128_G2 p(x, y, libff::alt_bn128_Fq2::one()); - if (!p.is_well_formed()) - BOOST_THROW_EXCEPTION(InvalidEncoding()); - return p; -} - -} - -pair dev::crypto::alt_bn128_pairing_product(dev::bytesConstRef _in) -{ - // Input: list of pairs of G1 and G2 points - // Output: 1 if pairing evaluates to 1, 0 otherwise (left-padded to 32 bytes) - - size_t constexpr pairSize = 2 * 32 + 2 * 64; - size_t const pairs = _in.size() / pairSize; - if (pairs * pairSize != _in.size()) - // Invalid length. - return {false, bytes{}}; - - try - { - initLibSnark(); - libff::alt_bn128_Fq12 x = libff::alt_bn128_Fq12::one(); - for (size_t i = 0; i < pairs; ++i) - { - bytesConstRef const pair = _in.cropped(i * pairSize, pairSize); - libff::alt_bn128_G1 const g1 = decodePointG1(pair); - libff::alt_bn128_G2 const p = decodePointG2(pair.cropped(2 * 32)); - if (-libff::alt_bn128_G2::scalar_field::one() * p + p != libff::alt_bn128_G2::zero()) - // p is not an element of the group (has wrong order) - return {false, bytes()}; - if (p.is_zero() || g1.is_zero()) - continue; // the pairing is one - x = x * libff::alt_bn128_miller_loop( - libff::alt_bn128_precompute_G1(g1), - libff::alt_bn128_precompute_G2(p) - ); - } - bool const result = libff::alt_bn128_final_exponentiation(x) == libff::alt_bn128_GT::one(); - return {true, h256{result}.asBytes()}; - } - catch (InvalidEncoding const&) - { - // Signal the call failure for invalid input. - return {false, bytes{}}; - } -} - -pair dev::crypto::alt_bn128_G1_add(dev::bytesConstRef _in) -{ - try - { - initLibSnark(); - libff::alt_bn128_G1 const p1 = decodePointG1(_in); - libff::alt_bn128_G1 const p2 = decodePointG1(_in.cropped(32 * 2)); - return {true, encodePointG1(p1 + p2)}; - } - catch (InvalidEncoding const&) - { - // Signal the call failure for invalid input. - return {false, bytes{}}; - } -} - -pair dev::crypto::alt_bn128_G1_mul(dev::bytesConstRef _in) -{ - try - { - initLibSnark(); - libff::alt_bn128_G1 const p = decodePointG1(_in.cropped(0)); - libff::alt_bn128_G1 const result = toLibsnarkBigint(h256(_in.cropped(64), h256::AlignLeft)) * p; - return {true, encodePointG1(result)}; - } - catch (InvalidEncoding const&) - { - // Signal the call failure for invalid input. - return {false, bytes{}}; - } -} diff --git a/libdevcrypto/LibSnark.h b/libdevcrypto/LibSnark.h deleted file mode 100644 index 693957a56..000000000 --- a/libdevcrypto/LibSnark.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - This file is part of cpp-ethereum. - - cpp-ethereum is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - cpp-ethereum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with cpp-ethereum. If not, see . - */ -/** - * @file LibSnark.h - */ - -#pragma once - -#include - -namespace dev -{ -namespace crypto -{ - -std::pair alt_bn128_pairing_product(bytesConstRef _in); -std::pair alt_bn128_G1_add(bytesConstRef _in); -std::pair alt_bn128_G1_mul(bytesConstRef _in); - -} -} diff --git a/retesteth/Constants.cpp b/retesteth/Constants.cpp new file mode 100644 index 000000000..d4c108f13 --- /dev/null +++ b/retesteth/Constants.cpp @@ -0,0 +1,24 @@ +#include "Constants.h" +using namespace test; +using namespace std; + +namespace test { + +string C_WITHDRAWALS_EMPTY_ROOT = "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"; +string C_EMPTY_STR = string(); + +namespace teststruct { + +FH8 C_FH8_ZERO("0x0000000000000000"); +FH20 C_FH20_ZERO("0x0000000000000000000000000000000000000000"); +FH32 C_FH32_ZERO("0x0000000000000000000000000000000000000000000000000000000000000000"); +FH256 C_FH256_ZERO( + "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000"); + +} +} + diff --git a/retesteth/Constants.h b/retesteth/Constants.h new file mode 100644 index 000000000..ea0eb1df6 --- /dev/null +++ b/retesteth/Constants.h @@ -0,0 +1,17 @@ +#pragma once +#include +#include + +namespace test { + +extern std::string C_WITHDRAWALS_EMPTY_ROOT; +extern std::string C_EMPTY_STR; + +namespace teststruct { + +extern FH8 C_FH8_ZERO; +extern FH20 C_FH20_ZERO; +extern FH32 C_FH32_ZERO; +extern FH256 C_FH256_ZERO; + +}} diff --git a/retesteth/EthChecks.cpp b/retesteth/EthChecks.cpp index a20316ca4..92aa87ead 100644 --- a/retesteth/EthChecks.cpp +++ b/retesteth/EthChecks.cpp @@ -4,8 +4,10 @@ #include #include #include +#include using namespace std; +mutex g_debugFlagAccess; namespace test::debug { Debug::Debug() @@ -28,8 +30,15 @@ Debug::Debug() m_channels[DC::RPC] = true; m_channels[DC::WARNING] = true; } + else if (flag == "RPC2") + { + m_channels[DC::RPC2] = true; + m_channels[DC::WARNING] = true; + } else if (flag == "STATS") m_channels[DC::STATS] = true; // Default test execution stats + else if (flag == "STATS2") + m_channels[DC::STATS2] = true; else if (flag == "STATE") m_channels[DC::STATE] = true; // Poststate output else if (flag == "SOCKET") @@ -48,6 +57,12 @@ Debug::Debug() initializeDefaultChannels(); }; +bool Debug::flag(DC _channel) const +{ + std::lock_guard lock(g_debugFlagAccess); + return m_channels.at(_channel); +} + void Debug::initializeDefaultChannels() { // Default log channel initialization @@ -69,7 +84,10 @@ void Debug::initializeDefaultChannels() if (verb >= 6) m_channels[DC::RPC] = true; if (verb >= 7) + { m_channels[DC::LOWLOG] = true; + m_channels[DC::RPC2] = true; + } if (Options::get().poststate.initialized() || Options::get().statediff.initialized()) m_channels[DC::STATE] = true; } diff --git a/retesteth/EthChecks.h b/retesteth/EthChecks.h index fa90462e2..616f7d182 100644 --- a/retesteth/EthChecks.h +++ b/retesteth/EthChecks.h @@ -7,6 +7,7 @@ namespace test::debug enum DC { RPC, + RPC2, DEFAULT, SOCKET, STATS, @@ -25,7 +26,7 @@ class Debug static Debug instance; return instance; } - bool flag(DC _channel) const { return m_channels.at(_channel); } + bool flag(DC _channel) const; private: Debug(); diff --git a/retesteth/ExitHandler.h b/retesteth/ExitHandler.h index 449beb552..85740cb4d 100644 --- a/retesteth/ExitHandler.h +++ b/retesteth/ExitHandler.h @@ -10,4 +10,9 @@ class ExitHandler static bool m_receivedExitSig; }; - +#define CHECKEXIT \ + if (ExitHandler::receivedExitSignal()) \ + return; +#define CHECKEXITR(RET) \ + if (ExitHandler::receivedExitSignal()) \ + return RET; diff --git a/retesteth/Options.cpp b/retesteth/Options.cpp index da8ff4c29..a6ac90a34 100644 --- a/retesteth/Options.cpp +++ b/retesteth/Options.cpp @@ -132,6 +132,8 @@ Options::Options(int argc, const char** argv) { if (rCurrentTestSuite.find("BCGeneral") != string::npos) return; + if (rCurrentTestSuite.find("EOFTests") != string::npos) + return; BOOST_THROW_EXCEPTION( InvalidOption("Error: `" + _name + "` option requires `-t GeneralStateTests`")); } @@ -157,19 +159,28 @@ Options::Options(int argc, const char** argv) ADD_OPTION(getvectors, "--getvectors", []() { cout << setw(30) << "--getvectors" << setw(25) << "Output all subunits of the given test (disables execution)\n"; }); + ADD_OPTION(t8ntoolcall, "--exportcall", []() { + cout << setw(30) << "--exportcall " << setw(25) << "Export t8ntool exec files to a folder (t8ntool only)\n"; + }); ADD_OPTION(statediff, "--statediff", [](){ cout << setw(30) << "--statediff" << setw(25) << "Print statediff post vs pre\n"; + cout << setw(30) << "--statediff xtoy" << setw(25) << "Statediff from block 'x' to block 'y'\n"; + cout << setw(30) << "--statediff x:ytox2:y2" << setw(25) << "Statediff from block 'x', transaction 'y' to block 'x2', transaction 'y2' (require --filltests)\n"; }); ADD_OPTION(vmtrace, "--vmtrace", [](){ cout << setw(30) << "--vmtrace" << setw(25) << "Trace transaction execution\n"; + cout << setw(30) << "--vmtrace x:y" << setw(25) << "Show vmtrace of block 'x', transaction 'y'\n"; }); ADD_OPTIONV(vmtraceraw, "--vmtraceraw", [](){ cout << setw(30) << "--vmtraceraw" << setw(25) << "Trace transaction execution raw format\n"; + cout << setw(30) << "--vmtraceraw x:y" << setw(25) << "Show vmtrace in raw format of block 'x', transaction 'y'\n"; cout << setw(30) << "--vmtraceraw " << setw(25) << "Trace transactions execution raw format to a given folder\n"; + cout << setw(30) << "--vmtraceraw x:y " << setw(25) << "Same as above but combined\n"; }, [this](){ vmtrace = true; - if (logVerbosity.val < 6 && vmtraceraw.outpath.empty()) - std::cout << "Warning: --vmtraceraw is defined, but trace is printed with verbosity level 6, which is not set" << std::endl; + vmtrace.isBlockSelected = vmtraceraw.isBlockSelected; + vmtrace.blockNumber = vmtraceraw.blockNumber; + vmtrace.transactionNumber = vmtraceraw.transactionNumber; }); ADD_OPTIONV(vmtrace_nomemory, "--vmtrace.nomemory", [](){ cout << setw(30) << "--vmtrace.nomemory" << setw(25) << "Disable memory in vmtrace/vmtraceraw\n"; @@ -198,7 +209,7 @@ Options::Options(int argc, const char** argv) ADD_OPTIONV(logVerbosity, "--verbosity", [](){ cout << setw(30) << "--verbosity " << setw(25) << "Set logs verbosity. 0 - silent, 1 - only errors, 2 - informative, >2 - detailed\n"; cout << setw(30) << "--verbosity " << setw(25) - << "Set logs channels. 'STATS|RPC|TESTLOG|LOWLOG|SOCKET|STATE'\n"; + << "Set logs channels. 'STATS|RPC|RPC2|TESTLOG|LOWLOG|SOCKET|STATE'\n"; },[this](){ // disable all output static std::ostringstream strCout; @@ -255,7 +266,9 @@ Options::Options(int argc, const char** argv) std::cout << "WARNING: `--fillchain` option provided without `--filltests`, activating `--filltests` (did you mean `--filltests`?)\n"; filltests = true; }}); - + ADD_OPTION(chainid, "--chainid", [](){ + cout << setw(30) << "--chainid" << setw(25) << "Override config chainid when generating transactions\n"; + }); ADD_OPTION(showhash, "--showhash", [](){ cout << setw(30) << "--showhash" << setw(25) << "Show filler hash debug information\n"; }); @@ -264,7 +277,9 @@ Options::Options(int argc, const char** argv) }); ADD_OPTIONV(poststate, "--poststate", [](){ cout << setw(30) << "--poststate" << setw(25) << "Debug(6) show test postState hash or fullstate, when used with --filltests export `postState` in StateTests\n"; + cout << setw(30) << "--poststate x:y" << setw(25) << "Show poststate of block 'x', transaction 'y'\n"; cout << setw(30) << "--poststate " << setw(25) << "Same as above plus export test post states into a folder\n"; + cout << setw(30) << "--poststate x:y " << setw(25) << "Same as above but combined\n"; }, [this](){ fullstate = true; }); @@ -300,6 +315,7 @@ Options::Options(int argc, const char** argv) dataobject::GCP_SPointer::DISABLETHREADSAFE(); } + Options const& Options::get(int argc, const char** argv) { static Options instance(argc, argv); @@ -463,6 +479,30 @@ int Options::Option::initArgs(list const& _argList, list seconBlock) + BOOST_THROW_EXCEPTION(InvalidOption("Error: `" + m_sOptionName + "` option arg format is `xtoy` or `x:ytox2:y2`, where `y >= x` or `x2 >= x`")); +} + +void Options::booloutpathselector_opt::parse2OptionalArgs(std::string const& _arg) +{ + // Can take 0 args, act as bool + // 1 arg = either path or block selector + // 2 arg = path and block selector in any order + size_t pos = _arg.find(":"); + if (pos != string::npos && !isBlockSelected) + { + blockNumber = atoi(_arg.substr(0, pos).c_str()); + transactionNumber = atoi(_arg.substr(pos + 1).c_str()); + isBlockSelected = true; + } + else + outpath = _arg; +} diff --git a/retesteth/Options.h b/retesteth/Options.h index 8178903dc..62b55451e 100644 --- a/retesteth/Options.h +++ b/retesteth/Options.h @@ -14,6 +14,7 @@ class Options { NONE, NONE_OPTIONAL, + NONE_OPTIONAL2, ONE, ONEMERGED }; @@ -36,6 +37,7 @@ class Options protected: virtual void initArg(std::string const& _arg) = 0; + virtual void initArg2(std::string const&){}; Option(){}; std::string m_sOptionHelp; std::string m_sOptionName; @@ -93,6 +95,35 @@ class Options void initArg(std::string const& _arg) override { outpath = _arg; } }; + struct statediff_opt : public bool_opt + { + statediff_opt(bool _arg) : bool_opt(_arg) { m_argType = ARGS::NONE_OPTIONAL; } + operator bool() const { return m_inited; } + bool isBlockSelected = false; + bool isTransSelected = false; + size_t firstBlock; + size_t firstTrnsx; + size_t seconBlock; + size_t seconTrnsx; + + protected: + void initArg(std::string const& _arg) override; + }; + + struct booloutpathselector_opt : public booloutpath_opt + { + booloutpathselector_opt(bool _arg) : booloutpath_opt(_arg) { m_argType = ARGS::NONE_OPTIONAL2; } + operator bool() const { return m_inited; } + size_t blockNumber; + size_t transactionNumber; + bool isBlockSelected = false; + + protected: + void initArg(std::string const& _arg) override { parse2OptionalArgs(_arg); } + void initArg2(std::string const& _arg) override { parse2OptionalArgs(_arg); } + void parse2OptionalArgs(std::string const& _arg); + }; + struct string_opt : public Option, std::string { string_opt() { m_argType = ARGS::ONE;} @@ -185,9 +216,9 @@ class Options int_opt trGasIndex= -1; int_opt trValueIndex = -1; bool_opt getvectors = false; - bool_opt vmtrace = false; - bool_opt statediff = false; - booloutpath_opt vmtraceraw = false; + booloutpathselector_opt vmtrace = false; + statediff_opt statediff = false; + booloutpathselector_opt vmtraceraw = false; bool_opt vmtrace_nomemory = false; bool_opt vmtrace_nostack = false; bool_opt vmtrace_noreturndata = false; @@ -198,6 +229,7 @@ class Options bool_opt exectimelog = false; bool_opt enableClientsOutput = false; bool_opt travisOutThread = false; + string_opt t8ntoolcall; // Additional Tests bool_opt all = false; @@ -208,9 +240,10 @@ class Options bool_opt filloutdated = false; bool_opt fillvmtrace = false; bool_opt fillchain = false; + sizet_opt chainid = 1; bool_opt showhash = false; bool_opt checkhash = false; - booloutpath_opt poststate = false; + booloutpathselector_opt poststate = false; bool_opt fullstate = false; bool_opt forceupdate = false; static bool isLegacy(); diff --git a/retesteth/TestHelper.cpp b/retesteth/TestHelper.cpp index 1cd8acdf8..bceecf24c 100644 --- a/retesteth/TestHelper.cpp +++ b/retesteth/TestHelper.cpp @@ -9,9 +9,11 @@ #include #include #include +#include using namespace std; using namespace dev; +using namespace boost::unit_test; namespace fs = boost::filesystem; namespace test { @@ -37,7 +39,7 @@ spDataObject readJsonData(fs::path const& _file, string const& _stopper, bool _a { try { - string s = dev::contentsString(_file); + string const s = dev::contentsString(_file); ETH_ERROR_REQUIRE_MESSAGE( s.length() > 0, "Contents of " + _file.string() + " is empty. Trying to parse empty file. (forgot --filltests?)"); return dataobject::ConvertJsoncppStringToData(s, _stopper, _autosort); @@ -54,7 +56,7 @@ spDataObject readYamlData(fs::path const& _file, bool _sort) { try { - string s = dev::contentsString(_file); + string const s = dev::contentsString(_file); ETH_ERROR_REQUIRE_MESSAGE( s.length() > 0, "Contents of " + _file.string() + " is empty. Trying to parse empty file. (forgot --filltests?)"); return dataobject::ConvertYamlToData(YAML::Load(s), _sort); @@ -66,16 +68,36 @@ spDataObject readYamlData(fs::path const& _file, bool _sort) } } -vector getFiles(fs::path const& _dirPath, set const _extentionMask, string const& _particularFile) +spDataObject readAutoDataWithoutOptions(boost::filesystem::path const& _file, bool _sort) +{ + try + { + string const s = dev::contentsString(_file); + if (s.length() == 0) + std::cerr << "Contents of " + _file.string() + " is empty. Trying to parse empty file." << std::endl; + if (_file.extension() == ".json") + return dataobject::ConvertJsoncppStringToData(s); + else if (_file.extension() == ".yml") + return dataobject::ConvertYamlToData(YAML::Load(s), _sort); + std::cerr << "Unknown test file: " << _file.string() << std::endl; + } + catch (std::exception const& _ex) + { + std::cerr << string("\nError when parsing file (") + _file.c_str() + ") " + _ex.what() << std::endl; + } + return spDataObject(0); +} + +vector getFiles(fs::path const& _dirPath, set const& _extentionMask, string const& _particularFile) { vector files; for (auto const& ext : _extentionMask) { if (!_particularFile.empty()) { - fs::path file = _dirPath / (_particularFile + ext); + fs::path const file = _dirPath / (_particularFile + ext); if (fs::exists(file)) - files.push_back(file); + files.emplace_back(file); } else { @@ -85,7 +107,7 @@ vector getFiles(fs::path const& _dirPath, set const _extention for (fsIterator it(_dirPath); it != fsIterator(); ++it) { if (fs::is_regular_file(it->path()) && it->path().extension() == ext) - files.push_back(it->path()); + files.emplace_back(it->path()); } } } @@ -166,7 +188,7 @@ vector levenshteinDistance(std::string const& _needle, std::vector explode(std::string const& s, char delim) std::vector result; std::istringstream iss(s); for (std::string token; std::getline(iss, token, delim);) - result.push_back(std::move(token)); + result.emplace_back(token); return result; } @@ -709,6 +739,17 @@ RLPStreamU::RLPStreamU(size_t _size) : m_size(_size) ETH_FAIL_MESSAGE("RLPStreamU does not support stream of multiple rlp items. It's a mock to wrap 1 transaction."); } +void removeSubChar(std::string& _string, std::vector _r) +{ + _string.erase( + std::remove_if(_string.begin(), _string.end(), [&_r](unsigned char ch) { + for (auto const& charToRemove : _r) + if (ch == charToRemove) + return true; + return false; + }), _string.end()); +} + void removeSubChar(std::string& _string, unsigned char _r) { _string.erase( @@ -725,4 +766,29 @@ string makePlussedFork(FORK const& _net) return string(); } +bool isBoostSuite(std::string const& suiteName) +{ + test_suite const* suite = &boost::unit_test::framework::master_test_suite(); + auto const allSuites = test::explode(suiteName, '/'); + for (auto const& suiteName : allSuites) + { + auto const suiteid = suite->get(suiteName); + if (suiteid != INV_TEST_UNIT_ID) + { + try + { + suite = &framework::get(suiteid); + } + catch (std::exception const&) + { + // asked test case + return false; + } + } + else + return false; + } + return true; +} + }//namespace diff --git a/retesteth/TestHelper.h b/retesteth/TestHelper.h index 2e0b06cd5..2897e90f8 100644 --- a/retesteth/TestHelper.h +++ b/retesteth/TestHelper.h @@ -23,9 +23,10 @@ Json::Value readJson(boost::filesystem::path const& _path); /// Safely read the json file into DataObject spDataObject readJsonData(boost::filesystem::path const& _file, std::string const& _stopper = std::string(), bool _autosort = false); spDataObject readYamlData(boost::filesystem::path const& _file, bool _sort = false); +spDataObject readAutoDataWithoutOptions(boost::filesystem::path const& _file, bool _sort = false); /// Get files from directory -std::vector getFiles(boost::filesystem::path const& _dirPath, std::set _extentionMask, std::string const& _particularFile = {}); +std::vector getFiles(boost::filesystem::path const& _dirPath, std::set const& _extentionMask, std::string const& _particularFile = {}); /// Get test repo path from ETHEREUM_TEST_PATH environment variable boost::filesystem::path getTestPath(); @@ -67,7 +68,7 @@ enum class ExecCMDWarning NoWarning, NoWarningNoError }; -std::string executeCmd(std::string const& _command, ExecCMDWarning _warningOnEmpty = ExecCMDWarning::WarningOnEmptyResult); +std::string executeCmd(std::string const& _command, int& _exitCode, ExecCMDWarning _warningOnEmpty = ExecCMDWarning::WarningOnEmptyResult); // Return the vector of most looking like as _needles strings from the vector std::vector levenshteinDistance( @@ -94,7 +95,9 @@ bool inArray(std::list const& _array, const T& _val) /// Explode string into array of strings by `delim` std::vector explode(std::string const& s, char delim); void removeSubChar(std::string& _string, unsigned char _r); +void removeSubChar(std::string& _string, std::vector _r); std::string makePlussedFork(test::teststruct::FORK const& _net); +bool isBoostSuite(std::string const& suiteName); /// See what kind of a string is str diff --git a/retesteth/TestOutputHelper.cpp b/retesteth/TestOutputHelper.cpp index 16093e31c..3328d1edd 100644 --- a/retesteth/TestOutputHelper.cpp +++ b/retesteth/TestOutputHelper.cpp @@ -31,14 +31,15 @@ using namespace test; using namespace test::debug; using namespace boost; using namespace boost::unit_test; +namespace fs = boost::filesystem; mutex g_outputVectors; static std::vector outputVectors; mutex g_finishedTestFoldersMapMutex; typedef std::set FolderNameSet; -static std::map finishedTestFoldersMap; -// static std::map exceptionTestFoldersMap; +static std::map finishedTestFoldersMap; +// static std::map exceptionTestFoldersMap; void checkUnfinishedTestFolders(); // Checkup that all test folders are active during the test run typedef std::pair execTimeName; @@ -109,7 +110,7 @@ bool TestOutputHelper::markError(std::string const& _message) // Mark the error string const testDebugInfo = m_testInfo.errorDebug(); - m_errors.push_back(_message + testDebugInfo); + m_errors.emplace_back(_message + testDebugInfo); if (testDebugInfo.empty()) ETH_WARNING(TestOutputHelper::get().testName() + ", Message: " + _message + ", has empty debugInfo! Missing debug Testinfo for test step."); @@ -200,7 +201,7 @@ void TestOutputHelper::finishTest() res.second = TestInfo::caseName(); std::cout << res.second + " time: " + fto_string(res.first) << "\n"; std::lock_guard lock(g_execTimeResults); - execTimeResults.push_back(res); + execTimeResults.emplace_back(res); } printBoostError(); // !! could delete instance of TestOutputHelper !! } @@ -302,13 +303,13 @@ thread::id TestOutputHelper::getThreadID() } // check if a boost path contain no test files -bool pathHasTests(boost::filesystem::path const& _path) +bool pathHasTests(fs::path const& _path) { - using fsIterator = boost::filesystem::directory_iterator; + using fsIterator = fs::directory_iterator; for (fsIterator it(_path); it != fsIterator(); ++it) { // if the extention of a test file - if (boost::filesystem::is_regular_file(it->path()) && + if (fs::is_regular_file(it->path()) && (it->path().extension() == ".json" || it->path().extension() == ".yml")) { // if the filename ends with Filler/Copier type @@ -322,47 +323,74 @@ bool pathHasTests(boost::filesystem::path const& _path) return false; } +string selectRootPath(string const& _str, string const& _tArgument) +{ + string masterPrefix = _tArgument; + size_t const pos1 = _str.find("src/"); + if (pos1 != string::npos) + { + size_t const pos2 = _str.find("/", pos1 + 4); + size_t const pos3 = _tArgument.find("/"); + if (pos3 != string::npos) + masterPrefix = _tArgument.substr(0, pos3); + if (pos2 != string::npos) + return masterPrefix + "/" + _str.substr(pos2 + 1); + } + return masterPrefix; +} + void checkUnfinishedTestFolders() { std::lock_guard lock(g_finishedTestFoldersMapMutex); + auto const& opt = Options::get(); // Unit tests does not mark test folders if (finishedTestFoldersMap.size() == 0) return; - if (Options::get().rCurrentTestSuite.empty()) + if (opt.rCurrentTestSuite.empty()) ETH_WARNING("Options rCurrentTestSuite is empty, total tests run can be wrong!"); // -t SuiteName/SubSuiteName/caseName parse caseName as filter // rCurrentTestSuite is empty if run without -t argument string filter; - size_t pos = Options::get().rCurrentTestSuite.rfind('/'); + size_t pos = opt.rCurrentTestSuite.rfind('/'); if (pos != string::npos) - filter = Options::get().rCurrentTestSuite.substr(pos + 1); + filter = opt.rCurrentTestSuite.substr(pos + 1); - std::map::const_iterator singleTest = + std::map::const_iterator singleTest = finishedTestFoldersMap.begin(); - if (!filter.empty() && finishedTestFoldersMap.size() <= 1 && boost::filesystem::exists(singleTest->first / filter)) + if (!filter.empty() && finishedTestFoldersMap.size() <= 1 && fs::exists(singleTest->first / filter)) { if (!pathHasTests(singleTest->first / filter)) - ETH_WARNING(string("Test folder ") + (singleTest->first / filter).c_str() + - " appears to have no tests!"); + ETH_WARNING(string("Test folder ") + (singleTest->first / filter).c_str() + " appears to have no tests!"); } else { for (auto const& allTestsIt : finishedTestFoldersMap) { - boost::filesystem::path path = allTestsIt.first; + fs::path path = allTestsIt.first; + if (!fs::exists(path)) + { + ETH_WARNING(path.string() + " does not exist!"); + continue; + } set allFolders; - using fsIterator = boost::filesystem::directory_iterator; + using fsIterator = fs::directory_iterator; for (fsIterator it(path); it != fsIterator(); ++it) { - if (boost::filesystem::is_directory(*it)) + if (fs::is_directory(*it)) { - string const folderName = it->path().filename().string(); - allFolders.insert(folderName); - if (!pathHasTests(it->path())) - ETH_WARNING(string("Test folder ") + it->path().c_str() + - " appears to have no tests!"); + string const suiteName = selectRootPath(it->path().string(), opt.rCurrentTestSuite); + bool const isSuite = isBoostSuite(suiteName); + + if (!isSuite) + { + string const folderName = it->path().filename().string(); + allFolders.insert(folderName); + + if (!pathHasTests(it->path())) + ETH_WARNING(string("Test folder ") + it->path().c_str() + " appears to have no tests!"); + } } } @@ -379,17 +407,18 @@ void checkUnfinishedTestFolders() // Mark test folder _folderName as finished for the test suite path _suitePath void TestOutputHelper::markTestFolderAsFinished( - boost::filesystem::path const& _suitePath, string const& _folderName) + fs::path const& _suitePath, string const& _folderName) { std::lock_guard lock(g_finishedTestFoldersMapMutex); finishedTestFoldersMap[_suitePath].emplace(_folderName); } - TestInfo::TestInfo(std::string const& _info, std::string const& _testName) : m_sFork(_info) { + namespace framework = boost::unit_test::framework; m_isGeneralTestInfo = true; - m_currentTestCaseName = boost::unit_test::framework::current_test_case().p_name; + m_currentTestCaseName = makeTestCaseName(); + if (!_testName.empty()) TestOutputHelper::get().setCurrentTestName(_testName); } @@ -427,10 +456,27 @@ std::string TestInfo::errorDebug() const return message + ")" + cDefault; } +string TestInfo::makeTestCaseName() const +{ + string name; + auto const& boostTCase = framework::current_test_case(); + try + { + auto const& boostSuite = framework::get(boostTCase.p_parent_id); + name = boostSuite.p_name.get() + "/"; + } + catch (std::exception const&) + { + ETH_WARNING("Error getting parent suite from boost!" + boostTCase.p_name.get()); + } + + return name + boostTCase.p_name.get(); +} + void TestOutputHelper::addTestVector(std::string&& _str) { std::lock_guard lock(g_outputVectors); - outputVectors.push_back(_str); + outputVectors.emplace_back(_str); } void TestOutputHelper::printTestVectors() diff --git a/retesteth/TestOutputHelper.h b/retesteth/TestOutputHelper.h index 7b7e397f3..e49aaf026 100644 --- a/retesteth/TestOutputHelper.h +++ b/retesteth/TestOutputHelper.h @@ -34,14 +34,14 @@ struct TestInfo : m_sFork(_fork), m_trD(_trD), m_trG(_trG), m_trV(_trV) { m_isStateTransactionInfo = true; - m_currentTestCaseName = boost::unit_test::framework::current_test_case().p_name; + m_currentTestCaseName = makeTestCaseName(); } TestInfo(std::string const& _fork, size_t _trD, size_t _trG, size_t _trV) : m_sFork(_fork), m_trD(_trD), m_trG(_trG), m_trV(_trV) { m_isStateTransactionInfo = true; - m_currentTestCaseName = boost::unit_test::framework::current_test_case().p_name; + m_currentTestCaseName = makeTestCaseName(); } TestInfo(std::string const& _fork, size_t _block, std::string const& _chainName = std::string()) @@ -51,7 +51,7 @@ struct TestInfo m_isStateTransactionInfo(false) { m_isBlockchainTestInfo = true; - m_currentTestCaseName = boost::unit_test::framework::current_test_case().p_name; + m_currentTestCaseName = makeTestCaseName(); } TestInfo(std::string const& _info, std::string const& _testName = std::string()); @@ -62,6 +62,9 @@ struct TestInfo void setTrDataDebug(std::string const& _data) { m_sTransactionData = _data; } +private: + std::string makeTestCaseName() const; + private: std::string m_sFork, m_sChainName; std::string m_currentTestCaseName; diff --git a/retesteth/compiler/Compiler.cpp b/retesteth/compiler/Compiler.cpp index 2cea5dd8a..7bb537b20 100644 --- a/retesteth/compiler/Compiler.cpp +++ b/retesteth/compiler/Compiler.cpp @@ -12,6 +12,33 @@ namespace fs = boost::filesystem; namespace { + +void removeCommentsFromCode(string& _code) +{ + size_t posComment = _code.find("#"); + while(posComment != string::npos) + { + size_t posEndl = string::npos; + size_t const posEndl1 = _code.find('\n'); + size_t const posEndl2 = _code.find("\\n"); + posEndl = min(posEndl1, posEndl2); + + if (posEndl != string::npos) + { + if (posEndl < posComment) + { + _code.erase(posEndl, 1); + posComment = _code.find("#"); + continue; + } + _code.erase(posComment, posEndl - posComment + 1); + } + else + _code.erase(posComment); + posComment = _code.find("#"); + } +} + string compileLLL(string const& _code) { #if defined(_WIN32) @@ -23,7 +50,8 @@ string compileLLL(string const& _code) writeFile(path.string(), _code); try { - string result = executeCmd(cmd); + int exitCode; + string result = executeCmd(cmd, exitCode); fs::remove_all(path); result = "0x" + result; test::compiler::utiles::checkHexHasEvenLength(result); @@ -55,7 +83,8 @@ bool tryCustomCompiler(string const& _code, string& _compiledCode) string cmd = compiler.second.string() + " " + path.string(); writeFile(path.string(), customCode); - _compiledCode = test::executeCmd(cmd); + int exitCode; + _compiledCode = test::executeCmd(cmd, exitCode); utiles::checkHexHasEvenLength(_compiledCode); return true; } @@ -99,6 +128,9 @@ void tryKnownCompilers(string const& _code, solContracts const& _preSolidity, st if (bRawEndline) { _compiledCode = _code.substr(pos + c_rawPrefix.length() + 1); + test::removeSubChar(_compiledCode, {' ', '-'}); + removeCommentsFromCode(_compiledCode); + test::removeSubChar(_compiledCode, {'\n', 'n', '\\'}); utiles::checkHexHasEvenLength(_compiledCode); found = true; } diff --git a/retesteth/compiler/Solidity.cpp b/retesteth/compiler/Solidity.cpp index 4194ba6d7..1bd09a228 100644 --- a/retesteth/compiler/Solidity.cpp +++ b/retesteth/compiler/Solidity.cpp @@ -435,7 +435,8 @@ solContracts compileSolidity(string const& _code) fs::path const path(fs::temp_directory_path() / fs::unique_path()); string const cmd = string("solc --bin-runtime ") + path.string(); writeFile(path.string(), _code); - string result = executeCmd(cmd); + int exitCode; + string result = executeCmd(cmd, exitCode); solContracts contracts; string const codeNamePrefix = "======="; diff --git a/retesteth/configs/ClientConfig.cpp b/retesteth/configs/ClientConfig.cpp index 4b3ea501a..ba9f4dea1 100644 --- a/retesteth/configs/ClientConfig.cpp +++ b/retesteth/configs/ClientConfig.cpp @@ -3,6 +3,8 @@ #include #include #include +#include +#include using namespace std; using namespace dataobject; using namespace test::debug; @@ -30,6 +32,8 @@ ClientConfig::ClientConfig(fs::path const& _clientConfigPath) : m_id(ClientConfi fs::path configFile = _clientConfigPath / "config"; ETH_FAIL_REQUIRE_MESSAGE(fs::exists(configFile), string("Client config not found: ") + configFile.c_str()); + m_pyspecsStartPath = _clientConfigPath.parent_path() / "pyspecsStart.sh"; + // Script to setup the instance fs::path setupScript = _clientConfigPath / "setup.sh"; if (fs::exists(setupScript)) @@ -267,11 +271,14 @@ std::string const& ClientConfig::translateException(string const& _exceptionName for (auto const& el : suggestions) message += el + ", "; message += " ...)"; - ETH_ERROR_MESSAGE("Config::getExceptionString '" + _exceptionName + "' not found in client config `exceptions` section! (" + - cfg.path().c_str() + ")" + message); + string const error = "Config::getExceptionString '" + _exceptionName + "' not found in client config `exceptions` section! (" + + cfg.path().c_str() + ")" + message; + if (Options::get().filltests) + ETH_ERROR_MESSAGE(error); + else + ETH_WARNING(error); // --- - static string const notfound = string(); - return notfound; + return C_EMPTY_STR; } // Get Contents of genesis template for specified FORK @@ -307,7 +314,8 @@ void ClientConfig::initializeFirstSetup() if (fs::exists(getSetupScript())) { auto cmd = [](string const& _cmd) { - test::executeCmd(_cmd, ExecCMDWarning::NoWarning); + int exitCode; + test::executeCmd(_cmd, exitCode, ExecCMDWarning::NoWarning); }; string const setup = getSetupScript().c_str(); ETH_DC_MESSAGE(DC::RPC, string("Initialize setup script: ") + setup); diff --git a/retesteth/configs/ClientConfig.h b/retesteth/configs/ClientConfig.h index 134ab181e..8e989073e 100644 --- a/retesteth/configs/ClientConfig.h +++ b/retesteth/configs/ClientConfig.h @@ -46,6 +46,7 @@ class ClientConfig // Path to name.sh file for IPC client initialization boost::filesystem::path const getShellPath() const { return cfgFile().shell(); } boost::filesystem::path const getConfigPath() const { return cfgFile().path(); } + std::string getOptionName() const { return m_clientConfigFile->path().parent_path().stem().string(); } // Functionality // Verify FORK is allowed by Fork + AdditionalForks and throw an error if not @@ -79,6 +80,7 @@ class ClientConfig boost::filesystem::path const& getSetupScript() const { return m_setupScriptPath; } boost::filesystem::path const& getStartScript() const { return m_starterScriptPath; } boost::filesystem::path const& getStopperScript() const { return m_stopperScriptPath; } + boost::filesystem::path const& getPySpecsStartScript() const { return m_pyspecsStartPath; } // Replace notations in requests if needed void performFieldReplace(DataObject& _data, FieldReplaceDir const& _dir) const; @@ -97,6 +99,7 @@ class ClientConfig boost::filesystem::path m_setupScriptPath; ///< Path to setup script (run once before thread exec) boost::filesystem::path m_starterScriptPath; ///< Path to starter script boost::filesystem::path m_stopperScriptPath; ///< Path to stopper script + boost::filesystem::path m_pyspecsStartPath; ///< Path to pyspecs exec script }; } // namespace test diff --git a/retesteth/configs/Options.cpp b/retesteth/configs/Options.cpp index 3191a1cf9..5bb910124 100644 --- a/retesteth/configs/Options.cpp +++ b/retesteth/configs/Options.cpp @@ -132,7 +132,7 @@ std::vector const& Options::DynamicOptions::getClientConfigs() ETH_DC_MESSAGE(DC::STATS, "Active client configurations: '" + clientNames + "'"); for (auto const& clientName : cfgs) - m_clientConfigs.push_back(ClientConfig(homeDir / clientName)); + m_clientConfigs.emplace_back(ClientConfig(homeDir / clientName)); } return m_clientConfigs; } diff --git a/retesteth/configs/Options.h b/retesteth/configs/Options.h index ebf9a6861..1d8682303 100644 --- a/retesteth/configs/Options.h +++ b/retesteth/configs/Options.h @@ -5,6 +5,8 @@ namespace retesteth::options { extern dataobject::DataObject map_configs; +extern std::string const yul_compiler_sh; +extern std::string const t8ntool_start; #define REGISTER(X) \ class gen##X { public: gen##X(); }; @@ -14,7 +16,8 @@ extern dataobject::DataObject map_configs; #define DECLARE_T8NTOOL(X) \ FOR_EACH(X, t8ntoolcfg, RewardsCfg, FrontierCfg, HomesteadCfg, EIP150Cfg, EIP158Cfg, ByzantiumCfg, \ ConstantinopleCfg, ConstantinopleFixCfg, IstanbulCfg, BerlinCfg, LondonCfg, MergeCfg, \ - ArrowGlacierCfg, GrayGlacierCfg, ArrowGlacierToMergeAtDiffC0000Cfg, \ + ShanghaiCfg, \ + ArrowGlacierCfg, GrayGlacierCfg, ArrowGlacierToMergeAtDiffC0000Cfg, MergeToShanghaiAtTime15kCfg, \ FrontierToHomesteadCfg, HomesteadToDaoCfg, HomesteadToEIP150Cfg, EIP158ToByzantiumCfg, \ ByzantiumToConstantinopleFixCfg, BerlinToLondonCfg ) @@ -22,6 +25,9 @@ extern dataobject::DataObject map_configs; FOR_EACH(X, etccfg, RewardsCfgETC, AtlantisCfgETC, AghartaCfgETC, PhoenixCfgETC, MagnetoCfgETC, \ MystiqueCfgETC) +#define DECLARE_NIMBUS(X) \ + FOR_EACH(X, nimbuscfg, RewardsCfgNIMBUS, MergeCfgNIMBUS) + #define DECLARE_ETCTR(X) \ FOR_EACH(X, etctranslatecfg, RewardsCfgETCTR, ByzantiumCfgETCTR, ConstantinopleCfgETCTR, ConstantinopleFixCfgETCTR, \ IstanbulCfgETCTR, BerlinCfgETCTR, LondonCfgETCTR, MergeCfgETCTR) @@ -35,6 +41,9 @@ extern dataobject::DataObject map_configs; #define DECLARE_BESU(X) \ FOR_EACH(X, besucfg) +#define DECLARE_EVMONE(X) \ + FOR_EACH(X, evmonecfg) + #define DECLARE_T8NTOOL_EIP(X) \ FOR_EACH(X, t8ntooleipcfg, t8ntooleip_genRewardsCfg, t8ntooleip_genLondon1884Cfg) @@ -48,10 +57,12 @@ extern dataobject::DataObject map_configs; // Main Configs (T8NTOOL is the base config that puts in to default for other clients as well) DECLARE_T8NTOOL(REGISTER) DECLARE_BESU(REGISTER) +DECLARE_EVMONE(REGISTER) DECLARE_ETC(REGISTER) DECLARE_ETCTR(REGISTER) DECLARE_OEWRAP(REGISTER) DECLARE_ETHJS(REGISTER) +DECLARE_NIMBUS(REGISTER) // Example configs DECLARE_T8NTOOL_EIP(REGISTER) @@ -65,10 +76,12 @@ class OptionsInit OptionsInit() { DECLARE_T8NTOOL(INIT) DECLARE_BESU(INIT) + DECLARE_EVMONE(INIT) DECLARE_ETC(INIT) DECLARE_ETCTR(INIT) DECLARE_OEWRAP(INIT) DECLARE_ETHJS(INIT) + DECLARE_NIMBUS(INIT) DECLARE_T8NTOOL_EIP(INIT) DECLARE_ALETH(INIT) diff --git a/retesteth/configs/clientconfigs/besu.cpp b/retesteth/configs/clientconfigs/besu.cpp index 347645542..5548868a7 100644 --- a/retesteth/configs/clientconfigs/besu.cpp +++ b/retesteth/configs/clientconfigs/besu.cpp @@ -6,18 +6,18 @@ namespace retesteth::options { string const besu_config = R"({ "name" : "Hyperledger Besu on TCP", - "socketType" : "tcp", - "socketAddress" : [ - "127.0.0.1:47710", - "127.0.0.1:47711", - "127.0.0.1:47712", - "127.0.0.1:47713" - "127.0.0.1:47714", - "127.0.0.1:47715", - "127.0.0.1:47716", - "127.0.0.1:47717" - ], - "initializeTime" : "5", + "socketType" : "tranition-tool", + "socketAddress" : "start.sh", + "initializeTime" : "0", + "checkDifficulty" : true, + "calculateDifficulty" : false, + "checkBasefee" : true, + "calculateBasefee" : false, + "checkLogsHash" : true, + "support1559" : true, + "transactionsAsJson" : false, + "tmpDir" : "/dev/shm", + "defaultChainID" : 1, "forks" : [ "Frontier", "Homestead", @@ -28,7 +28,9 @@ string const besu_config = R"({ "ConstantinopleFix", "Istanbul", "Berlin", - "London" + "London", + "Merge", + "Shanghai" ], "additionalForks" : [ "FrontierToHomesteadAt5", @@ -38,33 +40,251 @@ string const besu_config = R"({ "ByzantiumToConstantinopleFixAt5", "BerlinToLondonAt5", "ArrowGlacier", - "GrayGlacier" + "GrayGlacier", + "MergeToShanghaiAtTime15k" + ], + "fillerSkipForks" : [ + "Merge+3540+3670", + "Merge+3860", + "Merge+3855" ], "exceptions" : { - "ExtraDataTooBig" : "extra-data too long", - "InvalidDifficulty" : "invalid difficulty" + "AddressTooShort" : "input string too short for common.Address", + "AddressTooLong" : "rlp: input string too long for common.Address, decoding into (types.Transaction)(types.LegacyTx).To", + "NonceMax" : "nonce exceeds 2^64-1", + "NonceTooLong" : "rlp: input string too long for uint64, decoding into (types.Transaction)(types.LegacyTx).Nonce", + "InvalidVRS" : "invalid transaction v, r, s values", + "InvalidV" : "rlp: expected input string or byte for *big.Int, decoding into (types.Transaction)(types.LegacyTx).V", + "InvalidR" : "rlp: expected input string or byte for *big.Int, decoding into (types.Transaction)(types.LegacyTx).R", + "InvalidS" : "rlp: expected input string or byte for *big.Int, decoding into (types.Transaction)(types.LegacyTx).S", + "InvalidChainID" : "invalid chain id for signer", + "ECRecoveryFail" : "recovery failed", + "InvalidStateRoot" : "", + "ExtraDataTooBig" : "Error importing raw rlp block: Header extraData > 32 bytes", + "InvalidData" : "rlp: expected input string or byte for []uint8, decoding into (types.Transaction)(types.LegacyTx).Data", + "InvalidDifficulty" : "Invalid difficulty:", + "InvalidDifficulty2" : "Error in field: difficulty", + "InvalidWithdrawals" : "Error in field: withdrawalsRoot", + "InvalidDifficulty_TooLarge" : "Blockheader parse error: VALUE >u256", + "InvalidGasLimit" : "Header gasLimit > 0x7fffffffffffffff", + "InvalidGasLimit2" : "Invalid gaslimit:", + "InvalidGasLimit3" : "GasLimit must be < 0x7fffffffffffffff", + "InvalidGasLimit4" : "rlp: input string too long for uint64, decoding into (types.Transaction)(types.LegacyTx).Gas", + "InvalidGasLimit5" : "rlp: expected input string or byte for uint64, decoding into (types.Transaction)(types.LegacyTx).Gas", + "InvalidValue" : "value exceeds 256 bits", + "InvalidGasPrice" : "gasPrice exceeds 256 bits", + "InvalidMaxPriorityFeePerGas" : "maxPriorityFeePerGas exceeds 256 bits", + "InvalidMaxFeePerGas" : "maxFeePerGas exceeds 256 bits", + "InvalidNonce" : "rlp: expected input string or byte for uint64, decoding into (types.Transaction)(types.LegacyTx).Nonce", + "InvalidTo" : "rlp: expected input string or byte for common.Address, decoding into (types.Transaction)(types.LegacyTx).To", + "GasLimitPriceProductOverflow" : "gas * gasPrice exceeds 256 bits", + "TooMuchGasUsed" : "Invalid gasUsed:", + "TooMuchGasUsed2" : "Error importing raw rlp block: t8ntool didn't return a transaction with hash", + "LeadingZerosGasLimit" : "rlp: non-canonical integer (leading zero bytes) for uint64, decoding into (types.Transaction)(types.LegacyTx).Gas", + "LeadingZerosGasPrice" : "rlp: non-canonical integer (leading zero bytes) for *big.Int, decoding into (types.Transaction)(types.LegacyTx).GasPrice", + "LeadingZerosValue" : "rlp: non-canonical integer (leading zero bytes) for *big.Int, decoding into (types.Transaction)(types.LegacyTx).Value", + "LeadingZerosNonce" : "rlp: non-canonical integer (leading zero bytes) for uint64, decoding into (types.Transaction)(types.LegacyTx).Nonce", + "LeadingZerosR" : "rlp: non-canonical integer (leading zero bytes) for *big.Int, decoding into (types.Transaction)(types.LegacyTx).R", + "LeadingZerosS" : "rlp: non-canonical integer (leading zero bytes) for *big.Int, decoding into (types.Transaction)(types.LegacyTx).S", + "LeadingZerosV" : "rlp: non-canonical integer (leading zero bytes) for *big.Int, decoding into (types.Transaction)(types.LegacyTx).V", + "LeadingZerosDataSize" : "rlp: non-canonical size information for []uint8, decoding into (types.Transaction)(types.LegacyTx).Data", + "LeadingZerosNonceSize" : "rlp: non-canonical size information for uint64, decoding into (types.Transaction)(types.LegacyTx).Nonce", + "InvalidNumber" : "BlockHeader number != parent.number + 1", + "InvalidTimestampEqualParent" : "timestamp equals parent's", + "InvalidTimestampOlderParent" : "BlockHeader timestamp is less or equal then it's parent block!", + "InvalidLogBloom" : "Error in field: bloom", + "InvalidStateRoot" : "Error in field: stateRoot", + "InvalidGasUsed" : "Error in field: gasUsed", + "InvalidGasUsed2" : "t8ntool didn't return a transaction with hash", + "InvalidBlockMixHash" : "invalid mix digest", + "InvalidBlockNonce" : "", + "UnknownParent" : "unknown parent hash", + "UnknownParent2" : "unknown parent hash", + "InvalidReceiptsStateRoot" : "Error in field: receiptTrie", + "InvalidTransactionsRoot" : "Error in field: transactionsTrie", + "InvalidUnclesHash" : "Error in field: uncleHash", + "InvalidUncleParentHash" : "Parent block hash not found:", + "UncleInChain" : "Block is already in chain!", + "UncleIsAncestor" : "Block is already in chain!", + "UncleParentIsNotAncestor" : "Uncle number is wrong!", + "TooManyUncles" : "Too many uncles!", + "UncleIsBrother" : "Uncle is brother!", + "OutOfGas" : "out of gas", + "SenderNotEOA" : "sender not an eoa:", + "IntrinsicGas" : "t8ntool didn't return a transaction with hash", + "ExtraDataIncorrectDAO" : "BlockHeader require Dao ExtraData!", + "InvalidTransactionVRS" : "t8ntool didn't return a transaction with hash", + "BLOCKHEADER_VALUE_TOOLARGE" : "Blockheader parse error: VALUE >u256", + "TRANSACTION_VALUE_TOOLARGE" : "TransactionLegacy convertion error: VALUE >u256", + "TRANSACTION_VALUE_TOOSHORT" : "t8ntool didn't return a transaction with hash", + "TR_NonceHasMaxValue" : "nonce has max value:", + "OVERSIZE_RLP" : "Error importing raw rlp block: OversizeRLP", + "RLP_BadCast" : "BadCast", + "RLP_ExpectedAsList" : "expected to be list", + "RLP_TooFewElements" : "rlp: too few elements ", + "RLP_TooManyElements" : "rlp: input list has too many elements ", + "RLP_InputContainsMoreThanOneValue" : "Error importing raw rlp block: OversizeRLP", + "RLP_VALUESIZE_MORE_AVAILABLEINPUTLENGTH" : "Error importing raw rlp block: UndersizeRLP", + "RLP_ELEMENT_LARGER_CONTAININGLIST_UNDERSIZE" : "Error importing raw rlp block: UndersizeRLP", + "RLP_ELEMENT_LARGER_CONTAININGLIST_OVERSIZE" : "Error importing raw rlp block: OversizeRLP", + "RLP_ExpectedInputList_EXTBLOCK" : "Error importing raw rlp block: RLP is expected to be list", + "RLP_InvalidArg0_UNMARSHAL_BYTES" : "Error importing raw rlp block: BadCast", + "RLP_ExpectedInputList_HEADER_DECODEINTO_BLOCK_EXTBLOCK" : "Error importing raw rlp block: BlockHeader RLP is expected to be list", + "RLP_InputList_TooManyElements_HEADER_DECODEINTO_BLOCK_EXTBLOCK_HEADER" : "Error importing raw rlp block: Uncleheader RLP is expected to be list", + "RLP_InputList_TooManyElements_TXDATA_DECODEINTO_BLOCK_EXTBLOCK_TXS0" : "Error importing raw rlp block: OversizeRLP", + "RLP_InputString_TooShort_ADDRESS_DECODEINTO_BLOCK_EXTBLOCK_HEADER_COINBASE" : "Error importing raw rlp block: OversizeRLP", + "RLP_InputString_TooShort_ADDRESS_DECODEINTO_BLOCK_EXTBLOCK_HEADER_COINBASE2" : "Blockheader parse error: Key `coinbase` is not hash20", + "RLP_InputString_TooShort_ADDRESS_DECODEINTO_BLOCK_EXTBLOCK_TXS0_RECIPIENT" : "TransactionLegacy convertion error: Key `to` is not hash20", + "RLP_InputString_TooLong_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_ROOT" : "Error importing raw rlp block: OversizeRLP", + "RLP_InputString_TooLong_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_ROOT2" : "Blockheader parse error: Key `stateRoot` is not hash32", + "RLP_InputString_TooLong_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_MIXDIGEST" : "Error importing raw rlp block: OversizeRLP", + "RLP_InputString_TooLong_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_MIXDIGEST2" : "Blockheader parse error: Key `mixHash` is not hash32", + "RLP_InputString_TooLong_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_PARENTHASH" : "Error importing raw rlp block: OversizeRLP", + "RLP_InputString_TooLong_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_PARENTHASH2" : "Blockheader parse error: Key `parentHash` is not hash32", + "RLP_InputString_TooLong_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_RECEIPTHASH" : "Error importing raw rlp block: OversizeRLP", + "RLP_InputString_TooLong_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_RECEIPTHASH2" : "Blockheader parse error: Key `receiptTrie` is not hash32", + "RLP_InputString_TooLong_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_TXHASH" : "Blockheader parse error: Key `transactionsTrie` is not hash32", + "RLP_InputString_TooLong_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_UNCLEHASH" : "Error importing raw rlp block: OversizeRLP", + "RLP_InputString_TooLong_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_UNCLEHASH2" : "Blockheader parse error: Key `uncleHash` is not hash32", + "RLP_InputString_TooLong_UINT64_DECODEINTO_BLOCK_EXTBLOCK_HEADER_GASLIMIT" : "Blockheader parse error: VALUE >u256", + "RLP_InputString_TooLong_UINT64_DECODEINTO_BLOCK_EXTBLOCK_HEADER_GASUSED" : "Blockheader parse error: VALUE >u256", + "RLP_InputString_TooLong_UINT64_DECODEINTO_BLOCK_EXTBLOCK_HEADER_TIME" : "Blockheader parse error: VALUE >u256", + "RLP_InputString_TooLong_UINT64_DECODEINTO_BLOCK_EXTBLOCK_TXS0_GASLIMIT" : "TransactionLegacy convertion error: VALUE >u256", + "RLP_InputString_TooShort_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_RECEIPTHASH" : "Error importing raw rlp block: OversizeRLP", + "RLP_InputString_TooShort_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_RECEIPTHASH2" : "Blockheader parse error: Key `receiptTrie` is not hash32", + "RLP_InputString_TooShort_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_ROOT" : "Blockheader parse error: Key `stateRoot` is not hash32", + "RLP_InputString_TooShort_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_MIXDIGEST" : "Error importing raw rlp block: OversizeRLP", + "RLP_InputString_TooShort_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_MIXDIGEST2" : "Blockheader parse error: Key `mixHash` is not hash32", + "RLP_InputString_TooShort_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_PARENTHASH" : "Error importing raw rlp block: OversizeRLP", + "RLP_InputString_TooShort_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_PARENTHASH2" : "Blockheader parse error: Key `parentHash` is not hash32", + "RLP_InputString_TooShort_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_UNCLEHASH" : "Error importing raw rlp block: OversizeRLP", + "RLP_InputString_TooShort_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_UNCLEHASH2" : "Blockheader parse error: Key `uncleHash` is not hash32", + "RLP_InputString_TooShort_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_TXHASH" : "Error importing raw rlp block: OversizeRLP", + "RLP_InputString_TooShort_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_TXHASH2" : "Blockheader parse error: Key `transactionsTrie` is not hash32", + "RLP_InputString_TooShort_BLOOM_DECODEINTO_BLOCK_EXTBLOCK_HEADER_BLOOM" : "Error importing raw rlp block: OversizeRLP", + "RLP_NonCanonicalINT_LeadingZeros_BIGINT_DECODEINTO_BLOCK_EXTBLOCK_HEADER_DIFFICULTY" : "Error importing raw rlp block: OversizeRLP", + "RLP_NonCanonicalINT_LeadingZeros_BIGINT_DECODEINTO_BLOCK_EXTBLOCK_HEADER_DIFFICULTY2" : "Blockheader parse error: VALUE has leading 0", + "RLP_NonCanonicalINT_LeadingZeros_UINT64_DECODEINTO_BLOCK_EXTBLOCK_HEADER_GASLIMIT" : "Error importing raw rlp block: OversizeRLP", + "RLP_NonCanonicalINT_LeadingZeros_UINT64_DECODEINTO_BLOCK_EXTBLOCK_HEADER_GASLIMIT2" : "Blockheader parse error: VALUE has leading 0", + "RLP_NonCanonicalINT_LeadingZeros_UINT64_DECODEINTO_BLOCK_EXTBLOCK_HEADER_GASUSED" : "Error importing raw rlp block: OversizeRLP", + "RLP_NonCanonicalINT_LeadingZeros_UINT64_DECODEINTO_BLOCK_EXTBLOCK_HEADER_GASUSED2" : "Blockheader parse error: VALUE has leading 0", + "RLP_NonCanonicalINT_LeadingZeros_UINT64_DECODEINTO_BLOCK_EXTBLOCK_HEADER_TIME" : "Error importing raw rlp block: OversizeRLP", + "RLP_NonCanonicalINT_LeadingZeros_UINT64_DECODEINTO_BLOCK_EXTBLOCK_HEADER_TIME2" : "Blockheader parse error: VALUE has leading 0", + "RLP_NonCanonicalINT_LeadingZeros_UINT64_DECODEINTO_BLOCK_EXTBLOCK_TXS0_GASLIMIT" : "Error importing raw rlp block: OversizeRLP", + "RLP_NonCanonicalINT_LeadingZeros_UINT64_DECODEINTO_BLOCK_EXTBLOCK_TXS0_GASLIMIT2" : "TransactionLegacy convertion error: VALUE has leading 0", + "RLP_NonCanonicalINT_LeadingZeros_BIGINT_DECODEINTO_BLOCK_EXTBLOCK_HEADER_NUMBER" : "Error importing raw rlp block: OversizeRLP", + "RLP_NonCanonicalINT_LeadingZeros_BIGINT_DECODEINTO_BLOCK_EXTBLOCK_HEADER_NUMBER2" : "Error importing raw rlp block: OversizeRLP", + "RLP_NonCanonicalINT_LeadingZeros_BIGINT_DECODEINTO_BLOCK_EXTBLOCK_TXS0_TXDATA_PRICE" : "Error importing raw rlp block: OversizeRLP", + "RLP_NonCanonicalINT_LeadingZeros_BIGINT_DECODEINTO_BLOCK_EXTBLOCK_TXS0_TXDATA_R" : "TransactionLegacy convertion error: VALUE has leading 0", + "RLP_NonCanonicalINT_LeadingZeros_BIGINT_DECODEINTO_BLOCK_EXTBLOCK_TXS0_TXDATA_S" : "TransactionLegacy convertion error: VALUE has leading 0", + "RLP_InputString_TooLong_BLOOM_DECODEINTO_BLOCK_EXTBLOCK_HEADER_BLOOM" : "Blockheader parse error: Key `bloom` is not hash256", + "RLP_ExpectedInputString_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_PARENTHASH" : "Error importing raw rlp block: Blockheader RLP field is not data!", + "RLP_ExpectedInputString_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_RECEIPTHASH" : "Error importing raw rlp block: Blockheader RLP field is not data!", + "RLP_ExpectedInputString_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_ROOT" : "Error importing raw rlp block: Blockheader RLP field is not data!", + "RLP_ExpectedInputString_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_MIXDIGEST" : "Error importing raw rlp block: Blockheader RLP field is not data!", + "RLP_ExpectedInputString_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_TXHASH" : "Error importing raw rlp block: Blockheader RLP field is not data!", + "RLP_ExpectedInputString_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_UNCLEHASH" : "Error importing raw rlp block: Blockheader RLP field is not data!", + "RLP_ExpectedInputString_ADDRESS_DECODEINTO_BLOCK_EXTBLOCK_HEADER_COINBASE" : "Error importing raw rlp block: Blockheader RLP field is not data!", + "RLP_ExpectedInputString_ADDRESS_DECODEINTO_BLOCK_EXTBLOCK_TX0_RECIPIENT" : "Error importing raw rlp block: Transaction RLP field is not data!", + "RLP_InputString_TooLong_ADDRESS_DECODEINTO_BLOCK_EXTBLOCK_HEADER_COINBASE" : "Blockheader parse error: Key `coinbase` is not hash20", + "RLP_InputString_TooLong_ADDRESS_DECODEINTO_BLOCK_EXTBLOCK_TXS0_RECIPIENT" : "TransactionLegacy convertion error: Key `to` is not hash20", + "RLP_ExpectedInputString_BIGINT_DECODEINTO_BLOCK_EXTBLOCK_HEADER_DIFFICULTY" : "Error importing raw rlp block: Blockheader RLP field is not data!", + "RLP_ExpectedInputString_BIGINT_DECODEINTO_BLOCK_EXTBLOCK_TXS0_TXR" : "Error importing raw rlp block: Transaction RLP field is not data!", + "RLP_ExpectedInputString_BIGINT_DECODEINTO_BLOCK_EXTBLOCK_TXS0_TXS" : "Error importing raw rlp block: Transaction RLP field is not data!", + "RLP_ExpectedInputString_UINT64_DECODEINTO_BLOCK_EXTBLOCK_HEADER_GASLIMIT" : "Error importing raw rlp block: Blockheader RLP field is not data!", + "RLP_ExpectedInputString_UINT64_DECODEINTO_BLOCK_EXTBLOCK_HEADER_GASUSED" : "Error importing raw rlp block: Blockheader RLP field is not data!", + "RLP_ExpectedInputString_UINT64_DECODEINTO_BLOCK_EXTBLOCK_HEADER_TIME" : "Error importing raw rlp block: Blockheader RLP field is not data!", + "RLP_ExpectedInputString_UINT64_DECODEINTO_BLOCK_EXTBLOCK_TXS0_GASLIMIT" : "Error importing raw rlp block: Transaction RLP field is not data!", + "RLP_ExpectedInputString_NONCE_DECODEINTO_BLOCK_EXTBLOCK_HEADER_NONCE" : "Error importing raw rlp block: Blockheader RLP field is not data!", + "RLP_ExpectedInputString_UINT8_DECODEINTO_BLOCK_EXTBLOCK_TXS0_PAYLOAD" : "Error importing raw rlp block: OversizeRLP", + "RLP_InputString_TooLong_BLOCKNONCE_DECODEINTO_BLOCK_EXTBLOCK_HEADER_NONCE" : "Error importing raw rlp block: OversizeRLP", + "RLP_InputString_TooLong_BLOCKNONCE_DECODEINTO_BLOCK_EXTBLOCK_HEADER_NONCE2" : "Blockheader parse error: Key `nonce` is not hash8", + "RLP_NonCanonical_SizeInfo_EXTBLOCK" : "Error importing raw rlp block: BadRLP", + "RLP_ExpectedInputList_TRANSACTION_DECODEINTO_BLOCK_EXTBLOCK_TXS" : "Error importing raw rlp block: BadCast", + "RLP_ExpectedInputList_HEADER_DECODEINTO_BLOCK_EXTBLOCK_UNCLES" : "Error importing raw rlp block: OversizeRLP", + "RLP_ExpectedInputList_TXDATA_DECODEINTO_BLOCK_EXTBLOCK_TXS0" : "Error importing raw rlp block: Transaction RLP is expected to be list", + "RLP_Error_EOF" : "ERROR(11): unexpected EOF", + "RLP_Error_RLP_Size" : "ERROR(11): rlp: value size exceeds available input length", + "RLP_Error_Size_Information" : "ERROR(11): rlp: non-canonical size information", + "LegacyBlockImportImpossible" : "Legacy block import is impossible", + "LegacyBlockImportImpossible2" : "Legacy block can only be on top of LegacyBlock", + "LegacyBlockBaseFeeTransaction" : "BaseFee transaction in a Legacy blcok", + "1559BlockImportImpossible_HeaderIsLegacy" : "1559 block must be on top of 1559", + "1559BlockImportImpossible_BaseFeeWrong": "Error in field: baseFeePerGas", + "1559BlockImportImpossible_InitialBaseFeeWrong": "Initial baseFee must be 1000000000", + "1559BlockImportImpossible_TargetGasLow": "gasTarget decreased too much", + "1559BlockImportImpossible_TargetGasHigh": "gasTarget increased too much", + "1559BlockImportImpossible_InitialGasLimitInvalid": "Invalid block1559: Initial gasLimit must be", + "MergeBlockImportImpossible" : "Trying to import Merge block on top of Shanghai block after transition", + "ShanghaiBlockImportImpossible" : "Shanghai block on top of Merge block before transition", + "TR_IntrinsicGas" : "intrinsic gas too low:", + "TR_NoFunds" : "insufficient funds for gas * price + value", + "TR_NoFundsValue" : "insufficient funds for transfer", + "TR_FeeCapLessThanBlocks" : "max fee per gas less than block base fee", + "TR_GasLimitReached" : "gas limit reached", + "TR_NonceTooHigh" : "nonce too high", + "TR_NonceTooLow" : "nonce too low", + "TR_TypeNotSupported" : "transaction type not supported", + "TR_TipGtFeeCap": "max priority fee per gas higher than max fee per gas", + "TR_TooShort": "typed transaction too short", + "TR_InitCodeLimitExceeded" : "max initcode size exceeded", + "1559BaseFeeTooLarge": "TransactionBaseFee convertion error: VALUE >u256", + "1559PriorityFeeGreaterThanBaseFee": "maxFeePerGas \u003c maxPriorityFeePerGas", + "2930AccessListAddressTooLong": "rlp: input string too long for common.Address, decoding into (types.Transaction)(types.AccessListTx).AccessList[0].Address", + "2930AccessListAddressTooShort": "rlp: input string too short for common.Address, decoding into (types.Transaction)(types.AccessListTx).AccessList[0].Address", + "2930AccessListStorageHashTooLong": "rlp: input string too long for common.Hash, decoding into (types.Transaction)(types.AccessListTx).AccessList[0].StorageKeys[0]", + "1559LeadingZerosBaseFee": "rlp: non-canonical integer (leading zero bytes) for *big.Int, decoding into (types.Transaction)(types.DynamicFeeTx).GasFeeCap", + "1559LeadingZerosPriorityFee": "rlp: non-canonical integer (leading zero bytes) for *big.Int, decoding into (types.Transaction)(types.DynamicFeeTx).GasTipCap", + "2930AccessListStorageHashTooShort": "rlp: input string too short for common.Hash, decoding into (types.Transaction)(types.AccessListTx).AccessList[0].StorageKeys[0]", + "2930AccessListStorageHashTooLong": "rlp: input string too long for common.Hash, decoding into (types.Transaction)(types.AccessListTx).AccessList[0].StorageKeys[0]", + "3675PoWBlockRejected" : "Invalid block1559: Chain switched to PoS!", + "3675PoSBlockRejected" : "Parent (transition) block has not reached TTD", + "3675PreMerge1559BlockRejected" : "Trying to import 1559 block on top of PoS block", + "INPUT_UNMARSHAL_ERROR" : "cannot unmarshal hex", + "INPUT_UNMARSHAL_SIZE_ERROR" : "failed unmarshaling", + "RLP_BODY_UNMARSHAL_ERROR" : "Rlp structure is wrong", + "PostMergeUncleHashIsNotEmpty" : "block.uncleHash != empty", + "PostMergeDifficultyIsNot0" : "block.difficulty must be 0" } })"; string const besu_start = R"(#!/bin/sh -threads=1 -if [ "${1:-0}" -gt 1 ] -then - threads=$1 +wevm=$(which besuevm) +if [ -z $wevm ]; then + >&2 echo "Can't find Hyperledger Besu's evm 'besuevm' executable alias in the system path!" + exit 1 fi -mkdir ~/.retesteth/logs -i=0 -while [ "$i" -lt $threads ]; do - tmpdir=$(mktemp -d -t ci-XXXXXXXXXX) - file=$(date +"%m-%d-%y-%s") - besu retesteth --rpc-http-port $((47710+$i)) --data-path=$tmpdir --logging=DEBUG >> ~/.retesteth/logs/besu-$file & - i=$(( i + 1 )) -done -)"; - -string const besu_stop = R"(#!/bin/sh -killall -9 java +if [ $1 = "t8n" ] || [ $1 = "b11r" ]; then + besuevm $1 $2 $3 $4 $5 $6 $7 $8 $9 $10 $11 $12 $13 $14 $15 $16 $17 $18 $19 $20 $21 $22 $23 $24 $25 $26 +elif [ $1 = "-v" ]; then + besuevm --version +else + stateProvided=0 + readErrorLog=0 + errorLogFile="" + cmdArgs="" + for index in ${1} ${2} ${3} ${4} ${5} ${6} ${7} ${8} ${9} ${10} ${11} ${12} ${13} ${14} ${15} ${16} ${17} ${18} ${19} ${20} ${21} ${22} ${23} ${24} ${25} ${26}; do + if [ $index = "--input.alloc" ]; then + stateProvided=1 + fi + if [ $readErrorLog -eq 1 ]; then + errorLogFile=$index + readErrorLog=0 + continue + fi + if [ $index = "--output.errorlog" ]; then + readErrorLog=1 + continue + fi + cmdArgs=$cmdArgs" "$index + done + if [ $stateProvided -eq 1 ]; then + besuevm t8n $cmdArgs 2> $errorLogFile + else + besuevm t9n $cmdArgs 2> $errorLogFile + fi +fi )"; genbesucfg::genbesucfg() @@ -85,8 +305,8 @@ genbesucfg::genbesucfg() { spDataObject obj; (*obj)["exec"] = true; - (*obj)["path"] = "besu/stop.sh"; - (*obj)["content"] = besu_stop; + (*obj)["path"] = "besu/yul.sh"; + (*obj)["content"] = yul_compiler_sh; map_configs.addArrayObject(obj); } } diff --git a/retesteth/configs/clientconfigs/etc.cpp b/retesteth/configs/clientconfigs/etc.cpp index 6b418f920..591f31402 100644 --- a/retesteth/configs/clientconfigs/etc.cpp +++ b/retesteth/configs/clientconfigs/etc.cpp @@ -225,20 +225,41 @@ string const etc_config = R"({ })"; string const etc_start = R"(#!/bin/sh -if [ $1 = "-v" ]; then + +wevm=$(which evmetc) +if [ -z $wevm ]; then + >&2 echo "Can't find Core Geths's evm 'evmetc' executable alias in the system path!" + exit 1 +fi + +if [ $1 = "t8n" ] || [ $1 = "b11r" ]; then + evmetc $1 $2 $3 $4 $5 $6 $7 $8 $9 $10 $11 $12 $13 $14 $15 $16 $17 $18 $19 $20 $21 $22 $23 $24 $25 $26 +elif [ $1 = "-v" ]; then evmetc -v else stateProvided=0 - for index in ${1} ${2} ${3} ${4} ${5} ${6} ${7} ${8} ${9} ${10} ${11} ${12} ${13} ${14} ${15} ${16} ${17} ${18} ${19} ${20} ; do + readErrorLog=0 + errorLogFile="" + cmdArgs="" + for index in ${1} ${2} ${3} ${4} ${5} ${6} ${7} ${8} ${9} ${10} ${11} ${12} ${13} ${14} ${15} ${16} ${17} ${18} ${19} ${20} ${21} ${22} ${23} ${24} ${25} ${26}; do if [ $index = "--input.alloc" ]; then stateProvided=1 - break fi + if [ $readErrorLog -eq 1 ]; then + errorLogFile=$index + readErrorLog=0 + continue + fi + if [ $index = "--output.errorlog" ]; then + readErrorLog=1 + continue + fi + cmdArgs=$cmdArgs" "$index done if [ $stateProvided -eq 1 ]; then - evmetc t8n ${1} ${2} ${3} ${4} ${5} ${6} ${7} ${8} ${9} ${10} ${11} ${12} ${13} ${14} ${15} ${16} ${17} ${18} ${19} ${20} --verbosity 2 + evmetc t8n $cmdArgs --verbosity 2 2> $errorLogFile else - evmetc t9n ${1} ${2} ${3} ${4} ${5} ${6} ${7} ${8} ${9} ${10} ${11} ${12} ${13} ${14} ${15} ${16} ${17} ${18} ${19} ${20} + evmetc t9n $cmdArgs 2> $errorLogFile fi fi )"; @@ -264,16 +285,6 @@ echo "0x600360005500" )"; -string const etc_yulcompiler = R"(#!/bin/sh -solc=$(which solc) -if [ -z $solc ]; then - >&2 echo "yul.sh \"Yul compilation error: 'solc' not found!\"" - echo "0x" -else - echo 0x`solc --assemble $1 2>/dev/null | grep "Binary representation:" -A 1 | tail -n1` -fi -)"; - genetccfg::genetccfg() { { @@ -300,7 +311,7 @@ genetccfg::genetccfg() spDataObject obj; (*obj)["exec"] = true; (*obj)["path"] = "etc/yul.sh"; - (*obj)["content"] = etc_yulcompiler; + (*obj)["content"] = yul_compiler_sh; map_configs.addArrayObject(obj); } } diff --git a/retesteth/configs/clientconfigs/etctranslate.cpp b/retesteth/configs/clientconfigs/etctranslate.cpp index 6ff57b4da..aa93cc6d2 100644 --- a/retesteth/configs/clientconfigs/etctranslate.cpp +++ b/retesteth/configs/clientconfigs/etctranslate.cpp @@ -225,7 +225,16 @@ string const etctr_config = R"({ })"; string const etctr_start = R"(#!/bin/sh -if [ $1 = "-v" ]; then + +wevm=$(which evmetc) +if [ -z $wevm ]; then + >&2 echo "Can't find Core Geths's evm 'evmetc' executable alias in the system path!" + exit 1 +fi + +if [ $1 = "t8n" ] || [ $1 = "b11r" ]; then + evmetc $1 $2 $3 $4 $5 $6 $7 $8 $9 $10 $11 $12 $13 $14 $15 $16 $17 $18 $19 $20 $21 $22 $23 $24 $25 $26 +elif [ $1 = "-v" ]; then evmetc -v else stateProvided=0 @@ -264,16 +273,6 @@ echo "0x600360005500" )"; -string const etctr_yulcompiler = R"(#!/bin/sh -solc=$(which solc) -if [ -z $solc ]; then - >&2 echo "yul.sh \"Yul compilation error: 'solc' not found!\"" - echo "0x" -else - echo 0x`solc --assemble $1 2>/dev/null | grep "Binary representation:" -A 1 | tail -n1` -fi -)"; - genetctranslatecfg::genetctranslatecfg() { { @@ -300,7 +299,7 @@ genetctranslatecfg::genetctranslatecfg() spDataObject obj; (*obj)["exec"] = true; (*obj)["path"] = "etctranslate/yul.sh"; - (*obj)["content"] = etctr_yulcompiler; + (*obj)["content"] = yul_compiler_sh; map_configs.addArrayObject(obj); } } diff --git a/retesteth/configs/clientconfigs/ethereumjs.cpp b/retesteth/configs/clientconfigs/ethereumjs.cpp index 272a70895..f70fb3a0d 100644 --- a/retesteth/configs/clientconfigs/ethereumjs.cpp +++ b/retesteth/configs/clientconfigs/ethereumjs.cpp @@ -32,6 +32,13 @@ string const ethereumjs_config = R"({ "BerlinToLondonAt5", "ArrowGlacier" ], + "fillerSkipForks" : [ + "Merge+3540+3670", + "Merge+3860", + "Merge+3855", + "MergeToShanghaiAtTime15k", + "Shanghai" + ], "exceptions":{ "AddressTooShort":"", "AddressTooLong":"", diff --git a/retesteth/configs/clientconfigs/evmone.cpp b/retesteth/configs/clientconfigs/evmone.cpp new file mode 100644 index 000000000..4538a328f --- /dev/null +++ b/retesteth/configs/clientconfigs/evmone.cpp @@ -0,0 +1,311 @@ +#include +using namespace std; +using namespace dataobject; + +namespace retesteth::options +{ +string const evmone_config = R"({ + "name" : "EVMONE on StateTool", + "socketType" : "tranition-tool", + "socketAddress" : "start.sh", + "initializeTime" : "0", + "checkDifficulty" : true, + "calculateDifficulty" : false, + "checkBasefee" : true, + "calculateBasefee" : false, + "checkLogsHash" : true, + "support1559" : true, + "transactionsAsJson" : true, + "tmpDir" : "/dev/shm", + "defaultChainID" : 1, + "customCompilers" : { + ":yul" : "yul.sh" + }, + "forks" : [ + "Frontier", + "Homestead", + "EIP150", + "EIP158", + "Byzantium", + "Constantinople", + "ConstantinopleFix", + "Istanbul", + "Berlin", + "London", + "Merge" + ], + "additionalForks" : [ + "FrontierToHomesteadAt5", + "HomesteadToEIP150At5", + "EIP158ToByzantiumAt5", + "HomesteadToDaoAt5", + "ByzantiumToConstantinopleFixAt5", + "BerlinToLondonAt5", + "ArrowGlacier", + "ArrowGlacierToMergeAtDiffC0000", + "GrayGlacier" + ], + "fillerSkipForks" : [ + ], + "exceptions" : { + "AddressTooShort" : "input string too short for common.Address", + "AddressTooLong" : "rlp: input string too long for common.Address, decoding into (types.Transaction)(types.LegacyTx).To", + "NonceMax" : "nonce exceeds 2^64-1", + "NonceTooLong" : "rlp: input string too long for uint64, decoding into (types.Transaction)(types.LegacyTx).Nonce", + "InvalidVRS" : "invalid transaction v, r, s values", + "InvalidV" : "rlp: expected input string or byte for *big.Int, decoding into (types.Transaction)(types.LegacyTx).V", + "InvalidR" : "rlp: expected input string or byte for *big.Int, decoding into (types.Transaction)(types.LegacyTx).R", + "InvalidS" : "rlp: expected input string or byte for *big.Int, decoding into (types.Transaction)(types.LegacyTx).S", + "InvalidChainID" : "invalid chain id for signer", + "ECRecoveryFail" : "recovery failed", + "InvalidStateRoot" : "", + "ExtraDataTooBig" : "Error importing raw rlp block: Header extraData > 32 bytes", + "InvalidData" : "rlp: expected input string or byte for []uint8, decoding into (types.Transaction)(types.LegacyTx).Data", + "InvalidDifficulty" : "Invalid difficulty:", + "InvalidDifficulty2" : "Error in field: difficulty", + "InvalidWithdrawals" : "Error in field: withdrawalsRoot", + "InvalidDifficulty_TooLarge" : "Blockheader parse error: VALUE >u256", + "InvalidGasLimit" : "Header gasLimit > 0x7fffffffffffffff", + "InvalidGasLimit2" : "Invalid gaslimit:", + "InvalidGasLimit3" : "GasLimit must be < 0x7fffffffffffffff", + "InvalidGasLimit4" : "rlp: input string too long for uint64, decoding into (types.Transaction)(types.LegacyTx).Gas", + "InvalidGasLimit5" : "rlp: expected input string or byte for uint64, decoding into (types.Transaction)(types.LegacyTx).Gas", + "InvalidValue" : "value exceeds 256 bits", + "InvalidGasPrice" : "gasPrice exceeds 256 bits", + "InvalidMaxPriorityFeePerGas" : "maxPriorityFeePerGas exceeds 256 bits", + "InvalidMaxFeePerGas" : "maxFeePerGas exceeds 256 bits", + "InvalidNonce" : "rlp: expected input string or byte for uint64, decoding into (types.Transaction)(types.LegacyTx).Nonce", + "InvalidTo" : "rlp: expected input string or byte for common.Address, decoding into (types.Transaction)(types.LegacyTx).To", + "GasLimitPriceProductOverflow" : "gas * gasPrice exceeds 256 bits", + "TooMuchGasUsed" : "Invalid gasUsed:", + "TooMuchGasUsed2" : "Error importing raw rlp block: t8ntool didn't return a transaction with hash", + "LeadingZerosGasLimit" : "rlp: non-canonical integer (leading zero bytes) for uint64, decoding into (types.Transaction)(types.LegacyTx).Gas", + "LeadingZerosGasPrice" : "rlp: non-canonical integer (leading zero bytes) for *big.Int, decoding into (types.Transaction)(types.LegacyTx).GasPrice", + "LeadingZerosValue" : "rlp: non-canonical integer (leading zero bytes) for *big.Int, decoding into (types.Transaction)(types.LegacyTx).Value", + "LeadingZerosNonce" : "rlp: non-canonical integer (leading zero bytes) for uint64, decoding into (types.Transaction)(types.LegacyTx).Nonce", + "LeadingZerosR" : "rlp: non-canonical integer (leading zero bytes) for *big.Int, decoding into (types.Transaction)(types.LegacyTx).R", + "LeadingZerosS" : "rlp: non-canonical integer (leading zero bytes) for *big.Int, decoding into (types.Transaction)(types.LegacyTx).S", + "LeadingZerosV" : "rlp: non-canonical integer (leading zero bytes) for *big.Int, decoding into (types.Transaction)(types.LegacyTx).V", + "LeadingZerosDataSize" : "rlp: non-canonical size information for []uint8, decoding into (types.Transaction)(types.LegacyTx).Data", + "LeadingZerosNonceSize" : "rlp: non-canonical size information for uint64, decoding into (types.Transaction)(types.LegacyTx).Nonce", + "InvalidNumber" : "BlockHeader number != parent.number + 1", + "InvalidTimestampEqualParent" : "timestamp equals parent's", + "InvalidTimestampOlderParent" : "BlockHeader timestamp is less or equal then it's parent block!", + "InvalidLogBloom" : "Error in field: bloom", + "InvalidStateRoot" : "Error in field: stateRoot", + "InvalidGasUsed" : "Error in field: gasUsed", + "InvalidGasUsed2" : "t8ntool didn't return a transaction with hash", + "InvalidBlockMixHash" : "invalid mix digest", + "InvalidBlockNonce" : "", + "UnknownParent" : "unknown parent hash", + "UnknownParent2" : "unknown parent hash", + "InvalidReceiptsStateRoot" : "Error in field: receiptTrie", + "InvalidTransactionsRoot" : "Error in field: transactionsTrie", + "InvalidUnclesHash" : "Error in field: uncleHash", + "InvalidUncleParentHash" : "Parent block hash not found:", + "UncleInChain" : "Block is already in chain!", + "UncleIsAncestor" : "Block is already in chain!", + "UncleParentIsNotAncestor" : "Uncle number is wrong!", + "TooManyUncles" : "Too many uncles!", + "UncleIsBrother" : "Uncle is brother!", + "OutOfGas" : "out of gas", + "SenderNotEOA" : "sender not an eoa:", + "IntrinsicGas" : "t8ntool didn't return a transaction with hash", + "ExtraDataIncorrectDAO" : "BlockHeader require Dao ExtraData!", + "InvalidTransactionVRS" : "t8ntool didn't return a transaction with hash", + "BLOCKHEADER_VALUE_TOOLARGE" : "Blockheader parse error: VALUE >u256", + "TRANSACTION_VALUE_TOOLARGE" : "TransactionLegacy convertion error: VALUE >u256", + "TRANSACTION_VALUE_TOOSHORT" : "t8ntool didn't return a transaction with hash", + "TR_NonceHasMaxValue" : "nonce has max value:", + "OVERSIZE_RLP" : "Error importing raw rlp block: OversizeRLP", + "RLP_BadCast" : "BadCast", + "RLP_ExpectedAsList" : "expected to be list", + "RLP_TooFewElements" : "rlp: too few elements ", + "RLP_TooManyElements" : "rlp: input list has too many elements ", + "RLP_InputContainsMoreThanOneValue" : "Error importing raw rlp block: OversizeRLP", + "RLP_VALUESIZE_MORE_AVAILABLEINPUTLENGTH" : "Error importing raw rlp block: UndersizeRLP", + "RLP_ELEMENT_LARGER_CONTAININGLIST_UNDERSIZE" : "Error importing raw rlp block: UndersizeRLP", + "RLP_ELEMENT_LARGER_CONTAININGLIST_OVERSIZE" : "Error importing raw rlp block: OversizeRLP", + "RLP_ExpectedInputList_EXTBLOCK" : "Error importing raw rlp block: RLP is expected to be list", + "RLP_InvalidArg0_UNMARSHAL_BYTES" : "Error importing raw rlp block: BadCast", + "RLP_ExpectedInputList_HEADER_DECODEINTO_BLOCK_EXTBLOCK" : "Error importing raw rlp block: BlockHeader RLP is expected to be list", + "RLP_InputList_TooManyElements_HEADER_DECODEINTO_BLOCK_EXTBLOCK_HEADER" : "Error importing raw rlp block: Uncleheader RLP is expected to be list", + "RLP_InputList_TooManyElements_TXDATA_DECODEINTO_BLOCK_EXTBLOCK_TXS0" : "Error importing raw rlp block: OversizeRLP", + "RLP_InputString_TooShort_ADDRESS_DECODEINTO_BLOCK_EXTBLOCK_HEADER_COINBASE" : "Error importing raw rlp block: OversizeRLP", + "RLP_InputString_TooShort_ADDRESS_DECODEINTO_BLOCK_EXTBLOCK_HEADER_COINBASE2" : "Blockheader parse error: Key `coinbase` is not hash20", + "RLP_InputString_TooShort_ADDRESS_DECODEINTO_BLOCK_EXTBLOCK_TXS0_RECIPIENT" : "TransactionLegacy convertion error: Key `to` is not hash20", + "RLP_InputString_TooLong_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_ROOT" : "Error importing raw rlp block: OversizeRLP", + "RLP_InputString_TooLong_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_ROOT2" : "Blockheader parse error: Key `stateRoot` is not hash32", + "RLP_InputString_TooLong_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_MIXDIGEST" : "Error importing raw rlp block: OversizeRLP", + "RLP_InputString_TooLong_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_MIXDIGEST2" : "Blockheader parse error: Key `mixHash` is not hash32", + "RLP_InputString_TooLong_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_PARENTHASH" : "Error importing raw rlp block: OversizeRLP", + "RLP_InputString_TooLong_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_PARENTHASH2" : "Blockheader parse error: Key `parentHash` is not hash32", + "RLP_InputString_TooLong_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_RECEIPTHASH" : "Error importing raw rlp block: OversizeRLP", + "RLP_InputString_TooLong_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_RECEIPTHASH2" : "Blockheader parse error: Key `receiptTrie` is not hash32", + "RLP_InputString_TooLong_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_TXHASH" : "Blockheader parse error: Key `transactionsTrie` is not hash32", + "RLP_InputString_TooLong_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_UNCLEHASH" : "Error importing raw rlp block: OversizeRLP", + "RLP_InputString_TooLong_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_UNCLEHASH2" : "Blockheader parse error: Key `uncleHash` is not hash32", + "RLP_InputString_TooLong_UINT64_DECODEINTO_BLOCK_EXTBLOCK_HEADER_GASLIMIT" : "Blockheader parse error: VALUE >u256", + "RLP_InputString_TooLong_UINT64_DECODEINTO_BLOCK_EXTBLOCK_HEADER_GASUSED" : "Blockheader parse error: VALUE >u256", + "RLP_InputString_TooLong_UINT64_DECODEINTO_BLOCK_EXTBLOCK_HEADER_TIME" : "Blockheader parse error: VALUE >u256", + "RLP_InputString_TooLong_UINT64_DECODEINTO_BLOCK_EXTBLOCK_TXS0_GASLIMIT" : "TransactionLegacy convertion error: VALUE >u256", + "RLP_InputString_TooShort_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_RECEIPTHASH" : "Error importing raw rlp block: OversizeRLP", + "RLP_InputString_TooShort_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_RECEIPTHASH2" : "Blockheader parse error: Key `receiptTrie` is not hash32", + "RLP_InputString_TooShort_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_ROOT" : "Blockheader parse error: Key `stateRoot` is not hash32", + "RLP_InputString_TooShort_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_MIXDIGEST" : "Error importing raw rlp block: OversizeRLP", + "RLP_InputString_TooShort_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_MIXDIGEST2" : "Blockheader parse error: Key `mixHash` is not hash32", + "RLP_InputString_TooShort_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_PARENTHASH" : "Error importing raw rlp block: OversizeRLP", + "RLP_InputString_TooShort_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_PARENTHASH2" : "Blockheader parse error: Key `parentHash` is not hash32", + "RLP_InputString_TooShort_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_UNCLEHASH" : "Error importing raw rlp block: OversizeRLP", + "RLP_InputString_TooShort_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_UNCLEHASH2" : "Blockheader parse error: Key `uncleHash` is not hash32", + "RLP_InputString_TooShort_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_TXHASH" : "Error importing raw rlp block: OversizeRLP", + "RLP_InputString_TooShort_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_TXHASH2" : "Blockheader parse error: Key `transactionsTrie` is not hash32", + "RLP_InputString_TooShort_BLOOM_DECODEINTO_BLOCK_EXTBLOCK_HEADER_BLOOM" : "Error importing raw rlp block: OversizeRLP", + "RLP_NonCanonicalINT_LeadingZeros_BIGINT_DECODEINTO_BLOCK_EXTBLOCK_HEADER_DIFFICULTY" : "Error importing raw rlp block: OversizeRLP", + "RLP_NonCanonicalINT_LeadingZeros_BIGINT_DECODEINTO_BLOCK_EXTBLOCK_HEADER_DIFFICULTY2" : "Blockheader parse error: VALUE has leading 0", + "RLP_NonCanonicalINT_LeadingZeros_UINT64_DECODEINTO_BLOCK_EXTBLOCK_HEADER_GASLIMIT" : "Error importing raw rlp block: OversizeRLP", + "RLP_NonCanonicalINT_LeadingZeros_UINT64_DECODEINTO_BLOCK_EXTBLOCK_HEADER_GASLIMIT2" : "Blockheader parse error: VALUE has leading 0", + "RLP_NonCanonicalINT_LeadingZeros_UINT64_DECODEINTO_BLOCK_EXTBLOCK_HEADER_GASUSED" : "Error importing raw rlp block: OversizeRLP", + "RLP_NonCanonicalINT_LeadingZeros_UINT64_DECODEINTO_BLOCK_EXTBLOCK_HEADER_GASUSED2" : "Blockheader parse error: VALUE has leading 0", + "RLP_NonCanonicalINT_LeadingZeros_UINT64_DECODEINTO_BLOCK_EXTBLOCK_HEADER_TIME" : "Error importing raw rlp block: OversizeRLP", + "RLP_NonCanonicalINT_LeadingZeros_UINT64_DECODEINTO_BLOCK_EXTBLOCK_HEADER_TIME2" : "Blockheader parse error: VALUE has leading 0", + "RLP_NonCanonicalINT_LeadingZeros_UINT64_DECODEINTO_BLOCK_EXTBLOCK_TXS0_GASLIMIT" : "Error importing raw rlp block: OversizeRLP", + "RLP_NonCanonicalINT_LeadingZeros_UINT64_DECODEINTO_BLOCK_EXTBLOCK_TXS0_GASLIMIT2" : "TransactionLegacy convertion error: VALUE has leading 0", + "RLP_NonCanonicalINT_LeadingZeros_BIGINT_DECODEINTO_BLOCK_EXTBLOCK_HEADER_NUMBER" : "Error importing raw rlp block: OversizeRLP", + "RLP_NonCanonicalINT_LeadingZeros_BIGINT_DECODEINTO_BLOCK_EXTBLOCK_HEADER_NUMBER2" : "Error importing raw rlp block: OversizeRLP", + "RLP_NonCanonicalINT_LeadingZeros_BIGINT_DECODEINTO_BLOCK_EXTBLOCK_TXS0_TXDATA_PRICE" : "Error importing raw rlp block: OversizeRLP", + "RLP_NonCanonicalINT_LeadingZeros_BIGINT_DECODEINTO_BLOCK_EXTBLOCK_TXS0_TXDATA_R" : "TransactionLegacy convertion error: VALUE has leading 0", + "RLP_NonCanonicalINT_LeadingZeros_BIGINT_DECODEINTO_BLOCK_EXTBLOCK_TXS0_TXDATA_S" : "TransactionLegacy convertion error: VALUE has leading 0", + "RLP_InputString_TooLong_BLOOM_DECODEINTO_BLOCK_EXTBLOCK_HEADER_BLOOM" : "Blockheader parse error: Key `bloom` is not hash256", + "RLP_ExpectedInputString_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_PARENTHASH" : "Error importing raw rlp block: Blockheader RLP field is not data!", + "RLP_ExpectedInputString_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_RECEIPTHASH" : "Error importing raw rlp block: Blockheader RLP field is not data!", + "RLP_ExpectedInputString_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_ROOT" : "Error importing raw rlp block: Blockheader RLP field is not data!", + "RLP_ExpectedInputString_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_MIXDIGEST" : "Error importing raw rlp block: Blockheader RLP field is not data!", + "RLP_ExpectedInputString_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_TXHASH" : "Error importing raw rlp block: Blockheader RLP field is not data!", + "RLP_ExpectedInputString_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_UNCLEHASH" : "Error importing raw rlp block: Blockheader RLP field is not data!", + "RLP_ExpectedInputString_ADDRESS_DECODEINTO_BLOCK_EXTBLOCK_HEADER_COINBASE" : "Error importing raw rlp block: Blockheader RLP field is not data!", + "RLP_ExpectedInputString_ADDRESS_DECODEINTO_BLOCK_EXTBLOCK_TX0_RECIPIENT" : "Error importing raw rlp block: Transaction RLP field is not data!", + "RLP_InputString_TooLong_ADDRESS_DECODEINTO_BLOCK_EXTBLOCK_HEADER_COINBASE" : "Blockheader parse error: Key `coinbase` is not hash20", + "RLP_InputString_TooLong_ADDRESS_DECODEINTO_BLOCK_EXTBLOCK_TXS0_RECIPIENT" : "TransactionLegacy convertion error: Key `to` is not hash20", + "RLP_ExpectedInputString_BIGINT_DECODEINTO_BLOCK_EXTBLOCK_HEADER_DIFFICULTY" : "Error importing raw rlp block: Blockheader RLP field is not data!", + "RLP_ExpectedInputString_BIGINT_DECODEINTO_BLOCK_EXTBLOCK_TXS0_TXR" : "Error importing raw rlp block: Transaction RLP field is not data!", + "RLP_ExpectedInputString_BIGINT_DECODEINTO_BLOCK_EXTBLOCK_TXS0_TXS" : "Error importing raw rlp block: Transaction RLP field is not data!", + "RLP_ExpectedInputString_UINT64_DECODEINTO_BLOCK_EXTBLOCK_HEADER_GASLIMIT" : "Error importing raw rlp block: Blockheader RLP field is not data!", + "RLP_ExpectedInputString_UINT64_DECODEINTO_BLOCK_EXTBLOCK_HEADER_GASUSED" : "Error importing raw rlp block: Blockheader RLP field is not data!", + "RLP_ExpectedInputString_UINT64_DECODEINTO_BLOCK_EXTBLOCK_HEADER_TIME" : "Error importing raw rlp block: Blockheader RLP field is not data!", + "RLP_ExpectedInputString_UINT64_DECODEINTO_BLOCK_EXTBLOCK_TXS0_GASLIMIT" : "Error importing raw rlp block: Transaction RLP field is not data!", + "RLP_ExpectedInputString_NONCE_DECODEINTO_BLOCK_EXTBLOCK_HEADER_NONCE" : "Error importing raw rlp block: Blockheader RLP field is not data!", + "RLP_ExpectedInputString_UINT8_DECODEINTO_BLOCK_EXTBLOCK_TXS0_PAYLOAD" : "Error importing raw rlp block: OversizeRLP", + "RLP_InputString_TooLong_BLOCKNONCE_DECODEINTO_BLOCK_EXTBLOCK_HEADER_NONCE" : "Error importing raw rlp block: OversizeRLP", + "RLP_InputString_TooLong_BLOCKNONCE_DECODEINTO_BLOCK_EXTBLOCK_HEADER_NONCE2" : "Blockheader parse error: Key `nonce` is not hash8", + "RLP_NonCanonical_SizeInfo_EXTBLOCK" : "Error importing raw rlp block: BadRLP", + "RLP_ExpectedInputList_TRANSACTION_DECODEINTO_BLOCK_EXTBLOCK_TXS" : "Error importing raw rlp block: BadCast", + "RLP_ExpectedInputList_HEADER_DECODEINTO_BLOCK_EXTBLOCK_UNCLES" : "Error importing raw rlp block: OversizeRLP", + "RLP_ExpectedInputList_TXDATA_DECODEINTO_BLOCK_EXTBLOCK_TXS0" : "Error importing raw rlp block: Transaction RLP is expected to be list", + "RLP_Error_EOF" : "ERROR(11): unexpected EOF", + "RLP_Error_RLP_Size" : "ERROR(11): rlp: value size exceeds available input length", + "RLP_Error_Size_Information" : "ERROR(11): rlp: non-canonical size information", + "LegacyBlockImportImpossible" : "Legacy block import is impossible", + "LegacyBlockImportImpossible2" : "Legacy block can only be on top of LegacyBlock", + "LegacyBlockBaseFeeTransaction" : "BaseFee transaction in a Legacy blcok", + "1559BlockImportImpossible_HeaderIsLegacy" : "1559 block must be on top of 1559", + "1559BlockImportImpossible_BaseFeeWrong": "Error in field: baseFeePerGas", + "1559BlockImportImpossible_InitialBaseFeeWrong": "Initial baseFee must be 1000000000", + "1559BlockImportImpossible_TargetGasLow": "gasTarget decreased too much", + "1559BlockImportImpossible_TargetGasHigh": "gasTarget increased too much", + "1559BlockImportImpossible_InitialGasLimitInvalid": "Invalid block1559: Initial gasLimit must be", + "MergeBlockImportImpossible" : "Trying to import Merge block on top of Shanghai block after transition", + "ShanghaiBlockImportImpossible" : "Shanghai block on top of Merge block before transition", + "TR_IntrinsicGas" : "intrinsic gas too low:", + "TR_NoFunds" : "insufficient funds for gas * price + value", + "TR_NoFundsValue" : "insufficient funds for transfer", + "TR_FeeCapLessThanBlocks" : "max fee per gas less than block base fee", + "TR_GasLimitReached" : "gas limit reached", + "TR_NonceTooHigh" : "nonce too high", + "TR_NonceTooLow" : "nonce too low", + "TR_TypeNotSupported" : "transaction type not supported", + "TR_TipGtFeeCap": "max priority fee per gas higher than max fee per gas", + "TR_TooShort": "typed transaction too short", + "TR_InitCodeLimitExceeded" : "max initcode size exceeded", + "1559BaseFeeTooLarge": "TransactionBaseFee convertion error: VALUE >u256", + "1559PriorityFeeGreaterThanBaseFee": "maxFeePerGas \u003c maxPriorityFeePerGas", + "2930AccessListAddressTooLong": "rlp: input string too long for common.Address, decoding into (types.Transaction)(types.AccessListTx).AccessList[0].Address", + "2930AccessListAddressTooShort": "rlp: input string too short for common.Address, decoding into (types.Transaction)(types.AccessListTx).AccessList[0].Address", + "2930AccessListStorageHashTooLong": "rlp: input string too long for common.Hash, decoding into (types.Transaction)(types.AccessListTx).AccessList[0].StorageKeys[0]", + "1559LeadingZerosBaseFee": "rlp: non-canonical integer (leading zero bytes) for *big.Int, decoding into (types.Transaction)(types.DynamicFeeTx).GasFeeCap", + "1559LeadingZerosPriorityFee": "rlp: non-canonical integer (leading zero bytes) for *big.Int, decoding into (types.Transaction)(types.DynamicFeeTx).GasTipCap", + "2930AccessListStorageHashTooShort": "rlp: input string too short for common.Hash, decoding into (types.Transaction)(types.AccessListTx).AccessList[0].StorageKeys[0]", + "2930AccessListStorageHashTooLong": "rlp: input string too long for common.Hash, decoding into (types.Transaction)(types.AccessListTx).AccessList[0].StorageKeys[0]", + "3675PoWBlockRejected" : "Invalid block1559: Chain switched to PoS!", + "3675PoSBlockRejected" : "Parent (transition) block has not reached TTD", + "3675PreMerge1559BlockRejected" : "Trying to import 1559 block on top of PoS block", + "INPUT_UNMARSHAL_ERROR" : "cannot unmarshal hex", + "INPUT_UNMARSHAL_SIZE_ERROR" : "failed unmarshaling", + "RLP_BODY_UNMARSHAL_ERROR" : "Rlp structure is wrong" + } +})"; + +string const evmone_start = R"(#!/bin/sh + +wevm=$(which evmone) +if [ -z $wevm ]; then + >&2 echo "Can't find EvmOne's 'evmone' executable alias in the system path!" + exit 1 +fi + +if [ $1 = "t8n" ] || [ $1 = "b11r" ]; then + evmone $1 $2 $3 $4 $5 $6 $7 $8 $9 $10 $11 $12 $13 $14 $15 $16 $17 $18 $19 $20 $21 $22 $23 $24 $25 $26 +elif [ $1 = "-v" ]; then + evmone -v +else + stateProvided=0 + readErrorLog=0 + errorLogFile="" + cmdArgs="" + for index in ${1} ${2} ${3} ${4} ${5} ${6} ${7} ${8} ${9} ${10} ${11} ${12} ${13} ${14} ${15} ${16} ${17} ${18} ${19} ${20} ${21} ${22} ${23} ${24} ${25} ${26}; do + if [ $index = "--input.alloc" ]; then + stateProvided=1 + fi + if [ $readErrorLog -eq 1 ]; then + errorLogFile=$index + readErrorLog=0 + continue + fi + if [ $index = "--output.errorlog" ]; then + readErrorLog=1 + continue + fi + cmdArgs=$cmdArgs" "$index + done + if [ $stateProvided -eq 1 ]; then + evmone $cmdArgs --verbosity 2 2> $errorLogFile + else + evmone t9n $cmdArgs 2> $errorLogFile + fi +fi +)"; + +genevmonecfg::genevmonecfg() +{ + { + spDataObject obj; + (*obj)["path"] = "evmone/config"; + (*obj)["content"] = evmone_config; + map_configs.addArrayObject(obj); + } + { + spDataObject obj; + (*obj)["exec"] = true; + (*obj)["path"] = "evmone/start.sh"; + (*obj)["content"] = evmone_start; + map_configs.addArrayObject(obj); + } + { + spDataObject obj; + (*obj)["exec"] = true; + (*obj)["path"] = "evmone/yul.sh"; + (*obj)["content"] = yul_compiler_sh; + map_configs.addArrayObject(obj); + } +} +} // namespace retesteth::options diff --git a/retesteth/configs/clientconfigs/nimbus.cpp b/retesteth/configs/clientconfigs/nimbus.cpp new file mode 100644 index 000000000..1990bc1e0 --- /dev/null +++ b/retesteth/configs/clientconfigs/nimbus.cpp @@ -0,0 +1,337 @@ +#include +using namespace std; +using namespace dataobject; + +namespace retesteth::options +{ +string const nimbus_config = R"({ + "name" : "Ethereum NIMBUS on StateTool", + "socketType" : "tranition-tool", + "socketAddress" : "start.sh", + "checkLogsHash" : true, + "checkBasefee" : true, + "defaultChainID" : 1, + "customCompilers" : { + ":yul" : "yul.sh", + ":mycompiler" : "mycompiler.sh" + }, + "forks" : [ + "Frontier", + "Homestead", + "EIP150", + "EIP158", + "Byzantium", + "Constantinople", + "ConstantinopleFix", + "Istanbul", + "Berlin", + "London", + "Merge", + "Shanghai" + ], + "additionalForks" : [ + "FrontierToHomesteadAt5", + "HomesteadToEIP150At5", + "EIP158ToByzantiumAt5", + "HomesteadToDaoAt5", + "ByzantiumToConstantinopleFixAt5", + "BerlinToLondonAt5", + "ArrowGlacier", + "ArrowGlacierToMergeAtDiffC0000", + "GrayGlacier", + "MergeToShanghaiAtTime15k" + ], + "fillerSkipForks" : [ + "Merge+3540+3670", + "Merge+3860", + "Merge+3855" + ], + "exceptions" : { + "AddressTooShort" : "input string too short for common.Address", + "AddressTooLong" : "rlp: input string too long for common.Address, decoding into (types.Transaction)(types.LegacyTx).To", + "NonceMax" : "nonce exceeds 2^64-1", + "NonceTooLong" : "rlp: input string too long for uint64, decoding into (types.Transaction)(types.LegacyTx).Nonce", + "InvalidVRS" : "invalid transaction v, r, s values", + "InvalidV" : "rlp: expected input string or byte for *big.Int, decoding into (types.Transaction)(types.LegacyTx).V", + "InvalidR" : "rlp: expected input string or byte for *big.Int, decoding into (types.Transaction)(types.LegacyTx).R", + "InvalidS" : "rlp: expected input string or byte for *big.Int, decoding into (types.Transaction)(types.LegacyTx).S", + "InvalidChainID" : "invalid chain id for signer", + "ECRecoveryFail" : "recovery failed", + "InvalidStateRoot" : "", + "ExtraDataTooBig" : "Error importing raw rlp block: Header extraData > 32 bytes", + "InvalidData" : "rlp: expected input string or byte for []uint8, decoding into (types.Transaction)(types.LegacyTx).Data", + "InvalidDifficulty" : "Invalid difficulty:", + "InvalidDifficulty2" : "Error in field: difficulty", + "InvalidDifficulty_TooLarge" : "Blockheader parse error: VALUE >u256", + "InvalidWithdrawals" : "Error in field: withdrawalsRoot", + "InvalidGasLimit" : "Header gasLimit > 0x7fffffffffffffff", + "InvalidGasLimit2" : "Invalid gaslimit:", + "InvalidGasLimit3" : "GasLimit must be < 0x7fffffffffffffff", + "InvalidGasLimit4" : "rlp: input string too long for uint64, decoding into (types.Transaction)(types.LegacyTx).Gas", + "InvalidGasLimit5" : "rlp: expected input string or byte for uint64, decoding into (types.Transaction)(types.LegacyTx).Gas", + "InvalidValue" : "value exceeds 256 bits", + "InvalidGasPrice" : "gasPrice exceeds 256 bits", + "InvalidMaxPriorityFeePerGas" : "maxPriorityFeePerGas exceeds 256 bits", + "InvalidMaxFeePerGas" : "maxFeePerGas exceeds 256 bits", + "InvalidNonce" : "rlp: expected input string or byte for uint64, decoding into (types.Transaction)(types.LegacyTx).Nonce", + "InvalidTo" : "rlp: expected input string or byte for common.Address, decoding into (types.Transaction)(types.LegacyTx).To", + "GasLimitPriceProductOverflow" : "gas * gasPrice exceeds 256 bits", + "TooMuchGasUsed" : "Invalid gasUsed:", + "TooMuchGasUsed2" : "Error importing raw rlp block: t8ntool didn't return a transaction with hash", + "LeadingZerosGasLimit" : "rlp: non-canonical integer (leading zero bytes) for uint64, decoding into (types.Transaction)(types.LegacyTx).Gas", + "LeadingZerosGasPrice" : "rlp: non-canonical integer (leading zero bytes) for *big.Int, decoding into (types.Transaction)(types.LegacyTx).GasPrice", + "LeadingZerosValue" : "rlp: non-canonical integer (leading zero bytes) for *big.Int, decoding into (types.Transaction)(types.LegacyTx).Value", + "LeadingZerosNonce" : "rlp: non-canonical integer (leading zero bytes) for uint64, decoding into (types.Transaction)(types.LegacyTx).Nonce", + "LeadingZerosR" : "rlp: non-canonical integer (leading zero bytes) for *big.Int, decoding into (types.Transaction)(types.LegacyTx).R", + "LeadingZerosS" : "rlp: non-canonical integer (leading zero bytes) for *big.Int, decoding into (types.Transaction)(types.LegacyTx).S", + "LeadingZerosV" : "rlp: non-canonical integer (leading zero bytes) for *big.Int, decoding into (types.Transaction)(types.LegacyTx).V", + "LeadingZerosDataSize" : "rlp: non-canonical size information for []uint8, decoding into (types.Transaction)(types.LegacyTx).Data", + "LeadingZerosNonceSize" : "rlp: non-canonical size information for uint64, decoding into (types.Transaction)(types.LegacyTx).Nonce", + "InvalidNumber" : "BlockHeader number != parent.number + 1", + "InvalidTimestampEqualParent" : "timestamp equals parent's", + "InvalidTimestampOlderParent" : "BlockHeader timestamp is less or equal then it's parent block!", + "InvalidLogBloom" : "Error in field: bloom", + "InvalidStateRoot" : "Error in field: stateRoot", + "InvalidGasUsed" : "Error in field: gasUsed", + "InvalidGasUsed2" : "t8ntool didn't return a transaction with hash", + "InvalidBlockMixHash" : "invalid mix digest", + "InvalidBlockNonce" : "", + "UnknownParent" : "unknown parent hash", + "UnknownParent2" : "unknown parent hash", + "InvalidReceiptsStateRoot" : "Error in field: receiptTrie", + "InvalidTransactionsRoot" : "Error in field: transactionsTrie", + "InvalidUnclesHash" : "Error in field: uncleHash", + "InvalidUncleParentHash" : "Parent block hash not found:", + "UncleInChain" : "Block is already in chain!", + "UncleIsAncestor" : "Block is already in chain!", + "UncleParentIsNotAncestor" : "Uncle number is wrong!", + "TooManyUncles" : "Too many uncles!", + "UncleIsBrother" : "Uncle is brother!", + "OutOfGas" : "out of gas", + "SenderNotEOA" : "processTransaction failed", + "IntrinsicGas" : "t8ntool didn't return a transaction with hash", + "ExtraDataIncorrectDAO" : "BlockHeader require Dao ExtraData!", + "InvalidTransactionVRS" : "t8ntool didn't return a transaction with hash", + "BLOCKHEADER_VALUE_TOOLARGE" : "Blockheader parse error: VALUE >u256", + "TRANSACTION_VALUE_TOOLARGE" : "TransactionLegacy convertion error: VALUE >u256", + "TRANSACTION_VALUE_TOOSHORT" : "t8ntool didn't return a transaction with hash", + "TR_NonceHasMaxValue" : "processTransaction failed", + "OVERSIZE_RLP" : "Error importing raw rlp block: OversizeRLP", + "RLP_BadCast" : "BadCast", + "RLP_ExpectedAsList" : "expected to be list", + "RLP_TooFewElements" : "rlp: too few elements ", + "RLP_TooManyElements" : "rlp: input list has too many elements ", + "RLP_InputContainsMoreThanOneValue" : "Error importing raw rlp block: OversizeRLP", + "RLP_VALUESIZE_MORE_AVAILABLEINPUTLENGTH" : "Error importing raw rlp block: UndersizeRLP", + "RLP_ELEMENT_LARGER_CONTAININGLIST_UNDERSIZE" : "Error importing raw rlp block: UndersizeRLP", + "RLP_ELEMENT_LARGER_CONTAININGLIST_OVERSIZE" : "Error importing raw rlp block: OversizeRLP", + "RLP_ExpectedInputList_EXTBLOCK" : "Error importing raw rlp block: RLP is expected to be list", + "RLP_InvalidArg0_UNMARSHAL_BYTES" : "Error importing raw rlp block: BadCast", + "RLP_ExpectedInputList_HEADER_DECODEINTO_BLOCK_EXTBLOCK" : "Error importing raw rlp block: BlockHeader RLP is expected to be list", + "RLP_InputList_TooManyElements_HEADER_DECODEINTO_BLOCK_EXTBLOCK_HEADER" : "Error importing raw rlp block: Uncleheader RLP is expected to be list", + "RLP_InputList_TooManyElements_TXDATA_DECODEINTO_BLOCK_EXTBLOCK_TXS0" : "Error importing raw rlp block: OversizeRLP", + "RLP_InputString_TooShort_ADDRESS_DECODEINTO_BLOCK_EXTBLOCK_HEADER_COINBASE" : "Error importing raw rlp block: OversizeRLP", + "RLP_InputString_TooShort_ADDRESS_DECODEINTO_BLOCK_EXTBLOCK_HEADER_COINBASE2" : "Blockheader parse error: Key `coinbase` is not hash20", + "RLP_InputString_TooShort_ADDRESS_DECODEINTO_BLOCK_EXTBLOCK_TXS0_RECIPIENT" : "TransactionLegacy convertion error: Key `to` is not hash20", + "RLP_InputString_TooLong_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_ROOT" : "Error importing raw rlp block: OversizeRLP", + "RLP_InputString_TooLong_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_ROOT2" : "Blockheader parse error: Key `stateRoot` is not hash32", + "RLP_InputString_TooLong_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_MIXDIGEST" : "Error importing raw rlp block: OversizeRLP", + "RLP_InputString_TooLong_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_MIXDIGEST2" : "Blockheader parse error: Key `mixHash` is not hash32", + "RLP_InputString_TooLong_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_PARENTHASH" : "Error importing raw rlp block: OversizeRLP", + "RLP_InputString_TooLong_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_PARENTHASH2" : "Blockheader parse error: Key `parentHash` is not hash32", + "RLP_InputString_TooLong_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_RECEIPTHASH" : "Error importing raw rlp block: OversizeRLP", + "RLP_InputString_TooLong_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_RECEIPTHASH2" : "Blockheader parse error: Key `receiptTrie` is not hash32", + "RLP_InputString_TooLong_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_TXHASH" : "Blockheader parse error: Key `transactionsTrie` is not hash32", + "RLP_InputString_TooLong_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_UNCLEHASH" : "Error importing raw rlp block: OversizeRLP", + "RLP_InputString_TooLong_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_UNCLEHASH2" : "Blockheader parse error: Key `uncleHash` is not hash32", + "RLP_InputString_TooLong_UINT64_DECODEINTO_BLOCK_EXTBLOCK_HEADER_GASLIMIT" : "Blockheader parse error: VALUE >u256", + "RLP_InputString_TooLong_UINT64_DECODEINTO_BLOCK_EXTBLOCK_HEADER_GASUSED" : "Blockheader parse error: VALUE >u256", + "RLP_InputString_TooLong_UINT64_DECODEINTO_BLOCK_EXTBLOCK_HEADER_TIME" : "Blockheader parse error: VALUE >u256", + "RLP_InputString_TooLong_UINT64_DECODEINTO_BLOCK_EXTBLOCK_TXS0_GASLIMIT" : "TransactionLegacy convertion error: VALUE >u256", + "RLP_InputString_TooShort_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_RECEIPTHASH" : "Error importing raw rlp block: OversizeRLP", + "RLP_InputString_TooShort_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_RECEIPTHASH2" : "Blockheader parse error: Key `receiptTrie` is not hash32", + "RLP_InputString_TooShort_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_ROOT" : "Blockheader parse error: Key `stateRoot` is not hash32", + "RLP_InputString_TooShort_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_MIXDIGEST" : "Error importing raw rlp block: OversizeRLP", + "RLP_InputString_TooShort_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_MIXDIGEST2" : "Blockheader parse error: Key `mixHash` is not hash32", + "RLP_InputString_TooShort_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_PARENTHASH" : "Error importing raw rlp block: OversizeRLP", + "RLP_InputString_TooShort_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_PARENTHASH2" : "Blockheader parse error: Key `parentHash` is not hash32", + "RLP_InputString_TooShort_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_UNCLEHASH" : "Error importing raw rlp block: OversizeRLP", + "RLP_InputString_TooShort_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_UNCLEHASH2" : "Blockheader parse error: Key `uncleHash` is not hash32", + "RLP_InputString_TooShort_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_TXHASH" : "Error importing raw rlp block: OversizeRLP", + "RLP_InputString_TooShort_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_TXHASH2" : "Blockheader parse error: Key `transactionsTrie` is not hash32", + "RLP_InputString_TooShort_BLOOM_DECODEINTO_BLOCK_EXTBLOCK_HEADER_BLOOM" : "Error importing raw rlp block: OversizeRLP", + "RLP_NonCanonicalINT_LeadingZeros_BIGINT_DECODEINTO_BLOCK_EXTBLOCK_HEADER_DIFFICULTY" : "Error importing raw rlp block: OversizeRLP", + "RLP_NonCanonicalINT_LeadingZeros_BIGINT_DECODEINTO_BLOCK_EXTBLOCK_HEADER_DIFFICULTY2" : "Blockheader parse error: VALUE has leading 0", + "RLP_NonCanonicalINT_LeadingZeros_UINT64_DECODEINTO_BLOCK_EXTBLOCK_HEADER_GASLIMIT" : "Error importing raw rlp block: OversizeRLP", + "RLP_NonCanonicalINT_LeadingZeros_UINT64_DECODEINTO_BLOCK_EXTBLOCK_HEADER_GASLIMIT2" : "Blockheader parse error: VALUE has leading 0", + "RLP_NonCanonicalINT_LeadingZeros_UINT64_DECODEINTO_BLOCK_EXTBLOCK_HEADER_GASUSED" : "Error importing raw rlp block: OversizeRLP", + "RLP_NonCanonicalINT_LeadingZeros_UINT64_DECODEINTO_BLOCK_EXTBLOCK_HEADER_GASUSED2" : "Blockheader parse error: VALUE has leading 0", + "RLP_NonCanonicalINT_LeadingZeros_UINT64_DECODEINTO_BLOCK_EXTBLOCK_HEADER_TIME" : "Error importing raw rlp block: OversizeRLP", + "RLP_NonCanonicalINT_LeadingZeros_UINT64_DECODEINTO_BLOCK_EXTBLOCK_HEADER_TIME2" : "Blockheader parse error: VALUE has leading 0", + "RLP_NonCanonicalINT_LeadingZeros_UINT64_DECODEINTO_BLOCK_EXTBLOCK_TXS0_GASLIMIT" : "Error importing raw rlp block: OversizeRLP", + "RLP_NonCanonicalINT_LeadingZeros_UINT64_DECODEINTO_BLOCK_EXTBLOCK_TXS0_GASLIMIT2" : "TransactionLegacy convertion error: VALUE has leading 0", + "RLP_NonCanonicalINT_LeadingZeros_BIGINT_DECODEINTO_BLOCK_EXTBLOCK_HEADER_NUMBER" : "Error importing raw rlp block: OversizeRLP", + "RLP_NonCanonicalINT_LeadingZeros_BIGINT_DECODEINTO_BLOCK_EXTBLOCK_HEADER_NUMBER2" : "Error importing raw rlp block: OversizeRLP", + "RLP_NonCanonicalINT_LeadingZeros_BIGINT_DECODEINTO_BLOCK_EXTBLOCK_TXS0_TXDATA_PRICE" : "Error importing raw rlp block: OversizeRLP", + "RLP_NonCanonicalINT_LeadingZeros_BIGINT_DECODEINTO_BLOCK_EXTBLOCK_TXS0_TXDATA_R" : "TransactionLegacy convertion error: VALUE has leading 0", + "RLP_NonCanonicalINT_LeadingZeros_BIGINT_DECODEINTO_BLOCK_EXTBLOCK_TXS0_TXDATA_S" : "TransactionLegacy convertion error: VALUE has leading 0", + "RLP_InputString_TooLong_BLOOM_DECODEINTO_BLOCK_EXTBLOCK_HEADER_BLOOM" : "Blockheader parse error: Key `bloom` is not hash256", + "RLP_ExpectedInputString_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_PARENTHASH" : "Error importing raw rlp block: Blockheader RLP field is not data!", + "RLP_ExpectedInputString_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_RECEIPTHASH" : "Error importing raw rlp block: Blockheader RLP field is not data!", + "RLP_ExpectedInputString_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_ROOT" : "Error importing raw rlp block: Blockheader RLP field is not data!", + "RLP_ExpectedInputString_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_MIXDIGEST" : "Error importing raw rlp block: Blockheader RLP field is not data!", + "RLP_ExpectedInputString_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_TXHASH" : "Error importing raw rlp block: Blockheader RLP field is not data!", + "RLP_ExpectedInputString_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_UNCLEHASH" : "Error importing raw rlp block: Blockheader RLP field is not data!", + "RLP_ExpectedInputString_ADDRESS_DECODEINTO_BLOCK_EXTBLOCK_HEADER_COINBASE" : "Error importing raw rlp block: Blockheader RLP field is not data!", + "RLP_ExpectedInputString_ADDRESS_DECODEINTO_BLOCK_EXTBLOCK_TX0_RECIPIENT" : "Error importing raw rlp block: Transaction RLP field is not data!", + "RLP_InputString_TooLong_ADDRESS_DECODEINTO_BLOCK_EXTBLOCK_HEADER_COINBASE" : "Blockheader parse error: Key `coinbase` is not hash20", + "RLP_InputString_TooLong_ADDRESS_DECODEINTO_BLOCK_EXTBLOCK_TXS0_RECIPIENT" : "TransactionLegacy convertion error: Key `to` is not hash20", + "RLP_ExpectedInputString_BIGINT_DECODEINTO_BLOCK_EXTBLOCK_HEADER_DIFFICULTY" : "Error importing raw rlp block: Blockheader RLP field is not data!", + "RLP_ExpectedInputString_BIGINT_DECODEINTO_BLOCK_EXTBLOCK_TXS0_TXR" : "Error importing raw rlp block: Transaction RLP field is not data!", + "RLP_ExpectedInputString_BIGINT_DECODEINTO_BLOCK_EXTBLOCK_TXS0_TXS" : "Error importing raw rlp block: Transaction RLP field is not data!", + "RLP_ExpectedInputString_UINT64_DECODEINTO_BLOCK_EXTBLOCK_HEADER_GASLIMIT" : "Error importing raw rlp block: Blockheader RLP field is not data!", + "RLP_ExpectedInputString_UINT64_DECODEINTO_BLOCK_EXTBLOCK_HEADER_GASUSED" : "Error importing raw rlp block: Blockheader RLP field is not data!", + "RLP_ExpectedInputString_UINT64_DECODEINTO_BLOCK_EXTBLOCK_HEADER_TIME" : "Error importing raw rlp block: Blockheader RLP field is not data!", + "RLP_ExpectedInputString_UINT64_DECODEINTO_BLOCK_EXTBLOCK_TXS0_GASLIMIT" : "Error importing raw rlp block: Transaction RLP field is not data!", + "RLP_ExpectedInputString_NONCE_DECODEINTO_BLOCK_EXTBLOCK_HEADER_NONCE" : "Error importing raw rlp block: Blockheader RLP field is not data!", + "RLP_ExpectedInputString_UINT8_DECODEINTO_BLOCK_EXTBLOCK_TXS0_PAYLOAD" : "Error importing raw rlp block: OversizeRLP", + "RLP_InputString_TooLong_BLOCKNONCE_DECODEINTO_BLOCK_EXTBLOCK_HEADER_NONCE" : "Error importing raw rlp block: OversizeRLP", + "RLP_InputString_TooLong_BLOCKNONCE_DECODEINTO_BLOCK_EXTBLOCK_HEADER_NONCE2" : "Blockheader parse error: Key `nonce` is not hash8", + "RLP_NonCanonical_SizeInfo_EXTBLOCK" : "Error importing raw rlp block: BadRLP", + "RLP_ExpectedInputList_TRANSACTION_DECODEINTO_BLOCK_EXTBLOCK_TXS" : "Error importing raw rlp block: BadCast", + "RLP_ExpectedInputList_HEADER_DECODEINTO_BLOCK_EXTBLOCK_UNCLES" : "Error importing raw rlp block: OversizeRLP", + "RLP_ExpectedInputList_TXDATA_DECODEINTO_BLOCK_EXTBLOCK_TXS0" : "Error importing raw rlp block: Transaction RLP is expected to be list", + "RLP_Error_EOF" : "ERROR(11): unexpected EOF", + "RLP_Error_RLP_Size" : "ERROR(11): rlp: value size exceeds available input length", + "RLP_Error_Size_Information" : "ERROR(11): rlp: non-canonical size information", + "LegacyBlockImportImpossible" : "Legacy block import is impossible", + "LegacyBlockImportImpossible2" : "Legacy block can only be on top of LegacyBlock", + "LegacyBlockBaseFeeTransaction" : "BaseFee transaction in a Legacy blcok", + "1559BlockImportImpossible_HeaderIsLegacy" : "1559 block must be on top of 1559", + "1559BlockImportImpossible_BaseFeeWrong": "Error in field: baseFeePerGas", + "1559BlockImportImpossible_InitialBaseFeeWrong": "Initial baseFee must be 1000000000", + "1559BlockImportImpossible_TargetGasLow": "gasTarget decreased too much", + "1559BlockImportImpossible_TargetGasHigh": "gasTarget increased too much", + "1559BlockImportImpossible_InitialGasLimitInvalid": "Invalid block1559: Initial gasLimit must be", + "TR_IntrinsicGas" : "processTransaction failed", + "TR_NoFunds" : "", + "TR_NoFundsValue" : "processTransaction failed", + "TR_FeeCapLessThanBlocks" : "processTransaction failed", + "TR_GasLimitReached" : "processTransaction failed", + "TR_NonceTooHigh" : "processTransaction failed", + "TR_NonceTooLow" : "processTransaction failed", + "TR_TypeNotSupported" : "processTransaction failed", + "TR_TipGtFeeCap": "processTransaction failed", + "TR_TooShort": "processTransaction failed", + "TR_InitCodeLimitExceeded" : "processTransaction failed", + "1559BaseFeeTooLarge": "TransactionBaseFee convertion error: VALUE >u256", + "1559PriorityFeeGreaterThanBaseFee": "maxFeePerGas \u003c maxPriorityFeePerGas", + "2930AccessListAddressTooLong": "rlp: input string too long for common.Address, decoding into (types.Transaction)(types.AccessListTx).AccessList[0].Address", + "2930AccessListAddressTooShort": "rlp: input string too short for common.Address, decoding into (types.Transaction)(types.AccessListTx).AccessList[0].Address", + "2930AccessListStorageHashTooLong": "rlp: input string too long for common.Hash, decoding into (types.Transaction)(types.AccessListTx).AccessList[0].StorageKeys[0]", + "1559LeadingZerosBaseFee": "rlp: non-canonical integer (leading zero bytes) for *big.Int, decoding into (types.Transaction)(types.DynamicFeeTx).GasFeeCap", + "1559LeadingZerosPriorityFee": "rlp: non-canonical integer (leading zero bytes) for *big.Int, decoding into (types.Transaction)(types.DynamicFeeTx).GasTipCap", + "2930AccessListStorageHashTooShort": "rlp: input string too short for common.Hash, decoding into (types.Transaction)(types.AccessListTx).AccessList[0].StorageKeys[0]", + "2930AccessListStorageHashTooLong": "rlp: input string too long for common.Hash, decoding into (types.Transaction)(types.AccessListTx).AccessList[0].StorageKeys[0]", + "3675PoWBlockRejected" : "Invalid block1559: Chain switched to PoS!", + "3675PoSBlockRejected" : "Parent (transition) block has not reached TTD", + "3675PreMerge1559BlockRejected" : "Trying to import 1559 block on top of PoS block", + "INPUT_UNMARSHAL_ERROR" : "cannot unmarshal hex", + "INPUT_UNMARSHAL_SIZE_ERROR" : "failed unmarshaling", + "RLP_BODY_UNMARSHAL_ERROR" : "Rlp structure is wrong", + "PostMergeUncleHashIsNotEmpty" : "block.uncleHash != empty", + "PostMergeDifficultyIsNot0" : "block.difficulty must be 0" + } +})"; + +string const nimbus_start = R"(#!/bin/sh + +wevm=$(which evm_nimbus) +if [ -z $wevm ]; then + >&2 echo "Can't find Nimbus's 'evm_nimbus' executable alias in the system path!" + exit 1 +fi + +if [ $1 = "t8n" ] || [ $1 = "b11r" ]; then + evm_nimbus $1 $2 $3 $4 $5 $6 $7 $8 $9 $10 $11 $12 $13 $14 $15 $16 $17 $18 $19 $20 $21 $22 $23 $24 $25 $26 +elif [ $1 = "-v" ]; then + evm_nimbus --version +else + stateProvided=0 + readErrorLog=0 + errorLogFile="" + cmdArgs="" + for index in ${1} ${2} ${3} ${4} ${5} ${6} ${7} ${8} ${9} ${10} ${11} ${12} ${13} ${14} ${15} ${16} ${17} ${18} ${19} ${20} ${21} ${22} ${23} ${24} ${25} ${26}; do + if [ $index = "--input.alloc" ]; then + stateProvided=1 + fi + if [ $readErrorLog -eq 1 ]; then + errorLogFile=$index + readErrorLog=0 + continue + fi + if [ $index = "--output.errorlog" ]; then + readErrorLog=1 + continue + fi + cmdArgs=$cmdArgs" "$index + done + if [ $stateProvided -eq 1 ]; then + evm_nimbus $cmdArgs --verbosity 2 2> $errorLogFile + else + evm_nimbus $cmdArgs 2> $errorLogFile + fi +fi +)"; + +string const nimbus_customcompiler = R"(#!/bin/sh +# You can call a custom executable here +# The code src comes in argument $1 as a path to a file containg the code +# So if you have custom compiler installed in the system the command would look like: +# mycompiler $1 + +# Make sure your tool output clean bytecode only with no log or debug messages +echo "0x600360005500" + +# Copy this file under any name you want and make the changes +# In config file replace add the keyword and path to executable accordingly +# "customCompilers" : { +# ":mycompiler" : "mycompiler.sh", +# ":keyword" : "myscript.sh" +# }, +# Where :keyword would be looked in test's Filler files +# And myscript.sh located in the system or .retesteth/default/myscript.sh with a call to your custom tool +# just like described in this file." +)"; + +gennimbuscfg::gennimbuscfg() +{ + { + spDataObject obj; + (*obj)["path"] = "nimbus/config"; + (*obj)["content"] = nimbus_config; + map_configs.addArrayObject(obj); + } + { + spDataObject obj; + (*obj)["exec"] = true; + (*obj)["path"] = "nimbus/start.sh"; + (*obj)["content"] = nimbus_start; + map_configs.addArrayObject(obj); + } + { + spDataObject obj; + (*obj)["exec"] = true; + (*obj)["path"] = "nimbus/mycompiler.sh"; + (*obj)["content"] = nimbus_customcompiler; + map_configs.addArrayObject(obj); + } + { + spDataObject obj; + (*obj)["exec"] = true; + (*obj)["path"] = "nimbus/yul.sh"; + (*obj)["content"] = yul_compiler_sh; + map_configs.addArrayObject(obj); + } +} +} // namespace retesteth::options diff --git a/retesteth/configs/clientconfigs/t8ntool.cpp b/retesteth/configs/clientconfigs/t8ntool.cpp index e416957e2..7863b3239 100644 --- a/retesteth/configs/clientconfigs/t8ntool.cpp +++ b/retesteth/configs/clientconfigs/t8ntool.cpp @@ -8,8 +8,15 @@ string const t8ntool_config = R"({ "name" : "Ethereum GO on StateTool", "socketType" : "tranition-tool", "socketAddress" : "start.sh", - "checkLogsHash" : true, + "initializeTime" : "0", + "checkDifficulty" : true, + "calculateDifficulty" : false, "checkBasefee" : true, + "calculateBasefee" : false, + "checkLogsHash" : true, + "support1559" : true, + "transactionsAsJson" : false, + "tmpDir" : "/dev/shm", "defaultChainID" : 1, "customCompilers" : { ":yul" : "yul.sh", @@ -26,7 +33,8 @@ string const t8ntool_config = R"({ "Istanbul", "Berlin", "London", - "Merge" + "Merge", + "Shanghai" ], "additionalForks" : [ "FrontierToHomesteadAt5", @@ -37,11 +45,10 @@ string const t8ntool_config = R"({ "BerlinToLondonAt5", "ArrowGlacier", "ArrowGlacierToMergeAtDiffC0000", - "GrayGlacier" + "GrayGlacier", + "MergeToShanghaiAtTime15k" ], "fillerSkipForks" : [ - "Merge+3540+3670", - "Merge+3860" ], "exceptions" : { "AddressTooShort" : "input string too short for common.Address", @@ -59,6 +66,7 @@ string const t8ntool_config = R"({ "InvalidData" : "rlp: expected input string or byte for []uint8, decoding into (types.Transaction)(types.LegacyTx).Data", "InvalidDifficulty" : "Invalid difficulty:", "InvalidDifficulty2" : "Error in field: difficulty", + "InvalidWithdrawals" : "Error in field: withdrawalsRoot", "InvalidDifficulty_TooLarge" : "Blockheader parse error: VALUE >u256", "InvalidGasLimit" : "Header gasLimit > 0x7fffffffffffffff", "InvalidGasLimit2" : "Invalid gaslimit:", @@ -113,6 +121,8 @@ string const t8ntool_config = R"({ "TRANSACTION_VALUE_TOOSHORT" : "t8ntool didn't return a transaction with hash", "TR_NonceHasMaxValue" : "nonce has max value:", "OVERSIZE_RLP" : "Error importing raw rlp block: OversizeRLP", + "RLP_BadCast" : "BadCast", + "RLP_ExpectedAsList" : "expected to be list", "RLP_TooFewElements" : "rlp: too few elements ", "RLP_TooManyElements" : "rlp: input list has too many elements ", "RLP_InputContainsMoreThanOneValue" : "Error importing raw rlp block: OversizeRLP", @@ -207,6 +217,8 @@ string const t8ntool_config = R"({ "1559BlockImportImpossible_TargetGasLow": "gasTarget decreased too much", "1559BlockImportImpossible_TargetGasHigh": "gasTarget increased too much", "1559BlockImportImpossible_InitialGasLimitInvalid": "Invalid block1559: Initial gasLimit must be", + "MergeBlockImportImpossible" : "Trying to import Merge block on top of Shanghai block after transition", + "ShanghaiBlockImportImpossible" : "Shanghai block on top of Merge block before transition", "TR_IntrinsicGas" : "intrinsic gas too low:", "TR_NoFunds" : "insufficient funds for gas * price + value", "TR_NoFundsValue" : "insufficient funds for transfer", @@ -217,6 +229,7 @@ string const t8ntool_config = R"({ "TR_TypeNotSupported" : "transaction type not supported", "TR_TipGtFeeCap": "max priority fee per gas higher than max fee per gas", "TR_TooShort": "typed transaction too short", + "TR_InitCodeLimitExceeded" : "max initcode size exceeded", "1559BaseFeeTooLarge": "TransactionBaseFee convertion error: VALUE >u256", "1559PriorityFeeGreaterThanBaseFee": "maxFeePerGas \u003c maxPriorityFeePerGas", "2930AccessListAddressTooLong": "rlp: input string too long for common.Address, decoding into (types.Transaction)(types.AccessListTx).AccessList[0].Address", @@ -228,25 +241,51 @@ string const t8ntool_config = R"({ "2930AccessListStorageHashTooLong": "rlp: input string too long for common.Hash, decoding into (types.Transaction)(types.AccessListTx).AccessList[0].StorageKeys[0]", "3675PoWBlockRejected" : "Invalid block1559: Chain switched to PoS!", "3675PoSBlockRejected" : "Parent (transition) block has not reached TTD", - "3675PreMerge1559BlockRejected" : "Trying to import 1559 block on top of PoS block" + "3675PreMerge1559BlockRejected" : "Trying to import 1559 block on top of PoS block", + "INPUT_UNMARSHAL_ERROR" : "cannot unmarshal hex", + "INPUT_UNMARSHAL_SIZE_ERROR" : "failed unmarshaling", + "RLP_BODY_UNMARSHAL_ERROR" : "Rlp structure is wrong", + "PostMergeUncleHashIsNotEmpty" : "block.uncleHash != empty", + "PostMergeDifficultyIsNot0" : "block.difficulty must be 0" } })"; string const t8ntool_start = R"(#!/bin/sh -if [ $1 = "-v" ]; then + +wevm=$(which evm) +if [ -z $wevm ]; then + >&2 echo "Can't find geth's 'evm' executable alias in the system path!" + exit 1 +fi + +if [ $1 = "t8n" ] || [ $1 = "b11r" ]; then + evm $1 $2 $3 $4 $5 $6 $7 $8 $9 $10 $11 $12 $13 $14 $15 $16 $17 $18 $19 $20 $21 $22 $23 $24 $25 $26 +elif [ $1 = "-v" ]; then evm -v else stateProvided=0 - for index in ${1} ${2} ${3} ${4} ${5} ${6} ${7} ${8} ${9} ${10} ${11} ${12} ${13} ${14} ${15} ${16} ${17} ${18} ${19} ${20} ; do + readErrorLog=0 + errorLogFile="" + cmdArgs="" + for index in ${1} ${2} ${3} ${4} ${5} ${6} ${7} ${8} ${9} ${10} ${11} ${12} ${13} ${14} ${15} ${16} ${17} ${18} ${19} ${20} ${21} ${22} ${23} ${24} ${25} ${26}; do if [ $index = "--input.alloc" ]; then stateProvided=1 - break fi + if [ $readErrorLog -eq 1 ]; then + errorLogFile=$index + readErrorLog=0 + continue + fi + if [ $index = "--output.errorlog" ]; then + readErrorLog=1 + continue + fi + cmdArgs=$cmdArgs" "$index done if [ $stateProvided -eq 1 ]; then - evm t8n ${1} ${2} ${3} ${4} ${5} ${6} ${7} ${8} ${9} ${10} ${11} ${12} ${13} ${14} ${15} ${16} ${17} ${18} ${19} ${20} --verbosity 2 + evm t8n $cmdArgs --verbosity 2 2> $errorLogFile else - evm t9n ${1} ${2} ${3} ${4} ${5} ${6} ${7} ${8} ${9} ${10} ${11} ${12} ${13} ${14} ${15} ${16} ${17} ${18} ${19} ${20} + evm t9n $cmdArgs 2> $errorLogFile fi fi )"; @@ -271,17 +310,40 @@ echo "0x600360005500" # just like described in this file." )"; - -string const t8ntool_yulcompiler = R"(#!/bin/sh +string const yul_compiler_sh = R"(#!/bin/sh solc=$(which solc) if [ -z $solc ]; then >&2 echo "yul.sh \"Yul compilation error: 'solc' not found!\"" echo "0x" else - echo 0x`solc --assemble $1 2>/dev/null | grep "Binary representation:" -A 1 | tail -n1` + out=$(solc --assemble $1 2>&1) + a=$(echo "$out" | grep "Binary representation:" -A 1 | tail -n1) + case "$out" in + *Error*) >&2 echo "yul.sh \"Yul compilation error: \"\n$out";; + * ) echo 0x$a;; + esac fi )"; +string const py_compiler_sh = R"(#!/bin/bash +if [ -z "$PYSPECS_PATH" ] +then + >&2 echo "Error: env variable 'PYSPECS_PATH' is not set!" + exit 1; +fi + +cd $PYSPECS_PATH +python3 -m venv ./venv/ +source ./venv/bin/activate + +SRCPATH=$1 +FILLER=$2 +OUTPUT=$3 +EVMT8N=$4 + +tf --filler-path $SRCPATH --output $OUTPUT --test-module $FILLER --no-output-structure --evm-bin $EVMT8N +)"; + gent8ntoolcfg::gent8ntoolcfg() { { @@ -308,7 +370,14 @@ gent8ntoolcfg::gent8ntoolcfg() spDataObject obj; (*obj)["exec"] = true; (*obj)["path"] = "t8ntool/yul.sh"; - (*obj)["content"] = t8ntool_yulcompiler; + (*obj)["content"] = yul_compiler_sh; + map_configs.addArrayObject(obj); + } + { + spDataObject obj; + (*obj)["exec"] = true; + (*obj)["path"] = "pyspecsStart.sh"; + (*obj)["content"] = py_compiler_sh; map_configs.addArrayObject(obj); } { @@ -335,7 +404,7 @@ gent8ntoolcfg::gent8ntoolcfg() spDataObject obj; (*obj)["exec"] = true; (*obj)["path"] = "default/yul.sh"; - (*obj)["content"] = t8ntool_yulcompiler; + (*obj)["content"] = yul_compiler_sh; map_configs.addArrayObject(obj); } } diff --git a/retesteth/configs/clientconfigs/t8ntooleip.cpp b/retesteth/configs/clientconfigs/t8ntooleip.cpp index 846467e78..6444ac9a9 100644 --- a/retesteth/configs/clientconfigs/t8ntooleip.cpp +++ b/retesteth/configs/clientconfigs/t8ntooleip.cpp @@ -4,12 +4,17 @@ using namespace dataobject; namespace retesteth::options { + string const t8ntooleip_config = R"({ - "name" : "Ethereum GO on StateTool + Custom EIP", + "name" : "Ethereum GO on StateTool", "socketType" : "tranition-tool", "socketAddress" : "start.sh", "checkLogsHash" : true, "checkBasefee" : true, + "defaultChainID" : 1, + "customCompilers" : { + ":yul" : "yul.sh" + }, "forks" : [ "Frontier", "Homestead", @@ -21,8 +26,8 @@ string const t8ntooleip_config = R"({ "Istanbul", "Berlin", "London", - "London+1884", - "Merge" + "Merge", + "Shanghai" ], "additionalForks" : [ "FrontierToHomesteadAt5", @@ -33,7 +38,12 @@ string const t8ntooleip_config = R"({ "BerlinToLondonAt5", "ArrowGlacier", "ArrowGlacierToMergeAtDiffC0000", - "GrayGlacier" + "GrayGlacier", + "MergeToShanghaiAtTime15k" + ], + "fillerSkipForks" : [ + "Merge+3540+3670", + "Merge+3860" ], "exceptions" : { "AddressTooShort" : "input string too short for common.Address", @@ -51,6 +61,7 @@ string const t8ntooleip_config = R"({ "InvalidData" : "rlp: expected input string or byte for []uint8, decoding into (types.Transaction)(types.LegacyTx).Data", "InvalidDifficulty" : "Invalid difficulty:", "InvalidDifficulty2" : "Error in field: difficulty", + "InvalidWithdrawals" : "Error in field: withdrawalsRoot", "InvalidDifficulty_TooLarge" : "Blockheader parse error: VALUE >u256", "InvalidGasLimit" : "Header gasLimit > 0x7fffffffffffffff", "InvalidGasLimit2" : "Invalid gaslimit:", @@ -105,6 +116,8 @@ string const t8ntooleip_config = R"({ "TRANSACTION_VALUE_TOOSHORT" : "t8ntool didn't return a transaction with hash", "TR_NonceHasMaxValue" : "nonce has max value:", "OVERSIZE_RLP" : "Error importing raw rlp block: OversizeRLP", + "RLP_BadCast" : "BadCast", + "RLP_ExpectedAsList" : "expected to be list", "RLP_TooFewElements" : "rlp: too few elements ", "RLP_TooManyElements" : "rlp: input list has too many elements ", "RLP_InputContainsMoreThanOneValue" : "Error importing raw rlp block: OversizeRLP", @@ -194,11 +207,13 @@ string const t8ntooleip_config = R"({ "LegacyBlockImportImpossible2" : "Legacy block can only be on top of LegacyBlock", "LegacyBlockBaseFeeTransaction" : "BaseFee transaction in a Legacy blcok", "1559BlockImportImpossible_HeaderIsLegacy" : "1559 block must be on top of 1559", - "1559BlockImportImpossible_BaseFeeWrong": "base fee not correct!", + "1559BlockImportImpossible_BaseFeeWrong": "Error in field: baseFeePerGas", "1559BlockImportImpossible_InitialBaseFeeWrong": "Initial baseFee must be 1000000000", "1559BlockImportImpossible_TargetGasLow": "gasTarget decreased too much", "1559BlockImportImpossible_TargetGasHigh": "gasTarget increased too much", "1559BlockImportImpossible_InitialGasLimitInvalid": "Invalid block1559: Initial gasLimit must be", + "MergeBlockImportImpossible" : "Trying to import Merge block on top of Shanghai block after transition", + "ShanghaiBlockImportImpossible" : "Shanghai block on top of Merge block before transition", "TR_IntrinsicGas" : "intrinsic gas too low:", "TR_NoFunds" : "insufficient funds for gas * price + value", "TR_NoFundsValue" : "insufficient funds for transfer", @@ -209,6 +224,7 @@ string const t8ntooleip_config = R"({ "TR_TypeNotSupported" : "transaction type not supported", "TR_TipGtFeeCap": "max priority fee per gas higher than max fee per gas", "TR_TooShort": "typed transaction too short", + "TR_InitCodeLimitExceeded" : "max initcode size exceeded", "1559BaseFeeTooLarge": "TransactionBaseFee convertion error: VALUE >u256", "1559PriorityFeeGreaterThanBaseFee": "maxFeePerGas \u003c maxPriorityFeePerGas", "2930AccessListAddressTooLong": "rlp: input string too long for common.Address, decoding into (types.Transaction)(types.AccessListTx).AccessList[0].Address", @@ -220,28 +236,13 @@ string const t8ntooleip_config = R"({ "2930AccessListStorageHashTooLong": "rlp: input string too long for common.Hash, decoding into (types.Transaction)(types.AccessListTx).AccessList[0].StorageKeys[0]", "3675PoWBlockRejected" : "Invalid block1559: Chain switched to PoS!", "3675PoSBlockRejected" : "Parent (transition) block has not reached TTD", - "3675PreMerge1559BlockRejected" : "Trying to import 1559 block on top of PoS block" + "3675PreMerge1559BlockRejected" : "Trying to import 1559 block on top of PoS block", + "INPUT_UNMARSHAL_ERROR" : "cannot unmarshal hex", + "INPUT_UNMARSHAL_SIZE_ERROR" : "failed unmarshaling", + "RLP_BODY_UNMARSHAL_ERROR" : "Rlp structure is wrong" } })"; -string const t8ntooleip_start = R"(#!/bin/sh -if [ $1 = "-v" ]; then - evm -v -else - stateProvided=0 - for index in ${1} ${2} ${3} ${4} ${5} ${6} ${7} ${8} ${9} ${10} ${11} ${12} ${13} ${14} ${15} ${16} ${17} ${18} ${19} ${20} ; do - if [ $index = "--input.alloc" ]; then - stateProvided=1 - break - fi - done - if [ $stateProvided -eq 1 ]; then - evm t8n ${1} ${2} ${3} ${4} ${5} ${6} ${7} ${8} ${9} ${10} ${11} ${12} ${13} ${14} ${15} ${16} ${17} ${18} ${19} ${20} --verbosity 2 - else - evm t9n ${1} ${2} ${3} ${4} ${5} ${6} ${7} ${8} ${9} ${10} ${11} ${12} ${13} ${14} ${15} ${16} ${17} ${18} ${19} ${20} - fi -fi -)"; gent8ntooleipcfg::gent8ntooleipcfg() { @@ -255,8 +256,16 @@ gent8ntooleipcfg::gent8ntooleipcfg() spDataObject obj; (*obj)["exec"] = true; (*obj)["path"] = "t8ntooleip/start.sh"; - (*obj)["content"] = t8ntooleip_start; + (*obj)["content"] = t8ntool_start; + map_configs.addArrayObject(obj); + } + { + spDataObject obj; + (*obj)["exec"] = true; + (*obj)["path"] = "t8ntooleip/yul.sh"; + (*obj)["content"] = yul_compiler_sh; map_configs.addArrayObject(obj); } + } } // namespace retesteth::options diff --git a/retesteth/configs/genesis/default/ArrowGlacier.cpp b/retesteth/configs/genesis/default/ArrowGlacier.cpp index 148b27683..ac27edc6e 100644 --- a/retesteth/configs/genesis/default/ArrowGlacier.cpp +++ b/retesteth/configs/genesis/default/ArrowGlacier.cpp @@ -4,24 +4,6 @@ using namespace dataobject; namespace retesteth::options { -const string default_ArrowGlacier_config = R"({ - "params" : { - "homesteadForkBlock" : "0x00", - "EIP150ForkBlock" : "0x00", - "EIP158ForkBlock" : "0x00", - "byzantiumForkBlock" : "0x00", - "constantinopleForkBlock" : "0x00", - "constantinopleFixForkBlock" : "0x00", - "istanbulForkBlock" : "0x00", - "berlinForkBlock" : "0x00", - "londonForkBlock" : "0x00", - "arrowGlacierForkBlock" : "0x00", - "chainID" : "0x01" - }, - "accounts" : { - } -})"; - const string t8ntool_ArrowGlacier_config = R"({ "params" : { "fork" : "ArrowGlacier", @@ -36,11 +18,6 @@ const string t8ntool_ArrowGlacier_config = R"({ genArrowGlacierCfg::genArrowGlacierCfg() { - spDataObject obj(new DataObject()); - (*obj)["path"] = "besu/genesis/ArrowGlacier.json"; - (*obj)["content"] = default_ArrowGlacier_config; - map_configs.addArrayObject(obj); - spDataObject obj2(new DataObject()); (*obj2)["path"] = "default/genesis/ArrowGlacier.json"; (*obj2)["content"] = t8ntool_ArrowGlacier_config; diff --git a/retesteth/configs/genesis/default/ArrowGlacierToMergeAtC0000.cpp b/retesteth/configs/genesis/default/ArrowGlacierToMergeAtC0000.cpp index a7d2363c0..c3079a9ac 100644 --- a/retesteth/configs/genesis/default/ArrowGlacierToMergeAtC0000.cpp +++ b/retesteth/configs/genesis/default/ArrowGlacierToMergeAtC0000.cpp @@ -4,25 +4,6 @@ using namespace dataobject; namespace retesteth::options { -const string default_ArrowGlacierToMergeAtDiffC0000_config = R"({ - "params" : { - "homesteadForkBlock" : "0x00", - "EIP150ForkBlock" : "0x00", - "EIP158ForkBlock" : "0x00", - "byzantiumForkBlock" : "0x00", - "constantinopleForkBlock" : "0x00", - "constantinopleFixForkBlock" : "0x00", - "istanbulForkBlock" : "0x00", - "berlinForkBlock" : "0x00", - "londonForkBlock" : "0x00", - "arrowGlacierForkBlock" : "0x00", - "terminalTotalDifficulty" : "0x0C0000", - "chainID" : "0x01" - }, - "accounts" : { - } -})"; - const string t8ntool_ArrowGlacierToMergeAtDiffC0000_config = R"({ "params" : { "fork" : "ArrowGlacierToMergeAtDiffC0000", @@ -38,11 +19,6 @@ const string t8ntool_ArrowGlacierToMergeAtDiffC0000_config = R"({ genArrowGlacierToMergeAtDiffC0000Cfg::genArrowGlacierToMergeAtDiffC0000Cfg() { - spDataObject obj(new DataObject()); - (*obj)["path"] = "besu/genesis/ArrowGlacierToMergeAtDiffC0000.json"; - (*obj)["content"] = default_ArrowGlacierToMergeAtDiffC0000_config; - map_configs.addArrayObject(obj); - spDataObject obj2(new DataObject()); (*obj2)["path"] = "default/genesis/ArrowGlacierToMergeAtDiffC0000.json"; (*obj2)["content"] = t8ntool_ArrowGlacierToMergeAtDiffC0000_config; diff --git a/retesteth/configs/genesis/default/Berlin.cpp b/retesteth/configs/genesis/default/Berlin.cpp index 5b84bdf25..cef540bbb 100644 --- a/retesteth/configs/genesis/default/Berlin.cpp +++ b/retesteth/configs/genesis/default/Berlin.cpp @@ -4,22 +4,6 @@ using namespace dataobject; namespace retesteth::options { -const string default_Berlin_config = R"({ - "params" : { - "homesteadForkBlock" : "0x00", - "EIP150ForkBlock" : "0x00", - "EIP158ForkBlock" : "0x00", - "byzantiumForkBlock" : "0x00", - "constantinopleForkBlock" : "0x00", - "constantinopleFixForkBlock" : "0x00", - "istanbulForkBlock" : "0x00", - "berlinForkBlock" : "0x00", - "chainID" : "0x01" - }, - "accounts" : { - } -})"; - const string t8ntool_Berlin_config = R"({ "params" : { "fork" : "Berlin", @@ -34,11 +18,6 @@ const string t8ntool_Berlin_config = R"({ genBerlinCfg::genBerlinCfg() { - spDataObject obj; - (*obj)["path"] = "besu/genesis/Berlin.json"; - (*obj)["content"] = default_Berlin_config; - map_configs.addArrayObject(obj); - spDataObject obj2; (*obj2)["path"] = "default/genesis/Berlin.json"; (*obj2)["content"] = t8ntool_Berlin_config; diff --git a/retesteth/configs/genesis/default/BerlinToLondonAt5.cpp b/retesteth/configs/genesis/default/BerlinToLondonAt5.cpp index 4c36273b2..2c13099a0 100644 --- a/retesteth/configs/genesis/default/BerlinToLondonAt5.cpp +++ b/retesteth/configs/genesis/default/BerlinToLondonAt5.cpp @@ -4,21 +4,6 @@ using namespace dataobject; namespace retesteth::options { -const string default_BerlinToLondonAt5_config = R"({ - "params" : { - "homesteadForkBlock" : "0x00", - "EIP150ForkBlock" : "0x00", - "EIP158ForkBlock" : "0x00", - "byzantiumForkBlock" : "0x00", - "constantinopleForkBlock" : "0x00", - "constantinopleFixForkBlock" : "0x00", - "berlinForkBlock" : "0x00", - "londonForkBlock" : "0x05" - }, - "accounts" : { - } -})"; - const string t8ntool_BerlinToLondonAt5_config = R"({ "params" : { "fork" : "BerlinToLondonAt5", @@ -34,12 +19,6 @@ const string t8ntool_BerlinToLondonAt5_config = R"({ genBerlinToLondonCfg::genBerlinToLondonCfg() { - { - spDataObject obj; - (*obj)["path"] = "besu/genesis/BerlinToLondonAt5.json"; - (*obj)["content"] = default_BerlinToLondonAt5_config; - map_configs.addArrayObject(obj); - } { spDataObject obj; (*obj)["path"] = "default/genesis/BerlinToLondonAt5.json"; diff --git a/retesteth/configs/genesis/default/Byzantium.cpp b/retesteth/configs/genesis/default/Byzantium.cpp index 8c50d9ff9..6f8b7319a 100644 --- a/retesteth/configs/genesis/default/Byzantium.cpp +++ b/retesteth/configs/genesis/default/Byzantium.cpp @@ -4,17 +4,6 @@ using namespace dataobject; namespace retesteth::options { -const string default_Byzantium_config = R"({ - "params" : { - "homesteadForkBlock" : "0x00", - "EIP150ForkBlock" : "0x00", - "EIP158ForkBlock" : "0x00", - "byzantiumForkBlock" : "0x00" - }, - "accounts" : { - } -})"; - const string t8ntool_Byzantium_config = R"({ "params" : { "fork" : "Byzantium", @@ -28,11 +17,6 @@ const string t8ntool_Byzantium_config = R"({ genByzantiumCfg::genByzantiumCfg() { - spDataObject obj; - (*obj)["path"] = "besu/genesis/Byzantium.json"; - (*obj)["content"] = default_Byzantium_config; - map_configs.addArrayObject(obj); - spDataObject obj2; (*obj2)["path"] = "default/genesis/Byzantium.json"; (*obj2)["content"] = t8ntool_Byzantium_config; diff --git a/retesteth/configs/genesis/default/ByzantiumToConstantinopleFixAt5.cpp b/retesteth/configs/genesis/default/ByzantiumToConstantinopleFixAt5.cpp index 27eac5d9d..8a59b1626 100644 --- a/retesteth/configs/genesis/default/ByzantiumToConstantinopleFixAt5.cpp +++ b/retesteth/configs/genesis/default/ByzantiumToConstantinopleFixAt5.cpp @@ -4,19 +4,6 @@ using namespace dataobject; namespace retesteth::options { -const string default_ByzantiumToConstantinopleFixAt5_config = R"({ - "params" : { - "homesteadForkBlock" : "0x00", - "EIP150ForkBlock" : "0x00", - "EIP158ForkBlock" : "0x00", - "byzantiumForkBlock" : "0x00", - "constantinopleForkBlock" : "0x05", - "constantinopleFixForkBlock" : "0x05" - }, - "accounts" : { - } -})"; - const string t8ntool_ByzantiumToConstantinopleFixAt5_config = R"({ "params" : { "fork" : "ByzantiumToConstantinopleFixAt5", @@ -31,11 +18,6 @@ const string t8ntool_ByzantiumToConstantinopleFixAt5_config = R"({ genByzantiumToConstantinopleFixCfg::genByzantiumToConstantinopleFixCfg() { - spDataObject obj; - (*obj)["path"] = "besu/genesis/ByzantiumToConstantinopleFixAt5.json"; - (*obj)["content"] = default_ByzantiumToConstantinopleFixAt5_config; - map_configs.addArrayObject(obj); - spDataObject obj2; (*obj2)["path"] = "default/genesis/ByzantiumToConstantinopleFixAt5.json"; (*obj2)["content"] = t8ntool_ByzantiumToConstantinopleFixAt5_config; diff --git a/retesteth/configs/genesis/default/Constantinople.cpp b/retesteth/configs/genesis/default/Constantinople.cpp index 714b6236c..674d41156 100644 --- a/retesteth/configs/genesis/default/Constantinople.cpp +++ b/retesteth/configs/genesis/default/Constantinople.cpp @@ -4,18 +4,6 @@ using namespace dataobject; namespace retesteth::options { -const string default_Constantinople_config = R"({ - "params" : { - "homesteadForkBlock" : "0x00", - "EIP150ForkBlock" : "0x00", - "EIP158ForkBlock" : "0x00", - "byzantiumForkBlock" : "0x00", - "constantinopleForkBlock" : "0x00" - }, - "accounts" : { - } -})"; - const string t8ntool_Constantinople_config = R"({ "params" : { "fork" : "Constantinople", @@ -30,11 +18,6 @@ const string t8ntool_Constantinople_config = R"({ genConstantinopleCfg::genConstantinopleCfg() { - spDataObject obj; - (*obj)["path"] = "besu/genesis/Constantinople.json"; - (*obj)["content"] = default_Constantinople_config; - map_configs.addArrayObject(obj); - spDataObject obj2; (*obj2)["path"] = "default/genesis/Constantinople.json"; (*obj2)["content"] = t8ntool_Constantinople_config; diff --git a/retesteth/configs/genesis/default/ConstantinopleFix.cpp b/retesteth/configs/genesis/default/ConstantinopleFix.cpp index cdcfa27cd..eafb6daba 100644 --- a/retesteth/configs/genesis/default/ConstantinopleFix.cpp +++ b/retesteth/configs/genesis/default/ConstantinopleFix.cpp @@ -4,19 +4,6 @@ using namespace dataobject; namespace retesteth::options { -const string default_ConstantinopleFix_config = R"({ - "params" : { - "homesteadForkBlock" : "0x00", - "EIP150ForkBlock" : "0x00", - "EIP158ForkBlock" : "0x00", - "byzantiumForkBlock" : "0x00", - "constantinopleForkBlock" : "0x00", - "constantinopleFixForkBlock" : "0x00" - }, - "accounts" : { - } -})"; - const string t8ntool_ConstantinopleFix_config = R"({ "params" : { "fork" : "ConstantinopleFix", @@ -31,11 +18,6 @@ const string t8ntool_ConstantinopleFix_config = R"({ genConstantinopleFixCfg::genConstantinopleFixCfg() { - spDataObject obj; - (*obj)["path"] = "besu/genesis/ConstantinopleFix.json"; - (*obj)["content"] = default_ConstantinopleFix_config; - map_configs.addArrayObject(obj); - spDataObject obj2; (*obj2)["path"] = "default/genesis/ConstantinopleFix.json"; (*obj2)["content"] = t8ntool_ConstantinopleFix_config; diff --git a/retesteth/configs/genesis/default/EIP150.cpp b/retesteth/configs/genesis/default/EIP150.cpp index 5c14b0f13..d401f25c5 100644 --- a/retesteth/configs/genesis/default/EIP150.cpp +++ b/retesteth/configs/genesis/default/EIP150.cpp @@ -4,15 +4,6 @@ using namespace dataobject; namespace retesteth::options { -const string default_EIP150_config = R"({ - "params" : { - "homesteadForkBlock" : "0x00", - "EIP150ForkBlock" : "0x00" - }, - "accounts" : { - } -})"; - const string t8ntool_EIP150_config = R"({ "params" : { "fork" : "EIP150", @@ -25,11 +16,6 @@ const string t8ntool_EIP150_config = R"({ genEIP150Cfg::genEIP150Cfg() { - spDataObject obj; - (*obj)["path"] = "besu/genesis/EIP150.json"; - (*obj)["content"] = default_EIP150_config; - map_configs.addArrayObject(obj); - spDataObject obj2; (*obj2)["path"] = "default/genesis/EIP150.json"; (*obj2)["content"] = t8ntool_EIP150_config; diff --git a/retesteth/configs/genesis/default/EIP158.cpp b/retesteth/configs/genesis/default/EIP158.cpp index cb6bac599..a28eee953 100644 --- a/retesteth/configs/genesis/default/EIP158.cpp +++ b/retesteth/configs/genesis/default/EIP158.cpp @@ -4,16 +4,6 @@ using namespace dataobject; namespace retesteth::options { -const string default_EIP158_config = R"({ - "params" : { - "homesteadForkBlock" : "0x00", - "EIP150ForkBlock" : "0x00", - "EIP158ForkBlock" : "0x00" - }, - "accounts" : { - } -})"; - const string t8ntool_EIP158_config = R"({ "params" : { "fork" : "EIP158", @@ -26,11 +16,6 @@ const string t8ntool_EIP158_config = R"({ genEIP158Cfg::genEIP158Cfg() { - spDataObject obj; - (*obj)["path"] = "besu/genesis/EIP158.json"; - (*obj)["content"] = default_EIP158_config; - map_configs.addArrayObject(obj); - spDataObject obj2; (*obj2)["path"] = "default/genesis/EIP158.json"; (*obj2)["content"] = t8ntool_EIP158_config; diff --git a/retesteth/configs/genesis/default/EIP158ToByzantiumAt5.cpp b/retesteth/configs/genesis/default/EIP158ToByzantiumAt5.cpp index 6fe788f3c..70a327ddc 100644 --- a/retesteth/configs/genesis/default/EIP158ToByzantiumAt5.cpp +++ b/retesteth/configs/genesis/default/EIP158ToByzantiumAt5.cpp @@ -4,17 +4,6 @@ using namespace dataobject; namespace retesteth::options { -const string default_EIP158ToByzantiumAt5_config = R"({ - "params" : { - "homesteadForkBlock" : "0x00", - "EIP150ForkBlock" : "0x00", - "EIP158ForkBlock" : "0x00", - "byzantiumForkBlock" : "0x05" - }, - "accounts" : { - } -})"; - const string t8ntool_EIP158ToByzantiumAt5_config = R"({ "params" : { "fork" : "EIP158ToByzantiumAt5", @@ -28,11 +17,6 @@ const string t8ntool_EIP158ToByzantiumAt5_config = R"({ genEIP158ToByzantiumCfg::genEIP158ToByzantiumCfg() { - spDataObject obj; - (*obj)["path"] = "besu/genesis/EIP158ToByzantiumAt5.json"; - (*obj)["content"] = default_EIP158ToByzantiumAt5_config; - map_configs.addArrayObject(obj); - spDataObject obj2; (*obj2)["path"] = "default/genesis/EIP158ToByzantiumAt5.json"; (*obj2)["content"] = t8ntool_EIP158ToByzantiumAt5_config; diff --git a/retesteth/configs/genesis/default/Frontier.cpp b/retesteth/configs/genesis/default/Frontier.cpp index 662cf2304..b2ff30335 100644 --- a/retesteth/configs/genesis/default/Frontier.cpp +++ b/retesteth/configs/genesis/default/Frontier.cpp @@ -4,13 +4,6 @@ using namespace dataobject; namespace retesteth::options { -const string default_Frontier_config = R"({ - "params" : { - }, - "accounts" : { - } -})"; - const string t8ntool_Frontier_config = R"({ "params" : { "fork" : "Frontier", @@ -22,11 +15,6 @@ const string t8ntool_Frontier_config = R"({ genFrontierCfg::genFrontierCfg() { - spDataObject obj; - (*obj)["path"] = "besu/genesis/Frontier.json"; - (*obj)["content"] = default_Frontier_config; - map_configs.addArrayObject(obj); - spDataObject obj2; (*obj2)["path"] = "default/genesis/Frontier.json"; (*obj2)["content"] = t8ntool_Frontier_config; diff --git a/retesteth/configs/genesis/default/FrontierToHomesteadAt5.cpp b/retesteth/configs/genesis/default/FrontierToHomesteadAt5.cpp index 8b15da30d..f2237025e 100644 --- a/retesteth/configs/genesis/default/FrontierToHomesteadAt5.cpp +++ b/retesteth/configs/genesis/default/FrontierToHomesteadAt5.cpp @@ -4,14 +4,6 @@ using namespace dataobject; namespace retesteth::options { -const string default_FrontierToHomesteadAt5_config = R"({ - "params" : { - "homesteadForkBlock" : "0x05" - }, - "accounts" : { - } -})"; - const string t8ntool_FrontierToHomesteadAt5_config = R"({ "params" : { "fork" : "FrontierToHomesteadAt5", @@ -24,11 +16,6 @@ const string t8ntool_FrontierToHomesteadAt5_config = R"({ genFrontierToHomesteadCfg::genFrontierToHomesteadCfg() { - spDataObject obj; - (*obj)["path"] = "besu/genesis/FrontierToHomesteadAt5.json"; - (*obj)["content"] = default_FrontierToHomesteadAt5_config; - map_configs.addArrayObject(obj); - spDataObject obj2; (*obj2)["path"] = "default/genesis/FrontierToHomesteadAt5.json"; (*obj2)["content"] = t8ntool_FrontierToHomesteadAt5_config; diff --git a/retesteth/configs/genesis/default/GrayGlacier.cpp b/retesteth/configs/genesis/default/GrayGlacier.cpp index 6aecdadc8..01345db70 100644 --- a/retesteth/configs/genesis/default/GrayGlacier.cpp +++ b/retesteth/configs/genesis/default/GrayGlacier.cpp @@ -4,25 +4,6 @@ using namespace dataobject; namespace retesteth::options { -const string default_GrayGlacier_config = R"({ - "params" : { - "homesteadForkBlock" : "0x00", - "EIP150ForkBlock" : "0x00", - "EIP158ForkBlock" : "0x00", - "byzantiumForkBlock" : "0x00", - "constantinopleForkBlock" : "0x00", - "constantinopleFixForkBlock" : "0x00", - "istanbulForkBlock" : "0x00", - "berlinForkBlock" : "0x00", - "londonForkBlock" : "0x00", - "arrowGlacierForkBlock" : "0x00", - "grayGlacierForkBlock" : "0x00", - "chainID" : "0x01" - }, - "accounts" : { - } -})"; - const string t8ntool_GrayGlacier_config = R"({ "params" : { "fork" : "GrayGlacier", @@ -37,11 +18,6 @@ const string t8ntool_GrayGlacier_config = R"({ genGrayGlacierCfg::genGrayGlacierCfg() { - spDataObject obj(new DataObject()); - (*obj)["path"] = "besu/genesis/GrayGlacier.json"; - (*obj)["content"] = default_GrayGlacier_config; - map_configs.addArrayObject(obj); - spDataObject obj2(new DataObject()); (*obj2)["path"] = "default/genesis/GrayGlacier.json"; (*obj2)["content"] = t8ntool_GrayGlacier_config; diff --git a/retesteth/configs/genesis/default/Homestead.cpp b/retesteth/configs/genesis/default/Homestead.cpp index 792f930e9..a47aad3f0 100644 --- a/retesteth/configs/genesis/default/Homestead.cpp +++ b/retesteth/configs/genesis/default/Homestead.cpp @@ -4,14 +4,6 @@ using namespace dataobject; namespace retesteth::options { -const string default_Homestead_config = R"({ - "params" : { - "homesteadForkBlock" : "0x00" - }, - "accounts" : { - } -})"; - const string t8ntool_Homestead_config = R"({ "params" : { "fork" : "Homestead", @@ -24,11 +16,6 @@ const string t8ntool_Homestead_config = R"({ genHomesteadCfg::genHomesteadCfg() { - spDataObject obj; - (*obj)["path"] = "besu/genesis/Homestead.json"; - (*obj)["content"] = default_Homestead_config; - map_configs.addArrayObject(obj); - spDataObject obj2; (*obj2)["path"] = "default/genesis/Homestead.json"; (*obj2)["content"] = t8ntool_Homestead_config; diff --git a/retesteth/configs/genesis/default/HomesteadToDaoAt5.cpp b/retesteth/configs/genesis/default/HomesteadToDaoAt5.cpp index d8b45b319..b2b0688cc 100644 --- a/retesteth/configs/genesis/default/HomesteadToDaoAt5.cpp +++ b/retesteth/configs/genesis/default/HomesteadToDaoAt5.cpp @@ -4,15 +4,6 @@ using namespace dataobject; namespace retesteth::options { -const string default_HomesteadToDaoAt5_config = R"({ - "params" : { - "homesteadForkBlock" : "0x00", - "daoHardforkBlock" : "0x05" - }, - "accounts" : { - } -})"; - const string t8ntool_HomesteadToDaoAt5_config = R"({ "params" : { "fork" : "HomesteadToDaoAt5", @@ -25,11 +16,6 @@ const string t8ntool_HomesteadToDaoAt5_config = R"({ genHomesteadToDaoCfg::genHomesteadToDaoCfg() { - spDataObject obj; - (*obj)["path"] = "besu/genesis/HomesteadToDaoAt5.json"; - (*obj)["content"] = default_HomesteadToDaoAt5_config; - map_configs.addArrayObject(obj); - spDataObject obj2; (*obj2)["path"] = "default/genesis/HomesteadToDaoAt5.json"; (*obj2)["content"] = t8ntool_HomesteadToDaoAt5_config; diff --git a/retesteth/configs/genesis/default/HomesteadToEIP150At5.cpp b/retesteth/configs/genesis/default/HomesteadToEIP150At5.cpp index ec77d7dae..e8681ceb4 100644 --- a/retesteth/configs/genesis/default/HomesteadToEIP150At5.cpp +++ b/retesteth/configs/genesis/default/HomesteadToEIP150At5.cpp @@ -4,15 +4,6 @@ using namespace dataobject; namespace retesteth::options { -const string default_HomesteadToEIP150At5_config = R"({ - "params" : { - "homesteadForkBlock" : "0x00", - "EIP150ForkBlock" : "0x05" - }, - "accounts" : { - } -})"; - const string t8ntool_HomesteadToEIP150At5_config = R"({ "params" : { "fork" : "HomesteadToEIP150At5", @@ -25,11 +16,6 @@ const string t8ntool_HomesteadToEIP150At5_config = R"({ genHomesteadToEIP150Cfg::genHomesteadToEIP150Cfg() { - spDataObject obj; - (*obj)["path"] = "besu/genesis/HomesteadToEIP150At5.json"; - (*obj)["content"] = default_HomesteadToEIP150At5_config; - map_configs.addArrayObject(obj); - spDataObject obj2; (*obj2)["path"] = "default/genesis/HomesteadToEIP150At5.json"; (*obj2)["content"] = t8ntool_HomesteadToEIP150At5_config; diff --git a/retesteth/configs/genesis/default/Istanbul.cpp b/retesteth/configs/genesis/default/Istanbul.cpp index 7913699a1..6b9e5e363 100644 --- a/retesteth/configs/genesis/default/Istanbul.cpp +++ b/retesteth/configs/genesis/default/Istanbul.cpp @@ -4,21 +4,6 @@ using namespace dataobject; namespace retesteth::options { -const string default_Istanbul_config = R"({ - "params" : { - "homesteadForkBlock" : "0x00", - "EIP150ForkBlock" : "0x00", - "EIP158ForkBlock" : "0x00", - "byzantiumForkBlock" : "0x00", - "constantinopleForkBlock" : "0x00", - "constantinopleFixForkBlock" : "0x00", - "istanbulForkBlock" : "0x00", - "chainID" : "0x01" - }, - "accounts" : { - } -})"; - const string t8ntool_Istanbul_config = R"({ "params" : { "fork" : "Istanbul", @@ -33,11 +18,6 @@ const string t8ntool_Istanbul_config = R"({ genIstanbulCfg::genIstanbulCfg() { - spDataObject obj; - (*obj)["path"] = "besu/genesis/Istanbul.json"; - (*obj)["content"] = default_Istanbul_config; - map_configs.addArrayObject(obj); - spDataObject obj2; (*obj2)["path"] = "default/genesis/Istanbul.json"; (*obj2)["content"] = t8ntool_Istanbul_config; diff --git a/retesteth/configs/genesis/default/London.cpp b/retesteth/configs/genesis/default/London.cpp index 36ccb32f7..03448669d 100644 --- a/retesteth/configs/genesis/default/London.cpp +++ b/retesteth/configs/genesis/default/London.cpp @@ -4,23 +4,6 @@ using namespace dataobject; namespace retesteth::options { -const string default_London_config = R"({ - "params" : { - "homesteadForkBlock" : "0x00", - "EIP150ForkBlock" : "0x00", - "EIP158ForkBlock" : "0x00", - "byzantiumForkBlock" : "0x00", - "constantinopleForkBlock" : "0x00", - "constantinopleFixForkBlock" : "0x00", - "istanbulForkBlock" : "0x00", - "berlinForkBlock" : "0x00", - "londonForkBlock" : "0x00", - "chainID" : "0x01" - }, - "accounts" : { - } -})"; - const string t8ntool_London_config = R"({ "params" : { "fork" : "London", @@ -35,11 +18,6 @@ const string t8ntool_London_config = R"({ genLondonCfg::genLondonCfg() { - spDataObject obj; - (*obj)["path"] = "besu/genesis/London.json"; - (*obj)["content"] = default_London_config; - map_configs.addArrayObject(obj); - spDataObject obj2; (*obj2)["path"] = "default/genesis/London.json"; (*obj2)["content"] = t8ntool_London_config; diff --git a/retesteth/configs/genesis/default/Merge.cpp b/retesteth/configs/genesis/default/Merge.cpp index 0fcc79585..f96649ae2 100644 --- a/retesteth/configs/genesis/default/Merge.cpp +++ b/retesteth/configs/genesis/default/Merge.cpp @@ -4,27 +4,9 @@ using namespace dataobject; namespace retesteth::options { -const string default_Merge_config = R"({ - "params" : { - "homesteadForkBlock" : "0x00", - "EIP150ForkBlock" : "0x00", - "EIP158ForkBlock" : "0x00", - "byzantiumForkBlock" : "0x00", - "constantinopleForkBlock" : "0x00", - "constantinopleFixForkBlock" : "0x00", - "istanbulForkBlock" : "0x00", - "berlinForkBlock" : "0x00", - "londonForkBlock" : "0x00", - "terminalTotalDifficulty" : "0x00", - "chainID" : "0x01" - }, - "accounts" : { - } -})"; - const string t8ntool_Merge_config = R"({ "params" : { - "fork" : "Merged", + "fork" : "Merge", "terminalTotalDifficulty" : "0x00", "constantinopleForkBlock" : "0x00", "byzantiumForkBlock" : "0x00", @@ -37,13 +19,6 @@ const string t8ntool_Merge_config = R"({ genMergeCfg::genMergeCfg() { - { - spDataObject obj; - (*obj)["path"] = "besu/genesis/Merge.json"; - (*obj)["content"] = default_Merge_config; - map_configs.addArrayObject(obj); - } - { spDataObject obj; (*obj)["path"] = "default/genesis/Merge.json"; diff --git a/retesteth/configs/genesis/default/MergeToShanghaiAt5.cpp b/retesteth/configs/genesis/default/MergeToShanghaiAt5.cpp new file mode 100644 index 000000000..03e8703d6 --- /dev/null +++ b/retesteth/configs/genesis/default/MergeToShanghaiAt5.cpp @@ -0,0 +1,27 @@ +#include +using namespace std; +using namespace dataobject; + +namespace retesteth::options +{ +const string t8ntool_MergeToShanghaiAtTime15k_config = R"({ + "params" : { + "fork" : "MergeToShanghaiAtTime15k", + "constantinopleForkBlock" : "0x00", + "byzantiumForkBlock" : "0x00", + "homesteadForkBlock" : "0x00", + "terminalTotalDifficulty" : "0x00", + "chainID" : "0x01" + }, + "accounts" : { + } +})"; + +genMergeToShanghaiAtTime15kCfg::genMergeToShanghaiAtTime15kCfg() +{ + spDataObject obj2(new DataObject()); + (*obj2)["path"] = "default/genesis/MergeToShanghaiAtTime15k.json"; + (*obj2)["content"] = t8ntool_MergeToShanghaiAtTime15k_config; + map_configs.addArrayObject(obj2); +} +} // namespace retesteth::options diff --git a/retesteth/configs/genesis/default/Shanghai.cpp b/retesteth/configs/genesis/default/Shanghai.cpp new file mode 100644 index 000000000..61b5fab92 --- /dev/null +++ b/retesteth/configs/genesis/default/Shanghai.cpp @@ -0,0 +1,29 @@ +#include +using namespace std; +using namespace dataobject; + +namespace retesteth::options +{ +const string t8ntool_Shanghai_config = R"({ + "params" : { + "fork" : "Shanghai", + "terminalTotalDifficulty" : "0x00", + "constantinopleForkBlock" : "0x00", + "byzantiumForkBlock" : "0x00", + "homesteadForkBlock" : "0x00", + "chainID" : "0x01" + }, + "accounts" : { + } +})"; + +genShanghaiCfg::genShanghaiCfg() +{ + { + spDataObject obj; + (*obj)["path"] = "default/genesis/Shanghai.json"; + (*obj)["content"] = t8ntool_Shanghai_config; + map_configs.addArrayObject(obj); + } +} +} // namespace retesteth::options diff --git a/retesteth/configs/genesis/default/correctMiningReward.cpp b/retesteth/configs/genesis/default/correctMiningReward.cpp index 3828b1d2d..971d68cc4 100644 --- a/retesteth/configs/genesis/default/correctMiningReward.cpp +++ b/retesteth/configs/genesis/default/correctMiningReward.cpp @@ -4,22 +4,6 @@ using namespace dataobject; namespace retesteth::options { -const string default_correctMiningReward_config = R"({ - "//comment" : "State Tests does not calculate mining reward in post conditions, so when filling a blockchain test out of it, the mining reward must be set", - "Frontier": "5000000000000000000", - "Homestead": "5000000000000000000", - "EIP150": "5000000000000000000", - "EIP158": "5000000000000000000", - "Byzantium": "3000000000000000000", - "Constantinople": "2000000000000000000", - "ConstantinopleFix": "2000000000000000000", - "Istanbul": "2000000000000000000", - "Berlin" : "2000000000000000000", - "London" : "2000000000000000000", - "ArrowGlacier" : "2000000000000000000", - "GrayGlacier" : "2000000000000000000" -})"; - const string t8ntool_correctMiningReward_config = R"({ "//comment" : "State Tests does not calculate mining reward in post conditions, so when filling a blockchain test out of it, the mining reward must be set", "Frontier": "5000000000000000000", @@ -41,16 +25,13 @@ const string t8ntool_correctMiningReward_config = R"({ "YOLOv3" : "2000000000000000000", "Aleut" : "2000000000000000000", "Merge" : "0", - "Merged" : "0" + "Merged" : "0", + "Shanghai" : "0" + })"; genRewardsCfg::genRewardsCfg() { - spDataObject obj; - (*obj)["path"] = "besu/genesis/correctMiningReward.json"; - (*obj)["content"] = default_correctMiningReward_config; - map_configs.addArrayObject(obj); - spDataObject obj2; (*obj2)["path"] = "default/genesis/correctMiningReward.json"; (*obj2)["content"] = t8ntool_correctMiningReward_config; diff --git a/retesteth/configs/genesis/nimbus/Merge.cpp b/retesteth/configs/genesis/nimbus/Merge.cpp new file mode 100644 index 000000000..5dac5c9da --- /dev/null +++ b/retesteth/configs/genesis/nimbus/Merge.cpp @@ -0,0 +1,30 @@ +#include +using namespace std; +using namespace dataobject; + +namespace retesteth::options +{ + +const string nimbus_Merge_config = R"({ + "params" : { + "fork" : "Merge", + "terminalTotalDifficulty" : "0x00", + "constantinopleForkBlock" : "0x00", + "byzantiumForkBlock" : "0x00", + "homesteadForkBlock" : "0x00", + "chainID" : "0x01" + }, + "accounts" : { + } +})"; + +genMergeCfgNIMBUS::genMergeCfgNIMBUS() +{ + { + spDataObject obj; + (*obj)["path"] = "nimbus/genesis/Merge.json"; + (*obj)["content"] = nimbus_Merge_config; + map_configs.addArrayObject(obj); + } +} +} // namespace retesteth::options diff --git a/retesteth/configs/genesis/nimbus/correctMiningReward.cpp b/retesteth/configs/genesis/nimbus/correctMiningReward.cpp new file mode 100644 index 000000000..315f13177 --- /dev/null +++ b/retesteth/configs/genesis/nimbus/correctMiningReward.cpp @@ -0,0 +1,40 @@ +#include +using namespace std; +using namespace dataobject; + +namespace retesteth::options +{ + +const string nimbus_correctMiningReward_config = R"({ + "//comment" : "State Tests does not calculate mining reward in post conditions, so when filling a blockchain test out of it, the mining reward must be set", + "Frontier": "5000000000000000000", + "Homestead": "5000000000000000000", + "EIP150": "5000000000000000000", + "EIP158": "5000000000000000000", + "Byzantium": "3000000000000000000", + "Constantinople": "2000000000000000000", + "ConstantinopleFix": "2000000000000000000", + "Istanbul": "2000000000000000000", + "Berlin" : "2000000000000000000", + "London" : "2000000000000000000", + "ArrowGlacier" : "2000000000000000000", + "GrayGlacier" : "2000000000000000000", + + "//comment" : "Retesteth calculate rewards on behalf of the tool when filling state tests", + "YOLOv1" : "2000000000000000000", + "YOLOv2" : "2000000000000000000", + "YOLOv3" : "2000000000000000000", + "Aleut" : "2000000000000000000", + "Merge" : "0", + "Merged" : "0", + "Shanghai" : "0" +})"; + +genRewardsCfgNIMBUS::genRewardsCfgNIMBUS() +{ + spDataObject obj; + (*obj)["path"] = "nimbus/genesis/correctMiningReward.json"; + (*obj)["content"] = nimbus_correctMiningReward_config; + map_configs.addArrayObject(obj); +} +} // namespace retesteth::options diff --git a/retesteth/configs/genesis/t8ntooleip/correctMiningReward.cpp b/retesteth/configs/genesis/t8ntooleip/correctMiningReward.cpp index f81e6303d..53b662f5b 100644 --- a/retesteth/configs/genesis/t8ntooleip/correctMiningReward.cpp +++ b/retesteth/configs/genesis/t8ntooleip/correctMiningReward.cpp @@ -26,7 +26,8 @@ const string t8ntooleip_correctMiningReward_config = R"({ "YOLOv3" : "2000000000000000000", "Aleut" : "2000000000000000000", "Merge" : "0", - "Merged" : "0" + "Merged" : "0", + "Shanghai" : "0" })"; gent8ntooleip_genRewardsCfg::gent8ntooleip_genRewardsCfg() diff --git a/retesteth/main.cpp b/retesteth/main.cpp index 2f048eb36..dafa3608f 100644 --- a/retesteth/main.cpp +++ b/retesteth/main.cpp @@ -41,15 +41,16 @@ int main(int argc, const char* argv[]) signal(SIGTERM, &ExitHandler::exitHandler); signal(SIGINT, &ExitHandler::exitHandler); - initializeOptions(argc, argv); - expandUnitTestsArg(argc, argv); - makeSingleTestFileSuite(argc, argv); + auto argv2 = preprocessOptions(argc, argv); + initializeOptions(argc, argv2); + expandUnitTestsArg(argc, argv2); + makeSingleTestFileSuite(argc, argv2); lookForUnregisteredTestFolders(); - if (!checkTestSuiteIsKnown(argc, argv)) + if (!checkTestSuiteIsKnown(argc, argv2)) return -1; - int result = runTheBoostTests(argc, argv); + int result = runTheBoostTests(argc, argv2); cleanMemory(); ExitHandler::doExit(); return result; diff --git a/retesteth/mainHelper.cpp b/retesteth/mainHelper.cpp index 967a73b9d..b264354e4 100644 --- a/retesteth/mainHelper.cpp +++ b/retesteth/mainHelper.cpp @@ -14,10 +14,14 @@ #include #include +#include +#include +#include using namespace std; using namespace test::debug; using namespace boost::unit_test; +namespace fs = boost::filesystem; namespace { @@ -25,6 +29,8 @@ static std::ostringstream strCout; std::streambuf* oldCoutStreamBuf; std::streambuf* oldCerrStreamBuf; std::string const c_sDynamicTestSuiteName = "customTestSuite"; +std::vector c_cleanDynamicChars; +const char** c_argv2 = nullptr; void runCustomTestFile() { @@ -303,6 +309,192 @@ void lookForUnregisteredTestFolders() void cleanMemory() { DynamicTestsBoostClean(); + for (size_t i = 0; i < c_cleanDynamicChars.size(); i++) + delete [] c_cleanDynamicChars[i]; + if (c_argv2 != nullptr) + delete [] c_argv2; } +string getTestType(string const& _filename) +{ + string type = "GeneralStateTests"; + if (fs::exists(_filename)) + { + spDataObject res = readAutoDataWithoutOptions(_filename); + if (res.isEmpty()) + return type; + + auto isBlockChainTest = [](DataObject const& _el) + { + return (_el.getKey() == "blocks") ? true : false; + }; + auto isStateTest = [](DataObject const& _el) + { + return (_el.getKey() == "env") ? true : false; + }; + if (res->performSearch(isBlockChainTest)) + return "BlockchainTests"; + if (res->performSearch(isStateTest)) + return "GeneralStateTests"; + } + return type; +} + +string getTestTArg(fs::path const& _cwd, string const& arg) +{ + const vector supportedSuites = { + "GeneralStateTests", "BlockchainTests", + "GeneralStateTestsFiller", "BlockchainTestsFiller", + "EOFTests", "EOFTestsFiller", + "EIPTests", "EIPTestsFiller"}; + string tArg; + fs::path cwd = _cwd; + while(!test::inArray(supportedSuites, cwd.stem().string()) && !cwd.empty()) + { + tArg.insert(0, cwd.stem().string() + "/"); + cwd = cwd.parent_path(); + } + if (!cwd.empty()) + { + string headTestSuite = cwd.stem().string(); + size_t const pos = headTestSuite.find("Filler"); + if (pos != string::npos) + headTestSuite = headTestSuite.erase(pos, 6); + else + { + if (cwd.parent_path().stem() == "BlockchainTests" && headTestSuite == "GeneralStateTests") + { + headTestSuite.insert(0, "BC"); + if (cwd.parent_path().parent_path().stem() == "Constantinople") + headTestSuite.insert(0, "LegacyTests/Constantinople/"); + } + if (cwd.parent_path().stem() == "EIPTests" && headTestSuite == "BlockchainTests") + headTestSuite.insert(0, "EIPTests/"); + + } + tArg.insert(0, headTestSuite + "/"); + } + + tArg.insert(tArg.size(), arg); + if (arg.at(arg.size()-1) == '/') + tArg = tArg.erase(tArg.size() - 1); + return tArg; +} + +// Preprocess the args +const char** preprocessOptions(int& _argc, const char* _argv[]) +{ + // if file.json is outside of the testpath + // parse "retesteth file.json" ==> "retesteth -t TestSuite -- --testfile file.json" + // else + // "retesteth file.json" ==> "retesteth -t TestSuite/Subsuite -- --singletest file.json" + // parse "retesteth Folder" ==> "retesteth -t TestSuite/Folder + + // Get Test Path before initializing options + fs::path testPath; + const char* ptestPath = std::getenv("ETHEREUM_TEST_PATH"); + if (ptestPath != nullptr) + testPath = fs::path(ptestPath); + auto const cwd = fs::path(fs::current_path()); + + string filenameArg; + string directoryArg; + bool fileInsideTheTestRepo = false; + + bool hasTArg = false; + vector options; + options.emplace_back(_argv[0]); + for (short i = 1; i < _argc; i++) + { + string const arg = string{_argv[i]}; + if (arg == "-t") + hasTArg = true; + + if (arg == "--testpath" && i + 1 < _argc) + testPath = fs::path(std::string{_argv[i + 1]}); + + bool isFile = (arg.find(".json") != string::npos || arg.find(".yml") != string::npos); + if (isFile && string{_argv[i - 1]} != "--testfile") + { + filenameArg = arg; + if (!testPath.empty() && fs::relative(cwd, testPath).string().find("..") == string::npos) + fileInsideTheTestRepo = true; + } + else if (fs::exists(cwd / arg) && fs::is_directory(cwd / arg)) + directoryArg = arg; + + options.emplace_back(arg); + } + + if (!hasTArg) + { + options.insert(options.begin() + 1, "-t"); + string suite; + if (!filenameArg.empty()) + { + if (fileInsideTheTestRepo) + { + suite = getTestTArg(cwd.parent_path(), cwd.stem().string()); + for (vector::iterator it = options.begin(); it != options.end(); it++) + { + if (*it == filenameArg) + { + (*it) = (fs::path(*it)).stem().string(); + options.insert(it, "--singletest"); + break; + } + } + } + else + { + suite = getTestType(filenameArg); + for (vector::iterator it = options.begin(); it != options.end(); it++) + { + if (*it == filenameArg) + { + options.insert(it, "--testfile"); + break; + } + } + } + } + else if (!directoryArg.empty()) + { + suite = getTestTArg(cwd, directoryArg); + for (vector::iterator it = options.begin(); it != options.end(); it++) + { + if (*it == directoryArg) + { + options.erase(it); + break; + } + } + } + + if (suite.empty()) + std::cerr << "preprocessOptions:: Error autodetecting -t argument!" << std::endl; + options.insert(options.begin() + 2, suite); + options.insert(options.begin() + 3, "--"); + } + + for (auto const& el : options) + std::cout << el << " "; + std::cout << std::endl; + + if (options.size() == (size_t)_argc) + return _argv; + size_t i = 0; + const char** argv2 = new const char*[options.size()]; + for (auto const& el : options) + { + char *buffer = new char[el.size() + 1]; //we need extra char for NUL + memcpy(buffer, el.c_str(), el.size() + 1); + c_cleanDynamicChars.emplace_back(buffer); + argv2[i++] = buffer; + } + _argc = options.size(); + return argv2; +} + + } // namespace test::main diff --git a/retesteth/mainHelper.h b/retesteth/mainHelper.h index 6026365be..f265b0a0d 100644 --- a/retesteth/mainHelper.h +++ b/retesteth/mainHelper.h @@ -5,6 +5,7 @@ namespace test::main { // Pre Processors +const char** preprocessOptions(int& _argc, const char* _argv[]); void initializeOptions(int _argc, const char* _argv[]); void expandUnitTestsArg(int _argc, const char* _argv[]); void makeSingleTestFileSuite(int _argc, const char* _argv[]); diff --git a/retesteth/session/RPCImpl.cpp b/retesteth/session/RPCImpl.cpp index 9db133263..d46fdb260 100644 --- a/retesteth/session/RPCImpl.cpp +++ b/retesteth/session/RPCImpl.cpp @@ -26,7 +26,7 @@ FH32 RPCImpl::eth_sendRawTransaction(BYTES const& _rlp, VALUE const& _secret) if (!m_lastInterfaceError.empty()) { ETH_WARNING("eth_sendRawTransaction:: " + m_lastInterfaceError.message()); - return FH32(FH32::zero()); + return FH32::zero(); } return FH32(result.getCContent()); } @@ -53,20 +53,20 @@ VALUE RPCImpl::eth_blockNumber() return VALUE(rpcCall("eth_blockNumber", {}).getCContent()); } -EthGetBlockBy RPCImpl::eth_getBlockByHash(FH32 const& _hash, Request _fullObjects) +spEthGetBlockBy RPCImpl::eth_getBlockByHash(FH32 const& _hash, Request _fullObjects) { spDataObject response = rpcCall("eth_getBlockByHash", {quote(_hash.asString()), _fullObjects == Request::FULLOBJECTS ? "true" : "false"}); ClientConfig const& cfg = Options::getCurrentConfig(); cfg.performFieldReplace(*response, FieldReplaceDir::ClientToRetesteth); - return EthGetBlockBy(response); + return spEthGetBlockBy(new EthGetBlockBy(response)); } -EthGetBlockBy RPCImpl::eth_getBlockByNumber(VALUE const& _blockNumber, Request _fullObjects) +spEthGetBlockBy RPCImpl::eth_getBlockByNumber(VALUE const& _blockNumber, Request _fullObjects) { spDataObject response = rpcCall("eth_getBlockByNumber", {quote(_blockNumber.asString()), _fullObjects == Request::FULLOBJECTS ? "true" : "false"}); ClientConfig const& cfg = Options::getCurrentConfig(); cfg.performFieldReplace(*response, FieldReplaceDir::ClientToRetesteth); - return EthGetBlockBy(response); + return spEthGetBlockBy(new EthGetBlockBy(response)); } spBYTES RPCImpl::eth_getCode(FH20 const& _address, VALUE const& _blockNumber) @@ -124,11 +124,17 @@ DebugVMTrace RPCImpl::debug_traceTransaction(FH32 const& _trHash) { (void)_trHash; ETH_FAIL_MESSAGE("RPCImpl::debug_traceTransaction is not implemented!"); - static DebugVMTrace empty("", "", FH32::zero(), ""); + static DebugVMTrace empty; return empty; } // Test +void RPCImpl::test_setChainParamsNoGenesis(spSetChainParamsArgs const& _config) +{ + (void) _config; + ETH_FAIL_MESSAGE("RPCImpl::test_setChainParamsNoGenesis is not implemented!"); +} + void RPCImpl::test_setChainParams(spSetChainParamsArgs const& _config) { RPCSession::currentCfgCountTestRun(); @@ -178,7 +184,7 @@ FH32 RPCImpl::test_importRawBlock(BYTES const& _blockRLP) spDataObject const res = rpcCall("test_importRawBlock", {quote(_blockRLP.asString())}, true); if (res->type() == DataType::String && res->asString().size() > 2) return FH32(res->asString()); - return FH32(FH32::zero()); + return FH32::zero(); } FH32 RPCImpl::test_getLogHash(FH32 const& _txHash) @@ -186,6 +192,12 @@ FH32 RPCImpl::test_getLogHash(FH32 const& _txHash) return FH32(rpcCall("test_getLogHash", {quote(_txHash.asString())})); } +void RPCImpl::test_registerWithdrawal(BYTES const& _rlp) +{ + (void) _rlp; + ETH_FAIL_MESSAGE("RPCImpl::test_registerWithdrawal is not implemented!"); +} + TestRawTransaction RPCImpl::test_rawTransaction(BYTES const& _rlp, FORK const& _fork) { spDataObject const res = rpcCall("test_rawTransaction", {quote(_rlp.asString()), quote(_fork.asString())}); diff --git a/retesteth/session/RPCImpl.h b/retesteth/session/RPCImpl.h index 060d6f845..ced35dc02 100644 --- a/retesteth/session/RPCImpl.h +++ b/retesteth/session/RPCImpl.h @@ -19,8 +19,8 @@ class RPCImpl : public SessionInterface // ETH Methods FH32 eth_sendRawTransaction(BYTES const& _rlp, VALUE const& _secret) override; VALUE eth_blockNumber() override; - EthGetBlockBy eth_getBlockByHash(FH32 const& _hash, Request _fullObjects) override; - EthGetBlockBy eth_getBlockByNumber(VALUE const& _blockNumber, Request _fullObjects) override; + spEthGetBlockBy eth_getBlockByHash(FH32 const& _hash, Request _fullObjects) override; + spEthGetBlockBy eth_getBlockByNumber(VALUE const& _blockNumber, Request _fullObjects) override; // Account functions spVALUE eth_getTransactionCount(FH20 const& _address, VALUE const& _blockNumber) override; @@ -40,10 +40,12 @@ class RPCImpl : public SessionInterface // Test void test_setChainParams(spSetChainParamsArgs const& _config) override; + void test_setChainParamsNoGenesis(spSetChainParamsArgs const& _config) override; void test_rewindToBlock(VALUE const& _blockNr) override; void test_modifyTimestamp(VALUE const& _timestamp) override; MineBlocksResult test_mineBlocks(size_t _number) override; FH32 test_importRawBlock(BYTES const& _blockRLP) override; + void test_registerWithdrawal(BYTES const& _rlp) override; FH32 test_getLogHash(FH32 const& _txHash) override; TestRawTransaction test_rawTransaction(BYTES const& _rlp, FORK const& _fork) override; VALUE test_calculateDifficulty(FORK const& _fork, VALUE const& _blockNumber, VALUE const& _parentTimestamp, diff --git a/retesteth/session/Session.cpp b/retesteth/session/Session.cpp index 10a946c96..8e2f308f9 100644 --- a/retesteth/session/Session.cpp +++ b/retesteth/session/Session.cpp @@ -74,9 +74,9 @@ void RPCSession::runNewInstanceOfAClient(thread::id const& _threadID, ClientConf string command = "bash"; std::vector args; - args.push_back(_config.getShellPath().c_str()); - args.push_back(tmpDir.string()); - args.push_back(ipcPath); + args.emplace_back(_config.getShellPath().c_str()); + args.emplace_back(tmpDir.string()); + args.emplace_back(ipcPath); int pid = 0; test::popenOutput mode = @@ -225,7 +225,8 @@ void RPCSession::restartScripts(bool _stop) size_t const threads = Options::get().threadCount; string const start = curCFG.getStartScript().c_str(); auto cmd = [](string const& _cmd, string const& _args) { - test::executeCmd(_cmd + " " + _args, ExecCMDWarning::NoWarning); + int exitCode; + test::executeCmd(_cmd + " " + _args, exitCode, ExecCMDWarning::NoWarning); }; switch (curCFG.cfgFile().socketType()) { @@ -336,10 +337,8 @@ void RPCSession::clear() std::lock_guard lock(g_socketMapMutex); std::vector closingThreads; for (auto& element : socketMap) - { - thread t(closeSession, element.first); - closingThreads.push_back(std::move(t)); - } + closingThreads.emplace_back(thread(closeSession, element.first)); + for (auto& th : closingThreads) th.join(); @@ -347,14 +346,16 @@ void RPCSession::clear() closingThreads.clear(); // If not running UnitTests or smth - if (Options::getDynamicOptions().activeConfigs() > 0 && Options::getDynamicOptions().currentConfigIsSet()) + auto const& dynOpt = Options::getDynamicOptions(); + if (dynOpt.activeConfigs() > 0 && dynOpt.currentConfigIsSet()) { - ClientConfig const& curCFG = Options::getDynamicOptions().getCurrentConfig(); + ClientConfig const& curCFG = dynOpt.getCurrentConfig(); if (!curCFG.getStopperScript().empty() && Options::get().nodesoverride.size() == 0) { - executeCmd(curCFG.getStopperScript().c_str(), ExecCMDWarning::NoWarningNoError); + int exitCode; + executeCmd(curCFG.getStopperScript().c_str(), exitCode, ExecCMDWarning::NoWarningNoError); ETH_DC_MESSAGE(DC::RPC, curCFG.getStopperScript().c_str()); - if (!ExitHandler::receivedExitSignal()) + if (!ExitHandler::receivedExitSignal() && curCFG.cfgFile().socketType() != ClientConfgSocketType::TransitionTool) { size_t const initTime = curCFG.cfgFile().initializeTime(); size_t const seconds = Options::get().lowcpu ? initTime + 10 : initTime; diff --git a/retesteth/session/SessionInterface.h b/retesteth/session/SessionInterface.h index 1696fea81..7d060cd0d 100644 --- a/retesteth/session/SessionInterface.h +++ b/retesteth/session/SessionInterface.h @@ -46,8 +46,8 @@ class SessionInterface virtual FH32 eth_sendRawTransaction(BYTES const& _rlp, VALUE const& _secret) = 0; virtual VALUE eth_blockNumber() = 0; - virtual EthGetBlockBy eth_getBlockByHash(FH32 const& _blockHash, Request _fullObjects) = 0; - virtual EthGetBlockBy eth_getBlockByNumber(VALUE const& _blockNumber, Request _fullObjects) = 0; + virtual spEthGetBlockBy eth_getBlockByHash(FH32 const& _blockHash, Request _fullObjects) = 0; + virtual spEthGetBlockBy eth_getBlockByNumber(VALUE const& _blockNumber, Request _fullObjects) = 0; // Account functions virtual spBYTES eth_getCode(FH20 const& _address, VALUE const& _blockNumber) = 0; @@ -67,11 +67,13 @@ class SessionInterface // Test virtual void test_setChainParams(spSetChainParamsArgs const& _config) = 0; + virtual void test_setChainParamsNoGenesis(spSetChainParamsArgs const& _config) = 0; virtual void test_rewindToBlock(VALUE const& _blockNr) = 0; virtual void test_modifyTimestamp(VALUE const& _timestamp) = 0; virtual MineBlocksResult test_mineBlocks(size_t _number) = 0; virtual FH32 test_importRawBlock(BYTES const& _blockRLP) = 0; virtual FH32 test_getLogHash(FH32 const& _txHash) = 0; + virtual void test_registerWithdrawal(BYTES const& _rlp) = 0; virtual TestRawTransaction test_rawTransaction(BYTES const& _rlp, FORK const& _fork) = 0; virtual VALUE test_calculateDifficulty(FORK const& _fork, VALUE const& _blockNumber, VALUE const& _parentTimestamp, VALUE const& _parentDifficulty, VALUE const& _currentTimestamp, VALUE const& _uncleNumber) = 0; diff --git a/retesteth/session/ToolBackend/BlockMining.cpp b/retesteth/session/ToolBackend/BlockMining.cpp index 7f14f66e4..b84e202e2 100644 --- a/retesteth/session/ToolBackend/BlockMining.cpp +++ b/retesteth/session/ToolBackend/BlockMining.cpp @@ -7,6 +7,7 @@ #include #include #include +#include using namespace std; using namespace dev; @@ -16,57 +17,50 @@ using namespace dataobject; using namespace test::teststruct; namespace fs = boost::filesystem; -namespace -{ -BlockchainTestFillerEnv* readBlockchainFillerTestEnv(spDataObjectMove _data, SealEngine _sEngine) -{ - // This peace is a copy of same code in BlockchainTestFiller.cpp - // Because this file emulates t8ntool as a 3d party (blockchain logic of it) - auto const& data = _data.getPointer(); - if (data->count("baseFeePerGas")) - { - spDataObject diff = data->atKey("difficulty").copy(); - (*diff).performModifier(mod_valueToCompactEvenHexPrefixed); - if (VALUE(diff->asString()) != 0) - return new BlockchainTestFillerEnv1559(_data, _sEngine); - else - return new BlockchainTestFillerEnvMerge(_data, _sEngine); - } - return new BlockchainTestFillerEnvLegacy(_data, _sEngine); -} -} // namespace - namespace toolimpl { void BlockMining::prepareEnvFile() { m_envPath = m_chainRef.tmpDir() / "env.json"; - auto spHeader = m_currentBlockRef.header()->asDataObject(); + auto const& cfgFile = Options::getCurrentConfig().cfgFile(); + + auto const& parentBlcokH = m_parentBlockRef.header(); + auto const& currentBlockH = m_currentBlockRef.header(); + + auto spHeader = currentBlockH->asDataObject(); spBlockchainTestFillerEnv env(readBlockchainFillerTestEnv(dataobject::move(spHeader), m_chainRef.engine())); spDataObject& envData = const_cast(env->asDataObject()); - if (m_parentBlockRef.header()->number() != m_currentBlockRef.header()->number()) + + if (parentBlcokH->number() != currentBlockH->number()) { - if (m_parentBlockRef.header()->hash() != m_currentBlockRef.header()->parentHash()) + if (parentBlcokH->hash() != currentBlockH->parentHash()) ETH_ERROR_MESSAGE("ToolChain::mineBlockOnTool: provided parent block != pending parent block hash!"); - (*envData).removeKey("currentDifficulty"); - (*envData)["parentTimestamp"] = m_parentBlockRef.header()->timestamp().asString(); - (*envData)["parentDifficulty"] = m_parentBlockRef.header()->difficulty().asString(); - (*envData)["parentUncleHash"] = m_parentBlockRef.header()->uncleHash().asString(); + + if (!cfgFile.calculateDifficulty()) + { + (*envData).removeKey("currentDifficulty"); + (*envData)["parentTimestamp"] = parentBlcokH->timestamp().asString(); + (*envData)["parentDifficulty"] = parentBlcokH->difficulty().asString(); + (*envData)["parentUncleHash"] = parentBlcokH->uncleHash().asString(); + } } - if (m_currentBlockRef.header()->type() == BlockType::BlockHeaderMerge) + if (isBlockExportCurrentRandom(currentBlockH)) + (*envData)["currentRandom"] = currentBlockH->mixHash().asString(); + + if (isBlockExportWithdrawals(currentBlockH)) { - (*envData)["currentRandom"] = m_currentBlockRef.header()->mixHash().asString(); + (*envData).atKeyPointer("withdrawals") = spDataObject(new DataObject(DataType::Array)); + for (auto const& wt : m_currentBlockRef.withdrawals()) + (*envData)["withdrawals"].addArrayObject(wt->asDataObject(ExportOrder::ToolStyle)); } - auto const& parentType = m_parentBlockRef.header()->type(); - if (parentType == BlockType::BlockHeader1559 || parentType == BlockType::BlockHeaderMerge) + if (isBlockExportBasefee(parentBlcokH)) { - auto const& cfgFile = Options::getCurrentConfig().cfgFile(); if (!cfgFile.calculateBasefee()) { (*envData).removeKey("currentBaseFee"); - BlockHeader1559 const& h1559 = (BlockHeader1559 const&) m_parentBlockRef.header().getCContent(); + BlockHeader1559 const& h1559 = (BlockHeader1559 const&) parentBlcokH.getCContent(); (*envData)["parentBaseFee"] = h1559.baseFee().asString(); (*envData)["parentGasUsed"] = h1559.gasUsed().asString(); (*envData)["parentGasLimit"] = h1559.gasLimit().asString(); @@ -80,7 +74,7 @@ void BlockMining::prepareEnvFile() for (auto const& un : m_currentBlockRef.uncles()) { spDataObject uncle; - int delta = (int)(m_currentBlockRef.header()->number() - un->number()).asBigInt(); + int delta = (int)(currentBlockH->number() - un->number()).asBigInt(); if (delta < 1) throw test::UpwardsException("Uncle header delta is < 1"); (*uncle)["delta"] = delta; @@ -104,7 +98,7 @@ void BlockMining::prepareAllocFile() void BlockMining::prepareTxnFile() { - bool exportRLP = true; + bool const exportRLP = !Options::getCurrentConfig().cfgFile().transactionsAsJson(); string const txsfile = exportRLP ? "txs.rlp" : "txs.json"; m_txsPath = m_chainRef.tmpDir() / txsfile; @@ -124,7 +118,12 @@ void BlockMining::prepareTxnFile() for (auto const& tr : m_currentBlockRef.transactions()) { if (tr->gasLimit().asBigInt() <= c_maxGasLimit) // tool fails on limits here. - txs.addArrayObject(tr->asDataObject(ExportOrder::ToolStyle)); + { + auto trData = tr->asDataObject(ExportOrder::ToolStyle); + (*trData)["hash"] = tr->hash().asString(); + (*trData)["sender"] = tr->sender().asString(); + txs.addArrayObject(trData); + } else ETH_WARNING("Retesteth rejecting tx with gasLimit > 64 bits for tool" + TestOutputHelper::get().testInfo().errorDebug()); @@ -139,41 +138,46 @@ void BlockMining::executeTransition() { m_outPath = m_chainRef.tmpDir() / "out.json"; m_outAllocPath = m_chainRef.tmpDir() / "outAlloc.json"; + m_outErrorPath = m_chainRef.tmpDir() / "error.json"; - string cmd = m_chainRef.toolPath().string(); + m_cmd = m_chainRef.toolPath().string(); // Convert FrontierToHomesteadAt5 -> Homestead if block > 5, and get reward - auto tupleRewardFork = prepareReward(m_engine, m_chainRef.fork(), m_currentBlockRef.header()->number(), m_currentBlockRef.totalDifficulty()); - cmd += " --state.fork " + std::get<1>(tupleRewardFork).asString(); - if (m_engine != SealEngine::NoReward) + auto tupleRewardFork = prepareReward(m_engine, m_chainRef.fork(), m_currentBlockRef); + m_cmd += " --state.fork " + std::get<1>(tupleRewardFork).asString(); + + if (m_engine == SealEngine::NoReward) + m_cmd += " --state.reward 0"; + else { if (m_engine == SealEngine::Genesis) - cmd += " --state.reward -1"; + m_cmd += " --state.reward -1"; else - cmd += " --state.reward " + std::get<0>(tupleRewardFork).asDecString(); + m_cmd += " --state.reward " + std::get<0>(tupleRewardFork).asDecString(); } auto const& params = m_chainRef.params().getCContent().params(); if (params.count("chainID")) - cmd += " --state.chainid " + VALUE(params.atKey("chainID")).asDecString(); + m_cmd += " --state.chainid " + VALUE(params.atKey("chainID")).asDecString(); - cmd += " --input.alloc " + m_allocPath.string(); - cmd += " --input.txs " + m_txsPath.string(); - cmd += " --input.env " + m_envPath.string(); - cmd += " --output.basedir " + m_chainRef.tmpDir().string(); - cmd += " --output.result " + m_outPath.filename().string(); - cmd += " --output.alloc " + m_outAllocPath.filename().string(); + m_cmd += " --input.alloc " + m_allocPath.string(); + m_cmd += " --input.txs " + m_txsPath.string(); + m_cmd += " --input.env " + m_envPath.string(); + m_cmd += " --output.basedir " + m_chainRef.tmpDir().string(); + m_cmd += " --output.result " + m_outPath.filename().string(); + m_cmd += " --output.alloc " + m_outAllocPath.filename().string(); + m_cmd += " --output.errorlog " + m_outErrorPath.string(); bool traceCondition = Options::get().vmtrace && m_currentBlockRef.header()->number() != 0; if (traceCondition) { - cmd += " --trace "; + m_cmd += " --trace "; if (!Options::get().vmtrace_nomemory) - cmd += "--trace.memory "; + m_cmd += "--trace.memory "; if (!Options::get().vmtrace_noreturndata) - cmd += "--trace.returndata "; + m_cmd += "--trace.returndata "; if (Options::get().vmtrace_nostack) - cmd += "--trace.nostack "; + m_cmd += "--trace.nostack "; } ETH_DC_MESSAGE(DC::RPC, "Alloc:\n" + m_allocPathContent); @@ -185,8 +189,15 @@ void BlockMining::executeTransition() } ETH_DC_MESSAGE(DC::RPC, "Env:\n" + m_envPathContent); - string out = test::executeCmd(cmd, ExecCMDWarning::NoWarning); - ETH_DC_MESSAGE(DC::RPC, cmd); + int exitcode; + string out = test::executeCmd(m_cmd, exitcode, ExecCMDWarning::NoWarningNoError); + ETH_DC_MESSAGE(DC::RPC, m_cmd); + if (exitcode != 0) + { + string const outErrorContent = dev::contentsString(m_outErrorPath.string()); + ETH_DC_MESSAGE(DC::RPC, "Err:\n" + outErrorContent); + throw test::UpwardsException(outErrorContent.empty() ? (out.empty() ? "Tool failed: " + m_cmd : out) : outErrorContent); + } ETH_DC_MESSAGE(DC::RPC, out); } @@ -196,10 +207,17 @@ ToolResponse BlockMining::readResult() string const outAllocPathContent = dev::contentsString(m_outAllocPath.string()); ETH_DC_MESSAGE(DC::RPC, "Res:\n" + outPathContent); ETH_DC_MESSAGE(DC::RPC, "RAlloc:\n" + outAllocPathContent); + if (outPathContent.empty()) - ETH_ERROR_MESSAGE("Tool returned empty file: " + m_outPath.string()); + { + string const outErrorContent = dev::contentsString(m_outErrorPath.string()); + ETH_ERROR_MESSAGE("Tool returned empty file: " + m_outPath.string() + "\n" + outErrorContent); + } if (outAllocPathContent.empty()) - ETH_ERROR_MESSAGE("Tool returned empty file: " + m_outAllocPath.string()); + { + string const outErrorContent = dev::contentsString(m_outErrorPath.string()); + ETH_ERROR_MESSAGE("Tool returned empty file: " + m_outAllocPath.string() + "\n" + outErrorContent); + } // Construct block rpc response ToolResponse toolResponse(ConvertJsoncppStringToData(outPathContent)); @@ -227,7 +245,7 @@ void BlockMining::traceTransactions(ToolResponse& _toolResponse) string const info = TestOutputHelper::get().testInfo().errorDebug(); string const traceinfo = "\nVMTrace:" + info + cDefault + preinfo; _toolResponse.attachDebugTrace(tr->hash(), - spDebugVMTrace(new DebugVMTrace(traceinfo, trNumber, tr->hash(), txTraceFile))); + spDebugVMTrace(new DebugVMTrace(traceinfo, txTraceFile))); } else ETH_DC_MESSAGE(DC::WARNING, "Trace file `" + txTraceFile.string() + "` not found!"); @@ -236,8 +254,35 @@ void BlockMining::traceTransactions(ToolResponse& _toolResponse) BlockMining::~BlockMining() { + auto const& t8ntoolcall = Options::get().t8ntoolcall; + if (!t8ntoolcall.empty()) + { + string folder = Options::get().getCurrentConfig().getOptionName() + "_"; + folder += m_chainRef.fork().asString() + "_block"; + folder += m_currentBlockRef.header()->number().asDecString() + "_"; + folder += m_currentBlockRef.header()->hash().asString().substr(0, 8); + auto const from = m_chainRef.tmpDir().string(); + auto const to = (t8ntoolcall / fs::path(folder)).string(); + + try + { + if (!fs::exists(to)) + fs::create_directories(to); + fs::copy(from, to); + } + catch (std::exception const& _ex) + { + ETH_WARNING(string() + "Can't export t8ntool call to destination file (check that dest is empty or use more test selectors like --singletest): \n" + _ex.what()); + } + + m_cmd = std::regex_replace(m_cmd, std::regex(m_chainRef.tmpDir().string()), to); + fs::path const cmdFile = to + "/command.sh"; + dev::writeFile(cmdFile, dev::asBytes(m_cmd)); + } + fs::remove(m_envPath); fs::remove(m_allocPath); + fs::remove(m_outErrorPath); fs::remove(m_txsPath); fs::remove(m_outPath); fs::remove(m_outAllocPath); diff --git a/retesteth/session/ToolBackend/BlockMining.h b/retesteth/session/ToolBackend/BlockMining.h index c1116cfbc..5832c2c22 100644 --- a/retesteth/session/ToolBackend/BlockMining.h +++ b/retesteth/session/ToolBackend/BlockMining.h @@ -38,6 +38,8 @@ class BlockMining std::string m_txsPathContent; boost::filesystem::path m_outPath; boost::filesystem::path m_outAllocPath; + boost::filesystem::path m_outErrorPath; + std::string m_cmd; void traceTransactions(ToolResponse& _toolResponse); }; } // namespace toolimpl diff --git a/retesteth/session/ToolBackend/ToolChain.cpp b/retesteth/session/ToolBackend/ToolChain.cpp index dbdbaed09..039b3d1d2 100644 --- a/retesteth/session/ToolBackend/ToolChain.cpp +++ b/retesteth/session/ToolBackend/ToolChain.cpp @@ -28,7 +28,7 @@ void correctHeaderByToolResponse(BlockHeader& _header, ToolResponse const& _res) namespace toolimpl { ToolChain::ToolChain( - EthereumBlockState const& _genesis, spSetChainParamsArgs const& _config, fs::path const& _toolPath, fs::path const& _tmpDir) + EthereumBlockState const& _genesis, spSetChainParamsArgs const& _config, fs::path const& _toolPath, fs::path const& _tmpDir, ToolChainGenesis _genesisPolicy) : m_initialParams(_config), m_engine(_config->sealEngine()), m_fork(new FORK(_config->params().atKey("fork"))), @@ -45,23 +45,29 @@ ToolChain::ToolChain( auto const& forks = opt.cfgFile().forks(); if (opt.cfgFile().support1559() && inArray(forks, m_fork.getCContent())) { + auto const genesisHeaderType = _genesis.header()->type(); if (compareFork(m_fork, CMP::lt, FORK("London")) - && _genesis.header()->type() == BlockType::BlockHeader1559) + && genesisHeaderType == BlockType::BlockHeader1559) throw test::UpwardsException("Constructing 1559 genesis on network which is lower London!"); if (compareFork(m_fork, CMP::ge, FORK("London")) - && _genesis.header()->type() != BlockType::BlockHeader1559 - && _genesis.header()->type() != BlockType::BlockHeaderMerge) + && genesisHeaderType != BlockType::BlockHeader1559 + && genesisHeaderType != BlockType::BlockHeaderMerge + && genesisHeaderType != BlockType::BlockHeaderShanghai) throw test::UpwardsException("Constructing legacy genesis on network which is higher London!"); } - // We yet don't know the state root of genesis. Ask the tool to calculate it - ToolResponse const res = mineBlockOnTool(_genesis, _genesis, SealEngine::NoReward); - EthereumBlockState genesisFixed(_genesis.header(), _genesis.state(), FH32::zero()); - genesisFixed.headerUnsafe().getContent().setStateRoot(res.stateRoot()); - genesisFixed.headerUnsafe().getContent().recalculateHash(); - genesisFixed.setTotalDifficulty(genesisFixed.header()->difficulty()); - m_blocks.push_back(genesisFixed); + + if (_genesisPolicy == ToolChainGenesis::CALCULATE) + { + // We yet don't know the state root of genesis. Ask the tool to calculate it + ToolResponse const res = mineBlockOnTool(_genesis, _genesis, SealEngine::NoReward); + genesisFixed.headerUnsafe().getContent().setStateRoot(res.stateRoot()); + genesisFixed.headerUnsafe().getContent().recalculateHash(); + genesisFixed.setTotalDifficulty(genesisFixed.header()->difficulty()); + } + + m_blocks.emplace_back(genesisFixed); } spSetChainParamsArgs genT9NChainParams(FORK const& _net) @@ -98,7 +104,7 @@ ToolChain::ToolChain( { // Calculate the difficutly of _currentBlock given _parentBlock ToolResponse res = mineBlockOnTool(_currentBlock, _parentBlock, SealEngine::NoReward); - m_blocks.push_back(_currentBlock); + m_blocks.emplace_back(_currentBlock); m_blocks.back().headerUnsafe().getContent().setDifficulty(res.currentDifficulty()); } @@ -115,18 +121,19 @@ spDataObject const ToolChain::mineBlock(EthereumBlockState const& _pendingBlock, // The tool can reject transactions changing the stateHash, TxRoot, TxReceipts, HeaderHash, GasUsed EthereumBlockState pendingFixed(_pendingBlock.header(), res.state(), res.logsHash()); - BlockHeader& pendingFixedHeader = pendingFixed.headerUnsafe().getContent(); - pendingFixedHeader.setNumber(m_blocks.size()); - correctHeaderByToolResponse(pendingFixedHeader, res); - if (_pendingBlock.header()->type() != BlockType::BlockHeaderMerge) - { - pendingFixedHeader.setDifficulty(res.currentDifficulty()); - checkDifficultyAgainstRetesteth(res.currentDifficulty(), pendingFixed.header()); - } - calculateAndCheckSetBaseFee(res.currentBasefee(), pendingFixed.headerUnsafe(), lastBlock().header()); + auto& pendingFixedHeader = pendingFixed.headerUnsafe(); + pendingFixedHeader.getContent().setNumber(m_blocks.size()); + + // Fetch hashes information from t8n tool response + correctHeaderByToolResponse(pendingFixedHeader.getContent(), res); + setAndCheckDifficulty(res.currentDifficulty(), pendingFixedHeader); + calculateAndCheckSetBaseFee(res.currentBasefee(), pendingFixedHeader, lastBlock().header()); + setWithdrawalsRoot(res.withdrawalsRoot(), pendingFixedHeader); spDataObject miningResult; miningResult = coorectTransactionsByToolResponse(res, pendingFixed, _pendingBlock, _req); + for (auto const& wt : _pendingBlock.withdrawals()) + pendingFixed.addWithdrawal(wt); correctUncleHeaders(pendingFixed, _pendingBlock); // Calculate header hash from header fields (does not recalc tx, un hashes) @@ -139,7 +146,7 @@ spDataObject const ToolChain::mineBlock(EthereumBlockState const& _pendingBlock, calculateAndSetTotalDifficulty(pendingFixed); pendingFixed.setTrsTrace(res.debugTrace()); - m_blocks.push_back(pendingFixed); + m_blocks.emplace_back(pendingFixed); return miningResult; } @@ -192,14 +199,43 @@ void ToolChain::checkBasefeeAgainstRetesteth(VALUE const& _toolBasefee, spBlockH } } +void ToolChain::setAndCheckDifficulty(VALUE const& _difficulty, spBlockHeader& _pendingHeader) +{ + if (isBlockExportDifficulty(_pendingHeader)) + { + if (Options::getCurrentConfig().cfgFile().calculateDifficulty()) + { + ChainOperationParams params = ChainOperationParams::defaultParams(toolParams()); + VALUE retestethDifficulty = calculateEthashDifficulty(params, _pendingHeader, lastBlock().header()); + _pendingHeader.getContent().setDifficulty(retestethDifficulty); + } + else + { + _pendingHeader.getContent().setDifficulty(_difficulty); + checkDifficultyAgainstRetesteth(_difficulty, _pendingHeader); + } + } +} + +void ToolChain::setWithdrawalsRoot(FH32 const& _withdrawalsRoot, spBlockHeader& _pendingHeader) +{ + if (isBlockExportWithdrawals(_pendingHeader)) + { + BlockHeaderShanghai& pendingFixedShanghaiHeader = BlockHeaderShanghai::castFrom(_pendingHeader.getContent()); + pendingFixedShanghaiHeader.setWithdrawalsRoot(_withdrawalsRoot); + } +} + void ToolChain::calculateAndCheckSetBaseFee(VALUE const& _toolBaseFee, spBlockHeader& _pendingHeader, spBlockHeader const& _parentHeader) { - bool isOn1559 = _pendingHeader.getCContent().type() == BlockType::BlockHeader1559 && _parentHeader->type() == BlockType::BlockHeader1559; - bool isOn1559ToMerge = _pendingHeader.getCContent().type() == BlockType::BlockHeaderMerge && _parentHeader->type() == BlockType::BlockHeader1559; - bool isOnMerge = _pendingHeader.getCContent().type() == BlockType::BlockHeaderMerge && _parentHeader->type() == BlockType::BlockHeaderMerge; + auto const pendingHeaderType = _pendingHeader.getCContent().type(); + bool const isOn1559 = pendingHeaderType == BlockType::BlockHeader1559 && _parentHeader->type() == BlockType::BlockHeader1559; + bool const isOn1559ToMerge = pendingHeaderType == BlockType::BlockHeaderMerge && _parentHeader->type() == BlockType::BlockHeader1559; + bool const isOnMerge = pendingHeaderType == BlockType::BlockHeaderMerge && _parentHeader->type() == BlockType::BlockHeaderMerge; + bool const isOnShanghai = pendingHeaderType == BlockType::BlockHeaderShanghai; // Calculate new baseFee - if (isOn1559 || isOn1559ToMerge || isOnMerge) + if (isOn1559 || isOn1559ToMerge || isOnMerge || isOnShanghai) { BlockHeader1559& pendingFixed1559Header = BlockHeader1559::castFrom(_pendingHeader.getContent()); diff --git a/retesteth/session/ToolBackend/ToolChain.h b/retesteth/session/ToolBackend/ToolChain.h index 0631c7f7a..f67b5827e 100644 --- a/retesteth/session/ToolBackend/ToolChain.h +++ b/retesteth/session/ToolBackend/ToolChain.h @@ -27,12 +27,18 @@ struct ToolParams : GCP_SPointerBase spVALUE m_londonForkBlock; }; +enum class ToolChainGenesis +{ + CALCULATE, + NOTCALCULATE +}; + // Manage test blockchains class ToolChain : public GCP_SPointerBase { public: ToolChain(EthereumBlockState const& _genesis, spSetChainParamsArgs const& _params, boost::filesystem::path const& _toolPath, - boost::filesystem::path const& _tmpDir); + boost::filesystem::path const& _tmpDir, ToolChainGenesis _genesisPolicy = ToolChainGenesis::CALCULATE); // Calculate difficulty from _blockA to _blockB constructor ToolChain(EthereumBlockState const& _blockA, EthereumBlockState const& _blockB, FORK const& _fork, @@ -60,7 +66,7 @@ class ToolChain : public GCP_SPointerBase void rewindToBlock(size_t _number); // Used for chain reorg - void insertBlock(EthereumBlockState const& _block) { m_blocks.push_back(_block); } + void insertBlock(EthereumBlockState const& _block) { m_blocks.emplace_back(_block); } boost::filesystem::path const& tmpDir() const { return m_tmpDir; } private: @@ -82,6 +88,8 @@ class ToolChain : public GCP_SPointerBase void checkDifficultyAgainstRetesteth(VALUE const& _toolDifficulty, spBlockHeader const& _pendingHeader); void checkBasefeeAgainstRetesteth(VALUE const& _toolBasefee, spBlockHeader const& _pendingHeader, spBlockHeader const& _parentHeader); void calculateAndCheckSetBaseFee(VALUE const& _toolBaseFee, spBlockHeader& _pendingHeader, spBlockHeader const& _parentHeader); + void setWithdrawalsRoot(FH32 const&, spBlockHeader&); + void setAndCheckDifficulty(VALUE const&, spBlockHeader&); spDataObject coorectTransactionsByToolResponse(ToolResponse const& _res, EthereumBlockState& _pendingFixed, EthereumBlockState const& _pendingBlock, Mining _miningReq); diff --git a/retesteth/session/ToolBackend/ToolChainHelper.cpp b/retesteth/session/ToolBackend/ToolChainHelper.cpp index d7efdb315..38244e8ec 100644 --- a/retesteth/session/ToolBackend/ToolChainHelper.cpp +++ b/retesteth/session/ToolBackend/ToolChainHelper.cpp @@ -70,7 +70,8 @@ static std::map RewardMapForToolBefore5 = { {"HomesteadToDaoAt5", "Homestead"}, {"ByzantiumToConstantinopleFixAt5", "Byzantium"}, {"BerlinToLondonAt5", "Berlin"}, - {"ArrowGlacierToMergeAtDiffC0000", "ArrowGlacier"} + {"ArrowGlacierToMergeAtDiffC0000", "ArrowGlacier"}, + {"MergeToShanghaiAtTime15k", "Merge"} }; static std::map RewardMapForToolAfter5 = { {"FrontierToHomesteadAt5", "Homestead"}, @@ -79,23 +80,31 @@ static std::map RewardMapForToolAfter5 = { {"HomesteadToDaoAt5", "Homestead"}, {"ByzantiumToConstantinopleFixAt5", "ConstantinopleFix"}, {"BerlinToLondonAt5", "London"}, - {"ArrowGlacierToMergeAtDiffC0000", "Merge"} + {"ArrowGlacierToMergeAtDiffC0000", "Merge"}, + {"MergeToShanghaiAtTime15k", "Shanghai"} }; -std::tuple prepareReward(SealEngine _engine, FORK const& _fork, VALUE const& _blockNumber, VALUE const& _currentTD) +std::tuple prepareReward(SealEngine _engine, FORK const& _fork, EthereumBlockState const& _curBlockRef) { if (_engine == SealEngine::Ethash) ETH_DC_MESSAGE(DC::LOWLOG, "t8ntool backend treat Ethash as NoProof!"); bool isMerge = false; bool posTransitionDifficultyNotReached = false; + bool timestampTransitionNotReached = false; if (_fork.asString() == "ArrowGlacierToMergeAtDiffC0000") { isMerge = true; // The TD here is the one before tool called for mining. so its like n-1 td. - if (_currentTD < VALUE(DataObject("0x0C0000"))) + if (_curBlockRef.totalDifficulty() < VALUE(DataObject("0x0C0000"))) posTransitionDifficultyNotReached = true; } + else if (_fork.asString() == "MergeToShanghaiAtTime15k") + { + isMerge = true; + if (_curBlockRef.header()->timestamp() < 15000) + timestampTransitionNotReached = true; + } // Setup mining rewards std::map const& rewards = Options::get().getCurrentConfig().getRewardMap(); @@ -118,7 +127,9 @@ std::tuple prepareReward(SealEngine _engine, FORK const& _fork, VAL return {rewards.at(fork).getCContent(), _fork}; else { - if ((!isMerge && _blockNumber < 5) || posTransitionDifficultyNotReached) + if ((!isMerge && _curBlockRef.header()->number() < 5) + || posTransitionDifficultyNotReached + || timestampTransitionNotReached) { if (!RewardMapForToolBefore5.count(fork)) { diff --git a/retesteth/session/ToolBackend/ToolChainHelper.h b/retesteth/session/ToolBackend/ToolChainHelper.h index e3b38755d..322e29bfb 100644 --- a/retesteth/session/ToolBackend/ToolChainHelper.h +++ b/retesteth/session/ToolBackend/ToolChainHelper.h @@ -1,6 +1,6 @@ #pragma once #include "ToolChain.h" -#include +#include namespace toolimpl { @@ -18,7 +18,7 @@ struct ChainOperationParams dev::bigint constantinopleForkBlock; dev::bigint londonForkBlock; }; -std::tuple prepareReward(SealEngine _engine, FORK const& _fork, VALUE const& _blockNumber, VALUE const& _currentTD); +std::tuple prepareReward(SealEngine _engine, FORK const& _fork, EthereumBlockState const&); VALUE calculateGasLimit(VALUE const& _parentGasLimit, VALUE const& _parentGasUsed); VALUE calculateEthashDifficulty( ChainOperationParams const& _chainParams, BlockHeader const& _bi, BlockHeader const& _parent); diff --git a/retesteth/session/ToolBackend/ToolChainManager.cpp b/retesteth/session/ToolBackend/ToolChainManager.cpp index 7453671da..3ad6c942f 100644 --- a/retesteth/session/ToolBackend/ToolChainManager.cpp +++ b/retesteth/session/ToolBackend/ToolChainManager.cpp @@ -5,6 +5,8 @@ #include #include #include +#include +#include using namespace std; using namespace dev; using namespace test; @@ -13,14 +15,18 @@ namespace fs = boost::filesystem; namespace toolimpl { -ToolChainManager::ToolChainManager(spSetChainParamsArgs const& _config, fs::path const& _toolPath, fs::path const& _tmpDir) +ToolChainManager::ToolChainManager( + spSetChainParamsArgs const& _config, + fs::path const& _toolPath, + fs::path const& _tmpDir, + ToolChainGenesis _genesisPolicy) { m_tmpDir = _tmpDir; m_toolPath = _toolPath; m_currentChain = 0; m_maxChains = 0; EthereumBlockState genesis(_config->genesis(), _config->state(), FH32::zero()); - m_chains[m_currentChain] = spToolChain(new ToolChain(genesis, _config, _toolPath, _tmpDir)); + m_chains[m_currentChain] = spToolChain(new ToolChain(genesis, _config, _toolPath, _tmpDir, _genesisPolicy)); m_pendingBlock = spEthereumBlockState(new EthereumBlockState(currentChain().lastBlock().header(), _config->state(), FH32::zero())); reorganizePendingBlock(); @@ -50,16 +56,12 @@ void ToolChainManager::rewindToBlock(VALUE const& _number) void ToolChainManager::reorganizePendingBlock() { EthereumBlockState const& bl = currentChain().lastBlock(); - if (currentChain().fork() == "BerlinToLondonAt5" && bl.header()->number() == 4) - init1559PendingBlock(bl); - else if (currentChain().fork() == "ArrowGlacierToMergeAtDiffC0000" && isTerminalPoWBlock()) - initMergePendingBlock(bl); - else - m_pendingBlock = spEthereumBlockState(new EthereumBlockState(bl.header(), bl.state(), bl.logHash())); + transitionPendingBlock(bl); BlockHeader& header = m_pendingBlock.getContent().headerUnsafe().getContent(); header.setNumber(bl.header()->number() + 1); m_pendingBlock.getContent().setTotalDifficulty(currentChain().lastBlock().totalDifficulty()); + m_pendingBlock.getContent().clear(); // Because aleth and geth+retesteth does this, but better be empty extraData header.setExtraData(bl.header()->extraData()); @@ -67,15 +69,20 @@ void ToolChainManager::reorganizePendingBlock() header.setExtraData(BYTES(DataObject("0x64616f2d686172642d666f726b"))); header.setParentHash(currentChain().lastBlock().header()->hash()); - bool isParent1559 = currentChain().lastBlock().header()->type() == BlockType::BlockHeader1559; - bool isParentMerge = currentChain().lastBlock().header()->type() == BlockType::BlockHeaderMerge; - if (isParent1559 || isParentMerge) + if (isBlockExportBasefee(currentChain().lastBlock().header())) { BlockHeader1559& header1559 = BlockHeader1559::castFrom(header); ChainOperationParams params = ChainOperationParams::defaultParams(currentChain().toolParams()); VALUE newFee = calculateEIP1559BaseFee(params, m_pendingBlock->header(), currentChain().lastBlock().header()); header1559.setBaseFee(VALUE(newFee)); } + + if (isBlockExportDifficulty(header) && Options::getCurrentConfig().cfgFile().calculateDifficulty()) + { + ChainOperationParams params = ChainOperationParams::defaultParams(currentChain().toolParams()); + VALUE retestethDifficulty = calculateEthashDifficulty(params, m_pendingBlock->header(), currentChain().lastBlock().header()); + header.setDifficulty(retestethDifficulty); + } } EthereumBlockState const& ToolChainManager::blockByNumber(VALUE const& _number) const @@ -100,6 +107,8 @@ EthereumBlockState const& ToolChainManager::blockByHash(FH32 const& _hash) const void ToolChainManager::modifyTimestamp(VALUE const& _time) { m_pendingBlock.getContent().headerUnsafe().getContent().setTimestamp(_time); + if (currentChain().fork() == "MergeToShanghaiAtTime15k" && m_pendingBlock->header()->timestamp() >= 15000) + initShanghaiPendingBlock(m_pendingBlock); } // Import Raw Block via t8ntool @@ -148,6 +157,19 @@ FH32 ToolChainManager::importRawBlock(BYTES const& _rlp) m_pendingBlock.getContent().addUncle(un); } + // TODO verify withdrawals rlp signature and block size + if (isBlockExportWithdrawals(header)) + { + verifyWithdrawalsRLP(rlp[3]); + for (auto const& wtRLP : rlp[3].toList()) + { + if (wtRLP.itemCount() != 4) + throw dev::RLPException("Rlp structure is wrong: Withdrawals RLP does not have 4 elements!"); + spWithdrawal wt(new Withdrawal(wtRLP)); + m_pendingBlock.getContent().addWithdrawal(wt); + } + } + mineBlocks(1, ToolChain::Mining::RequireValid); FH32 const importedHash = lastBlock().header()->hash(); if (importedHash != header->hash()) @@ -167,6 +189,7 @@ FH32 ToolChainManager::importRawBlock(BYTES const& _rlp) catch (std::exception const& _ex) { reorganizeChainForTotalDifficulty(); + m_pendingBlock.getContent().clear(); throw test::UpwardsException(string("Error importing raw rlp block: ") + _ex.what()); } } @@ -218,6 +241,21 @@ void ToolChainManager::reorganizeChainForTotalDifficulty() } } +void ToolChainManager::registerWithdrawal(BYTES const& _wt) +{ + try + { + dev::bytes decodeRLP = sfromHex(_wt.asString()); + dev::RLP rlp(decodeRLP, dev::RLP::VeryStrict); + spWithdrawal wt(new Withdrawal(rlp)); + m_pendingBlock.getContent().addWithdrawal(wt); + } + catch(std::exception const& _ex) + { + throw test::UpwardsException(string("Error importing rlp of withdrawal: ") + _ex.what()); + } +} + TestRawTransaction ToolChainManager::test_rawTransaction( BYTES const& _rlp, FORK const& _fork, fs::path const& _toolPath, fs::path const& _tmpDir) { @@ -226,7 +264,8 @@ TestRawTransaction ToolChainManager::test_rawTransaction( out["result"] = true; // Prepare transaction file - fs::path txsPath = _tmpDir / "tx.rlp"; + fs::path const txsPath = _tmpDir / "tx.rlp"; + fs::path const errorLog = _tmpDir / "error.txt"; // Rlp list header builder for given data test::RLPStreamU txsout(1); @@ -245,9 +284,11 @@ TestRawTransaction ToolChainManager::test_rawTransaction( string cmd = _toolPath.string(); cmd += " --input.txs " + txsPath.string(); cmd += " --state.fork " + _fork.asString(); - cmd += " 2>&1"; + cmd += " --output.errorlog " + errorLog.string(); + ETH_DC_MESSAGE(DC::RPC, cmd); - string response = test::executeCmd(cmd, ExecCMDWarning::NoWarningNoError); + int exitCode; + string response = test::executeCmd(cmd, exitCode, ExecCMDWarning::NoWarningNoError); ETH_DC_MESSAGE(DC::RPC, "T9N Response:\n" + response); @@ -258,14 +299,17 @@ TestRawTransaction ToolChainManager::test_rawTransaction( { res = dataobject::ConvertJsoncppStringToData(response); } - catch (std::exception const& _ex) { + catch (std::exception const& _ex) + { if (string(_ex.what()).find("can't read json") != string::npos) { // Unable to read json. treat response as exceptional failure on wrong input - ETH_WARNING("t9n returned invalid json, probably failed on input!"); + if (Options::get().filltests) + ETH_WARNING("t9n returned invalid json, probably failed on input!"); res = spDataObject(new DataObject(DataType::Array)); spDataObject errObj; - (*errObj)["error"] = response; + string const outErrorContent = dev::contentsString(errorLog.string()); + (*errObj)["error"] = outErrorContent; (*res).addSubObject(errObj); ETH_DC_MESSAGE(DC::RPC, "T9N Response reconstructed:\n" + res->asJson()); errorCaught = true; @@ -394,4 +438,36 @@ void ToolChainManager::initMergePendingBlock(EthereumBlockState const& _lastBloc m_pendingBlock = spEthereumBlockState(new EthereumBlockState(newPending, _lastBlock.state(), _lastBlock.logHash())); } +void ToolChainManager::initShanghaiPendingBlock(EthereumBlockState const& _lastBlock) +{ + spDataObject parentData = _lastBlock.header()->asDataObject(); + (*parentData)["withdrawalsRoot"] = C_WITHDRAWALS_EMPTY_ROOT; + spBlockHeader newPending(new BlockHeaderShanghai(parentData)); + m_pendingBlock = spEthereumBlockState(new EthereumBlockState(newPending, _lastBlock.state(), _lastBlock.logHash())); +} + +void ToolChainManager::transitionPendingBlock(EthereumBlockState const& _bl) +{ + auto const updatePending = [this, &_bl](){ + m_pendingBlock = spEthereumBlockState(new EthereumBlockState(_bl.header(), _bl.state(), _bl.logHash())); + }; + + // Transform pending block to new network + if (_bl.header()->number() == 4) + { + if (currentChain().fork() == "BerlinToLondonAt5") + { + init1559PendingBlock(_bl); + return; + } + } + + if (currentChain().fork() == "MergeToShanghaiAtTime15k" && m_pendingBlock->header()->timestamp() >= 15000) + initShanghaiPendingBlock(_bl); + else if (currentChain().fork() == "ArrowGlacierToMergeAtDiffC0000" && isTerminalPoWBlock()) + initMergePendingBlock(_bl); + else + updatePending(); +} + } // namespace toolimpl diff --git a/retesteth/session/ToolBackend/ToolChainManager.h b/retesteth/session/ToolBackend/ToolChainManager.h index 450656bbc..dd52da5c1 100644 --- a/retesteth/session/ToolBackend/ToolChainManager.h +++ b/retesteth/session/ToolBackend/ToolChainManager.h @@ -14,7 +14,7 @@ namespace toolimpl class ToolChainManager : public GCP_SPointerBase { public: - ToolChainManager(spSetChainParamsArgs const& _config, boost::filesystem::path const& _toolPath, boost::filesystem::path const& _tmpDir); + ToolChainManager(spSetChainParamsArgs const& _config, boost::filesystem::path const& _toolPath, boost::filesystem::path const& _tmpDir, ToolChainGenesis _genesisPolicy = ToolChainGenesis::CALCULATE); void addPendingTransaction(spTransaction const& _tr) { m_pendingBlock.getContent().addTransaction(_tr); } ToolChain const& currentChain() const @@ -30,6 +30,7 @@ class ToolChainManager : public GCP_SPointerBase EthereumBlockState const& blockByHash(FH32 const& _hash) const; void rewindToBlock(VALUE const& _number); void modifyTimestamp(VALUE const& _time); + void registerWithdrawal(BYTES const& _wt); // Transaction tests static TestRawTransaction test_rawTransaction( @@ -62,8 +63,10 @@ class ToolChainManager : public GCP_SPointerBase boost::filesystem::path m_toolPath; private: + void transitionPendingBlock(EthereumBlockState const&); void init1559PendingBlock(EthereumBlockState const&); void initMergePendingBlock(EthereumBlockState const&); + void initShanghaiPendingBlock(EthereumBlockState const&); bool isTerminalPoWBlock(); }; diff --git a/retesteth/session/ToolBackend/ToolImplHelper.cpp b/retesteth/session/ToolBackend/ToolImplHelper.cpp index 837c51de2..44cddeeef 100644 --- a/retesteth/session/ToolBackend/ToolImplHelper.cpp +++ b/retesteth/session/ToolBackend/ToolImplHelper.cpp @@ -35,25 +35,43 @@ spDataObject constructAccountRange(EthereumBlockState const& _block, FH32 const& return constructResponse; } -spDataObject constructEthGetBlockBy(EthereumBlockState const& _block) +spDataObject constructEthGetBlockBy(EthereumBlockState const& _block, test::session::Request _request) { + // Imitate eth_getBlockBy... rpc response spDataObject constructResponse = _block.header()->asDataObject(); spDataObject transactionArray(new DataObject(DataType::Array)); (*constructResponse).atKeyPointer("transactions") = transactionArray; - for (auto const& tr : _block.transactions()) + spDataObject arr(new DataObject(DataType::Array)); + (*constructResponse).atKeyPointer("uncles") = arr; + + if (_request == test::session::Request::FULLOBJECTS) { - spDataObject fullTransaction = tr->asDataObject(); - (*fullTransaction)["blockHash"] = _block.header()->hash().asString(); // We don't know the hash its in tool response - (*fullTransaction)["blockNumber"] = _block.header()->number().asString(); - (*fullTransaction)["from"] = FH20::zero().asString(); // Can be recovered from vrs - (*fullTransaction)["transactionIndex"] = "0x00"; // Its in tool response - (*fullTransaction)["hash"] = tr->hash().asString(); - (*constructResponse)["transactions"].addArrayObject(fullTransaction); + for (auto const& tr : _block.transactions()) + { + spDataObject fullTransaction = tr->asDataObject(); + (*fullTransaction)["blockHash"] = _block.header()->hash().asString(); // We don't know the hash its in tool response + (*fullTransaction)["blockNumber"] = _block.header()->number().asString(); + (*fullTransaction)["from"] = FH20::zero().asString(); // Can be recovered from vrs + (*fullTransaction)["transactionIndex"] = "0x00"; // Its in tool response + (*fullTransaction)["hash"] = tr->hash().asString(); + (*constructResponse)["transactions"].addArrayObject(fullTransaction); + } + + for (auto const& wt : _block.withdrawals()) + { + (*constructResponse)["withdrawals"].addArrayObject(wt->asDataObject()); + } + } + else + { + for (auto const& tr : _block.transactions()) + { + spDataObject trHash(new DataObject(tr->hash().asString())); + (*constructResponse)["transactions"].addArrayObject(trHash); + } } - spDataObject arr(new DataObject(DataType::Array)); - (*constructResponse).atKeyPointer("uncles") = arr; for (auto const& un : _block.uncles()) { spDataObject unHash(new DataObject(un->hash().asString())); @@ -113,19 +131,22 @@ spDataObject constructStorageRangeAt( // RLP Validators void verifyBlockRLP(dev::RLP const& _rlp) { + size_t const blockheader = 0; + size_t const transactions = 1; + size_t const uncles = 2; if (!_rlp.isList()) throw dev::RLPException("RLP is expected to be list"); - if (!_rlp[0].isList()) + if (!_rlp[blockheader].isList()) throw dev::RLPException("BlockHeader RLP is expected to be list"); for (size_t i = 0; i < 15; i++) { - if (!_rlp[0][i].isData()) + if (!_rlp[blockheader][i].isData()) throw dev::RLPException("Blockheader RLP field is not data!"); } - for (auto const& tr : _rlp[1]) + for (auto const& tr : _rlp[transactions]) { if (tr.isList()) { @@ -146,7 +167,7 @@ void verifyBlockRLP(dev::RLP const& _rlp) throw dev::RLPException("Transaction RLP is expected to be list"); } - for (auto const& un : _rlp[2]) + for (auto const& un : _rlp[uncles]) { if (!un.isList()) throw dev::RLPException("Uncleheader RLP is expected to be list"); diff --git a/retesteth/session/ToolBackend/ToolImplHelper.h b/retesteth/session/ToolBackend/ToolImplHelper.h index 4aedf478a..d4212cf44 100644 --- a/retesteth/session/ToolBackend/ToolImplHelper.h +++ b/retesteth/session/ToolBackend/ToolImplHelper.h @@ -1,6 +1,7 @@ #pragma once #include #include +#include namespace toolimpl { @@ -15,7 +16,7 @@ spDataObject constructStorageRangeAt( EthereumBlockState const& _block, FH20 const& _address, FH32 const& _begin, size_t _maxResult); // Construct RPC style response -spDataObject constructEthGetBlockBy(EthereumBlockState const& _block); +spDataObject constructEthGetBlockBy(EthereumBlockState const& _block, test::session::Request); // RLP Validators void verifyBlockRLP(dev::RLP const& _rlp); diff --git a/retesteth/session/ToolBackend/Verification.cpp b/retesteth/session/ToolBackend/Verification.cpp index 03db83ceb..fa90e192a 100644 --- a/retesteth/session/ToolBackend/Verification.cpp +++ b/retesteth/session/ToolBackend/Verification.cpp @@ -99,23 +99,38 @@ void verify1559Block(spBlockHeader const& _header, ToolChain const& _chain) } } -void verifyMergeBlock(spBlockHeader const& _header, ToolChain const& _chain) +void verifyCommonMergeRules(spBlockHeader const& _header, string const& _msg) { - (void)_chain; - check_blockType(_header->type(), BlockType::BlockHeaderMerge, "verifyMergeBlock"); - BlockHeaderMerge const& header = BlockHeaderMerge::castFrom(_header); /// Verify rules /// https://eips.ethereum.org/EIPS/eip-3675 if (header.uncleHash().asString() != "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347") - throw test::UpwardsException("Merge block.uncleHash != empty \n" + header.asDataObject()->asJson()); + throw test::UpwardsException(_msg + " block.uncleHash != empty \n" + header.asDataObject()->asJson()); if (header.difficulty() != 0) - throw test::UpwardsException("Merge block.difficulty must be 0! "); + throw test::UpwardsException(_msg + " block.difficulty must be 0! "); if (header.nonce().asString() != "0x0000000000000000") - throw test::UpwardsException("Merge block nonce != 0x00..00 \n" + header.asDataObject()->asJson()); + throw test::UpwardsException(_msg + " block nonce != 0x00..00 \n" + header.asDataObject()->asJson()); if ((header.extraData().asString().size()-2) / 2 > MAX_EXTRADATA_SIZE_IN_MERGE) - throw test::UpwardsException("Merge block extraDataSize > 32bytes \n" + header.asDataObject()->asJson()); + throw test::UpwardsException(_msg + " block extraDataSize > 32bytes \n" + header.asDataObject()->asJson()); +} + +void verifyShanghaiBlock(spBlockHeader const& _header, ToolChain const& _chain) +{ + (void)_chain; + check_blockType(_header->type(), BlockType::BlockHeaderShanghai, "verifyShanghaiBlock"); + + //BlockHeaderShanghai const& header = BlockHeaderShanghai::castFrom(_header); + verifyCommonMergeRules(_header, "Shanghai"); + + /// Verify shanghai rules +} + +void verifyMergeBlock(spBlockHeader const& _header, ToolChain const& _chain) +{ + (void)_chain; + check_blockType(_header->type(), BlockType::BlockHeaderMerge, "verifyMergeBlock"); + verifyCommonMergeRules(_header, "Merge"); } void verifyLegacyParent(spBlockHeader const& _header, spBlockHeader const& _parent, ToolChain const& _chain) @@ -140,8 +155,9 @@ void verify1559Parent_private(spBlockHeader const& _header, spBlockHeader const& void verify1559Parent(spBlockHeader const& _header, spBlockHeader const& _parent, ToolChain const& _chain) { - if (_parent->type() == BlockType::BlockHeaderMerge) + if (isBlockPoS(_parent)) throw test::UpwardsException("Trying to import 1559 block on top of PoS block!"); + check_blockType(_header->type(), BlockType::BlockHeader1559, "verify1559Parent"); check_difficultyDelta(_chain, _header, _parent); @@ -173,6 +189,23 @@ void verify1559Parent(spBlockHeader const& _header, spBlockHeader const& _parent verify1559Parent_private(_header, _parent, _chain); } +void verifyShanghaiParent(spBlockHeader const& _header, spBlockHeader const& _parent, ToolChain const& _chain) +{ + check_blockType(_header->type(), BlockType::BlockHeaderShanghai, "verifyShanghaiParent"); + if (_parent->type() == BlockType::BlockHeaderShanghai) + verifyShanghaiBlock(_parent, _chain); + else + { + if (_header->timestamp() >= 15000 && _chain.fork() == "MergeToShanghaiAtTime15k") + { + if (_parent->type() != BlockType::BlockHeaderMerge) + throw test::UpwardsException("Trying to import Shanghai block on top of Merge block before transition!!"); + } + else + throw test::UpwardsException("Trying to import Shanghai block on top of Merge block before transition!!"); + } +} + void verifyMergeParent(spBlockHeader const& _header, spBlockHeader const& _parent, ToolChain const& _chain, VALUE const& _parentTD) { /// Verify the rules @@ -185,6 +218,9 @@ void verifyMergeParent(spBlockHeader const& _header, spBlockHeader const& _paren check_baseFeeDelta(_chain, _header, _parent); + if (_parent->type() == BlockType::BlockHeaderShanghai) + throw test::UpwardsException("Trying to import Merge block on top of Shanghai block after transition!!"); + if (_parent->type() != BlockType::BlockHeaderMerge) { VALUE const TTD = isTTDDefined ? _chain.params()->params().atKey("terminalTotalDifficulty") : VALUE (DataObject("0xffffffffffffffffffffffffffff")); @@ -269,8 +305,11 @@ void verifyBlockParent(spBlockHeader const& _header, ToolChain const& _chain) case BlockType::BlockHeaderMerge: verifyMergeParent(_header, parentBlock.header(), _chain, parentBlock.totalDifficulty()); break; + case BlockType::BlockHeaderShanghai: + verifyShanghaiParent(_header, parentBlock.header(), _chain); + break; default: - throw test::UpwardsException("Unhandled block type check!"); + throw test::UpwardsException("verifyBlockParent::Unhandled block type check!"); } } } @@ -299,9 +338,35 @@ void verifyEthereumBlockHeader(spBlockHeader const& _header, ToolChain const& _c case BlockType::BlockHeaderMerge: verifyMergeBlock(_header, _chain); break; + case BlockType::BlockHeaderShanghai: + verifyShanghaiBlock(_header, _chain); + break; default: - throw test::UpwardsException("Unhandled block type check!"); + throw test::UpwardsException("verifyEthereumBlockHeader::Unhandled block type check!"); + } +} + +void verifyWithdrawalsRLP(dev::RLP const& _rlp) +{ + if (!_rlp.isList()) + throw dev::RLPException("Withdrawals RLP is expected to be list"); + for (auto const& wt : _rlp) + { + if (!wt.isList()) + throw dev::RLPException("Withdrawals RLP is expected to be list"); + + for (size_t i = 0; i < 4; i++) + { + if (!wt[i].isData()) + throw dev::RLPException("Rlp structure is wrong: Withdrawals RLP field is not data!"); + } } } +void verifyWithdrawalRecord(spWithdrawal const& _wtRecord) +{ + if (_wtRecord->index.getCContent() >= POW2_64) + throw test::UpwardsException("Withdrawals Index >= 2**64"); +} + } // namespace toolimpl diff --git a/retesteth/session/ToolBackend/Verification.h b/retesteth/session/ToolBackend/Verification.h index 1fe7e1902..3ca6bbea1 100644 --- a/retesteth/session/ToolBackend/Verification.h +++ b/retesteth/session/ToolBackend/Verification.h @@ -1,6 +1,6 @@ #pragma once #include "ToolChainHelper.h" -#include +#include namespace toolimpl { @@ -8,8 +8,13 @@ const size_t BASE_FEE_MAX_CHANGE_DENOMINATOR = 8; const size_t ELASTICITY_MULTIPLIER = 2; const size_t INITIAL_BASE_FEE = 1000000000; const size_t MAX_EXTRADATA_SIZE_IN_MERGE = 32; +const VALUE POW2_64(DataObject("0x10000000000000000")); // Blockchain logic validator void verifyEthereumBlockHeader(spBlockHeader const& _header, ToolChain const& _chain); +// Verify Withdrawals RLP in body +void verifyWithdrawalsRLP(dev::RLP const& _rlp); +void verifyWithdrawalRecord(spWithdrawal const& _wtRecord); + } // namespace toolimpl diff --git a/retesteth/session/ToolImpl.cpp b/retesteth/session/ToolImpl.cpp index 2adbd00d7..916d708dc 100644 --- a/retesteth/session/ToolImpl.cpp +++ b/retesteth/session/ToolImpl.cpp @@ -19,16 +19,21 @@ enum class CallType DONTFAILONUPWARDS, FAILEVERYTHING }; -#define TRYCATCHCALL(X, method, ctype) \ +#define TRYCATCHCALL(X, method, ctype, rpclog) \ try { \ X \ } \ catch (UpwardsException const& _ex) \ { \ makeRPCError(_ex.what()); \ - ETH_DC_MESSAGE(DC::RPC, string("Response ") + method + ": " + _ex.what()); \ + ETH_DC_MESSAGE(rpclog, string("Response ") + method + ": " + _ex.what()); \ if (ctype != CallType::DONTFAILONUPWARDS) \ - ETH_FAIL_MESSAGE(_ex.what()); \ + { \ + if (string(_ex.what()).find("exited with 512 code") == string::npos) \ + { ETH_FAIL_MESSAGE(_ex.what()); } \ + else \ + { ETH_ERROR_MESSAGE(_ex.what());} \ + } \ } \ catch (EthError const& _ex) \ { \ @@ -43,13 +48,14 @@ enum class CallType spDataObject ToolImpl::web3_clientVersion() { rpcCall("", {}); - ETH_DC_MESSAGE(DC::RPC, "\nRequest: web3_clientVersion"); + ETH_DC_MESSAGE(DC::RPC2, "\nRequest: web3_clientVersion"); string const cmd = m_toolPath.string() + " -v"; TRYCATCHCALL( - spDataObject res(new DataObject(test::executeCmd(cmd))); - ETH_DC_MESSAGE(DC::RPC, "Response: web3_clientVersion " + res->asString()); + int exitCode; + spDataObject res(new DataObject(test::executeCmd(cmd, exitCode))); + ETH_DC_MESSAGE(DC::RPC2, "Response: web3_clientVersion " + res->asString()); return res; - , "web3_clientVersion", CallType::FAILEVERYTHING) + , "web3_clientVersion", CallType::FAILEVERYTHING, DC::RPC2) return spDataObject(); } @@ -66,86 +72,82 @@ FH32 ToolImpl::eth_sendRawTransaction(BYTES const& _rlp, VALUE const& _secret) FH32 trHash = spTr.getContent().hash(); ETH_DC_MESSAGE(DC::RPC, "Response: " + trHash.asString()); return trHash; - , "eth_sendRawTransaction", CallType::FAILEVERYTHING) + , "eth_sendRawTransaction", CallType::FAILEVERYTHING, DC::RPC) return FH32::zero(); } spVALUE ToolImpl::eth_getTransactionCount(FH20 const& _address, VALUE const& _blockNumber) { rpcCall("", {}); - ETH_DC_MESSAGE(DC::RPC, "\nRequest: eth_getTransactionCount " + _blockNumber.asString() + " " + _address.asString()); + ETH_DC_MESSAGE(DC::RPC2, "\nRequest: eth_getTransactionCount " + _blockNumber.asString() + " " + _address.asString()); TRYCATCHCALL( spVALUE nonce (blockchain().blockByNumber(_blockNumber).state()->getAccount(_address).nonce().copy()); - ETH_DC_MESSAGE(DC::RPC, "Response: eth_getTransactionCount " + nonce->asDecString()); + ETH_DC_MESSAGE(DC::RPC2, "Response: eth_getTransactionCount " + nonce->asDecString()); return nonce; - , "eth_getTransactionCount", CallType::FAILEVERYTHING) + , "eth_getTransactionCount", CallType::FAILEVERYTHING, DC::RPC2) return spVALUE(0); } VALUE ToolImpl::eth_blockNumber() { rpcCall("", {}); - ETH_DC_MESSAGE(DC::RPC, "\nRequest: eth_blockNumber"); + ETH_DC_MESSAGE(DC::RPC2, "\nRequest: eth_blockNumber"); TRYCATCHCALL( VALUE const& number = m_toolChainManager.getContent().lastBlock().header()->number(); string const snumber = number.asDecString(); - ETH_DC_MESSAGE(DC::RPC, "Response: eth_blockNumber {" + snumber + "}"); + ETH_DC_MESSAGE(DC::RPC2, "Response: eth_blockNumber {" + snumber + "}"); return number; - , "eth_blockNumber", CallType::FAILEVERYTHING) + , "eth_blockNumber", CallType::FAILEVERYTHING, DC::RPC2) return VALUE(0); } -EthGetBlockBy ToolImpl::eth_getBlockByHash(FH32 const& _hash, Request _fullObjects) +spEthGetBlockBy ToolImpl::eth_getBlockByHash(FH32 const& _hash, Request _fullObjects) { rpcCall("", {}); - (void)_fullObjects; - ETH_DC_MESSAGE(DC::RPC, "\nRequest: eth_getBlockByHash `" + _hash.asString()); + ETH_DC_MESSAGE(DC::RPC2, "\nRequest: eth_getBlockByHash `" + _hash.asString()); TRYCATCHCALL( - spDataObject res = constructEthGetBlockBy(blockchain().blockByHash(_hash)); - ETH_DC_MESSAGE(DC::RPC, "Response: eth_getBlockByHash `" + res->asJson()); - return EthGetBlockBy(res); - , "eth_getBlockByHash", CallType::FAILEVERYTHING) - spDataObject spnull(0); - return EthGetBlockBy(spnull); + spDataObject res = constructEthGetBlockBy(blockchain().blockByHash(_hash), _fullObjects); + ETH_DC_MESSAGE(DC::RPC2, "Response: eth_getBlockByHash `" + res->asJson()); + return spEthGetBlockBy(new EthGetBlockBy(res)); + , "eth_getBlockByHash", CallType::FAILEVERYTHING, DC::RPC2) + return spEthGetBlockBy(0); } -EthGetBlockBy ToolImpl::eth_getBlockByNumber(VALUE const& _blockNumber, Request _fullObjects) +spEthGetBlockBy ToolImpl::eth_getBlockByNumber(VALUE const& _blockNumber, Request _fullObjects) { rpcCall("", {}); - (void)_fullObjects; - ETH_DC_MESSAGE(DC::RPC, "\nRequest: eth_getBlockByNumber `" + _blockNumber.asDecString()); + ETH_DC_MESSAGE(DC::RPC2, "\nRequest: eth_getBlockByNumber `" + _blockNumber.asDecString()); TRYCATCHCALL( - spDataObject res = constructEthGetBlockBy(blockchain().blockByNumber(_blockNumber)); - ETH_DC_MESSAGE(DC::RPC, "Response: eth_getBlockByNumber `" + res->asJson()); - return EthGetBlockBy(res); - , "eth_getBlockByNumber", CallType::FAILEVERYTHING) - spDataObject spnull(0); - return EthGetBlockBy(spnull); + spDataObject res = constructEthGetBlockBy(blockchain().blockByNumber(_blockNumber), _fullObjects); + ETH_DC_MESSAGE(DC::RPC2, "Response: eth_getBlockByNumber `" + res->asJson()); + return spEthGetBlockBy(new EthGetBlockBy(res)); + , "eth_getBlockByNumber", CallType::FAILEVERYTHING, DC::RPC2) + return spEthGetBlockBy(0); } spBYTES ToolImpl::eth_getCode(FH20 const& _address, VALUE const& _blockNumber) { rpcCall("", {}); - ETH_DC_MESSAGE(DC::RPC, "\nRequest: eth_getCode " + _blockNumber.asString() + " " + _address.asString()); + ETH_DC_MESSAGE(DC::RPC2, "\nRequest: eth_getCode " + _blockNumber.asString() + " " + _address.asString()); TRYCATCHCALL( spBYTES code(blockchain().blockByNumber(_blockNumber).state()->getAccount(_address).code().copy()); - ETH_DC_MESSAGE(DC::RPC, "Response: eth_getCode " + code->asString()); + ETH_DC_MESSAGE(DC::RPC2, "Response: eth_getCode " + code->asString()); return code; - , "eth_getCode", CallType::FAILEVERYTHING) + , "eth_getCode", CallType::FAILEVERYTHING, DC::RPC2) return spBYTES(0); } spVALUE ToolImpl::eth_getBalance(FH20 const& _address, VALUE const& _blockNumber) { rpcCall("", {}); - ETH_DC_MESSAGE(DC::RPC, "\nRequest: eth_getBalance " + _blockNumber.asString() + " " + _address.asString()); + ETH_DC_MESSAGE(DC::RPC2, "\nRequest: eth_getBalance " + _blockNumber.asString() + " " + _address.asString()); TRYCATCHCALL( // Make a copy here because we do not expose the memory of the tool backend spVALUE balance(blockchain().blockByNumber(_blockNumber).state()->getAccount(_address).balance().copy()); - ETH_DC_MESSAGE(DC::RPC, "Response: eth_getBalance " + balance->asDecString()); + ETH_DC_MESSAGE(DC::RPC2, "Response: eth_getBalance " + balance->asDecString()); return balance; - , "eth_getBalance", CallType::FAILEVERYTHING) + , "eth_getBalance", CallType::FAILEVERYTHING, DC::RPC2) return spVALUE(0); } @@ -154,15 +156,15 @@ DebugAccountRange ToolImpl::debug_accountRange( VALUE const& _blockNumber, VALUE const& _txIndex, FH32 const& _addressHash, size_t _maxResults) { rpcCall("", {}); - ETH_DC_MESSAGE(DC::RPC, "\nRequest: debug_accountRange `" + _blockNumber.asDecString() + " " + _addressHash.asString()); + ETH_DC_MESSAGE(DC::RPC2, "\nRequest: debug_accountRange `" + _blockNumber.asDecString() + " " + _addressHash.asString()); (void) _txIndex; TRYCATCHCALL( spDataObject constructResponse = constructAccountRange(blockchain().blockByNumber(_blockNumber), _addressHash, _maxResults); - ETH_DC_MESSAGE(DC::RPC, "Response: debug_accountRange " + constructResponse->asJson()); + ETH_DC_MESSAGE(DC::RPC2, "Response: debug_accountRange " + constructResponse->asJson()); return DebugAccountRange(constructResponse); - , "debug_accountRange", CallType::FAILEVERYTHING) + , "debug_accountRange", CallType::FAILEVERYTHING, DC::RPC2) return DebugAccountRange(DataObject()); } @@ -170,14 +172,14 @@ DebugAccountRange ToolImpl::debug_accountRange( FH32 const& _blockHash, VALUE const& _txIndex, FH32 const& _addressHash, size_t _maxResults) { rpcCall("", {}); - ETH_DC_MESSAGE(DC::RPC, "\nRequest: debug_accountRange " + _blockHash.asString() + " " + _addressHash.asString()); + ETH_DC_MESSAGE(DC::RPC2, "\nRequest: debug_accountRange " + _blockHash.asString() + " " + _addressHash.asString()); (void) _txIndex; TRYCATCHCALL( spDataObject constructResponse = constructAccountRange(blockchain().blockByHash(_blockHash), _addressHash, _maxResults); - ETH_DC_MESSAGE(DC::RPC, "Response: debug_accountRange " + constructResponse->asJson()); + ETH_DC_MESSAGE(DC::RPC2, "Response: debug_accountRange " + constructResponse->asJson()); return DebugAccountRange(constructResponse); - , "debug_accountRange", CallType::FAILEVERYTHING) + , "debug_accountRange", CallType::FAILEVERYTHING, DC::RPC2) return DebugAccountRange(DataObject()); } @@ -185,16 +187,16 @@ DebugStorageRangeAt ToolImpl::debug_storageRangeAt( VALUE const& _blockNumber, VALUE const& _txIndex, FH20 const& _address, FH32 const& _begin, int _maxResults) { rpcCall("", {}); - ETH_DC_MESSAGE(DC::RPC, "\nRequest: debug_storageRangeAt bl:" + _blockNumber.asDecString() + " ind:" + _begin.asString() + + ETH_DC_MESSAGE(DC::RPC2, "\nRequest: debug_storageRangeAt bl:" + _blockNumber.asDecString() + " ind:" + _begin.asString() + " addr:" + _address.asString()); (void) _txIndex; TRYCATCHCALL( spDataObject constructResponse = constructStorageRangeAt(blockchain().blockByNumber(_blockNumber), _address, _begin, _maxResults); - ETH_DC_MESSAGE(DC::RPC, "Response: debug_storageRangeAt " + constructResponse->asJson()); + ETH_DC_MESSAGE(DC::RPC2, "Response: debug_storageRangeAt " + constructResponse->asJson()); return DebugStorageRangeAt(constructResponse); - , "debug_storageRangeAt", CallType::FAILEVERYTHING) + , "debug_storageRangeAt", CallType::FAILEVERYTHING, DC::RPC2) return DebugStorageRangeAt(DataObject()); } @@ -202,26 +204,26 @@ DebugStorageRangeAt ToolImpl::debug_storageRangeAt( FH32 const& _blockHash, VALUE const& _txIndex, FH20 const& _address, FH32 const& _begin, int _maxResults) { rpcCall("", {}); - ETH_DC_MESSAGE(DC::RPC, "\nRequest: debug_storageRangeAt bl:" + _blockHash.asString() + " ind:" + _begin.asString() + + ETH_DC_MESSAGE(DC::RPC2, "\nRequest: debug_storageRangeAt bl:" + _blockHash.asString() + " ind:" + _begin.asString() + " addr:" + _address.asString()); (void) _txIndex; TRYCATCHCALL( spDataObject constructResponse = constructStorageRangeAt(blockchain().blockByHash(_blockHash), _address, _begin, _maxResults); - ETH_DC_MESSAGE(DC::RPC, "Response: debug_storageRangeAt " + constructResponse->asJson()); + ETH_DC_MESSAGE(DC::RPC2, "Response: debug_storageRangeAt " + constructResponse->asJson()); return DebugStorageRangeAt(constructResponse); - , "debug_storageRangeAt", CallType::FAILEVERYTHING) + , "debug_storageRangeAt", CallType::FAILEVERYTHING, DC::RPC2) return DebugStorageRangeAt(DataObject()); } DebugVMTrace ToolImpl::debug_traceTransaction(FH32 const& _trHash) { rpcCall("", {}); - ETH_DC_MESSAGE(DC::RPC, "\nRequest: debug_traceTransaction: " + _trHash.asString()); + ETH_DC_MESSAGE(DC::RPC2, "\nRequest: debug_traceTransaction: " + _trHash.asString()); TRYCATCHCALL( return blockchain().lastBlock().getTrTrace(_trHash); - , "debug_traceTransaction", CallType::FAILEVERYTHING) + , "debug_traceTransaction", CallType::FAILEVERYTHING, DC::RPC2) return DebugVMTrace(); } @@ -235,7 +237,20 @@ void ToolImpl::test_setChainParams(spSetChainParamsArgs const& _config) TRYCATCHCALL( m_toolChainManager = GCP_SPointer(new ToolChainManager(_config, m_toolPath, m_tmpDir)); ETH_DC_MESSAGE(DC::RPC, "Response test_setChainParams: {true}"); - , "test_setChainParams", CallType::FAILEVERYTHING) + , "test_setChainParams", CallType::FAILEVERYTHING, DC::RPC) + ETH_DC_MESSAGE(DC::RPC, "Response test_setChainParams: {false}"); +} + +void ToolImpl::test_setChainParamsNoGenesis(spSetChainParamsArgs const& _config) +{ + rpcCall("", {}); + ETH_DC_MESSAGE(DC::RPC, "\nRequest: test_setChainParams \n" + _config->asDataObject()->asJson()); + + // Ask tool to calculate genesis header stateRoot for genesisHeader + TRYCATCHCALL( + m_toolChainManager = GCP_SPointer(new ToolChainManager(_config, m_toolPath, m_tmpDir, ToolChainGenesis::NOTCALCULATE)); + ETH_DC_MESSAGE(DC::RPC, "Response test_setChainParams: {true}"); + , "test_setChainParams", CallType::FAILEVERYTHING, DC::RPC) ETH_DC_MESSAGE(DC::RPC, "Response test_setChainParams: {false}"); } @@ -245,18 +260,18 @@ void ToolImpl::test_rewindToBlock(VALUE const& _blockNr) ETH_DC_MESSAGE(DC::RPC, "\nRequest: test_rewindToBlock " + _blockNr.asDecString()); TRYCATCHCALL( blockchain().rewindToBlock(_blockNr); - , "test_rewindToBlock", CallType::DONTFAILONUPWARDS) + , "test_rewindToBlock", CallType::DONTFAILONUPWARDS, DC::RPC) ETH_DC_MESSAGE(DC::RPC, "Response: test_rewindToBlock: " + blockchain().lastBlock().header()->number().asDecString()); } void ToolImpl::test_modifyTimestamp(VALUE const& _timestamp) { rpcCall("", {}); - ETH_DC_MESSAGE(DC::RPC, "\nRequest: test_modifyTimestamp " + _timestamp.asDecString()); + ETH_DC_MESSAGE(DC::RPC2, "\nRequest: test_modifyTimestamp " + _timestamp.asDecString()); TRYCATCHCALL( blockchain().modifyTimestamp(_timestamp); - ETH_DC_MESSAGE(DC::RPC, "Response: test_modifyTimestamp " + _timestamp.asDecString()); - , "test_modifyTimestamp", CallType::DONTFAILONUPWARDS) + ETH_DC_MESSAGE(DC::RPC2, "Response: test_modifyTimestamp " + _timestamp.asDecString()); + , "test_modifyTimestamp", CallType::DONTFAILONUPWARDS, DC::RPC2) } MineBlocksResult ToolImpl::test_mineBlocks(size_t _number) @@ -267,8 +282,10 @@ MineBlocksResult ToolImpl::test_mineBlocks(size_t _number) spDataObject const res = blockchain().mineBlocks(_number); ETH_DC_MESSAGE(DC::RPC, "Response test_mineBlocks {" + blockchain().lastBlock().header()->number().asDecString() + "}"); ETH_DC_MESSAGE(DC::RPC, res->asJson()); + // test_mineBlocks assumed not to fail ever to be able to construct test block RLP + // for invalid block generation test_importRawBlock is used which takes malicious RLP return MineBlocksResult(res); - , "test_mineBlocks", CallType::FAILEVERYTHING) + , "test_mineBlocks", CallType::FAILEVERYTHING, DC::RPC) return MineBlocksResult(DataObject()); } @@ -283,7 +300,7 @@ FH32 ToolImpl::test_importRawBlock(BYTES const& _blockRLP) FH32 const hash = blockchain().importRawBlock(_blockRLP); ETH_DC_MESSAGE(DC::RPC, "Response test_importRawBlock: " + hash.asString()); return hash; - , "test_importRawBlock", CallType::DONTFAILONUPWARDS) + , "test_importRawBlock", CallType::DONTFAILONUPWARDS, DC::RPC) return FH32::zero(); } @@ -291,11 +308,11 @@ FH32 ToolImpl::test_getLogHash(FH32 const& _txHash) { rpcCall("", {}); TRYCATCHCALL( - ETH_DC_MESSAGE(DC::RPC, "\nRequest: test_getLogHash " + _txHash.asString()); + ETH_DC_MESSAGE(DC::RPC2, "\nRequest: test_getLogHash " + _txHash.asString()); FH32 const& res = blockchain().lastBlock().logHash(); - ETH_DC_MESSAGE(DC::RPC, "Response: test_getLogHash " + res.asString()); + ETH_DC_MESSAGE(DC::RPC2, "Response: test_getLogHash " + res.asString()); return res; - , "test_getLogHash", CallType::FAILEVERYTHING) + , "test_getLogHash", CallType::FAILEVERYTHING, DC::RPC2) return _txHash; } @@ -310,10 +327,20 @@ TestRawTransaction ToolImpl::test_rawTransaction(BYTES const& _rlp, FORK const& ETH_DC_MESSAGE(DC::RPC, "\nRequest: test_rawTransaction '" + _rlp.asString() + "', Fork: `" + t8nForkName.asString()); TestRawTransaction res = ToolChainManager::test_rawTransaction(_rlp, t8nForkName, m_toolPath, m_tmpDir); return res; - , "test_rawTransaction", CallType::FAILEVERYTHING) + , "test_rawTransaction", CallType::FAILEVERYTHING, DC::RPC) return TestRawTransaction(DataObject()); } +void ToolImpl::test_registerWithdrawal(BYTES const& _rlp) +{ + rpcCall("", {}); + TRYCATCHCALL( + ETH_DC_MESSAGE(DC::RPC, "\nRequest: test_registerWithdrawal '" + _rlp.asString()); + m_toolChainManager.getContent().registerWithdrawal(_rlp); + , "test_registerWithdrawal", CallType::FAILEVERYTHING, DC::RPC) +} + + VALUE ToolImpl::test_calculateDifficulty(FORK const& _fork, VALUE const& _blockNumber, VALUE const& _parentTimestamp, VALUE const& _parentDifficulty, VALUE const& _currentTimestamp, VALUE const& _uncleNumber) { @@ -324,7 +351,7 @@ VALUE ToolImpl::test_calculateDifficulty(FORK const& _fork, VALUE const& _blockN ", pd: " + _parentDifficulty.asString() + ", ct: " + _currentTimestamp.asString() + ", un: " + _uncleNumber.asString()); return ToolChainManager::test_calculateDifficulty(_fork, _blockNumber, _parentTimestamp, _parentDifficulty, _currentTimestamp, _uncleNumber, m_toolPath, m_tmpDir); - , "test_calculateDifficulty", CallType::FAILEVERYTHING) + , "test_calculateDifficulty", CallType::FAILEVERYTHING, DC::RPC) return VALUE(DataObject()); } diff --git a/retesteth/session/ToolImpl.h b/retesteth/session/ToolImpl.h index d1f6bb336..3f397b75a 100644 --- a/retesteth/session/ToolImpl.h +++ b/retesteth/session/ToolImpl.h @@ -21,8 +21,8 @@ class ToolImpl : public SessionInterface // ETH Methods FH32 eth_sendRawTransaction(BYTES const& _rlp, VALUE const& _secret) override; VALUE eth_blockNumber() override; - EthGetBlockBy eth_getBlockByHash(FH32 const& _hash, Request _fullObjects) override; - EthGetBlockBy eth_getBlockByNumber(VALUE const& _blockNumber, Request _fullObjects) override; + spEthGetBlockBy eth_getBlockByHash(FH32 const& _hash, Request _fullObjects) override; + spEthGetBlockBy eth_getBlockByNumber(VALUE const& _blockNumber, Request _fullObjects) override; // Account functions spVALUE eth_getTransactionCount(FH20 const& _address, VALUE const& _blockNumber) override; @@ -42,10 +42,12 @@ class ToolImpl : public SessionInterface // Test void test_setChainParams(spSetChainParamsArgs const& _config) override; + void test_setChainParamsNoGenesis(spSetChainParamsArgs const& _config) override; void test_rewindToBlock(VALUE const& _blockNr) override; void test_modifyTimestamp(VALUE const& _timestamp) override; MineBlocksResult test_mineBlocks(size_t _number) override; FH32 test_importRawBlock(BYTES const& _blockRLP) override; + void test_registerWithdrawal(BYTES const& _rlp) override; FH32 test_getLogHash(FH32 const& _txHash) override; TestRawTransaction test_rawTransaction(BYTES const& _rlp, FORK const& _fork) override; VALUE test_calculateDifficulty(FORK const& _fork, VALUE const& _blockNumber, VALUE const& _parentTimestamp, diff --git a/retesteth/testStructures/Common.cpp b/retesteth/testStructures/Common.cpp index f0321d8bc..b3c4dc3b0 100644 --- a/retesteth/testStructures/Common.cpp +++ b/retesteth/testStructures/Common.cpp @@ -48,6 +48,12 @@ void removeLeadingZeroes(string& _hexStr) namespace test::teststruct { +spFH20 convertSecretToPublic(VALUE const& _secret) +{ + spFH32 secret(new FH32(_secret.asString())); + return convertSecretToPublic(secret); +} + spFH20 convertSecretToPublic(spFH32 const& _secret) { const dev::Secret secret(_secret->asString()); @@ -80,12 +86,25 @@ void mod_removeComments(DataObject& _obj) for (auto& el : _obj.getSubObjectsUnsafe()) { if (el->getKey()[0] == '/' && el->getKey()[1] == '/') - keysToRemove.push_back(el->getKey()); + keysToRemove.emplace_back(el->getKey()); } for (auto const& key : keysToRemove) _obj.removeKey(key); } +void mod_valueToFH32(DataObject& _obj) +{ + if (_obj.type() == DataType::String) + { + size_t size = _obj.asString().size(); + if (_obj.asString().substr(0, 2) == "0x") + { + while (size++ < 66) + _obj.asStringUnsafe().insert(2, "0"); + } + } +} + void mod_valueToCompactEvenHexPrefixed(DataObject& _obj) { if (_obj.type() == DataType::String) @@ -260,7 +279,7 @@ void requireJsonFields(DataObject const& _o, std::string const& _config, std::ma if (!_validationMap.count(field->getKey())) { std::string const comment = "Unexpected field '" + field->getKey() + "' in config: " + _config; - ETH_ERROR_MESSAGE(comment + "\n" + _o.asJson()); + throw test::UpwardsException(comment + "\n" + _o.asJson()); } } @@ -273,7 +292,7 @@ void requireJsonFields(DataObject const& _o, std::string const& _config, std::ma if (vmap.second.second == jsonField::Required) { std::string const comment = "Expected field '" + vmap.first + "' not found in config: " + _config; - ETH_ERROR_MESSAGE(comment + "\n" + _o.asJson()); + throw test::UpwardsException(comment + "\n" + _o.asJson()); } else if (vmap.second.second == jsonField::Optional) continue; @@ -297,7 +316,7 @@ void requireJsonFields(DataObject const& _o, std::string const& _config, std::ma } std::string const comment = "Field '" + vmap.first + "' expected to be `" + sTypes + "`, but set to `" + DataObject::dataTypeAsString(_o.atKey(vmap.first).type()) + "` in " + _config; - ETH_ERROR_MESSAGE(comment + "\n" + _o.asJson()); + throw test::UpwardsException(comment + "\n" + _o.asJson()); } } } diff --git a/retesteth/testStructures/Common.h b/retesteth/testStructures/Common.h index 906de9a10..049bba3cb 100644 --- a/retesteth/testStructures/Common.h +++ b/retesteth/testStructures/Common.h @@ -1,8 +1,8 @@ #pragma once #include #include -#include -#include +#include +#include #include namespace test::teststruct @@ -18,6 +18,7 @@ void mod_keyToLowerCase(DataObject&); void mod_valueToCompactEvenHexPrefixed(DataObject&); void mod_keyToCompactEvenHexPrefixed(DataObject&); void mod_valueInsertZeroXPrefix(DataObject&); +void mod_valueToFH32(DataObject&); void mod_sortKeys(DataObject&); long long int hexOrDecStringToInt(std::string const& _str); @@ -74,5 +75,6 @@ void readExpectExceptions(DataObject const& _data, std::map& // Convert Secret Key to Public eth key spFH20 convertSecretToPublic(spFH32 const& _secret); +spFH20 convertSecretToPublic(VALUE const& _secret); } // namespace teststruct diff --git a/retesteth/testStructures/PrepareChainParams.cpp b/retesteth/testStructures/PrepareChainParams.cpp index 2a2db746f..3d3d272a4 100644 --- a/retesteth/testStructures/PrepareChainParams.cpp +++ b/retesteth/testStructures/PrepareChainParams.cpp @@ -61,22 +61,38 @@ spDataObject prepareGenesisSubsection(StateTestEnvBase const& _env, ParamsContex { (*genesis).removeKey("baseFeePerGas"); (*genesis).removeKey("currentRandom"); + (*genesis).removeKey("withdrawalsRoot"); return genesis; } + auto londify = [&_env, &_context](DataObject& _genesis){ + _genesis["baseFeePerGas"] = calculateGenesisBaseFee(_env.currentBaseFee(), _context); + }; + + auto mergify = [&_env](DataObject& _genesis){ + _genesis.removeKey("difficulty"); + _genesis["currentRandom"] = _env.currentRandom().asString(); + auto const randomH32 = dev::toCompactHexPrefixed(dev::u256(_genesis["currentRandom"].asString()), 32); + _genesis["mixHash"] = randomH32; + }; + if (!netIsAdditional) { bool knowLondon = cfg.checkForkInProgression("London"); if (knowLondon && compareFork(net, CMP::ge, FORK("London"))) - (*genesis)["baseFeePerGas"] = calculateGenesisBaseFee(_env.currentBaseFee(), _context); + londify(genesis.getContent()); bool knowMerge = cfg.checkForkInProgression("Merge"); if (knowMerge && compareFork(net, CMP::ge, FORK("Merge"))) { - (*genesis).removeKey("difficulty"); - (*genesis)["currentRandom"] = _env.currentRandom().asString(); - auto const randomH32 = dev::toCompactHexPrefixed(dev::u256((*genesis)["currentRandom"].asString()), 32); - (*genesis)["mixHash"] = randomH32; + mergify(genesis.getContent()); + } + + bool knowShaghai = cfg.checkForkInProgression("Shanghai"); + if (knowShaghai && compareFork(net, CMP::ge, FORK("Shanghai"))) + { + mergify(genesis.getContent()); + (*genesis)["withdrawalsRoot"] = _env.currentWithdrawalsRoot().asString(); } } else @@ -84,16 +100,35 @@ spDataObject prepareGenesisSubsection(StateTestEnvBase const& _env, ParamsContex // Net Is Additional, probably special transition net. // Can't get rid of this hardcode configs :((( if (_net == FORK("ArrowGlacierToMergeAtDiffC0000") || _net == FORK("ArrowGlacier")) - (*genesis)["baseFeePerGas"] = calculateGenesisBaseFee(_env.currentBaseFee(), _context); - + londify(genesis.getContent()); + else if (_net == FORK("MergeToShanghaiAtTime15k")) + { + londify(genesis.getContent()); + mergify(genesis.getContent()); + } } return genesis; -}} - +} -namespace test +void overrideChainIDByOptions(spDataObject& _genesis) { -namespace teststruct + if (Options::get().chainid.initialized()) + { + if ((*_genesis).count("params")) + { + string const chainIDOverride = dev::toCompactHexPrefixed((size_t)Options::get().chainid); + if ((*_genesis).atKey("params").count("chainID")) + (*_genesis).atKeyUnsafe("params").atKeyUnsafe("chainID") = chainIDOverride; + else + (*_genesis).atKeyUnsafe("params")["chainID"] = chainIDOverride; + } + } +} + +} + + +namespace test::teststruct { spSetChainParamsArgs prepareChainParams( FORK const& _net, SealEngine _engine, State const& _state, StateTestEnvBase const& _env, ParamsContext _context) @@ -103,6 +138,8 @@ spSetChainParamsArgs prepareChainParams( spDataObject genesis; (*genesis).copyFrom(cfg.getGenesisTemplate(_net).getCContent()); // TODO need copy? + overrideChainIDByOptions(genesis); + (*genesis)["sealEngine"] = sealEngineToStr(_engine); (*genesis).atKeyPointer("genesis") = prepareGenesisSubsection(_env, _context, _net); @@ -113,4 +150,3 @@ spSetChainParamsArgs prepareChainParams( } } // namespace teststruct -} // namespace test diff --git a/retesteth/testStructures/basetypes/FH20.cpp b/retesteth/testStructures/basetypes/FH20.cpp new file mode 100644 index 000000000..024d59472 --- /dev/null +++ b/retesteth/testStructures/basetypes/FH20.cpp @@ -0,0 +1,28 @@ +#include "FH20.h" +#include "Constants.h" +#include +#include +using namespace test::teststruct; + +FH20 const& FH20::zero() +{ + return C_FH20_ZERO; +} + +FH20 FH20::random() +{ + std::string initStr = "0x"; + std::vector hex{"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"}; + auto rng = std::default_random_engine{}; + for (size_t i = 0; i < 40; i++) + { + std::shuffle(hex.begin(), hex.end(), rng); + initStr += hex.at(5); + } + return FH20(DataObject(std::move(initStr))); +} + +FH20* FH20::copy() const +{ + return new FH20(asString()); +} diff --git a/retesteth/testStructures/basetypes/FH20.h b/retesteth/testStructures/basetypes/FH20.h index 96c84f98c..50939a937 100644 --- a/retesteth/testStructures/basetypes/FH20.h +++ b/retesteth/testStructures/basetypes/FH20.h @@ -1,13 +1,10 @@ #pragma once #include "FH.h" #include -#include -#include -namespace test -{ -namespace teststruct +namespace test::teststruct { + // Validate and manage the type of FixedHash20 // Deserialized from string of "0x1122...20" exact length struct FH20 : FH @@ -15,28 +12,12 @@ struct FH20 : FH FH20(dev::RLP const& _rlp) : FH(_rlp, 20) {} FH20(DataObject const& _data) : FH(_data, 20) {} FH20(std::string const& _data) : FH(_data, 20) {} - FH20* copy() const { return new FH20(asString()); } + FH20* copy() const; - static FH20 random() - { - std::string initStr = "0x"; - std::vector hex{"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"}; - auto rng = std::default_random_engine{}; - for (size_t i = 0; i < 40; i++) - { - std::shuffle(hex.begin(), hex.end(), rng); - initStr += hex.at(5); - } - return FH20(DataObject(std::move(initStr))); - } - static FH20 const& zero() - { - static FH20 zero("0x0000000000000000000000000000000000000000"); - return zero; - } + static FH20 random(); + static FH20 const& zero(); }; typedef GCP_SPointer spFH20; } // namespace teststruct -} // namespace test diff --git a/retesteth/testStructures/basetypes/FH256.cpp b/retesteth/testStructures/basetypes/FH256.cpp new file mode 100644 index 000000000..eae890c40 --- /dev/null +++ b/retesteth/testStructures/basetypes/FH256.cpp @@ -0,0 +1,13 @@ +#include "FH256.h" +#include "Constants.h" +using namespace test::teststruct; + +FH256 const& FH256::zero() +{ + return C_FH256_ZERO; +} + +FH256* FH256::copy() const +{ + return new FH256(asString()); +} diff --git a/retesteth/testStructures/basetypes/FH256.h b/retesteth/testStructures/basetypes/FH256.h index 6b2b49af3..bee330652 100644 --- a/retesteth/testStructures/basetypes/FH256.h +++ b/retesteth/testStructures/basetypes/FH256.h @@ -2,30 +2,19 @@ #include "FH.h" #include -namespace test -{ -namespace teststruct +namespace test::teststruct { + struct FH256 : FH { FH256(dev::RLP const& _rlp) : FH(_rlp, 256) {} FH256(DataObject const& _data) : FH(_data, 256) {} FH256(std::string const& _data) : FH(_data, 256) {} - FH256* copy() const { return new FH256(asString()); } + FH256* copy() const; - static FH256 const& zero() - { - static FH256 zero( - "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000"); - return zero; - } + static FH256 const& zero(); }; typedef GCP_SPointer spFH256; } // namespace teststruct -} // namespace test diff --git a/retesteth/testStructures/basetypes/FH32.cpp b/retesteth/testStructures/basetypes/FH32.cpp new file mode 100644 index 000000000..a11ed8773 --- /dev/null +++ b/retesteth/testStructures/basetypes/FH32.cpp @@ -0,0 +1,13 @@ +#include "FH32.h" +#include "Constants.h" +using namespace test::teststruct; + +FH32 const& FH32::zero() +{ + return C_FH32_ZERO; +} + +FH32* FH32::copy() const +{ + return new FH32(asString()); +} diff --git a/retesteth/testStructures/basetypes/FH32.h b/retesteth/testStructures/basetypes/FH32.h index 9a747a95a..09474f793 100644 --- a/retesteth/testStructures/basetypes/FH32.h +++ b/retesteth/testStructures/basetypes/FH32.h @@ -1,10 +1,9 @@ #pragma once #include "FH.h" #include -namespace test -{ -namespace teststruct +namespace test::teststruct { + // Validate and manage the type of FixedHash32 // Deserialized from string of "0x1122...32" exact length struct FH32 : FH @@ -12,17 +11,12 @@ struct FH32 : FH FH32(dev::RLP const& _rlp) : FH(_rlp, 32) {} FH32(DataObject const& _data) : FH(_data, 32) {} FH32(std::string const& _data) : FH(_data, 32) {} - FH32* copy() const { return new FH32(asString()); } + FH32* copy() const; bool isZero() const { return m_data.asString() == zero().asStringBytes(); } - static FH32 const& zero() - { - static FH32 zero("0x0000000000000000000000000000000000000000000000000000000000000000"); - return zero; - } + static FH32 const& zero(); }; typedef GCP_SPointer spFH32; } // namespace teststruct -} // namespace test diff --git a/retesteth/testStructures/basetypes/FH8.cpp b/retesteth/testStructures/basetypes/FH8.cpp new file mode 100644 index 000000000..238dc1260 --- /dev/null +++ b/retesteth/testStructures/basetypes/FH8.cpp @@ -0,0 +1,13 @@ +#include "FH8.h" +#include "Constants.h" +using namespace test::teststruct; + +FH8 const& FH8::zero() +{ + return C_FH8_ZERO; +} + +FH8* FH8::copy() const +{ + return new FH8(asString()); +} diff --git a/retesteth/testStructures/basetypes/FH8.h b/retesteth/testStructures/basetypes/FH8.h index 597447065..1102be808 100644 --- a/retesteth/testStructures/basetypes/FH8.h +++ b/retesteth/testStructures/basetypes/FH8.h @@ -2,25 +2,18 @@ #include "FH.h" #include -namespace test -{ -namespace teststruct +namespace test::teststruct { + struct FH8 : FH { FH8(dev::RLP const& _rlp) : FH(_rlp, 8) {} FH8(std::string const& _data) : FH(_data, 8) {} FH8(DataObject const& _data) : FH(_data, 8) {} - FH8* copy() const { return new FH8(asString()); } - - static FH8 const& zero() - { - static FH8 zero("0x0000000000000000"); - return zero; - } + FH8* copy() const; + static FH8 const& zero(); }; typedef GCP_SPointer spFH8; } // namespace teststruct -} // namespace test diff --git a/retesteth/testStructures/configs/ClientConfigFile.cpp b/retesteth/testStructures/configs/ClientConfigFile.cpp index fdef7bb9b..8e630e4be 100644 --- a/retesteth/testStructures/configs/ClientConfigFile.cpp +++ b/retesteth/testStructures/configs/ClientConfigFile.cpp @@ -21,8 +21,10 @@ void requireJsonFileStructure(DataObject const& _data) {"customCompilers", {{DataType::Object}, jsonField::Optional}}, {"initializeTime", {{DataType::String}, jsonField::Optional}}, {"tmpDir", {{DataType::String}, jsonField::Optional}}, + {"transactionsAsJson", {{DataType::Bool}, jsonField::Optional}}, {"checkLogsHash", {{DataType::Bool}, jsonField::Optional}}, {"checkDifficulty", {{DataType::Bool}, jsonField::Optional}}, + {"calculateDifficulty", {{DataType::Bool}, jsonField::Optional}}, {"support1559", {{DataType::Bool}, jsonField::Optional}}, {"checkBasefee", {{DataType::Bool}, jsonField::Optional}}, {"calculateBasefee", {{DataType::Bool}, jsonField::Optional}}, @@ -76,7 +78,7 @@ void ClientConfigFile::parseSocketType(DataObject const& _data, string const& _s IPADDRESS addr(el); if (test::inArray(m_socketAddress, addr)) ETH_ERROR_MESSAGE(_sErrorPath + "`socketAddress` section contain dublicate element: " + el->asString()); - m_socketAddress.push_back(addr); + m_socketAddress.emplace_back(addr); } } // IPC would connect to a client using shell script @@ -144,6 +146,10 @@ void ClientConfigFile::initWithData(DataObject const& _data) if (_data.count("checkDifficulty")) m_checkDifficulty = _data.atKey("checkDifficulty").asBool(); + m_calculateDifficulty = false; + if (_data.count("calculateDifficulty")) + m_calculateDifficulty = _data.atKey("calculateDifficulty").asBool(); + m_calculateBasefee = false; if (_data.count("calculateBasefee")) m_calculateBasefee = _data.atKey("calculateBasefee").asBool(); @@ -156,6 +162,9 @@ void ClientConfigFile::initWithData(DataObject const& _data) if (_data.count("support1559")) m_support1559 = _data.atKey("support1559").asBool(); + m_transactionsAsJson = false; + if (_data.count("transactionsAsJson")) + m_transactionsAsJson = _data.atKey("transactionsAsJson").asBool(); if (_data.count("tmpDir")) { @@ -175,7 +184,7 @@ void ClientConfigFile::initWithData(DataObject const& _data) continue; if (test::inArray(m_forks, FORK(el))) ETH_ERROR_MESSAGE(sErrorPath + "`forks` section contain dublicate element: " + el->asString()); - m_forks.push_back(FORK(el)); + m_forks.emplace_back(FORK(el)); } // Read additionalForks are allowed fork names to run on this client, but not used in translation @@ -185,7 +194,7 @@ void ClientConfigFile::initWithData(DataObject const& _data) continue; if (test::inArray(m_additionalForks, FORK(el))) ETH_ERROR_MESSAGE(sErrorPath + "`additionalForks` section contain dublicate element: " + el->asString()); - m_additionalForks.push_back(FORK(el)); + m_additionalForks.emplace_back(FORK(el)); } // Read fillerSkipForks are allowed to skip fork names when filling the test @@ -197,7 +206,7 @@ void ClientConfigFile::initWithData(DataObject const& _data) continue; if (test::inArray(m_skipForks, FORK(el))) ETH_ERROR_MESSAGE(sErrorPath + "`fillerSkipForks` section contain dublicate element: " + el->asString()); - m_skipForks.push_back(FORK(el)); + m_skipForks.emplace_back(FORK(el)); } } diff --git a/retesteth/testStructures/configs/ClientConfigFile.h b/retesteth/testStructures/configs/ClientConfigFile.h index f94735074..e9f62c211 100644 --- a/retesteth/testStructures/configs/ClientConfigFile.h +++ b/retesteth/testStructures/configs/ClientConfigFile.h @@ -33,10 +33,16 @@ struct ClientConfigFile : GCP_SPointerBase std::set allowedForks() const; std::set forkProgressionAsSet() const; bool checkLogsHash() const { return m_checkLogsHash; } + bool checkDifficulty() const { return m_checkDifficulty; } + bool calculateDifficulty() const { return m_calculateDifficulty; } + bool checkBasefee() const { return m_checkBasefee; } bool calculateBasefee() const { return m_calculateBasefee; } + + // ETC classic block format autoconvertion bool support1559() const { return m_support1559; } + bool transactionsAsJson() const { return m_transactionsAsJson; } std::map const& exceptions() const { return m_exceptions; } std::map const& fieldreplace() const { return m_fieldRaplce; } @@ -60,9 +66,11 @@ struct ClientConfigFile : GCP_SPointerBase boost::filesystem::path m_tmpDir; ///< Path to the temp dir for this config bool m_checkLogsHash; ///< Enable logsHash verification bool m_checkDifficulty; ///< Enable difficulty verification + bool m_calculateDifficulty; ///< Retesteth calculate difficulty for the client bool m_checkBasefee; ///< Enable basefee verifivation bool m_calculateBasefee; ///< Retesteth calculate basefee value bool m_support1559; ///< Support EIP1559 headers + bool m_transactionsAsJson; ///< Make T8N txs file as json not rlp size_t m_initializeTime; ///< Time to start the instance std::vector m_forks; ///< Allowed forks as network name std::vector m_additionalForks; ///< Allowed forks as network name diff --git a/retesteth/testStructures/types/BlockchainTests/BlockchainTest.cpp b/retesteth/testStructures/types/BlockchainTests/BlockchainTest.cpp index f966d72a2..62b9e1c1b 100644 --- a/retesteth/testStructures/types/BlockchainTests/BlockchainTest.cpp +++ b/retesteth/testStructures/types/BlockchainTests/BlockchainTest.cpp @@ -18,7 +18,12 @@ BlockchainTestEnv* readBlockchainTestEnv(DataObject const& _data) if (VALUE(diff->asString()) != 0) return new BlockchainTestEnv1559(_data); else - return new BlockchainTestEnvMerge(_data); + { + if (_data.count("withdrawalsRoot")) + return new BlockchainTestEnvShanghai(_data); + else + return new BlockchainTestEnvMerge(_data); + } return new BlockchainTestEnv1559(_data); } return new BlockchainTestEnvLegacy(_data); @@ -60,14 +65,17 @@ BlockchainTestInFilled::BlockchainTestInFilled(spDataObject& _data) else m_postHash = spFH32(new FH32(_data->atKey("postStateHash"))); - for (auto& el : _data.getContent().atKeyUnsafe("blocks").getSubObjectsUnsafe()) - m_blocks.push_back(BlockchainTestBlock(el)); + string const c_blocks = "blocks"; + m_blocks.reserve(_data->atKey(c_blocks).getSubObjects().size()); + for (auto& el : _data.getContent().atKeyUnsafe(c_blocks).getSubObjectsUnsafe()) + m_blocks.emplace_back(BlockchainTestBlock(el)); + m_lastBlockHash = spFH32(new FH32(_data->atKey("lastblockhash"))); if (_data->count("exceptions")) { for (size_t i = _data->atKey("exceptions").getSubObjects().size(); i > 0; i--) - m_exceptions.push_back(_data->atKey("exceptions").getSubObjects().at(i - 1)->asString()); + m_exceptions.emplace_back(_data->atKey("exceptions").getSubObjects().at(i - 1)->asString()); } } catch (std::exception const& _ex) @@ -84,10 +92,12 @@ BlockchainTest::BlockchainTest(spDataObject& _data) TestOutputHelper::get().get().testFile().string() + " A test file must contain an object value (json/yaml)."); ETH_ERROR_REQUIRE_MESSAGE(_data->getSubObjects().size() >= 1, TestOutputHelper::get().get().testFile().string() + " A test file must contain at least one test!"); + + m_tests.reserve(_data->getSubObjects().size()); for (auto& el : (*_data).getSubObjectsUnsafe()) { TestOutputHelper::get().setCurrentTestInfo(TestInfo("BlockchainTest", el->getKey())); - m_tests.push_back(BlockchainTestInFilled(el)); + m_tests.emplace_back(BlockchainTestInFilled(el)); } } catch (DataObjectException const& _ex) diff --git a/retesteth/testStructures/types/BlockchainTests/BlockchainTestFiller.cpp b/retesteth/testStructures/types/BlockchainTests/BlockchainTestFiller.cpp index 1c56bec19..af6501c9f 100644 --- a/retesteth/testStructures/types/BlockchainTests/BlockchainTestFiller.cpp +++ b/retesteth/testStructures/types/BlockchainTests/BlockchainTestFiller.cpp @@ -5,27 +5,8 @@ using namespace std; using namespace test::teststruct; -namespace -{ -BlockchainTestFillerEnv* readBlockchainFillerTestEnv(spDataObjectMove _data, SealEngine _sEngine) -{ - auto const& data = _data.getPointer(); - if (data->count("baseFeePerGas")) - { - spDataObject diff = data->atKey("difficulty").copy(); - (*diff).performModifier(mod_valueToCompactEvenHexPrefixed); - if (VALUE(diff->asString()) != 0) - return new BlockchainTestFillerEnv1559(_data, _sEngine); - else - return new BlockchainTestFillerEnvMerge(_data, _sEngine); - } - return new BlockchainTestFillerEnvLegacy(_data, _sEngine); -} -} // namespace -namespace test -{ -namespace teststruct +namespace test::teststruct { BlockchainTestInFiller::BlockchainTestInFiller(spDataObject& _data) { @@ -72,7 +53,7 @@ BlockchainTestInFiller::BlockchainTestInFiller(spDataObject& _data) std::set knownForks; for (auto& el2 : (*_data).atKeyUnsafe("expect").getSubObjectsUnsafe()) { - m_expects.push_back(el2); + m_expects.emplace_back(el2); BlockchainTestFillerExpectSection const& expect = m_expects.at(m_expects.size() - 1); for (auto const& fork : expect.forks()) { @@ -88,7 +69,7 @@ BlockchainTestInFiller::BlockchainTestInFiller(spDataObject& _data) if (_data->count("exceptions")) { for (size_t i = _data->atKey("exceptions").getSubObjects().size(); i > 0; i--) - m_exceptions.push_back(_data->atKey("exceptions").getSubObjects().at(i - 1)->asString()); + m_exceptions.emplace_back(_data->atKey("exceptions").getSubObjects().at(i - 1)->asString()); } if (_data->count("verify")) @@ -98,9 +79,12 @@ BlockchainTestInFiller::BlockchainTestInFiller(spDataObject& _data) } m_hasAtLeastOneUncle = false; - for (auto& el : (*_data).atKeyUnsafe("blocks").getSubObjectsUnsafe()) + + string const c_blocks = "blocks"; + m_blocks.reserve(_data->atKey(c_blocks).getSubObjects().size()); + for (auto& el : (*_data).atKeyUnsafe(c_blocks).getSubObjectsUnsafe()) { - m_blocks.push_back(BlockchainTestFillerBlock(el, nonceMap)); + m_blocks.emplace_back(BlockchainTestFillerBlock(el, nonceMap)); if (m_blocks.at(m_blocks.size() - 1).uncles().size() > 0) m_hasAtLeastOneUncle = true; } @@ -123,7 +107,7 @@ BlockchainTestFiller::BlockchainTestFiller(spDataObject& _data) for (auto& el : _data.getContent().getSubObjectsUnsafe()) { TestOutputHelper::get().setCurrentTestInfo(TestInfo("BlockchainTestFiller", el->getKey())); - m_tests.push_back(BlockchainTestInFiller(el)); + m_tests.emplace_back(BlockchainTestInFiller(el)); } } catch (DataObjectException const& _ex) @@ -155,4 +139,3 @@ std::set BlockchainTestInFiller::getAllForksFromExpectSections() const } } // namespace teststruct -} // namespace test diff --git a/retesteth/testStructures/types/BlockchainTests/Filled/BlockchainTestBlock.cpp b/retesteth/testStructures/types/BlockchainTests/Filled/BlockchainTestBlock.cpp index b396644d0..6d8346557 100644 --- a/retesteth/testStructures/types/BlockchainTests/Filled/BlockchainTestBlock.cpp +++ b/retesteth/testStructures/types/BlockchainTests/Filled/BlockchainTestBlock.cpp @@ -14,6 +14,7 @@ BlockchainTestBlock::BlockchainTestBlock(spDataObject& _data) {"chainname", {{DataType::String}, jsonField::Optional}}, // User information {"blocknumber", {{DataType::String}, jsonField::Optional}}, // User information {"transactions", {{DataType::Array}, jsonField::Optional}}, + {"withdrawals", {{DataType::Array}, jsonField::Optional}}, {"transactionSequence", {{DataType::Array}, jsonField::Optional}}, {"uncleHeaders", {{DataType::Array}, jsonField::Optional}}, {"expectException", {{DataType::String}, jsonField::Optional}}, // User information @@ -42,7 +43,13 @@ BlockchainTestBlock::BlockchainTestBlock(spDataObject& _data) m_blockHeader = readBlockHeader(_data->atKey("blockHeader")); for (auto& tr : _data.getContent().atKeyUnsafe("transactions").getSubObjectsUnsafe()) - m_transactions.push_back(readTransaction(dataobject::move(tr))); + m_transactions.emplace_back(readTransaction(dataobject::move(tr))); + + if (_data->count("withdrawals")) + { + for (auto const& wt : _data->atKey("withdrawals").getSubObjects()) + m_withdrawals.emplace_back(spWithdrawal(new Withdrawal(wt))); + } if (_data->count("transactionSequence")) { @@ -55,7 +62,7 @@ BlockchainTestBlock::BlockchainTestBlock(spDataObject& _data) } for (auto const& un : _data->atKey("uncleHeaders").getSubObjects()) - m_uncles.push_back(readBlockHeader(un)); + m_uncles.emplace_back(readBlockHeader(un)); } m_rlp = spBYTES(new BYTES(_data->atKey("rlp").asString())); } diff --git a/retesteth/testStructures/types/BlockchainTests/Filled/BlockchainTestBlock.h b/retesteth/testStructures/types/BlockchainTests/Filled/BlockchainTestBlock.h index 5f8b12c54..5cf15d056 100644 --- a/retesteth/testStructures/types/BlockchainTests/Filled/BlockchainTestBlock.h +++ b/retesteth/testStructures/types/BlockchainTests/Filled/BlockchainTestBlock.h @@ -1,7 +1,8 @@ #pragma once #include "../../../basetypes.h" -#include "../../Ethereum/BlockHeader.h" -#include "../../Ethereum/Transaction.h" +#include "../../Ethereum/Blocks/BlockHeader.h" +#include "../../Ethereum/Transactions/Transaction.h" +#include #include namespace test::teststruct @@ -19,6 +20,7 @@ struct BlockchainTestBlock : GCP_SPointerBase std::vector const& uncles() const { return m_uncles; } std::vector const& transactions() const { return m_transactions; } + std::vector const& withdrawals() const { return m_withdrawals; } std::vector const& transactionSequence() const { return m_transactionSequence; } private: @@ -29,6 +31,7 @@ struct BlockchainTestBlock : GCP_SPointerBase spBlockHeader m_blockHeader; std::vector m_uncles; std::vector m_transactions; + std::vector m_withdrawals; std::vector m_transactionSequence; spBYTES m_rlp; }; diff --git a/retesteth/testStructures/types/BlockchainTests/Filled/BlockchainTestEnv.cpp b/retesteth/testStructures/types/BlockchainTests/Filled/BlockchainTestEnv.cpp index 966cc6369..5d967bb27 100644 --- a/retesteth/testStructures/types/BlockchainTests/Filled/BlockchainTestEnv.cpp +++ b/retesteth/testStructures/types/BlockchainTests/Filled/BlockchainTestEnv.cpp @@ -88,12 +88,45 @@ void requireMergeBlockchainHeader(DataObject const& _data) {"sha3Uncles", {{DataType::String}, jsonField::Optional}}, {"uncleHash", {{DataType::String}, jsonField::Optional}}}); } + +void requireShanghaiBlockchainHeader(DataObject const& _data) +{ + REQUIRE_JSONFIELDS(_data, "GenesisBlockHeader(BlockchainTestEnvShanghai) " + _data.getKey(), + {{"bloom", {{DataType::String}, jsonField::Optional}}, + {"logsBloom", {{DataType::String}, jsonField::Optional}}, + {"coinbase", {{DataType::String}, jsonField::Optional}}, + {"author", {{DataType::String}, jsonField::Optional}}, + {"miner", {{DataType::String}, jsonField::Optional}}, + {"difficulty", {{DataType::String}, jsonField::Required}}, + {"extraData", {{DataType::String}, jsonField::Required}}, + {"gasLimit", {{DataType::String}, jsonField::Required}}, + {"baseFeePerGas", {{DataType::String}, jsonField::Required}}, + {"gasUsed", {{DataType::String}, jsonField::Required}}, + {"hash", {{DataType::String}, jsonField::Optional}}, + {"mixHash", {{DataType::String}, jsonField::Optional}}, + {"nonce", {{DataType::String}, jsonField::Optional}}, + {"number", {{DataType::String}, jsonField::Required}}, + {"parentHash", {{DataType::String}, jsonField::Required}}, + {"receiptTrie", {{DataType::String}, jsonField::Optional}}, + {"receiptsRoot", {{DataType::String}, jsonField::Optional}}, + {"stateRoot", {{DataType::String}, jsonField::Required}}, + {"timestamp", {{DataType::String}, jsonField::Required}}, + {"transactionsTrie", {{DataType::String}, jsonField::Optional}}, + {"transactionsRoot", {{DataType::String}, jsonField::Optional}}, + {"withdrawalsRoot", {{DataType::String}, jsonField::Required}}, + {"sha3Uncles", {{DataType::String}, jsonField::Optional}}, + {"uncleHash", {{DataType::String}, jsonField::Optional}}}); } -namespace test +} + +namespace test::teststruct { -namespace teststruct + +void BlockchainTestEnvShanghai::initializeShanghaiFields(DataObject const& _data) { + m_currentWithdrawalsRoot = spFH32(new FH32 (_data.atKey("withdrawalsRoot"))); +} void BlockchainTestEnvMerge::initializeMergeFields(DataObject const& _data) { @@ -139,6 +172,21 @@ BlockchainTestEnv1559::BlockchainTestEnv1559(DataObject const& _data) } } +BlockchainTestEnvShanghai::BlockchainTestEnvShanghai(DataObject const& _data) + : BlockchainTestEnvMerge() +{ + try { + requireShanghaiBlockchainHeader(_data); + initializeCommonFields(_data); + initializeMergeFields(_data); + initializeShanghaiFields(_data); + } + catch (std::exception const& _ex) + { + throw UpwardsException(string("BlockchainTestEnv(Shanghai) convertion error: ") + _ex.what() + _data.asJson()); + } +} + BlockchainTestEnvMerge::BlockchainTestEnvMerge(DataObject const& _data) { try { @@ -165,4 +213,3 @@ void BlockchainTestEnv::initializeCommonFields(DataObject const& _data) } } // namespace teststruct -} // namespace test diff --git a/retesteth/testStructures/types/BlockchainTests/Filled/BlockchainTestEnv.h b/retesteth/testStructures/types/BlockchainTests/Filled/BlockchainTestEnv.h index 46c7118bc..6bee7d89b 100644 --- a/retesteth/testStructures/types/BlockchainTests/Filled/BlockchainTestEnv.h +++ b/retesteth/testStructures/types/BlockchainTests/Filled/BlockchainTestEnv.h @@ -2,9 +2,7 @@ #include #include -namespace test -{ -namespace teststruct +namespace test::teststruct { // Blockchain test does not have Env section // This represent env section consructed from blockchain test genesis header @@ -42,6 +40,18 @@ struct BlockchainTestEnvMerge : BlockchainTestEnv protected: void initializeMergeFields(DataObject const&); + BlockchainTestEnvMerge(){}; + +private: + void define() const override {} +}; + +struct BlockchainTestEnvShanghai : BlockchainTestEnvMerge +{ + BlockchainTestEnvShanghai(DataObject const& _data); + +protected: + void initializeShanghaiFields(DataObject const&); private: void define() const override {} @@ -51,4 +61,3 @@ typedef GCP_SPointer spBlockchainTestEnv; } // namespace teststruct -} // namespace test diff --git a/retesteth/testStructures/types/BlockchainTests/Filler/BlockchainTestFillerBlock.cpp b/retesteth/testStructures/types/BlockchainTests/Filler/BlockchainTestFillerBlock.cpp index 27785eadd..8fd2281f8 100644 --- a/retesteth/testStructures/types/BlockchainTests/Filler/BlockchainTestFillerBlock.cpp +++ b/retesteth/testStructures/types/BlockchainTests/Filler/BlockchainTestFillerBlock.cpp @@ -19,6 +19,7 @@ BlockchainTestFillerBlock::BlockchainTestFillerBlock(spDataObject& _data, NonceM {"chainnetwork", {{DataType::String}, jsonField::Optional}}, {"transactions", {{DataType::Array}, jsonField::Optional}}, {"uncleHeaders", {{DataType::Array}, jsonField::Optional}}, + {"withdrawals", {{DataType::Array}, jsonField::Optional}}, {"expectException", {{DataType::Object}, jsonField::Optional}}, {"blockHeader", {{DataType::Object}, jsonField::Optional}}}); @@ -47,12 +48,20 @@ BlockchainTestFillerBlock::BlockchainTestFillerBlock(spDataObject& _data, NonceM m_network = spFORK(new FORK(_data->atKey("chainnetwork"))); if (_data->count("transactions")) - for (auto& tr : (*_data).atKeyUnsafe("transactions").getSubObjectsUnsafe()) - m_transactions.push_back(BlockchainTestFillerTransaction(dataobject::move(tr), _nonceMap)); + { + string const c_transactions = "transactions"; + m_transactions.reserve(_data->atKey(c_transactions).getSubObjects().size()); + for (auto& tr : (*_data).atKeyUnsafe(c_transactions).getSubObjectsUnsafe()) + m_transactions.emplace_back(BlockchainTestFillerTransaction(dataobject::move(tr), _nonceMap)); + } + + if (_data->count("withdrawals")) + for (auto& wt : (*_data).atKeyUnsafe("withdrawals").getSubObjectsUnsafe()) + m_withdrawals.emplace_back(BlockchainTestFillerWithdrawal(dataobject::move(wt))); if (_data->count("uncleHeaders")) for (auto const& un : _data->atKey("uncleHeaders").getSubObjects()) - m_uncles.push_back(BlockchainTestFillerUncle(un)); + m_uncles.emplace_back(BlockchainTestFillerUncle(un)); if (_data->count("expectException")) readExpectExceptions(_data->atKey("expectException"), m_expectExceptions); diff --git a/retesteth/testStructures/types/BlockchainTests/Filler/BlockchainTestFillerBlock.h b/retesteth/testStructures/types/BlockchainTests/Filler/BlockchainTestFillerBlock.h index f4bb11eb6..d4f96f589 100644 --- a/retesteth/testStructures/types/BlockchainTests/Filler/BlockchainTestFillerBlock.h +++ b/retesteth/testStructures/types/BlockchainTests/Filler/BlockchainTestFillerBlock.h @@ -1,10 +1,11 @@ #pragma once #include "../../../basetypes.h" #include "../../../configs/FORK.h" -#include "../../Ethereum/Transaction.h" +#include "../../Ethereum/Transactions/Transaction.h" #include "BlockchainTestFillerBlockHeaderOverwrite.h" #include "BlockchainTestFillerTransaction.h" #include "BlockchainTestFillerUncle.h" +#include "BlockchainTestFillerWithdrawal.h" #include namespace test @@ -52,6 +53,9 @@ struct BlockchainTestFillerBlock : GCP_SPointerBase // Uncle generate instruction section std::vector const& uncles() const { return m_uncles; } + // Uncle generate instruction section + std::vector const& withdrawals() const { return m_withdrawals; } + // Test Functions // Block can have exceptions expected to thrown by the client upon generation of the block std::string const& getExpectException(FORK const& _net) const @@ -81,6 +85,7 @@ struct BlockchainTestFillerBlock : GCP_SPointerBase std::vector m_uncles; std::vector m_transactions; + std::vector m_withdrawals; std::map m_expectExceptions; std::map m_overwriteHeaderByForkMap; diff --git a/retesteth/testStructures/types/BlockchainTests/Filler/BlockchainTestFillerBlockHeaderOverwrite.cpp b/retesteth/testStructures/types/BlockchainTests/Filler/BlockchainTestFillerBlockHeaderOverwrite.cpp index 81a4d9a07..8f33ffb40 100644 --- a/retesteth/testStructures/types/BlockchainTests/Filler/BlockchainTestFillerBlockHeaderOverwrite.cpp +++ b/retesteth/testStructures/types/BlockchainTests/Filler/BlockchainTestFillerBlockHeaderOverwrite.cpp @@ -18,6 +18,8 @@ BlockHeaderOverwrite::BlockHeaderOverwrite(DataObject const& _data) m_hasRelTimeStamp = true; m_relTimeStamp = hexOrDecStringToInt(_data.atKey("RelTimestamp").asString()); } + if (_data.count("forceNoWithdrawalsRLP")) + m_forceNoWithdrawalsRLP = true; } } // namespace teststruct diff --git a/retesteth/testStructures/types/BlockchainTests/Filler/BlockchainTestFillerBlockHeaderOverwrite.h b/retesteth/testStructures/types/BlockchainTests/Filler/BlockchainTestFillerBlockHeaderOverwrite.h index c20b05872..0b56d019c 100644 --- a/retesteth/testStructures/types/BlockchainTests/Filler/BlockchainTestFillerBlockHeaderOverwrite.h +++ b/retesteth/testStructures/types/BlockchainTests/Filler/BlockchainTestFillerBlockHeaderOverwrite.h @@ -1,7 +1,7 @@ #pragma once #include "../../../basetypes.h" #include "../../../configs/FORK.h" -#include "../../Ethereum/BlockHeaderIncomplete.h" +#include "../../Ethereum/Blocks/BlockHeaderIncomplete.h" #include namespace test @@ -18,8 +18,10 @@ struct BlockHeaderOverwrite : GCP_SPointerBase long long int relTimeStamp() const { return m_relTimeStamp; } bool hasBlockHeader() const { return !m_blockHeaderIncomplete.isEmpty(); } BlockHeaderIncomplete const& header() const { return m_blockHeaderIncomplete; } + bool forceNoWithdrawalsRLP() const { return m_forceNoWithdrawalsRLP; } private: + bool m_forceNoWithdrawalsRLP = false; bool m_hasRelTimeStamp = false; long long int m_relTimeStamp; spBlockHeaderIncomplete m_blockHeaderIncomplete; diff --git a/retesteth/testStructures/types/BlockchainTests/Filler/BlockchainTestFillerEnv.cpp b/retesteth/testStructures/types/BlockchainTests/Filler/BlockchainTestFillerEnv.cpp index 1657a68c2..a6ad1f02b 100644 --- a/retesteth/testStructures/types/BlockchainTests/Filler/BlockchainTestFillerEnv.cpp +++ b/retesteth/testStructures/types/BlockchainTests/Filler/BlockchainTestFillerEnv.cpp @@ -1,6 +1,7 @@ #include "BlockchainTestFillerEnv.h" #include #include +#include using namespace std; using namespace dataobject; using namespace test::teststruct; @@ -89,6 +90,35 @@ void requireMergeBlockchainHeader(spDataObject const& _data) {"uncleHash", {{DataType::String}, jsonField::Optional}}}); } +void requireShanghaiBlockchainHeader(spDataObject const& _data) +{ + REQUIRE_JSONFIELDS(_data, "GenesisBlockHeader(BlockchainTestFillerEnvShanghai) " + _data->getKey(), + {{"bloom", {{DataType::String}, jsonField::Optional}}, + {"logsBloom", {{DataType::String}, jsonField::Optional}}, + {"coinbase", {{DataType::String}, jsonField::Optional}}, + {"author", {{DataType::String}, jsonField::Optional}}, + {"miner", {{DataType::String}, jsonField::Optional}}, + {"difficulty", {{DataType::String}, jsonField::Required}}, + {"extraData", {{DataType::String}, jsonField::Required}}, + {"gasLimit", {{DataType::String}, jsonField::Required}}, + {"baseFeePerGas", {{DataType::String}, jsonField::Required}}, + {"gasUsed", {{DataType::String}, jsonField::Required}}, + {"hash", {{DataType::String}, jsonField::Optional}}, + {"mixHash", {{DataType::String}, jsonField::Optional}}, + {"nonce", {{DataType::String}, jsonField::Optional}}, + {"number", {{DataType::String}, jsonField::Required}}, + {"parentHash", {{DataType::String}, jsonField::Required}}, + {"receiptTrie", {{DataType::String}, jsonField::Optional}}, + {"receiptsRoot", {{DataType::String}, jsonField::Optional}}, + {"stateRoot", {{DataType::String}, jsonField::Required}}, + {"timestamp", {{DataType::String}, jsonField::Required}}, + {"transactionsTrie", {{DataType::String}, jsonField::Optional}}, + {"transactionsRoot", {{DataType::String}, jsonField::Optional}}, + {"withdrawalsRoot", {{DataType::String}, jsonField::Required}}, + {"sha3Uncles", {{DataType::String}, jsonField::Optional}}, + {"uncleHash", {{DataType::String}, jsonField::Optional}}}); +} + void convertDecFieldsToHex(spDataObject& _data) { (*_data).atKeyUnsafe("coinbase").performModifier(mod_valueInsertZeroXPrefix); @@ -119,9 +149,7 @@ spDataObject formatRawDataToRPCformat(spDataObject& _data) } -namespace test -{ -namespace teststruct +namespace test::teststruct { void BlockchainTestFillerEnv::initializeCommonFields(spDataObject const& _data, SealEngine _sEngine) @@ -136,8 +164,8 @@ void BlockchainTestFillerEnv::initializeCommonFields(spDataObject const& _data, throw test::UpwardsException("currentGasLimit must be < 0x7fffffffffffffff"); if (_sEngine == SealEngine::NoProof) { - m_currentNonce = spFH8(new FH8(FH8::zero())); - m_currentMixHash = spFH32(new FH32(FH32::zero())); + m_currentNonce = spFH8(FH8::zero().copy()); + m_currentMixHash = spFH32(FH32::zero().copy()); } else { @@ -149,6 +177,12 @@ void BlockchainTestFillerEnv::initializeCommonFields(spDataObject const& _data, m_currentBaseFee = spVALUE(new VALUE(DataObject("0x10"))); auto const& difficulty = m_currentDifficulty->asString(); m_currentRandom = spFH32(new FH32(dev::toCompactHexPrefixed(dev::u256(difficulty), 32))); + m_currentWithdrawalsRoot = spFH32(new FH32(DataObject(C_WITHDRAWALS_EMPTY_ROOT))); +} + +void BlockchainTestFillerEnvShanghai::initializeShanghaiFields(DataObject const& _data) +{ + m_currentWithdrawalsRoot = spFH32(new FH32(_data.atKey("withdrawalsRoot"))); } void BlockchainTestFillerEnvMerge::initializeMergeFields(DataObject const& _data) @@ -168,6 +202,24 @@ void BlockchainTestFillerEnvLegacy::initializeLegacyFields(DataObject const& _da m_currentDifficulty = spVALUE(new VALUE(_data.atKey("difficulty"))); } +BlockchainTestFillerEnvShanghai::BlockchainTestFillerEnvShanghai(spDataObjectMove _data, SealEngine _sEngine) + : BlockchainTestFillerEnvMerge() +{ + try { + m_raw = _data.getPointer(); + requireShanghaiBlockchainHeader(m_raw); + convertDecFieldsToHex(m_raw); + initializeCommonFields(m_raw, _sEngine); + initializeMergeFields(m_raw); + initializeShanghaiFields(m_raw); + m_raw = formatRawDataToRPCformat(m_raw); + } + catch (std::exception const& _ex) + { + throw UpwardsException(string("BlockchainTestFillerEnv(Shanghai) convertion error: ") + _ex.what()); + } +} + BlockchainTestFillerEnvMerge::BlockchainTestFillerEnvMerge(spDataObjectMove _data, SealEngine _sEngine) { try { @@ -217,5 +269,23 @@ BlockchainTestFillerEnvLegacy::BlockchainTestFillerEnvLegacy(spDataObjectMove _d } } +BlockchainTestFillerEnv* readBlockchainFillerTestEnv(spDataObjectMove _data, SealEngine _sEngine) +{ + auto const& data = _data.getPointer(); + if (data->count("baseFeePerGas")) + { + spDataObject diff = data->atKey("difficulty").copy(); + (*diff).performModifier(mod_valueToCompactEvenHexPrefixed); + if (VALUE(diff->asString()) != 0) + return new BlockchainTestFillerEnv1559(_data, _sEngine); + else + { + if (data->count("withdrawalsRoot")) + return new BlockchainTestFillerEnvShanghai(_data, _sEngine); + else + return new BlockchainTestFillerEnvMerge(_data, _sEngine); + } + } + return new BlockchainTestFillerEnvLegacy(_data, _sEngine); +} } // namespace teststruct -} // namespace test diff --git a/retesteth/testStructures/types/BlockchainTests/Filler/BlockchainTestFillerEnv.h b/retesteth/testStructures/types/BlockchainTests/Filler/BlockchainTestFillerEnv.h index 021dcc1ff..683e1b797 100644 --- a/retesteth/testStructures/types/BlockchainTests/Filler/BlockchainTestFillerEnv.h +++ b/retesteth/testStructures/types/BlockchainTests/Filler/BlockchainTestFillerEnv.h @@ -2,9 +2,7 @@ #include #include -namespace test -{ -namespace teststruct +namespace test::teststruct { // Blockchain test does not have Env section @@ -19,12 +17,13 @@ struct BlockchainTestFillerEnv : StateTestEnvBase }; -struct BlockchainTestFillerEnvMerge : BlockchainTestFillerEnv + +struct BlockchainTestFillerEnvLegacy : BlockchainTestFillerEnv { - BlockchainTestFillerEnvMerge(spDataObjectMove _data, SealEngine _sEngine); + BlockchainTestFillerEnvLegacy(spDataObjectMove _data, SealEngine _sEngine); protected: - void initializeMergeFields(DataObject const&); + void initializeLegacyFields(DataObject const&); private: void define() const override {} }; @@ -40,20 +39,29 @@ struct BlockchainTestFillerEnv1559 : BlockchainTestFillerEnv }; -struct BlockchainTestFillerEnvLegacy : BlockchainTestFillerEnv +struct BlockchainTestFillerEnvMerge : BlockchainTestFillerEnv { - BlockchainTestFillerEnvLegacy(spDataObjectMove _data, SealEngine _sEngine); + BlockchainTestFillerEnvMerge(spDataObjectMove _data, SealEngine _sEngine); protected: - void initializeLegacyFields(DataObject const&); + void initializeMergeFields(DataObject const&); + BlockchainTestFillerEnvMerge(){}; private: void define() const override {} +}; + +struct BlockchainTestFillerEnvShanghai : BlockchainTestFillerEnvMerge +{ + BlockchainTestFillerEnvShanghai(spDataObjectMove _data, SealEngine _sEngine); +protected: + void initializeShanghaiFields(DataObject const&); +private: + void define() const override {} }; typedef GCP_SPointer spBlockchainTestFillerEnv; - +BlockchainTestFillerEnv* readBlockchainFillerTestEnv(spDataObjectMove _data, SealEngine _sEngine); } // namespace teststruct -} // namespace test diff --git a/retesteth/testStructures/types/BlockchainTests/Filler/BlockchainTestFillerTransaction.h b/retesteth/testStructures/types/BlockchainTests/Filler/BlockchainTestFillerTransaction.h index e0158d278..230e00e96 100644 --- a/retesteth/testStructures/types/BlockchainTests/Filler/BlockchainTestFillerTransaction.h +++ b/retesteth/testStructures/types/BlockchainTests/Filler/BlockchainTestFillerTransaction.h @@ -1,5 +1,5 @@ #pragma once -#include "../../Ethereum/Transaction.h" +#include "../../Ethereum/Transactions/Transaction.h" #include namespace test { diff --git a/retesteth/testStructures/types/BlockchainTests/Filler/BlockchainTestFillerUncle.h b/retesteth/testStructures/types/BlockchainTests/Filler/BlockchainTestFillerUncle.h index 30d11cd57..614cde424 100644 --- a/retesteth/testStructures/types/BlockchainTests/Filler/BlockchainTestFillerUncle.h +++ b/retesteth/testStructures/types/BlockchainTests/Filler/BlockchainTestFillerUncle.h @@ -1,7 +1,7 @@ #pragma once #include "../../../basetypes.h" #include "../../../configs/FORK.h" -#include "../../Ethereum/BlockHeaderIncomplete.h" +#include "../../Ethereum/Blocks/BlockHeaderIncomplete.h" #include namespace test diff --git a/retesteth/testStructures/types/BlockchainTests/Filler/BlockchainTestFillerWithdrawal.cpp b/retesteth/testStructures/types/BlockchainTests/Filler/BlockchainTestFillerWithdrawal.cpp new file mode 100644 index 000000000..a4d70d1f1 --- /dev/null +++ b/retesteth/testStructures/types/BlockchainTests/Filler/BlockchainTestFillerWithdrawal.cpp @@ -0,0 +1,36 @@ +#include "BlockchainTestFillerWithdrawal.h" +#include +#include +using namespace std; +using namespace test; + +namespace test::teststruct +{ + +BlockchainTestFillerWithdrawal::BlockchainTestFillerWithdrawal(spDataObjectMove _data) +{ + try + { + auto record = _data.getPointer(); + REQUIRE_JSONFIELDS(record, "FillerBlock::WithdrawalRecord ", + {{"index", {{DataType::String}, jsonField::Required}}, + {"validatorIndex", {{DataType::String}, jsonField::Required}}, + {"address", {{DataType::String}, jsonField::Required}}, + {"amount", {{DataType::String}, jsonField::Required}}}); + + #define MODIFY(INDEX, MOD) \ + record.getContent().atKeyUnsafe(INDEX).performModifier(MOD); + + MODIFY("index", mod_valueToCompactEvenHexPrefixed) + MODIFY("validatorIndex", mod_valueToCompactEvenHexPrefixed) + MODIFY("amount", mod_valueToCompactEvenHexPrefixed) + + m_withdrawal = spWithdrawal(new Withdrawal(record)); + } + catch (std::exception const& _ex) + { + throw UpwardsException(string("Withdrawals convertion error: ") + _ex.what() + "\n"); + } +} + +} diff --git a/retesteth/testStructures/types/BlockchainTests/Filler/BlockchainTestFillerWithdrawal.h b/retesteth/testStructures/types/BlockchainTests/Filler/BlockchainTestFillerWithdrawal.h new file mode 100644 index 000000000..c5c163c6e --- /dev/null +++ b/retesteth/testStructures/types/BlockchainTests/Filler/BlockchainTestFillerWithdrawal.h @@ -0,0 +1,14 @@ +#pragma once +#include +#include +namespace test::teststruct +{ +struct BlockchainTestFillerWithdrawal +{ + BlockchainTestFillerWithdrawal(){}; + BlockchainTestFillerWithdrawal(dataobject::spDataObjectMove); + spWithdrawal const& withdrawal() const { return m_withdrawal; } +private: + spWithdrawal m_withdrawal; +}; +} // namespace test diff --git a/retesteth/testStructures/types/DifficultyTests/DifficultyTest.cpp b/retesteth/testStructures/types/DifficultyTests/DifficultyTest.cpp index 8d21de443..93c41a2a6 100644 --- a/retesteth/testStructures/types/DifficultyTests/DifficultyTest.cpp +++ b/retesteth/testStructures/types/DifficultyTests/DifficultyTest.cpp @@ -18,7 +18,7 @@ DifficultyTest::DifficultyTest(spDataObject& _data) for (auto& el : _data.getContent().getSubObjectsUnsafe()) { TestOutputHelper::get().setCurrentTestInfo(TestInfo("DifficultyTestFiller", el->getKey())); - m_tests.push_back(DifficultyTestInFilled(el)); + m_tests.emplace_back(DifficultyTestInFilled(el)); } } catch (DataObjectException const& _ex) @@ -46,7 +46,7 @@ DifficultyTestInFilled::DifficultyTestInFilled(spDataObject& _data) TestVector a; string const& network = subObjects.at(i)->getKey(); for (auto const& el : subObjects.at(i)->getSubObjects()) - a.push_back(DifficultyTestVector(el)); + a.emplace_back(DifficultyTestVector(el)); m_testVectors.emplace(network, a); } } diff --git a/retesteth/testStructures/types/DifficultyTests/DifficultyTestFiller.cpp b/retesteth/testStructures/types/DifficultyTests/DifficultyTestFiller.cpp index a2dbc76ac..d5fdca39d 100644 --- a/retesteth/testStructures/types/DifficultyTests/DifficultyTestFiller.cpp +++ b/retesteth/testStructures/types/DifficultyTests/DifficultyTestFiller.cpp @@ -21,7 +21,7 @@ DifficultyTestFiller::DifficultyTestFiller(spDataObject& _data) for (auto& el : _data.getContent().getSubObjectsUnsafe()) { TestOutputHelper::get().setCurrentTestInfo(TestInfo("TransactionTestFiller", el->getKey())); - m_tests.push_back(DifficultyTestInFiller(el)); + m_tests.emplace_back(DifficultyTestInFiller(el)); } } catch (DataObjectException const& _ex) @@ -60,7 +60,7 @@ DifficultyTestInFiller::DifficultyTestInFiller(spDataObject& _data) m_parentDiffD = DifficultyRange(_data.getContent().atKeyUnsafe("parentDifficutly")); for (auto const& el : _data->atKey("hasUncles").getSubObjects()) - m_uncles.push_back(el.getCContent().asInt()); + m_uncles.emplace_back(el.getCContent().asInt()); if (m_uncles.size() > 2) throw test::UpwardsException("hasUncles size is limited to 2!"); @@ -79,7 +79,7 @@ DifficultyRange::DifficultyRange(DataObject& _data) for (auto& el : _data.getSubObjectsUnsafe()) { mod_valueToCompactEvenHexPrefixed(el.getContent()); - m_vector.push_back(spVALUE(new VALUE(el))); + m_vector.emplace_back(spVALUE(new VALUE(el))); } } else if (_data.type() == DataType::String) @@ -119,7 +119,7 @@ DifficultyRange::DifficultyRange(DataObject& _data) throw test::UpwardsException("Parsing DifficultyRange `" + _data.getKey() + "` has too many steps (>100): " + steps.asDecString()); for (VALUE i = vBegin; i <= vEnd; i+= vStep) - m_vector.push_back(spVALUE(new VALUE(i.asBigInt()))); + m_vector.emplace_back(spVALUE(new VALUE(i.asBigInt()))); } else throw test::UpwardsException("Parsing DifficultyRange `" + _data.getKey() + "` has unexpected datatype!"); diff --git a/retesteth/testStructures/types/Ethereum/BlockHeaderReader.cpp b/retesteth/testStructures/types/Ethereum/BlockHeaderReader.cpp deleted file mode 100644 index 68a590059..000000000 --- a/retesteth/testStructures/types/Ethereum/BlockHeaderReader.cpp +++ /dev/null @@ -1,80 +0,0 @@ -#include "BlockHeaderReader.h" - -using namespace std; -using namespace dataobject; -using namespace test::teststruct; - -namespace { -bool isHeaderMerge(DataObject const& _filledData) -{ - string uncleHashName = "sha3Uncles"; - if (!_filledData.count(uncleHashName)) - uncleHashName = "uncleHash"; - - // https://eips.ethereum.org/EIPS/eip-3675 - static const FH32 mergeUncleHash("0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"); - if (VALUE(_filledData.atKey("difficulty")) == 0 - && FH32(_filledData.atKey(uncleHashName)) == mergeUncleHash - && FH8(_filledData.atKey("nonce")) == FH8::zero()) - { - return true; - } - return false; -} - -bool isHeaderMerge(dev::RLP const& _rlp) -{ - // 0 - parentHash // 8 - number - // 1 - uncleHash // 9 - gasLimit - // 2 - coinbase // 10 - gasUsed - // 3 - stateRoot // 11 - timestamp - // 4 - transactionTrie // 12 - extraData - // 5 - receiptTrie // 13 - mixHash - // 6 - bloom // 14 - nonce - // 7 - difficulty // 15 - baseFee - - // https://eips.ethereum.org/EIPS/eip-3675 - static const FH32 mergeUncleHash("0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"); - if (VALUE(_rlp[7]) == 0 - && FH32(_rlp[1]) == mergeUncleHash - && FH8(_rlp[14]) == FH8::zero()) - { - return true; - } - return false; -} - -} - -namespace test -{ -namespace teststruct -{ -spBlockHeader readBlockHeader(dev::RLP const& _rlp) -{ - if (_rlp.itemCount() == 15) - return spBlockHeader(new BlockHeaderLegacy(_rlp)); - else - { - if (isHeaderMerge(_rlp)) - return spBlockHeader(new BlockHeaderMerge(_rlp)); - else - return spBlockHeader(new BlockHeader1559(_rlp)); - } -} - -spBlockHeader readBlockHeader(DataObject const& _filledData) -{ - if (_filledData.count("baseFeePerGas")) - { - if (isHeaderMerge(_filledData)) - return spBlockHeader(new BlockHeaderMerge(_filledData)); - else - return spBlockHeader(new BlockHeader1559(_filledData)); - } - else - return spBlockHeader(new BlockHeaderLegacy(_filledData)); -} - -} // namespace teststruct -} // namespace test diff --git a/retesteth/testStructures/types/Ethereum/BlockHeaderReader.h b/retesteth/testStructures/types/Ethereum/BlockHeaderReader.h deleted file mode 100644 index f3c5e63f5..000000000 --- a/retesteth/testStructures/types/Ethereum/BlockHeaderReader.h +++ /dev/null @@ -1,12 +0,0 @@ -#include "BlockHeader.h" -#include "BlockHeader1559.h" -#include "BlockHeaderLegacy.h" -#include "BlockHeaderMerge.h" - - -namespace test::teststruct -{ -spBlockHeader readBlockHeader(DataObject const& _data); -spBlockHeader readBlockHeader(dev::RLP const& _rlp); - -} // namespace teststruct diff --git a/retesteth/testStructures/types/Ethereum/BlockHeader.cpp b/retesteth/testStructures/types/Ethereum/Blocks/BlockHeader.cpp similarity index 88% rename from retesteth/testStructures/types/Ethereum/BlockHeader.cpp rename to retesteth/testStructures/types/Ethereum/Blocks/BlockHeader.cpp index 269110b23..db55f5fba 100644 --- a/retesteth/testStructures/types/Ethereum/BlockHeader.cpp +++ b/retesteth/testStructures/types/Ethereum/Blocks/BlockHeader.cpp @@ -14,6 +14,8 @@ std::string BlockHeader::TypeToString(BlockType _t) return "BlockHeaderLegacy"; case BlockType::BlockHeaderMerge: return "BlockHeaderMerge"; + case BlockType::BlockHeaderShanghai: + return "BlockHeaderShanghai"; default: return "UnparsedBlockType"; } @@ -30,6 +32,8 @@ std::string BlockHeader::BlockTypeToString(BlockType _bl) return "BlockHeaderLegacy"; case BlockType::BlockHeaderMerge: return "BlockHeaderMerge"; + case BlockType::BlockHeaderShanghai: + return "BlockHeaderShanghai"; default: return "BlockHeaderUndefined"; }; diff --git a/retesteth/testStructures/types/Ethereum/BlockHeader.h b/retesteth/testStructures/types/Ethereum/Blocks/BlockHeader.h similarity index 97% rename from retesteth/testStructures/types/Ethereum/BlockHeader.h rename to retesteth/testStructures/types/Ethereum/Blocks/BlockHeader.h index d87f3c5bb..66770f10b 100644 --- a/retesteth/testStructures/types/Ethereum/BlockHeader.h +++ b/retesteth/testStructures/types/Ethereum/Blocks/BlockHeader.h @@ -1,5 +1,5 @@ #pragma once -#include "../../basetypes.h" +#include #include #include @@ -9,7 +9,8 @@ enum class BlockType { BlockHeaderLegacy, BlockHeader1559, - BlockHeaderMerge + BlockHeaderMerge, + BlockHeaderShanghai }; // Ethereum blockheader interface diff --git a/retesteth/testStructures/types/Ethereum/BlockHeader1559.cpp b/retesteth/testStructures/types/Ethereum/Blocks/BlockHeader1559.cpp similarity index 95% rename from retesteth/testStructures/types/Ethereum/BlockHeader1559.cpp rename to retesteth/testStructures/types/Ethereum/Blocks/BlockHeader1559.cpp index 558dbec55..cba48a0ea 100644 --- a/retesteth/testStructures/types/Ethereum/BlockHeader1559.cpp +++ b/retesteth/testStructures/types/Ethereum/Blocks/BlockHeader1559.cpp @@ -70,8 +70,8 @@ void BlockHeader1559::fromData(DataObject const& _data) else { ETH_DC_MESSAGE(DC::TESTLOG, "BlockHeader `mixHash` is not defined. Using default `0x00..00` value!"); - m_mixHash = spFH32(new FH32(FH32::zero())); - m_nonce = spFH8(new FH8(FH8::zero())); + m_mixHash = spFH32(FH32::zero().copy()); + m_nonce = spFH8(FH8::zero().copy()); } m_number = spVALUE(new VALUE(_data.atKey("number"))); @@ -181,7 +181,9 @@ BlockHeader1559& BlockHeader1559::castFrom(BlockHeader& _from) { try { - if (_from.type() != BlockType::BlockHeader1559 && _from.type() != BlockType::BlockHeaderMerge) + if (_from.type() != BlockType::BlockHeader1559 && + _from.type() != BlockType::BlockHeaderMerge && + _from.type() != BlockType::BlockHeaderShanghai) ETH_FAIL_MESSAGE("BlockHeader1559::castFrom() got wrong block type! `" + BlockHeader::TypeToString(_from.type())); return dynamic_cast(_from); } @@ -196,7 +198,9 @@ BlockHeader1559 const& BlockHeader1559::castFrom(spBlockHeader const& _from) { try { - if (_from->type() != BlockType::BlockHeader1559 && _from->type() != BlockType::BlockHeaderMerge) + if (_from->type() != BlockType::BlockHeader1559 && + _from->type() != BlockType::BlockHeaderMerge && + _from->type() != BlockType::BlockHeaderShanghai) ETH_FAIL_MESSAGE("BlockHeader1559::castFrom() got wrong block type! `" + BlockHeader::TypeToString(_from->type())); return dynamic_cast(_from.getCContent()); } diff --git a/retesteth/testStructures/types/Ethereum/BlockHeader1559.h b/retesteth/testStructures/types/Ethereum/Blocks/BlockHeader1559.h similarity index 95% rename from retesteth/testStructures/types/Ethereum/BlockHeader1559.h rename to retesteth/testStructures/types/Ethereum/Blocks/BlockHeader1559.h index c75ea9d84..0e251ec93 100644 --- a/retesteth/testStructures/types/Ethereum/BlockHeader1559.h +++ b/retesteth/testStructures/types/Ethereum/Blocks/BlockHeader1559.h @@ -1,5 +1,5 @@ #pragma once -#include "../../basetypes.h" +#include #include "BlockHeader.h" #include #include diff --git a/retesteth/testStructures/types/Ethereum/BlockHeaderIncomplete.cpp b/retesteth/testStructures/types/Ethereum/Blocks/BlockHeaderIncomplete.cpp similarity index 92% rename from retesteth/testStructures/types/Ethereum/BlockHeaderIncomplete.cpp rename to retesteth/testStructures/types/Ethereum/Blocks/BlockHeaderIncomplete.cpp index 3dec76076..9c700a1e5 100644 --- a/retesteth/testStructures/types/Ethereum/BlockHeaderIncomplete.cpp +++ b/retesteth/testStructures/types/Ethereum/Blocks/BlockHeaderIncomplete.cpp @@ -18,6 +18,7 @@ BlockHeaderIncomplete::BlockHeaderIncomplete(DataObject const& _data) {"extraData", {{DataType::String}, jsonField::Optional}}, {"gasLimit", {{DataType::String}, jsonField::Optional}}, {"baseFeePerGas", {{DataType::String}, jsonField::Optional}}, + {"withdrawalsRoot", {{DataType::String}, jsonField::Optional}}, {"gasUsed", {{DataType::String}, jsonField::Optional}}, {"hash", {{DataType::String}, jsonField::Optional}}, {"mixHash", {{DataType::String}, jsonField::Optional}}, @@ -29,6 +30,7 @@ BlockHeaderIncomplete::BlockHeaderIncomplete(DataObject const& _data) {"timestamp", {{DataType::String}, jsonField::Optional}}, {"transactionsTrie", {{DataType::String}, jsonField::Optional}}, {"remove", {{DataType::Array}, jsonField::Optional}}, + {"forceNoWithdrawalsRLP", {{DataType::String}, jsonField::Optional}}, {"uncleHash", {{DataType::String}, jsonField::Optional}}}); string const akey = _data.count("author") ? "author" : "coinbase"; @@ -78,6 +80,9 @@ BlockHeaderIncomplete::BlockHeaderIncomplete(DataObject const& _data) if (_data.count("baseFeePerGas")) m_baseFee = spVALUE(new VALUE(_data.atKey("baseFeePerGas"))); + if (_data.count("withdrawalsRoot")) + m_withdrawalsRoot = spFH32(new FH32(_data.atKey("withdrawalsRoot"))); + if (_data.count("remove")) test::parseJsonStrValueIntoSet(_data.atKey("remove"), m_removeKeys); @@ -85,7 +90,8 @@ BlockHeaderIncomplete::BlockHeaderIncomplete(DataObject const& _data) !m_gasLimit.isEmpty() || !m_gasUsed.isEmpty() || !m_hash.isEmpty() || !m_logsBloom.isEmpty() || !m_mixHash.isEmpty() || !m_nonce.isEmpty() || !m_number.isEmpty() || !m_parentHash.isEmpty() || !m_receiptsRoot.isEmpty() || !m_sha3Uncles.isEmpty() || !m_stateRoot.isEmpty() || - !m_timestamp.isEmpty() || !m_transactionsRoot.isEmpty() || !m_baseFee.isEmpty(); + !m_timestamp.isEmpty() || !m_transactionsRoot.isEmpty() || !m_baseFee.isEmpty() || + !m_withdrawalsRoot.isEmpty(); ETH_ERROR_REQUIRE_MESSAGE(hasAtLeastOneField, "BlockHeaderIncomplete must have at least one field!"); } @@ -128,6 +134,9 @@ spBlockHeader BlockHeaderIncomplete::overwriteBlockHeader(spBlockHeader const& _ overwrite["hash"] = m_hash->asString(); if (!m_baseFee.isEmpty()) overwrite["baseFeePerGas"] = m_baseFee->asString(); + if (!m_withdrawalsRoot.isEmpty()) + overwrite["withdrawalsRoot"] = m_withdrawalsRoot->asString(); + overwrite.removeKey("updatePoW"); // deprecated key for (auto const& el : m_removeKeys) overwrite.removeKey(el); diff --git a/retesteth/testStructures/types/Ethereum/BlockHeaderIncomplete.h b/retesteth/testStructures/types/Ethereum/Blocks/BlockHeaderIncomplete.h similarity index 91% rename from retesteth/testStructures/types/Ethereum/BlockHeaderIncomplete.h rename to retesteth/testStructures/types/Ethereum/Blocks/BlockHeaderIncomplete.h index 203b71af2..ca7aaf1e8 100644 --- a/retesteth/testStructures/types/Ethereum/BlockHeaderIncomplete.h +++ b/retesteth/testStructures/types/Ethereum/Blocks/BlockHeaderIncomplete.h @@ -1,5 +1,5 @@ #pragma once -#include "../../basetypes.h" +#include #include "BlockHeader.h" #include #include @@ -38,6 +38,9 @@ struct BlockHeaderIncomplete : GCP_SPointerBase // 1559 block spVALUE m_baseFee; + // Shanghai block + spFH32 m_withdrawalsRoot; + // Overwrite fields std::set m_removeKeys; }; diff --git a/retesteth/testStructures/types/Ethereum/BlockHeaderLegacy.cpp b/retesteth/testStructures/types/Ethereum/Blocks/BlockHeaderLegacy.cpp similarity index 98% rename from retesteth/testStructures/types/Ethereum/BlockHeaderLegacy.cpp rename to retesteth/testStructures/types/Ethereum/Blocks/BlockHeaderLegacy.cpp index 49ef4896c..68785a606 100644 --- a/retesteth/testStructures/types/Ethereum/BlockHeaderLegacy.cpp +++ b/retesteth/testStructures/types/Ethereum/Blocks/BlockHeaderLegacy.cpp @@ -66,8 +66,8 @@ void BlockHeaderLegacy::fromData(DataObject const& _data) else { ETH_DC_MESSAGE(DC::TESTLOG, "BlockHeader `mixHash` is not defined. Using default `0x00..00` value!"); - m_mixHash = spFH32(new FH32(FH32::zero())); - m_nonce = spFH8(new FH8(FH8::zero())); + m_mixHash = spFH32(FH32::zero().copy()); + m_nonce = spFH8(FH8::zero().copy()); } m_number = spVALUE(new VALUE(_data.atKey("number"))); diff --git a/retesteth/testStructures/types/Ethereum/BlockHeaderLegacy.h b/retesteth/testStructures/types/Ethereum/Blocks/BlockHeaderLegacy.h similarity index 94% rename from retesteth/testStructures/types/Ethereum/BlockHeaderLegacy.h rename to retesteth/testStructures/types/Ethereum/Blocks/BlockHeaderLegacy.h index ae37db4cb..f63525057 100644 --- a/retesteth/testStructures/types/Ethereum/BlockHeaderLegacy.h +++ b/retesteth/testStructures/types/Ethereum/Blocks/BlockHeaderLegacy.h @@ -1,5 +1,5 @@ #pragma once -#include "../../basetypes.h" +#include #include "BlockHeader.h" #include #include diff --git a/retesteth/testStructures/types/Ethereum/BlockHeaderMerge.cpp b/retesteth/testStructures/types/Ethereum/Blocks/BlockHeaderMerge.cpp similarity index 80% rename from retesteth/testStructures/types/Ethereum/BlockHeaderMerge.cpp rename to retesteth/testStructures/types/Ethereum/Blocks/BlockHeaderMerge.cpp index b76722a64..d2dcfdc11 100644 --- a/retesteth/testStructures/types/Ethereum/BlockHeaderMerge.cpp +++ b/retesteth/testStructures/types/Ethereum/Blocks/BlockHeaderMerge.cpp @@ -10,7 +10,8 @@ BlockHeaderMerge& BlockHeaderMerge::castFrom(BlockHeader& _from) { try { - if (_from.type() != BlockType::BlockHeaderMerge) + if (_from.type() != BlockType::BlockHeaderMerge && + _from.type() != BlockType::BlockHeaderShanghai) ETH_FAIL_MESSAGE("BlockHeaderMerge::castFrom() got wrong block type!"); return dynamic_cast(_from); } @@ -25,7 +26,8 @@ BlockHeaderMerge const& BlockHeaderMerge::castFrom(spBlockHeader const& _from) { try { - if (_from->type() != BlockType::BlockHeaderMerge) + if (_from->type() != BlockType::BlockHeaderMerge && + _from->type() != BlockType::BlockHeaderShanghai) ETH_FAIL_MESSAGE("BlockHeaderMerge::castFrom() got wrong block type!"); return dynamic_cast(_from.getCContent()); } diff --git a/retesteth/testStructures/types/Ethereum/BlockHeaderMerge.h b/retesteth/testStructures/types/Ethereum/Blocks/BlockHeaderMerge.h similarity index 93% rename from retesteth/testStructures/types/Ethereum/BlockHeaderMerge.h rename to retesteth/testStructures/types/Ethereum/Blocks/BlockHeaderMerge.h index 3ffd49283..8e874ae83 100644 --- a/retesteth/testStructures/types/Ethereum/BlockHeaderMerge.h +++ b/retesteth/testStructures/types/Ethereum/Blocks/BlockHeaderMerge.h @@ -1,5 +1,5 @@ #pragma once -#include "../../basetypes.h" +#include #include "BlockHeader1559.h" #include #include diff --git a/retesteth/testStructures/types/Ethereum/Blocks/BlockHeaderReader.cpp b/retesteth/testStructures/types/Ethereum/Blocks/BlockHeaderReader.cpp new file mode 100644 index 000000000..34984bbd0 --- /dev/null +++ b/retesteth/testStructures/types/Ethereum/Blocks/BlockHeaderReader.cpp @@ -0,0 +1,162 @@ +#include "BlockHeaderReader.h" +#include + +using namespace std; +using namespace dataobject; +using namespace test::teststruct; + +namespace { + +bool isHeaderShanghai(DataObject const& _filledData) +{ + if (_filledData.count("withdrawalsRoot")) + return true; + return false; +} + +bool isHeaderMerge(DataObject const& _filledData) +{ + if (!_filledData.count("baseFeePerGas") || _filledData.count("withdrawalsRoot")) + return false; + + string uncleHashName = "sha3Uncles"; + if (!_filledData.count(uncleHashName)) + uncleHashName = "uncleHash"; + + // https://eips.ethereum.org/EIPS/eip-3675 + static const FH32 mergeUncleHash("0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"); + if (VALUE(_filledData.atKey("difficulty")) == 0 + && FH32(_filledData.atKey(uncleHashName)) == mergeUncleHash + && FH8(_filledData.atKey("nonce")) == FH8::zero()) + { + return true; + } + return false; +} + +bool isHeader1559(DataObject const& _filledData) +{ + if (_filledData.count("baseFeePerGas") && !isHeaderMerge(_filledData) + && !_filledData.count("withdrawalsRoot")) + return true; + return false; +} + +bool isHeaderLegacy(DataObject const& _filledData) +{ + if (!_filledData.count("baseFeePerGas")) + return true; + return false; +} + +bool isHeaderShanghai(dev::RLP const& _rlp) +{ + return (_rlp.itemCount() == 17); +} + + +bool isHeaderMerge(dev::RLP const& _rlp) +{ + if (_rlp.itemCount() != 16) + return false; + // 0 - parentHash // 8 - number + // 1 - uncleHash // 9 - gasLimit + // 2 - coinbase // 10 - gasUsed + // 3 - stateRoot // 11 - timestamp + // 4 - transactionTrie // 12 - extraData + // 5 - receiptTrie // 13 - mixHash + // 6 - bloom // 14 - nonce + // 7 - difficulty // 15 - baseFee + + // https://eips.ethereum.org/EIPS/eip-3675 + static const FH32 mergeUncleHash("0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"); + if (VALUE(_rlp[7]) == 0 + && FH32(_rlp[1]) == mergeUncleHash + && FH8(_rlp[14]) == FH8::zero()) + { + return true; + } + return false; +} + +bool isHeader1559(dev::RLP const& _rlp) +{ + return (_rlp.itemCount() == 16 && !isHeaderMerge(_rlp)); +} + +bool isHeaderLegacy(dev::RLP const& _rlp) +{ + return (_rlp.itemCount() == 15); +} + +} + +namespace test::teststruct +{ + +spBlockHeader readBlockHeader(dev::RLP const& _rlp) +{ + if (isHeaderLegacy(_rlp)) + return spBlockHeader(new BlockHeaderLegacy(_rlp)); + + if (isHeader1559(_rlp)) + return spBlockHeader(new BlockHeader1559(_rlp)); + + if (isHeaderMerge(_rlp)) + return spBlockHeader(new BlockHeaderMerge(_rlp)); + + if (isHeaderShanghai(_rlp)) + return spBlockHeader(new BlockHeaderShanghai(_rlp)); + + ETH_ERROR_MESSAGE("readBlockHeader: unknown block type! /n" + dev::asString(_rlp.toBytes())); + return spBlockHeader(new BlockHeaderLegacy(_rlp)); +} + +spBlockHeader readBlockHeader(DataObject const& _filledData) +{ + if (isHeaderLegacy(_filledData)) + return spBlockHeader(new BlockHeaderLegacy(_filledData)); + + if (isHeader1559(_filledData)) + return spBlockHeader(new BlockHeader1559(_filledData)); + + if (isHeaderMerge(_filledData)) + return spBlockHeader(new BlockHeaderMerge(_filledData)); + + if (isHeaderShanghai(_filledData)) + return spBlockHeader(new BlockHeaderShanghai(_filledData)); + + ETH_ERROR_MESSAGE("readBlockHeader: unknown block type! /n" + _filledData.asJson()); + return spBlockHeader(new BlockHeaderLegacy(_filledData)); +} + +bool isBlockPoS(BlockHeader const& _header) +{ + return isBlockExportCurrentRandom(_header); +} + +bool isBlockExportCurrentRandom(BlockHeader const& _header) +{ + return _header.type() == BlockType::BlockHeaderMerge + || _header.type() == BlockType::BlockHeaderShanghai; +} + +bool isBlockExportWithdrawals(BlockHeader const& _header) +{ + return _header.type() == BlockType::BlockHeaderShanghai; +} + +bool isBlockExportBasefee(BlockHeader const& _header) +{ + return _header.type() == BlockType::BlockHeader1559 + || _header.type() == BlockType::BlockHeaderMerge + || _header.type() == BlockType::BlockHeaderShanghai; +} + +bool isBlockExportDifficulty(BlockHeader const& _header) +{ + return _header.type() == BlockType::BlockHeaderLegacy + || _header.type() == BlockType::BlockHeader1559; +} + +} // namespace teststruct diff --git a/retesteth/testStructures/types/Ethereum/Blocks/BlockHeaderReader.h b/retesteth/testStructures/types/Ethereum/Blocks/BlockHeaderReader.h new file mode 100644 index 000000000..d1e6cec25 --- /dev/null +++ b/retesteth/testStructures/types/Ethereum/Blocks/BlockHeaderReader.h @@ -0,0 +1,20 @@ +#include "BlockHeader.h" +#include "BlockHeader1559.h" +#include "BlockHeaderLegacy.h" +#include "BlockHeaderMerge.h" +#include "BlockHeaderShanghai.h" + +namespace test::teststruct +{ +spBlockHeader readBlockHeader(DataObject const& _data); +spBlockHeader readBlockHeader(dev::RLP const& _rlp); + +// Block Serialization conditions +bool isBlockExportCurrentRandom(BlockHeader const&); +bool isBlockExportWithdrawals(BlockHeader const&); +bool isBlockExportBasefee(BlockHeader const&); +bool isBlockExportDifficulty(BlockHeader const&); + +bool isBlockPoS(BlockHeader const&); + +} // namespace teststruct diff --git a/retesteth/testStructures/types/Ethereum/Blocks/BlockHeaderShanghai.cpp b/retesteth/testStructures/types/Ethereum/Blocks/BlockHeaderShanghai.cpp new file mode 100644 index 000000000..a3048d007 --- /dev/null +++ b/retesteth/testStructures/types/Ethereum/Blocks/BlockHeaderShanghai.cpp @@ -0,0 +1,221 @@ +#include "BlockHeaderShanghai.h" +#include +#include +#include +#include + +using namespace std; +using namespace dev; +using namespace test::debug; + +namespace test::teststruct +{ + +void BlockHeaderShanghai::fromData(DataObject const& _data) +{ + try + { + // Allowed fields for this structure + REQUIRE_JSONFIELDS(_data, "BlockHeader1559 " + _data.getKey(), + { + {"bloom", {{DataType::String}, jsonField::Optional}}, + {"logsBloom", {{DataType::String}, jsonField::Optional}}, + {"coinbase", {{DataType::String}, jsonField::Optional}}, + {"author", {{DataType::String}, jsonField::Optional}}, + {"miner", {{DataType::String}, jsonField::Optional}}, + {"difficulty", {{DataType::String}, jsonField::Required}}, + {"extraData", {{DataType::String}, jsonField::Required}}, + {"gasLimit", {{DataType::String}, jsonField::Required}}, + {"baseFeePerGas", {{DataType::String}, jsonField::Required}}, + {"gasUsed", {{DataType::String}, jsonField::Required}}, + {"hash", {{DataType::String}, jsonField::Optional}}, + {"mixHash", {{DataType::String}, jsonField::Optional}}, + {"nonce", {{DataType::String}, jsonField::Optional}}, + {"number", {{DataType::String}, jsonField::Required}}, + {"parentHash", {{DataType::String}, jsonField::Required}}, + {"receiptTrie", {{DataType::String}, jsonField::Optional}}, + {"receiptsRoot", {{DataType::String}, jsonField::Optional}}, + {"stateRoot", {{DataType::String}, jsonField::Required}}, + {"timestamp", {{DataType::String}, jsonField::Required}}, + {"transactionsTrie", {{DataType::String}, jsonField::Optional}}, + {"transactionsRoot", {{DataType::String}, jsonField::Optional}}, + {"sha3Uncles", {{DataType::String}, jsonField::Optional}}, + {"uncleHash", {{DataType::String}, jsonField::Optional}}, + {"withdrawalsRoot", {{DataType::String}, jsonField::Required}}, + {"rejectedTransactions", {{DataType::Array}, jsonField::Optional}}, // EthGetBlockBy test debug field + {"seedHash", {{DataType::String}, jsonField::Optional}}, // EthGetBlockBy aleth field + {"boundary", {{DataType::String}, jsonField::Optional}}, // EthGetBlockBy aleth field + {"size", {{DataType::String}, jsonField::Optional}}, // EthGetBlockBy field + {"totalDifficulty", {{DataType::String}, jsonField::Optional}}, // EthGetBlockBy field + {"transactions", {{DataType::Array}, jsonField::Optional}}, // EthGetBlockBy field + {"uncles", {{DataType::Array}, jsonField::Optional}}, // EthGetBlockBy field + {"withdrawals", {{DataType::Array}, jsonField::Optional}} // EthGetBlockBy field + }); + + string const akey = _data.count("author") ? "author" : + _data.count("miner") ? "miner" : "coinbase"; + m_author = spFH20(new FH20(_data.atKey(akey))); + m_difficulty = spVALUE(new VALUE(_data.atKey("difficulty"))); + m_extraData = spBYTES(new BYTES(_data.atKey("extraData"))); + m_gasLimit = spVALUE(new VALUE(_data.atKey("gasLimit"))); + + m_baseFee = spVALUE(new VALUE(_data.atKey("baseFeePerGas"))); + m_gasUsed = spVALUE(new VALUE(_data.atKey("gasUsed"))); + if (_data.count("hash")) + m_hash = spFH32(new FH32(_data.atKey("hash"))); + string const bkey = _data.count("logsBloom") ? "logsBloom" : "bloom"; + m_logsBloom = spFH256(new FH256(_data.atKey(bkey))); + + if (_data.count("nonce")) + { + m_mixHash = spFH32(new FH32(_data.atKey("mixHash"))); + m_nonce = spFH8(new FH8(_data.atKey("nonce"))); + } + else + { + ETH_DC_MESSAGE(DC::TESTLOG, "BlockHeader `mixHash` is not defined. Using default `0x00..00` value!"); + m_mixHash = spFH32(FH32::zero().copy()); + m_nonce = spFH8(FH8::zero().copy()); + } + + m_number = spVALUE(new VALUE(_data.atKey("number"))); + m_parentHash = spFH32(new FH32(_data.atKey("parentHash"))); + string const rkey = _data.count("receiptsRoot") ? "receiptsRoot" : "receiptTrie"; + m_receiptsRoot = spFH32(new FH32(_data.atKey(rkey))); + string const ukey = _data.count("sha3Uncles") ? "sha3Uncles" : "uncleHash"; + m_sha3Uncles = spFH32(new FH32(_data.atKey(ukey))); + m_stateRoot = spFH32(new FH32(_data.atKey("stateRoot"))); + m_timestamp = spVALUE(new VALUE(_data.atKey("timestamp"))); + string const tkey = _data.count("transactionsRoot") ? "transactionsRoot" : "transactionsTrie"; + m_transactionsRoot = spFH32(new FH32(_data.atKey(tkey))); + m_withdrawalsRoot = spFH32(new FH32(_data.atKey("withdrawalsRoot"))); + + // Manual hash calculation + if (m_hash.isEmpty()) + recalculateHash(); + } + catch (std::exception const& _ex) + { + throw test::UpwardsException(string("BlockheaderShanghai parse error: ") + _ex.what()); + } +} + +BlockHeaderShanghai::BlockHeaderShanghai(DataObject const& _data) +{ + fromData(_data); +} + +BlockHeaderShanghai::BlockHeaderShanghai(dev::RLP const& _rlp) +{ + // 0 - parentHash // 8 - number + // 1 - uncleHash // 9 - gasLimit + // 2 - coinbase // 10 - gasUsed + // 3 - stateRoot // 11 - timestamp + // 4 - transactionTrie // 12 - extraData + // 5 - receiptTrie // 13 - mixHash + // 6 - bloom // 14 - nonce + // 7 - difficulty // 15 - baseFee + // 16 - withdrawals root + + size_t i = 0; + m_parentHash = spFH32(new FH32(_rlp[i++])); + m_sha3Uncles = spFH32(new FH32(_rlp[i++])); + m_author = spFH20(new FH20(_rlp[i++])); + m_stateRoot = spFH32(new FH32(_rlp[i++])); + m_transactionsRoot = spFH32(new FH32(_rlp[i++])); + m_receiptsRoot = spFH32(new FH32(_rlp[i++])); + m_logsBloom = spFH256(new FH256(_rlp[i++])); + m_difficulty = spVALUE(new VALUE(_rlp[i++])); + m_number = spVALUE(new VALUE(_rlp[i++])); + m_gasLimit = spVALUE(new VALUE(_rlp[i++])); + m_gasUsed = spVALUE(new VALUE(_rlp[i++])); + m_timestamp = spVALUE(new VALUE(_rlp[i++])); + m_extraData = spBYTES(new BYTES(_rlp[i++])); + m_mixHash = spFH32(new FH32(_rlp[i++])); + m_nonce = spFH8(new FH8(_rlp[i++])); + m_baseFee = spVALUE(new VALUE(_rlp[i++])); + m_withdrawalsRoot = spFH32(new FH32(_rlp[i++])); + recalculateHash(); +} + +spDataObject BlockHeaderShanghai::asDataObject() const +{ + spDataObject out; + (*out)["bloom"] = m_logsBloom->asString(); + (*out)["coinbase"] = m_author->asString(); + (*out)["difficulty"] = m_difficulty->asString(); + (*out)["extraData"] = m_extraData->asString(); + (*out)["gasLimit"] = m_gasLimit->asString(); + (*out)["gasUsed"] = m_gasUsed->asString(); + (*out)["hash"] = m_hash->asString(); + (*out)["mixHash"] = m_mixHash->asString(); + (*out)["nonce"] = m_nonce->asString(); + (*out)["number"] = m_number->asString(); + (*out)["parentHash"] = m_parentHash->asString(); + (*out)["receiptTrie"] = m_receiptsRoot->asString(); + (*out)["stateRoot"] = m_stateRoot->asString(); + (*out)["timestamp"] = m_timestamp->asString(); + (*out)["transactionsTrie"] = m_transactionsRoot->asString(); + (*out)["uncleHash"] = m_sha3Uncles->asString(); + (*out)["baseFeePerGas"] = m_baseFee->asString(); + (*out)["withdrawalsRoot"] = m_withdrawalsRoot->asString(); + return out; +} + +const RLPStream BlockHeaderShanghai::asRLPStream() const +{ + RLPStream header; + header.appendList(17); + + header << h256(m_parentHash->asString()); + header << h256(m_sha3Uncles->asString()); + header << Address(m_author->asString()); + header << h256(m_stateRoot->asString()); + header << h256(m_transactionsRoot->asString()); + header << h256(m_receiptsRoot->asString()); + header << h2048(m_logsBloom->asString()); + header << m_difficulty->asBigInt(); + header << m_number->asBigInt(); + header << m_gasLimit->asBigInt(); + header << m_gasUsed->asBigInt(); + header << m_timestamp->asBigInt(); + header << test::sfromHex(m_extraData->asString()); + header << h256(m_mixHash->asString()); + header << h64(m_nonce->asString()); + header << m_baseFee->asBigInt(); + header << h256(m_withdrawalsRoot->asString()); + return header; +} + +BlockHeaderShanghai& BlockHeaderShanghai::castFrom(BlockHeader& _from) +{ + try + { + if (_from.type() != BlockType::BlockHeaderShanghai) + ETH_FAIL_MESSAGE("BlockHeaderShanghai::castFrom() got wrong block type!"); + return dynamic_cast(_from); + } + catch (...) + { + ETH_FAIL_MESSAGE("BlockHeaderShanghai::castFrom() failed!"); + } + return dynamic_cast(_from); +} + +BlockHeaderShanghai const& BlockHeaderShanghai::castFrom(spBlockHeader const& _from) +{ + try + { + if (_from->type() != BlockType::BlockHeaderShanghai) + ETH_FAIL_MESSAGE("BlockHeaderShanghai::castFrom() got wrong block type!"); + return dynamic_cast(_from.getCContent()); + } + catch (...) + { + ETH_FAIL_MESSAGE("BlockHeaderShanghai::castFrom() failed!"); + } + spBlockHeaderShanghai foo(new BlockHeaderShanghai(DataObject())); + return foo.getCContent(); +} + +} // namespace teststruct diff --git a/retesteth/testStructures/types/Ethereum/Blocks/BlockHeaderShanghai.h b/retesteth/testStructures/types/Ethereum/Blocks/BlockHeaderShanghai.h new file mode 100644 index 000000000..4c68fc2e9 --- /dev/null +++ b/retesteth/testStructures/types/Ethereum/Blocks/BlockHeaderShanghai.h @@ -0,0 +1,34 @@ +#pragma once +#include +#include "BlockHeaderMerge.h" +#include +#include + +namespace test::teststruct +{ +struct BlockHeaderShanghai : BlockHeaderMerge +{ + BlockHeaderShanghai(DataObject const& _in); + BlockHeaderShanghai(dev::RLP const& _in); + + spDataObject asDataObject() const override; + dev::RLPStream const asRLPStream() const override; + BlockType type() const override { return BlockType::BlockHeaderShanghai; } + + FH32 const& withdrawalsRoot() const { return m_withdrawalsRoot; } + void setWithdrawalsRoot(FH32 const& _wRoot) { m_withdrawalsRoot = spFH32(_wRoot.copy()); } + + static BlockHeaderShanghai const& castFrom(spBlockHeader const& _from); + static BlockHeaderShanghai& castFrom(BlockHeader& _from); + +protected: + void fromData(DataObject const&) override; + + spFH32 m_withdrawalsRoot; + BlockHeaderShanghai(){}; +}; + +typedef GCP_SPointer spBlockHeaderShanghai; + + +} // namespace teststruct diff --git a/retesteth/testStructures/types/Ethereum/EthereumBlock.cpp b/retesteth/testStructures/types/Ethereum/EthereumBlock.cpp index e03561fbf..8d04a237b 100644 --- a/retesteth/testStructures/types/Ethereum/EthereumBlock.cpp +++ b/retesteth/testStructures/types/Ethereum/EthereumBlock.cpp @@ -35,8 +35,11 @@ BYTES const EthereumBlock::getRLP() const { try { - // RLP of a block - RLPStream stream(3); + bool const isExportWithdrawalsRLP = + (m_header->type() == BlockType::BlockHeaderShanghai || m_forceWithdrawalsRLP) + && !m_forceNoWithdrawalsRLP; + + RLPStream stream(isExportWithdrawalsRLP ? 4 : 3); stream.appendRaw(m_header->asRLPStream().out()); // Transaction list @@ -51,6 +54,15 @@ BYTES const EthereumBlock::getRLP() const uncleList.appendRaw(un->asRLPStream().out()); stream.appendRaw(uncleList.out()); + // Withdrawals + if (isExportWithdrawalsRLP) + { + RLPStream withdrawalsList(m_withdrawals.size()); + for (auto const& wt : m_withdrawals) + withdrawalsList.appendRaw(wt->asRLPStream().out()); + stream.appendRaw(withdrawalsList.out()); + } + return BYTES(dev::toHexPrefixed(stream.out())); } catch (std::exception const& _ex) @@ -65,8 +77,8 @@ DebugVMTrace const& EthereumBlockState::getTrTrace(FH32 const& _hash) const if (m_transactionsTrace.count(_hash)) return m_transactionsTrace.at(_hash); else - ETH_ERROR_MESSAGE("Transaction trace not found! (" + _hash.asString() + ")"); - static DebugVMTrace empty("", "", FH32::zero(), ""); + ETH_WARNING("Transaction trace not found! (" + _hash.asString() + ")"); + static DebugVMTrace empty; return empty; } diff --git a/retesteth/testStructures/types/Ethereum/EthereumBlock.h b/retesteth/testStructures/types/Ethereum/EthereumBlock.h index fe1cbd85b..d6708a5f4 100644 --- a/retesteth/testStructures/types/Ethereum/EthereumBlock.h +++ b/retesteth/testStructures/types/Ethereum/EthereumBlock.h @@ -1,38 +1,47 @@ #pragma once -#include "../../basetypes.h" -#include "../Ethereum/BlockHeader.h" -#include "../Ethereum/BlockHeaderReader.h" +#include +#include "../Ethereum/Blocks/BlockHeader.h" +#include "../Ethereum/Blocks/BlockHeaderReader.h" #include "../Ethereum/State.h" -#include "../Ethereum/Transaction.h" +#include "../Ethereum/Transactions/Transaction.h" +#include "../Ethereum/Withdrawals.h" #include #include #include -namespace test -{ -namespace teststruct +namespace test::teststruct { + // Ethereum Block for RLP managment struct EthereumBlock : GCP_SPointerBase { EthereumBlock(spBlockHeader const& _header) : m_header(_header) {} - void addTransaction(spTransaction const& _tr) { m_transactions.push_back(_tr); } - void addUncle(spBlockHeader const& _header) { m_uncles.push_back(_header); } + void addTransaction(spTransaction const& _tr) { m_transactions.emplace_back(_tr); } + void addUncle(spBlockHeader const& _header) { m_uncles.emplace_back(_header); } + void addWithdrawal(spWithdrawal const& _withdrawal) { m_withdrawals.emplace_back(_withdrawal); } void replaceHeader(spBlockHeader const& _header) { m_header = readBlockHeader(_header->asDataObject()); } void recalculateUncleHash(); BYTES const getRLP() const; + void forceWithdrawalsRLP() { m_forceWithdrawalsRLP = true; } + void forceNoWithdrawalsRLP() { m_forceNoWithdrawalsRLP = true; } spBlockHeader const& header() const { return m_header; } spBlockHeader& headerUnsafe() { return m_header; } std::vector const& uncles() const { return m_uncles; } std::vector const& transactions() const { return m_transactions; } + void clear() { m_transactions.clear(); m_withdrawals.clear(); m_uncles.clear(); } + std::vector const& withdrawals() const { return m_withdrawals; } protected: EthereumBlock() {} spBlockHeader m_header; std::vector m_transactions; std::vector m_uncles; + std::vector m_withdrawals; +protected: + bool m_forceWithdrawalsRLP = false; + bool m_forceNoWithdrawalsRLP = false; }; struct EthereumBlockState : EthereumBlock @@ -67,4 +76,3 @@ typedef GCP_SPointer spEthereumBlock; typedef GCP_SPointer spEthereumBlockState; } // namespace teststruct -} // namespace test diff --git a/retesteth/testStructures/types/Ethereum/Storage.h b/retesteth/testStructures/types/Ethereum/Storage.h index 7afeb836f..744c6bb70 100644 --- a/retesteth/testStructures/types/Ethereum/Storage.h +++ b/retesteth/testStructures/types/Ethereum/Storage.h @@ -1,5 +1,5 @@ #pragma once -#include "../../basetypes.h" +#include #include namespace test { diff --git a/retesteth/testStructures/types/Ethereum/Transaction.cpp b/retesteth/testStructures/types/Ethereum/Transaction.cpp deleted file mode 100644 index 51ebebb04..000000000 --- a/retesteth/testStructures/types/Ethereum/Transaction.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include "Transaction.h" -#include -#include - -using namespace test; -using namespace test::debug; -namespace test::teststruct -{ - -void Transaction::setChainID(VALUE const& _chainID) { - if (m_secretKey.getCContent() != 0) - { - m_chainID = spVALUE(_chainID.copy()); - buildVRS(); - } - else - ETH_DC_MESSAGE(DC::LOWLOG, "Calling Transaction::setChainID for transaction without secretKey!"); -} - -Transaction::Transaction() -{ - m_chainID = spVALUE(new VALUE(Options::get().getCurrentConfig().cfgFile().defaultChainID())); -} - -} diff --git a/retesteth/testStructures/types/Ethereum/Transactions/Transaction.cpp b/retesteth/testStructures/types/Ethereum/Transactions/Transaction.cpp new file mode 100644 index 000000000..73b6bf917 --- /dev/null +++ b/retesteth/testStructures/types/Ethereum/Transactions/Transaction.cpp @@ -0,0 +1,69 @@ +#include "Transaction.h" +#include +#include +#include +#include + +using namespace test; +using namespace test::debug; +namespace test::teststruct +{ + +void Transaction::setChainID(VALUE const& _chainID) { + if (m_secretKey.getCContent() != 0) + { + m_chainID = spVALUE(_chainID.copy()); + buildVRS(); + } + else + ETH_DC_MESSAGE(DC::LOWLOG, "Calling Transaction::setChainID for transaction without secretKey!"); +} + +Transaction::Transaction() +{ + m_chainID = spVALUE(new VALUE(Options::get().getCurrentConfig().cfgFile().defaultChainID())); +} + +FH20 const& Transaction::sender() const +{ + if (m_sender.isEmpty()) + { + if (m_secretKey.getCContent() != 0) + { + m_sender = convertSecretToPublic(m_secretKey); + return m_sender; + } + else + { + try + { + bool const legacyV = (type() == TransactionType::LEGACY && m_chainID->asBigInt() == 1); + dev::byte const v(legacyV ? m_v->asBigInt() - 27 : m_v->asBigInt()); + + DataObject rs; + rs["r"] = m_r->asString(); + rs["s"] = m_s->asString(); + rs.performModifier(mod_valueToFH32); + + dev::h256 const r(rs.atKey("r").asString()); + dev::h256 const s(rs.atKey("s").asString()); + dev::h256 const recoverHash = buildVRSHash(); + dev::SignatureStruct const sig(r,s,v); + dev::Public const pubkey = dev::recover(sig, recoverHash); + auto const address = dev::toAddress(pubkey); + m_sender = spFH20(new FH20(dev::toHexPrefixed(address))); + return m_sender; + } + catch (std::exception const& _ex) + { + ETH_WARNING("Transaction::sender() const:: error recovering sender! \n" + asDataObject()->asJson()); + m_sender = spFH20(FH20::zero().copy()); + return m_sender; + } + } + } + else + return m_sender; +} + +} diff --git a/retesteth/testStructures/types/Ethereum/Transaction.h b/retesteth/testStructures/types/Ethereum/Transactions/Transaction.h similarity index 94% rename from retesteth/testStructures/types/Ethereum/Transaction.h rename to retesteth/testStructures/types/Ethereum/Transactions/Transaction.h index 1d6994904..a7e5fc634 100644 --- a/retesteth/testStructures/types/Ethereum/Transaction.h +++ b/retesteth/testStructures/types/Ethereum/Transactions/Transaction.h @@ -1,5 +1,5 @@ #pragma once -#include "../../basetypes.h" +#include #include #include @@ -34,6 +34,7 @@ struct Transaction : GCP_SPointerBase VALUE const& s() const { return m_s; } FH32 const& hash() const { return m_hash; } + FH20 const& sender() const; BYTES const& getRawBytes() const { return m_rawRLPdata; } dev::RLPStream const& asRLPStream() const { return m_outRlpStream; } @@ -53,6 +54,7 @@ struct Transaction : GCP_SPointerBase // Potected transaction interface virtual void fromDataObject(DataObject const&) = 0; virtual void fromRLP(dev::RLP const&) = 0; + virtual dev::h256 buildVRSHash() const = 0; virtual void buildVRS() = 0; virtual void streamHeader(dev::RLPStream& _stream) const = 0; virtual void rebuildRLP() = 0; @@ -82,6 +84,7 @@ struct Transaction : GCP_SPointerBase dev::RLPStream m_outRlpStream; spBYTES m_rawRLPdata; // raw transaction data without rlp header (for typed transactions) spVALUE m_secretKey = spVALUE(new VALUE(0)); // Additional info for t8ntool transaction wrapper + mutable spFH20 m_sender; }; typedef GCP_SPointer spTransaction; diff --git a/retesteth/testStructures/types/Ethereum/TransactionAccessList.cpp b/retesteth/testStructures/types/Ethereum/Transactions/TransactionAccessList.cpp similarity index 97% rename from retesteth/testStructures/types/Ethereum/TransactionAccessList.cpp rename to retesteth/testStructures/types/Ethereum/Transactions/TransactionAccessList.cpp index 11f99cce7..d2b4452eb 100644 --- a/retesteth/testStructures/types/Ethereum/TransactionAccessList.cpp +++ b/retesteth/testStructures/types/Ethereum/Transactions/TransactionAccessList.cpp @@ -58,6 +58,8 @@ void TransactionAccessList::fromDataObject(DataObject const& _data) m_gasPrice = spVALUE(new VALUE(_data.atKey("gasPrice"))); m_nonce = spVALUE(new VALUE(_data.atKey("nonce"))); m_value = spVALUE(new VALUE(_data.atKey("value"))); + if (_data.count("sender")) + m_sender = spFH20(new FH20(_data.atKey("sender"))); if (_data.count("chainId")) m_chainID = spVALUE(new VALUE(_data.atKey("chainId"))); @@ -139,7 +141,7 @@ void TransactionAccessList::fromRLP(dev::RLP const& _rlp) rebuildRLP(); } -void TransactionAccessList::buildVRS() +dev::h256 TransactionAccessList::buildVRSHash() const { dev::RLPStream stream; stream.appendList(8); @@ -148,8 +150,12 @@ void TransactionAccessList::buildVRS() // Alter output with prefixed 01 byte + tr.rlp dev::bytes outa = stream.out(); outa.insert(outa.begin(), dev::byte(1)); // txType + return dev::sha3(outa); +} - const dev::h256 hash(dev::sha3(outa)); +void TransactionAccessList::buildVRS() +{ + const dev::h256 hash = buildVRSHash(); const dev::Secret secret(m_secretKey->asString()); dev::Signature sig = dev::sign(secret, hash); dev::SignatureStruct sigStruct = *(dev::SignatureStruct const*)&sig; diff --git a/retesteth/testStructures/types/Ethereum/TransactionAccessList.h b/retesteth/testStructures/types/Ethereum/Transactions/TransactionAccessList.h similarity index 95% rename from retesteth/testStructures/types/Ethereum/TransactionAccessList.h rename to retesteth/testStructures/types/Ethereum/Transactions/TransactionAccessList.h index e6c1c5252..d383c6bf9 100644 --- a/retesteth/testStructures/types/Ethereum/TransactionAccessList.h +++ b/retesteth/testStructures/types/Ethereum/Transactions/TransactionAccessList.h @@ -22,6 +22,7 @@ struct TransactionAccessList : TransactionLegacy // Override protected interface void fromRLP(dev::RLP const&) override; void fromDataObject(DataObject const&) override; + dev::h256 buildVRSHash() const override; void buildVRS() override; void streamHeader(dev::RLPStream& _stream) const override; void rebuildRLP() override; diff --git a/retesteth/testStructures/types/Ethereum/TransactionBaseFee.cpp b/retesteth/testStructures/types/Ethereum/Transactions/TransactionBaseFee.cpp similarity index 97% rename from retesteth/testStructures/types/Ethereum/TransactionBaseFee.cpp rename to retesteth/testStructures/types/Ethereum/Transactions/TransactionBaseFee.cpp index 1d7893569..e253ef23f 100644 --- a/retesteth/testStructures/types/Ethereum/TransactionBaseFee.cpp +++ b/retesteth/testStructures/types/Ethereum/Transactions/TransactionBaseFee.cpp @@ -64,6 +64,8 @@ void TransactionBaseFee::fromDataObject(DataObject const& _data) m_gasLimit = spVALUE(new VALUE(_data.atKey("gasLimit"))); m_nonce = spVALUE(new VALUE(_data.atKey("nonce"))); m_value = spVALUE(new VALUE(_data.atKey("value"))); + if (_data.count("sender")) + m_sender = spFH20(new FH20(_data.atKey("sender"))); if (_data.count("chainId")) m_chainID = spVALUE(new VALUE(_data.atKey("chainId"))); @@ -143,8 +145,7 @@ void TransactionBaseFee::fromRLP(dev::RLP const& _rlp) rebuildRLP(); } - -void TransactionBaseFee::buildVRS() +dev::h256 TransactionBaseFee::buildVRSHash() const { dev::RLPStream stream; stream.appendList(9); @@ -153,9 +154,13 @@ void TransactionBaseFee::buildVRS() // Alter output with prefixed 02 byte + tr.rlp dev::bytes outa = stream.out(); outa.insert(outa.begin(), dev::byte(2)); // txType + return dev::sha3(outa); +} +void TransactionBaseFee::buildVRS() +{ const dev::Secret secret(m_secretKey->asString()); - const dev::h256 hash(dev::sha3(outa)); + const dev::h256 hash = buildVRSHash(); dev::Signature sig = dev::sign(secret, hash); dev::SignatureStruct sigStruct = *(dev::SignatureStruct const*)&sig; ETH_FAIL_REQUIRE_MESSAGE( @@ -209,6 +214,9 @@ const spDataObject TransactionBaseFee::asDataObject(ExportOrder _order) const (*out)["v"] = m_v->asString(); (*out)["r"] = m_r->asString(); (*out)["s"] = m_s->asString(); + if (!m_sender.isEmpty()) + (*out)["sender"] = m_sender->asString(); + if (_order == ExportOrder::ToolStyle) { (*out).performModifier(mod_removeLeadingZerosFromHexValues, DataObject::ModifierOption::RECURSIVE, {"data", "to"}); diff --git a/retesteth/testStructures/types/Ethereum/TransactionBaseFee.h b/retesteth/testStructures/types/Ethereum/Transactions/TransactionBaseFee.h similarity index 95% rename from retesteth/testStructures/types/Ethereum/TransactionBaseFee.h rename to retesteth/testStructures/types/Ethereum/Transactions/TransactionBaseFee.h index e79542f0f..b3f41fdd1 100644 --- a/retesteth/testStructures/types/Ethereum/TransactionBaseFee.h +++ b/retesteth/testStructures/types/Ethereum/Transactions/TransactionBaseFee.h @@ -19,6 +19,7 @@ struct TransactionBaseFee : Transaction void fromRLP(dev::RLP const&) override; void fromDataObject(DataObject const&) override; + dev::h256 buildVRSHash() const override; void buildVRS() override; void streamHeader(dev::RLPStream& _stream) const override; diff --git a/retesteth/testStructures/types/Ethereum/TransactionLegacy.cpp b/retesteth/testStructures/types/Ethereum/Transactions/TransactionLegacy.cpp similarity index 94% rename from retesteth/testStructures/types/Ethereum/TransactionLegacy.cpp rename to retesteth/testStructures/types/Ethereum/Transactions/TransactionLegacy.cpp index b6b5a5149..95e459c4f 100644 --- a/retesteth/testStructures/types/Ethereum/TransactionLegacy.cpp +++ b/retesteth/testStructures/types/Ethereum/Transactions/TransactionLegacy.cpp @@ -55,6 +55,9 @@ void TransactionLegacy::fromDataObject(DataObject const& _data) m_nonce = spVALUE(new VALUE(_data.atKey("nonce"))); m_value = spVALUE(new VALUE(_data.atKey("value"))); + if (_data.count("sender")) + m_sender = spFH20(new FH20(_data.atKey("sender"))); + if (_data.count("chainId")) m_chainID = spVALUE(new VALUE(_data.atKey("chainId"))); @@ -118,7 +121,10 @@ void TransactionLegacy::fromRLP(dev::RLP const& _rlp) { int chainID = std::floor((double)(m_v.getCContent().asBigInt() - 35) / 2); if (chainID < 0) - ETH_WARNING("Error decoding chainID from transaction RLP: " + test::fto_string(chainID)); + { + if (Options::get().filltests) + ETH_WARNING("Error decoding chainID from transaction RLP: " + test::fto_string(chainID)); + } else m_chainID = spVALUE(new VALUE(chainID)); } @@ -152,7 +158,7 @@ void TransactionLegacy::streamHeader(dev::RLPStream& _s) const _s << test::sfromHex(data().asString()); } -void TransactionLegacy::buildVRS() +dev::h256 TransactionLegacy::buildVRSHash() const { dev::RLPStream stream; stream.appendList((m_chainID.getCContent() == 1) ? 6 : 9); @@ -163,8 +169,12 @@ void TransactionLegacy::buildVRS() stream << VALUE(0).serializeRLP(); stream << VALUE(0).serializeRLP(); } + return dev::sha3(stream.out()); +} - const dev::h256 hash(dev::sha3(stream.out())); +void TransactionLegacy::buildVRS() +{ + const dev::h256 hash = buildVRSHash(); const dev::Secret secret(m_secretKey->asString()); dev::Signature sig = dev::sign(secret, hash); dev::SignatureStruct sigStruct = *(dev::SignatureStruct const*)&sig; @@ -207,6 +217,8 @@ const spDataObject TransactionLegacy::asDataObject(ExportOrder _order) const (*out)["v"] = m_v->asString(); (*out)["r"] = m_r->asString(); (*out)["s"] = m_s->asString(); + if (!m_sender.isEmpty()) + (*out)["sender"] = m_sender->asString(); if (_order == ExportOrder::ToolStyle) { diff --git a/retesteth/testStructures/types/Ethereum/TransactionLegacy.h b/retesteth/testStructures/types/Ethereum/Transactions/TransactionLegacy.h similarity index 91% rename from retesteth/testStructures/types/Ethereum/TransactionLegacy.h rename to retesteth/testStructures/types/Ethereum/Transactions/TransactionLegacy.h index 1088bac09..bbd346bf3 100644 --- a/retesteth/testStructures/types/Ethereum/TransactionLegacy.h +++ b/retesteth/testStructures/types/Ethereum/Transactions/TransactionLegacy.h @@ -1,5 +1,5 @@ #pragma once -#include "../../basetypes.h" +#include #include "Transaction.h" #include #include @@ -27,6 +27,7 @@ struct TransactionLegacy : Transaction // Potected transaction interface virtual void fromRLP(dev::RLP const&) override; virtual void fromDataObject(DataObject const&) override; + virtual dev::h256 buildVRSHash() const override; virtual void buildVRS() override; virtual void streamHeader(dev::RLPStream& _stream) const override; virtual void rebuildRLP() override; diff --git a/retesteth/testStructures/types/Ethereum/TransactionReader.cpp b/retesteth/testStructures/types/Ethereum/Transactions/TransactionReader.cpp similarity index 100% rename from retesteth/testStructures/types/Ethereum/TransactionReader.cpp rename to retesteth/testStructures/types/Ethereum/Transactions/TransactionReader.cpp diff --git a/retesteth/testStructures/types/Ethereum/TransactionReader.h b/retesteth/testStructures/types/Ethereum/Transactions/TransactionReader.h similarity index 100% rename from retesteth/testStructures/types/Ethereum/TransactionReader.h rename to retesteth/testStructures/types/Ethereum/Transactions/TransactionReader.h diff --git a/retesteth/testStructures/types/Ethereum/Withdrawals.cpp b/retesteth/testStructures/types/Ethereum/Withdrawals.cpp new file mode 100644 index 000000000..e13311cf3 --- /dev/null +++ b/retesteth/testStructures/types/Ethereum/Withdrawals.cpp @@ -0,0 +1,60 @@ +#include "Withdrawals.h" +#include +#include +#include +using namespace dataobject; +using namespace test; +using namespace test::debug; +using namespace std; +using namespace dev; + +namespace test::teststruct { + +Withdrawal::Withdrawal(DataObject const& _data) +{ + REQUIRE_JSONFIELDS(_data, "WithdrawalRecord ", + {{"index", {{DataType::String}, jsonField::Required}}, + {"validatorIndex", {{DataType::String}, jsonField::Required}}, + {"address", {{DataType::String}, jsonField::Required}}, + {"amount", {{DataType::String}, jsonField::Required}}}); + index = spVALUE(new VALUE(_data.atKey("index"))); + validatorIndex = spVALUE(new VALUE(_data.atKey("validatorIndex"))); + address = spFH20(new FH20(_data.atKey("address"))); + amount = spVALUE(new VALUE(_data.atKey("amount"))); +} + +Withdrawal::Withdrawal(dev::RLP const& _rlp) +{ + size_t i = 0; + index = spVALUE(new VALUE(_rlp[i++])); + validatorIndex = spVALUE(new VALUE(_rlp[i++])); + address = spFH20(new FH20(_rlp[i++])); + amount = spVALUE(new VALUE(_rlp[i++])); +} + + +spDataObject Withdrawal::asDataObject(ExportOrder _order) const +{ + spDataObject ret(new DataObject(DataType::Object)); + (*ret)["index"] = index->asString(); + (*ret)["validatorIndex"] = validatorIndex->asString(); + (*ret)["amount"] = amount->asString(); + if (_order == ExportOrder::ToolStyle) + (*ret).performModifier(mod_removeLeadingZerosFromHexValues); + (*ret)["address"] = address->asString(); + return ret; +} + +const RLPStream Withdrawal::asRLPStream() const +{ + RLPStream rlp; + rlp.appendList(4); + rlp << index->serializeRLP(); + rlp << validatorIndex->serializeRLP(); + rlp << address->serializeRLP(); + rlp << amount->serializeRLP(); + return rlp; +} + + +} diff --git a/retesteth/testStructures/types/Ethereum/Withdrawals.h b/retesteth/testStructures/types/Ethereum/Withdrawals.h new file mode 100644 index 000000000..844468b77 --- /dev/null +++ b/retesteth/testStructures/types/Ethereum/Withdrawals.h @@ -0,0 +1,23 @@ +#pragma once +#include +#include +#include + +namespace test::teststruct +{ + +struct Withdrawal : GCP_SPointerBase +{ + Withdrawal(DataObject const&); + Withdrawal(dev::RLP const&); + spDataObject asDataObject(ExportOrder _order = ExportOrder::Default) const; + spVALUE index; + spVALUE validatorIndex; + spFH20 address; + spVALUE amount; + const dev::RLPStream asRLPStream() const; +}; + +typedef dataobject::GCP_SPointer spWithdrawal; + +} // namespace teststruct diff --git a/retesteth/testStructures/types/RPC/DebugAccountRange.cpp b/retesteth/testStructures/types/RPC/DebugAccountRange.cpp index 509170d12..e6d4594d9 100644 --- a/retesteth/testStructures/types/RPC/DebugAccountRange.cpp +++ b/retesteth/testStructures/types/RPC/DebugAccountRange.cpp @@ -13,7 +13,7 @@ DebugAccountRange::DebugAccountRange(DataObject const& _data) {{"addressMap", {{DataType::Object}, jsonField::Required}}, {"nextKey", {{DataType::String}, jsonField::Required}}}); for (auto const& record : _data.atKey("addressMap").getSubObjects()) - m_addresses.push_back(spFH20(new FH20(record))); + m_addresses.emplace_back(spFH20(new FH20(record))); m_nextKey = spFH32(new FH32(_data.atKey("nextKey"))); } catch (std::exception const& _ex) diff --git a/retesteth/testStructures/types/RPC/DebugAccountRange.h b/retesteth/testStructures/types/RPC/DebugAccountRange.h index 3061ede0f..f6770f5ac 100644 --- a/retesteth/testStructures/types/RPC/DebugAccountRange.h +++ b/retesteth/testStructures/types/RPC/DebugAccountRange.h @@ -1,5 +1,5 @@ #pragma once -#include "../../basetypes.h" +#include #include namespace test diff --git a/retesteth/testStructures/types/RPC/DebugStorageRangeAt.cpp b/retesteth/testStructures/types/RPC/DebugStorageRangeAt.cpp index 226946900..1ace25215 100644 --- a/retesteth/testStructures/types/RPC/DebugStorageRangeAt.cpp +++ b/retesteth/testStructures/types/RPC/DebugStorageRangeAt.cpp @@ -25,7 +25,7 @@ DebugStorageRangeAt::DebugStorageRangeAt(DataObject const& _data) else { ETH_DC_MESSAGE(DC::LOWLOG, "DebugStorageRangeAt key `nextKey` is not set, use `0x00..00` instead."); - m_nextKey = spFH32(new FH32(FH32::zero())); + m_nextKey = spFH32(FH32::zero().copy()); } } catch (std::exception const& _ex) diff --git a/retesteth/testStructures/types/RPC/DebugStorageRangeAt.h b/retesteth/testStructures/types/RPC/DebugStorageRangeAt.h index 6f22dac4f..4a190f408 100644 --- a/retesteth/testStructures/types/RPC/DebugStorageRangeAt.h +++ b/retesteth/testStructures/types/RPC/DebugStorageRangeAt.h @@ -1,5 +1,5 @@ #pragma once -#include "../../basetypes.h" +#include #include "../Ethereum/Storage.h" #include diff --git a/retesteth/testStructures/types/RPC/DebugTraceTransaction.cpp b/retesteth/testStructures/types/RPC/DebugTraceTransaction.cpp index 897cbe230..ae14a3d2c 100644 --- a/retesteth/testStructures/types/RPC/DebugTraceTransaction.cpp +++ b/retesteth/testStructures/types/RPC/DebugTraceTransaction.cpp @@ -15,7 +15,7 @@ DebugTraceTransaction::DebugTraceTransaction(DataObject const& _data) {"return", {{DataType::String}, jsonField::Required}}}); for (auto const& entry : _data.atKey("structLogs").getSubObjects()) - m_entries.push_back(DebugTraceTransactionLog(entry)); + m_entries.emplace_back(DebugTraceTransactionLog(entry)); m_gas = spVALUE(new VALUE(_data.atKey("gas"))); m_return = spBYTES(new BYTES(_data.atKey("return"))); } diff --git a/retesteth/testStructures/types/RPC/DebugTraceTransaction.h b/retesteth/testStructures/types/RPC/DebugTraceTransaction.h index 09e085aba..14cab993e 100644 --- a/retesteth/testStructures/types/RPC/DebugTraceTransaction.h +++ b/retesteth/testStructures/types/RPC/DebugTraceTransaction.h @@ -1,5 +1,5 @@ #pragma once -#include "../../basetypes.h" +#include #include namespace test diff --git a/retesteth/testStructures/types/RPC/DebugVMTrace.cpp b/retesteth/testStructures/types/RPC/DebugVMTrace.cpp index 31e8b1775..afd68ef7b 100644 --- a/retesteth/testStructures/types/RPC/DebugVMTrace.cpp +++ b/retesteth/testStructures/types/RPC/DebugVMTrace.cpp @@ -10,104 +10,61 @@ using namespace std; using namespace test::debug; namespace fs = boost::filesystem; +const size_t c_maxRowsToPrint = 300; const string c_tooManyRawsMessage = "==TOO MANY LOG ROWS TO PRINT (Use --vmtraceraw )=="; + namespace test::teststruct { -VMLogRecord::VMLogRecord(DataObject const& _obj) + +DebugVMTrace::DebugVMTraceRaw::DebugVMTraceRaw(string const& _info, fs::path const& _logs) { + m_infoString = _info; + string line; + size_t k = 0; + if (!fs::exists(_logs)) + return; + try { - if (_obj.getSubObjects().size() == 4) - { - REQUIRE_JSONFIELDS(_obj, "VMLogRecord " + _obj.getKey(), - { - {"output", {{DataType::String}, jsonField::Required}}, - {"gasUsed", {{DataType::String}, jsonField::Required}}, - {"time", {{DataType::Integer}, jsonField::Required}}, - {"error", {{DataType::String}, jsonField::Required}}}); - } - else - { - REQUIRE_JSONFIELDS(_obj, "VMLogRecord " + _obj.getKey(), - {{"pc", {{DataType::Integer}, jsonField::Required}}, - {"op", {{DataType::Integer}, jsonField::Required}}, - {"gas", {{DataType::String}, jsonField::Required}}, - {"gasCost", {{DataType::String}, jsonField::Required}}, - {"memory", {{DataType::String}, jsonField::Optional}}, - {"memSize", {{DataType::Integer}, jsonField::Required}}, - {"stack", {{DataType::Array}, jsonField::Required}}, - {"depth", {{DataType::Integer}, jsonField::Required}}, - {"refund", {{DataType::Integer}, jsonField::Required}}, - {"opName", {{DataType::String}, jsonField::Required}}, - {"returnData", {{DataType::String}, jsonField::Optional}}, - {"error", {{DataType::String}, jsonField::Optional}}}); - } - - if (_obj.getSubObjects().size() == 4) - { - error = _obj.atKey("error").asString(); - isShort = true; - } - else + fs::ifstream fileHandler(_logs); + while (getline(fileHandler, line)) { - pc = _obj.atKey("pc").asInt(); - op = _obj.atKey("op").asInt(); - gas = spVALUE(new VALUE(_obj.atKey("gas"))); - gasCost = spVALUE(new VALUE(_obj.atKey("gasCost"))); - if (_obj.count("memory")) - memory = spBYTES(new BYTES(_obj.atKey("memory"))); - else - memory = spBYTES(new BYTES(DataObject("0x"))); - memSize = _obj.atKey("memSize").asInt(); - for (auto const& el : _obj.atKey("stack").getSubObjects()) - stack.push_back(el->asString()); - if (_obj.count("returnData")) - returnData = spBYTES(new BYTES(_obj.atKey("returnData"))); - else - returnData = spBYTES(new BYTES(DataObject("0x"))); - depth = _obj.atKey("depth").asInt(); - refund = _obj.atKey("refund").asInt(); - opName = _obj.atKey("opName").asString(); - error = _obj.count("error") ? _obj.atKey("error").asString() : ""; + if (++k < c_maxRowsToPrint) + m_rawUnparsedLogs += line + "\n"; + else if (k == c_maxRowsToPrint) + { + m_rawUnparsedLogs += c_tooManyRawsMessage; + break; + } } - + if (m_rawUnparsedLogs.empty()) + ETH_WARNING("Reading empty vmtrace logs: " + _logs.string()); + fileHandler.close(); } - catch (std::exception const& _ex) - { - throw UpwardsException(string("VMLogRecord parse error: ") + _ex.what()); + catch (const ifstream::failure& e) { + throw UpwardsException("Error reading trace file: " + _logs.string()); } } +void DebugVMTrace::DebugVMTraceRaw::print() +{ + ETH_DC_MESSAGE(DC::DEFAULT, m_infoString); + ETH_DC_MESSAGE(DC::DEFAULT, m_rawUnparsedLogs); +} -DebugVMTrace::DebugVMTrace( - string const& _info, string const& _trNumber, FH32 const& _trHash, boost::filesystem::path const& _logs) +DebugVMTrace::DebugVMTraceNice::DebugVMTraceNice(string const& _info, fs::path const& _logs) { + m_infoString = _info; + string line; + size_t k = 0; + if (!fs::exists(_logs)) + return; + try { - m_infoString = _info; - m_trNumber = _trNumber; - m_trHash = spFH32(_trHash.copy()); - - string line; - size_t k = 0; - const size_t c_maxRowsToPrint = 100; fs::ifstream fileHandler(_logs); - - auto readLog = [this](string const& _line){ - auto const data = ConvertJsoncppStringToData(_line); - if (data->getSubObjects().size() == 3) - { - m_output = data->atKey("output").asString(); - m_gasUsed = spVALUE(new VALUE(data->atKey("gasUsed"))); - m_time = data->atKey("time").asInt(); - } - else - m_log.push_back(VMLogRecord(data)); - }; - if (Options::get().fillvmtrace) { - // Load logs optimized while (getline(fileHandler, line)) readLog(line); } @@ -116,22 +73,40 @@ DebugVMTrace::DebugVMTrace( while (getline(fileHandler, line)) { if (++k < c_maxRowsToPrint) - { - m_rawUnparsedLogs += line + "\n"; readLog(line); - } else if (k == c_maxRowsToPrint) { m_limitReached = true; - m_rawUnparsedLogs += c_tooManyRawsMessage; - m_output = ""; - m_gasUsed = spVALUE(new VALUE(DataObject("0x00"))); - m_time = 0; break; } } } + if (m_log.size() == 0) + ETH_WARNING("Reading empty vmtrace logs: " + _logs.string()); fileHandler.close(); + } + catch (const ifstream::failure& e) { + throw UpwardsException("Error reading trace file: " + _logs.string()); + } +} + +void DebugVMTrace::DebugVMTraceNice::readLog(string const& _line) +{ + auto const data = ConvertJsoncppStringToData(_line); + m_log.emplace_back(VMLogRecord(data)); +} + +DebugVMTrace::DebugVMTrace(string const& _info, fs::path const& _logs) +{ + try + { + if (!fs::exists(_logs)) + throw EthError("Log file not found: `" + _logs.string()); + + if (Options::get().vmtraceraw) + m_impl.reset(new DebugVMTraceRaw(_info, _logs)); + else + m_impl.reset(new DebugVMTraceNice(_info, _logs)); // Take a handle of t8ntool file in our own tmp path auto const uniqueFolder = fs::unique_path(); @@ -145,25 +120,21 @@ DebugVMTrace::DebugVMTrace( } } -void DebugVMTrace::print() -{ - ETH_DC_MESSAGE(DC::DEFAULT, m_infoString); - ETH_DC_MESSAGE(DC::DEFAULT, m_rawUnparsedLogs); -} -void DebugVMTrace::printNice() +void DebugVMTrace::DebugVMTraceNice::print() { ETH_DC_MESSAGE(DC::DEFAULT, m_infoString); if (m_log.size() == 0) return; string s_comment = ""; - dev::bigint maxGas = m_log.at(0).gas->asBigInt(); + dev::bigint maxGas = m_log.at(0).isShort ? 500000 : m_log.at(0).gas->asBigInt(); size_t k = 0; size_t const step = 9; string const stepw = " "; + std::cout << cBYellowBlack << "N" << setw(15) << "OPNAME" << setw(10) << "GASCOST" << setw(10) << "TOTALGAS" << setw(10) - << "REMAINGAS" << setw(20) << "ERROR" << cDefault << std::endl; + << "REMAINGAS" << setw(10) << "STACK" << cDefault << std::endl; for (VMLogRecord const& el : m_log) { // Last record with error info @@ -180,8 +151,24 @@ void DebugVMTrace::printNice() << setw(15) << el.opName << setw(10) << el.gasCost->asDecString() << setw(10) << maxGas - el.gas->asBigInt() - << setw(10) << el.gas->asDecString() - << setw(20) << el.error << std::endl; + << setw(10) << el.gas->asDecString(); + + const size_t c_stackPreviewSize = 10; + if (el.stack.size()) + std::cout << setw(5) << el.stack.size() << ":["; + for (auto const& stackEl : el.stack) + { + if (stackEl.size() > c_stackPreviewSize) + std::cout << stackEl.substr(2, c_stackPreviewSize) << "...,"; + else + std::cout << stackEl.substr(2) << ","; + } + + if (el.stack.size()) + std::cout << "]"; + std::cout << std::endl; + if (el.error.size()) + std::cout << "Detected error: " << el.error << std::endl; // Opcode highlight static vector callopcodes = { "CALLCODE", "CALL", "DELEGATECALL" }; @@ -231,4 +218,15 @@ void DebugVMTrace::exportLogs(fs::path const& _folder) } } +std::vector const& DebugVMTrace::getLog() +{ + return m_impl->getLog(); +} + +void DebugVMTrace::print() +{ + if (m_impl) + m_impl->print(); +} + } // namespace teststruct diff --git a/retesteth/testStructures/types/RPC/DebugVMTrace.h b/retesteth/testStructures/types/RPC/DebugVMTrace.h index 9720fabaa..6e52c8d0e 100644 --- a/retesteth/testStructures/types/RPC/DebugVMTrace.h +++ b/retesteth/testStructures/types/RPC/DebugVMTrace.h @@ -1,59 +1,54 @@ #pragma once -#include "../../basetypes.h" +#include "VMLogRecord.h" #include #include - namespace test::teststruct { -/* - * VMTrace: (stExample/add11, fork: Istanbul, TrInfo: d: 0, g: 0, v: 0) -Transaction number: 0, hash: 0x5363f287fccaad86a0ce8d2c5b15b4b917afe6ebac6a87e61884bf18fc7af58a -{"pc":0,"op":96,"gas":"0x5c878","gasCost":"0x3","memory":"0x","memSize":0, - "stack":[],"returnStack":[],"returnData":null,"depth":1,"refund":0,"opName":"PUSH1","error":""} -*/ - -struct VMLogRecord -{ - VMLogRecord(DataObject const&); - size_t pc; - size_t op; - spVALUE gas; - spVALUE gasCost; - spBYTES memory; - long long memSize; - std::vector stack; - spBYTES returnData; - size_t depth; - spVALUE refund; - std::string opName; - std::string error; - bool isShort = false; -}; -struct DebugVMTrace : GCP_SPointerBase +class DebugVMTrace : public GCP_SPointerBase { +private: + class DebugVMTraceImplInterface + { + public: + virtual void print() = 0; + std::vector const& getLog() const { return m_log; }; + virtual ~DebugVMTraceImplInterface(){} + protected: + std::string m_infoString; + std::vector m_log; + }; + class DebugVMTraceRaw : public DebugVMTraceImplInterface + { + public: + DebugVMTraceRaw(std::string const& _info, boost::filesystem::path const&); + void print() override; + private: + std::string m_rawUnparsedLogs; + }; + class DebugVMTraceNice : public DebugVMTraceImplInterface + { + public: + DebugVMTraceNice(std::string const& _info, boost::filesystem::path const&); + void print() override; + private: + void readLog(std::string const&); + bool m_limitReached = false; + }; + + +public: DebugVMTrace() {} // for tuples - DebugVMTrace(std::string const& _info, std::string const& _trNumber, FH32 const& _trHash, boost::filesystem::path const& _logs); + DebugVMTrace(std::string const& _info, boost::filesystem::path const& _logs); void print(); - void printNice(); void exportLogs(boost::filesystem::path const& _folder); - std::vector const& getLog() const { return m_log; } + std::vector const& getLog(); ~DebugVMTrace(); private: - std::string m_infoString; - std::string m_trNumber; - spFH32 m_trHash; - std::vector m_log; - std::string m_rawUnparsedLogs; + std::shared_ptr m_impl; boost::filesystem::path m_rawVmTraceFile; - bool m_limitReached = false; - - // Last record - std::string m_output; - spVALUE m_gasUsed; - long long m_time; }; typedef GCP_SPointer spDebugVMTrace; diff --git a/retesteth/testStructures/types/RPC/EthGetBlockBy.cpp b/retesteth/testStructures/types/RPC/EthGetBlockBy.cpp index fdd42795e..97b1f0e58 100644 --- a/retesteth/testStructures/types/RPC/EthGetBlockBy.cpp +++ b/retesteth/testStructures/types/RPC/EthGetBlockBy.cpp @@ -29,6 +29,7 @@ EthGetBlockBy::EthGetBlockBy(spDataObject& _data) {"stateRoot", {{DataType::String}, jsonField::Required}}, {"timestamp", {{DataType::String}, jsonField::Required}}, {"transactionsRoot", {{DataType::String}, jsonField::Required}}, + {"withdrawalsRoot", {{DataType::String}, jsonField::Optional}}, //Shanghai field {"sha3Uncles", {{DataType::String}, jsonField::Required}}, {"seedHash", {{DataType::String}, jsonField::Optional}}, //Aleth field {"boundary", {{DataType::String}, jsonField::Optional}}, //Aleth field @@ -36,6 +37,7 @@ EthGetBlockBy::EthGetBlockBy(spDataObject& _data) {"size", {{DataType::String}, jsonField::Required}}, {"totalDifficulty", {{DataType::String}, jsonField::Required}}, {"uncles", {{DataType::Array}, jsonField::Required}}, + {"withdrawals", {{DataType::Array}, jsonField::Optional}}, {"transactions", {{DataType::Array}, jsonField::Required}}}); @@ -45,18 +47,30 @@ EthGetBlockBy::EthGetBlockBy(spDataObject& _data) m_totalDifficulty = spVALUE(new VALUE(_data->atKey("totalDifficulty"))); m_lessobjects = false; - for (auto& el : _data.getContent().atKeyUnsafe("transactions").getSubObjectsUnsafe()) + string const c_transactions = "transactions"; + m_transactions.reserve(_data->atKey(c_transactions).getSubObjects().size()); + for (auto& el : _data.getContent().atKeyUnsafe(c_transactions).getSubObjectsUnsafe()) { (*el).renameKey("input", "data"); (*el).renameKey("gas", "gasLimit"); - m_transactions.push_back(EthGetBlockByTransaction(dataobject::move(el))); - if (!m_transactions.at(m_transactions.size() - 1).isFullTransaction()) + m_transactions.emplace_back(spEthGetBlockByTransaction(new EthGetBlockByTransaction(dataobject::move(el)))); + if (!m_transactions.at(m_transactions.size() - 1)->isFullTransaction()) m_lessobjects = true; } + string const c_withdrawals = "withdrawals"; + if (_data->count(c_withdrawals)) + { + m_withdrawals.reserve(_data->atKey(c_withdrawals).getSubObjects().size()); + for (auto& el : _data.getContent().atKeyUnsafe(c_withdrawals).getSubObjectsUnsafe()) + m_withdrawals.emplace_back(spEthGetBlockByWithdrawal(new EthGetBlockByWithdrawal(dataobject::move(el)))); + } + // Remote eth_getBlockBy* always return uncles as hashes. - for (auto const& un : _data->atKey("uncles").getSubObjects()) - m_uncles.push_back(FH32(un)); + string const c_uncles = "uncles"; + m_uncles.reserve(_data->atKey(c_uncles).getSubObjects().size()); + for (auto const& un : _data->atKey(c_uncles).getSubObjects()) + m_uncles.emplace_back(FH32(un)); } catch (std::exception const& _ex) { @@ -68,7 +82,7 @@ bool EthGetBlockBy::hasTransaction(FH32 const& _hash) const { for (auto const& tr : m_transactions) { - if (tr.hash() == _hash) + if (tr->hash() == _hash) return true; } return false; @@ -79,7 +93,9 @@ BYTES EthGetBlockBy::getRLPHeaderTransactions() const { EthereumBlock block(m_header); for (auto const& tr : m_transactions) - block.addTransaction(tr.transaction()); + block.addTransaction(tr->transaction()); + for (auto const& wt: m_withdrawals) + block.addWithdrawal(wt->withdrawal()); return block.getRLP(); } diff --git a/retesteth/testStructures/types/RPC/EthGetBlockBy.h b/retesteth/testStructures/types/RPC/EthGetBlockBy.h index 6700caa8b..ecd509901 100644 --- a/retesteth/testStructures/types/RPC/EthGetBlockBy.h +++ b/retesteth/testStructures/types/RPC/EthGetBlockBy.h @@ -1,19 +1,19 @@ #pragma once -#include "../../basetypes.h" -#include "../Ethereum/BlockHeader.h" +#include +#include "../Ethereum/Blocks/BlockHeader.h" #include "SubElements/EthGetBlockByTransaction.h" +#include "SubElements/EthGetBlockByWithdrawal.h" #include -namespace test -{ -namespace teststruct +namespace test::teststruct { + // Structure for RPC response eth_getBlockByHash/eth_getBlockByNumber struct EthGetBlockBy : GCP_SPointerBase { EthGetBlockBy(spDataObject&); spBlockHeader const& header() const { return m_header; } - std::vector const& transactions() const { return m_transactions; } + std::vector const& transactions() const { return m_transactions; } std::vector const& uncles() const { return m_uncles; } BYTES getRLPHeaderTransactions() const; @@ -24,12 +24,14 @@ struct EthGetBlockBy : GCP_SPointerBase EthGetBlockBy() {} bool m_lessobjects = false; spBlockHeader m_header; - std::vector m_transactions; + std::vector m_transactions; + std::vector m_withdrawals; std::vector m_uncles; spVALUE m_size; spVALUE m_totalDifficulty; }; +typedef GCP_SPointer spEthGetBlockBy; + } // namespace teststruct -} // namespace test diff --git a/retesteth/testStructures/types/RPC/MineBlocksResult.h b/retesteth/testStructures/types/RPC/MineBlocksResult.h index 58e3432a2..e49ff2e8a 100644 --- a/retesteth/testStructures/types/RPC/MineBlocksResult.h +++ b/retesteth/testStructures/types/RPC/MineBlocksResult.h @@ -1,5 +1,5 @@ #pragma once -#include "../../basetypes.h" +#include #include #include diff --git a/retesteth/testStructures/types/RPC/SetChainParamsArgs.cpp b/retesteth/testStructures/types/RPC/SetChainParamsArgs.cpp index 1d079aea1..7d5797343 100644 --- a/retesteth/testStructures/types/RPC/SetChainParamsArgs.cpp +++ b/retesteth/testStructures/types/RPC/SetChainParamsArgs.cpp @@ -1,5 +1,6 @@ #include "SetChainParamsArgs.h" #include +#include using namespace dataobject; using namespace test::teststruct; @@ -20,7 +21,12 @@ spSetChainParamsArgsGenesis readGenesis(DataObject const& _data) if (_data.count("baseFeePerGas")) { if (_data.count("currentRandom")) - return spSetChainParamsArgsGenesis(new SetChainParamsArgsGenesisMerge(_data)); + { + if (_data.count("withdrawalsRoot")) + return spSetChainParamsArgsGenesis(new SetChainParamsArgsGenesisShanghai(_data)); + else + return spSetChainParamsArgsGenesis(new SetChainParamsArgsGenesisMerge(_data)); + } else return spSetChainParamsArgsGenesis(new SetChainParamsArgsGenesis1559(_data)); } @@ -81,6 +87,23 @@ SetChainParamsArgsGenesisMerge::SetChainParamsArgsGenesisMerge(DataObject const& }); } +SetChainParamsArgsGenesisShanghai::SetChainParamsArgsGenesisShanghai(DataObject const& _data) + : SetChainParamsArgsGenesis(_data, false) +{ + REQUIRE_JSONFIELDS(_data, "SetChainParamsArgs::genesis(Shanghai) ", + { + {"author", {{DataType::String}, jsonField::Required}}, + {"gasLimit", {{DataType::String}, jsonField::Required}}, + {"baseFeePerGas", {{DataType::String}, jsonField::Required}}, + {"currentRandom", {{DataType::String}, jsonField::Required}}, + {"withdrawalsRoot", {{DataType::String}, jsonField::Required}}, + {"extraData", {{DataType::String}, jsonField::Required}}, + {"timestamp", {{DataType::String}, jsonField::Required}}, + {"nonce", {{DataType::String}, jsonField::Required}}, + {"mixHash", {{DataType::String}, jsonField::Required}} + }); +} + SetChainParamsArgs::SetChainParamsArgs(spDataObject& _data) { requireSetChainParamsScheme(_data); @@ -103,11 +126,15 @@ spDataObject SetChainParamsArgs::asDataObject() const (*out)["genesis"]["difficulty"] = m_genesis->difficulty().asString(); (*out)["genesis"]["gasLimit"] = m_genesis->gasLimit().asString(); - if (m_genesis->type() == BlockType::BlockHeader1559 - || m_genesis->type() == BlockType::BlockHeaderMerge) + if (isBlockExportBasefee(m_genesis)) { BlockHeader1559 const& newbl = BlockHeader1559::castFrom(m_genesis); (*out)["genesis"]["baseFeePerGas"] = newbl.baseFee().asString(); + if (isBlockExportWithdrawals(m_genesis)) + { + BlockHeaderShanghai const& newbl = BlockHeaderShanghai::castFrom(m_genesis); + (*out)["genesis"]["withdrawalsRoot"] = newbl.withdrawalsRoot().asString(); + } } (*out)["genesis"]["extraData"] = m_genesis->extraData().asString(); @@ -132,9 +159,9 @@ spDataObject SetChainParamsArgsGenesis::buildCommonBlockHeader() const fullBlockHeader["bloom"] = FH256::zero().asString(); fullBlockHeader["gasUsed"] = "0x00"; fullBlockHeader["number"] = "0x00"; - fullBlockHeader["receiptTrie"] = "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"; + fullBlockHeader["receiptTrie"] = C_WITHDRAWALS_EMPTY_ROOT; fullBlockHeader["stateRoot"] = FH32::zero().asString(); - fullBlockHeader["transactionsTrie"] = "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"; + fullBlockHeader["transactionsTrie"] = C_WITHDRAWALS_EMPTY_ROOT; fullBlockHeader["uncleHash"] = "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"; fullBlockHeader["parentHash"] = FH32::zero().asString(); return _fullBlockHeader; @@ -165,5 +192,16 @@ spBlockHeader SetChainParamsArgsGenesisMerge::constructBlockHeader() const return readBlockHeader(header); } +spBlockHeader SetChainParamsArgsGenesisShanghai::constructBlockHeader() const +{ + spDataObject header = buildCommonBlockHeader(); + (*header)["baseFeePerGas"] = m_dataRef.atKey("baseFeePerGas").asString(); + (*header)["difficulty"] = "0x00"; + auto const curRandomU256 = dev::u256(m_dataRef.atKey("currentRandom").asString()); + (*header)["mixHash"] = dev::toCompactHexPrefixed(curRandomU256, 32); + (*header)["withdrawalsRoot"] = m_dataRef.atKey("withdrawalsRoot").asString(); + return readBlockHeader(header); +} + } // namespace teststruct } // namespace test diff --git a/retesteth/testStructures/types/RPC/SetChainParamsArgs.h b/retesteth/testStructures/types/RPC/SetChainParamsArgs.h index 98d667e32..34777737b 100644 --- a/retesteth/testStructures/types/RPC/SetChainParamsArgs.h +++ b/retesteth/testStructures/types/RPC/SetChainParamsArgs.h @@ -1,6 +1,6 @@ #pragma once -#include "../Ethereum/BlockHeader.h" -#include "../Ethereum/BlockHeader1559.h" +#include "../Ethereum/Blocks/BlockHeader.h" +#include "../Ethereum/Blocks/BlockHeader1559.h" #include "../Ethereum/State.h" #include @@ -47,6 +47,11 @@ struct SetChainParamsArgsGenesisMerge : SetChainParamsArgsGenesis SetChainParamsArgsGenesisMerge(DataObject const&); spBlockHeader constructBlockHeader() const override; }; +struct SetChainParamsArgsGenesisShanghai : SetChainParamsArgsGenesis +{ + SetChainParamsArgsGenesisShanghai(DataObject const&); + spBlockHeader constructBlockHeader() const override; +}; typedef GCP_SPointer spSetChainParamsArgs; typedef GCP_SPointer spSetChainParamsArgsGenesis; diff --git a/retesteth/testStructures/types/RPC/SubElements/EthGetBlockByTransaction.h b/retesteth/testStructures/types/RPC/SubElements/EthGetBlockByTransaction.h index 5202d47e3..27e988a3c 100644 --- a/retesteth/testStructures/types/RPC/SubElements/EthGetBlockByTransaction.h +++ b/retesteth/testStructures/types/RPC/SubElements/EthGetBlockByTransaction.h @@ -1,14 +1,13 @@ #pragma once #include "../../../basetypes.h" -#include "../../Ethereum/Transaction.h" +#include "../../Ethereum/Transactions/Transaction.h" #include -namespace test -{ -namespace teststruct +namespace test::teststruct { + // Transaction Structure inside RPC response eth_getBlockByHash/eth_getBlockByNumber -struct EthGetBlockByTransaction +struct EthGetBlockByTransaction : GCP_SPointerBase { EthGetBlockByTransaction(spDataObjectMove); FH32 const& hash() const { return m_hash; } @@ -39,5 +38,6 @@ struct EthGetBlockByTransaction spVALUE m_transactionIndex; }; +typedef GCP_SPointer spEthGetBlockByTransaction; + } // namespace teststruct -} // namespace test diff --git a/retesteth/testStructures/types/RPC/SubElements/EthGetBlockByWithdrawal.cpp b/retesteth/testStructures/types/RPC/SubElements/EthGetBlockByWithdrawal.cpp new file mode 100644 index 000000000..56f354306 --- /dev/null +++ b/retesteth/testStructures/types/RPC/SubElements/EthGetBlockByWithdrawal.cpp @@ -0,0 +1,21 @@ +#include "EthGetBlockByWithdrawal.h" +#include +#include + +using namespace std; +namespace test::teststruct +{ +EthGetBlockByWithdrawal::EthGetBlockByWithdrawal(spDataObjectMove _data) +{ + try + { + spDataObject data = _data.getPointer(); + m_withdrawal = spWithdrawal(new Withdrawal(_data)); + } + catch (std::exception const& _ex) + { + ETH_ERROR_MESSAGE(string("EthGetBlockByWithdrawal unmarshal error: ") + _ex.what()); + } +} + +} // namespace teststruct diff --git a/retesteth/testStructures/types/RPC/SubElements/EthGetBlockByWithdrawal.h b/retesteth/testStructures/types/RPC/SubElements/EthGetBlockByWithdrawal.h new file mode 100644 index 000000000..f084cd3a5 --- /dev/null +++ b/retesteth/testStructures/types/RPC/SubElements/EthGetBlockByWithdrawal.h @@ -0,0 +1,19 @@ +#pragma once +#include "../../../basetypes.h" +#include +#include + +namespace test::teststruct +{ +// Withdrawals Structure inside RPC response eth_getBlockByHash/eth_getBlockByNumber +struct EthGetBlockByWithdrawal : GCP_SPointerBase +{ + EthGetBlockByWithdrawal(spDataObjectMove); + spWithdrawal const& withdrawal() const { return m_withdrawal; } +private: + spWithdrawal m_withdrawal; +}; + +typedef GCP_SPointer spEthGetBlockByWithdrawal; + +} // namespace teststruct diff --git a/retesteth/testStructures/types/RPC/TestRawTranasction.h b/retesteth/testStructures/types/RPC/TestRawTranasction.h index e8aff85ef..93e244e8c 100644 --- a/retesteth/testStructures/types/RPC/TestRawTranasction.h +++ b/retesteth/testStructures/types/RPC/TestRawTranasction.h @@ -1,5 +1,5 @@ #pragma once -#include "../../basetypes.h" +#include #include "MineBlocksResult.h" #include diff --git a/retesteth/testStructures/types/RPC/ToolResponse.cpp b/retesteth/testStructures/types/RPC/ToolResponse.cpp index 79bf5dae4..b5b819ef4 100644 --- a/retesteth/testStructures/types/RPC/ToolResponse.cpp +++ b/retesteth/testStructures/types/RPC/ToolResponse.cpp @@ -1,4 +1,5 @@ #include "ToolResponse.h" +#include "Constants.h" #include namespace test::teststruct @@ -13,6 +14,7 @@ ToolResponse::ToolResponse(DataObject const& _data) {"logsBloom", {{DataType::String}, jsonField::Required}}, {"currentDifficulty", {{DataType::String, DataType::Null}, jsonField::Required}}, {"currentBaseFee", {{DataType::String, DataType::Null}, jsonField::Optional}}, + {"withdrawalsRoot", {{DataType::String}, jsonField::Optional}}, {"rejected", {{DataType::Array}, jsonField::Optional}}, {"gasUsed", {{DataType::String}, jsonField::Optional}}, {"receipts", {{DataType::Array}, jsonField::Required}}}); @@ -23,23 +25,27 @@ ToolResponse::ToolResponse(DataObject const& _data) m_logsHash = spFH32(new FH32(_data.atKey("logsHash"))); m_logsBloom = spFH256(new FH256(_data.atKey("logsBloom"))); + m_currentDifficulty = spVALUE(new VALUE(0)); if (_data.atKey("currentDifficulty").type() != DataType::Null) m_currentDifficulty = spVALUE(new VALUE(_data.atKey("currentDifficulty"))); - else - m_currentDifficulty = spVALUE(new VALUE(0)); + m_currentBasefee = spVALUE(new VALUE(0)); if (_data.count("currentBaseFee")) m_currentBasefee = spVALUE(new VALUE(_data.atKey("currentBaseFee"))); - else - m_currentBasefee = spVALUE(new VALUE(0)); - for (auto const& el : _data.atKey("receipts").getSubObjects()) - m_receipts.push_back(ToolResponseReceipt(el)); + m_withdrawalsRoot = spFH32(new FH32(C_WITHDRAWALS_EMPTY_ROOT)); + if (_data.count("withdrawalsRoot")) + m_withdrawalsRoot = spFH32(new FH32(_data.atKey("withdrawalsRoot"))); + + auto const& receipts = _data.atKey("receipts").getSubObjects(); + m_receipts.reserve(receipts.size()); + for (auto const& el : receipts) + m_receipts.emplace_back(ToolResponseReceipt(el)); if (_data.count("rejected")) { for (auto const& el : _data.atKey("rejected").getSubObjects()) - m_rejectedTransactions.push_back(ToolResponseRejected(el)); + m_rejectedTransactions.emplace_back(ToolResponseRejected(el)); } } diff --git a/retesteth/testStructures/types/RPC/ToolResponse.h b/retesteth/testStructures/types/RPC/ToolResponse.h index fd7562193..c6e6b476d 100644 --- a/retesteth/testStructures/types/RPC/ToolResponse.h +++ b/retesteth/testStructures/types/RPC/ToolResponse.h @@ -1,5 +1,5 @@ #pragma once -#include "../../basetypes.h" +#include #include "../Ethereum/State.h" #include "SubElements/ToolResponseReceipt.h" #include "SubElements/ToolResponseRejected.h" @@ -20,6 +20,7 @@ struct ToolResponse FH256 const& logsBloom() const { return m_logsBloom; } VALUE const& currentDifficulty() const { return m_currentDifficulty; } VALUE const& currentBasefee() const { return m_currentBasefee; } + FH32 const& withdrawalsRoot() const { return m_withdrawalsRoot;} VALUE totalGasUsed() const { VALUE totalGasUsed = 0; @@ -45,10 +46,10 @@ struct ToolResponse spFH256 m_logsBloom; spVALUE m_currentDifficulty; spVALUE m_currentBasefee; + spFH32 m_withdrawalsRoot; std::vector m_receipts; spState m_stateResponse; std::map m_debugTrace; - std::vector m_rejectedTransactions; }; diff --git a/retesteth/testStructures/types/RPC/VMLogRecord.cpp b/retesteth/testStructures/types/RPC/VMLogRecord.cpp new file mode 100644 index 000000000..e3933f3ef --- /dev/null +++ b/retesteth/testStructures/types/RPC/VMLogRecord.cpp @@ -0,0 +1,88 @@ +#include +#include +#include "VMLogRecord.h" +using namespace test; +using namespace test::teststruct; +using namespace dataobject; +using namespace std; + +VMLogRecord::VMLogRecord(DataObject const& _obj) +{ + try + { + if (_obj.getSubObjects().size() == 2) + { + REQUIRE_JSONFIELDS(_obj, "VMLogRecord " + _obj.getKey(), + { + {"output", {{DataType::String}, jsonField::Required}}, + {"gasUsed", {{DataType::String}, jsonField::Required}}}); + isShort = true; + } + else if (_obj.getSubObjects().size() == 3) + { + REQUIRE_JSONFIELDS(_obj, "VMLogRecord " + _obj.getKey(), + { + {"output", {{DataType::String}, jsonField::Required}}, + {"gasUsed", {{DataType::String}, jsonField::Required}}, + {"error", {{DataType::String}, jsonField::Required}}}); + isShort = true; + } + else if (_obj.getSubObjects().size() == 4) + { + REQUIRE_JSONFIELDS(_obj, "VMLogRecord " + _obj.getKey(), + { + {"output", {{DataType::String}, jsonField::Required}}, + {"gasUsed", {{DataType::String}, jsonField::Required}}, + {"time", {{DataType::Integer}, jsonField::Required}}, + {"error", {{DataType::String}, jsonField::Required}}}); + isShort = true; + } + else + { + REQUIRE_JSONFIELDS(_obj, "VMLogRecord " + _obj.getKey(), + {{"pc", {{DataType::Integer}, jsonField::Required}}, + {"op", {{DataType::Integer}, jsonField::Required}}, + {"gas", {{DataType::String}, jsonField::Required}}, + {"gasCost", {{DataType::String}, jsonField::Required}}, + {"memory", {{DataType::String}, jsonField::Optional}}, + {"memSize", {{DataType::Integer}, jsonField::Required}}, + {"stack", {{DataType::Array}, jsonField::Required}}, + {"depth", {{DataType::Integer}, jsonField::Required}}, + {"refund", {{DataType::Integer}, jsonField::Required}}, + {"opName", {{DataType::String}, jsonField::Required}}, + {"returnData", {{DataType::String}, jsonField::Optional}}, + {"error", {{DataType::String}, jsonField::Optional}}}); + } + + if (_obj.count("error")) + error = _obj.atKey("error").asString(); + + if (_obj.getSubObjects().size() > 4) + { + pc = _obj.atKey("pc").asInt(); + op = _obj.atKey("op").asInt(); + gas = spVALUE(new VALUE(_obj.atKey("gas"))); + gasCost = spVALUE(new VALUE(_obj.atKey("gasCost"))); + if (_obj.count("memory")) + memory = spBYTES(new BYTES(_obj.atKey("memory"))); + else + memory = spBYTES(new BYTES(DataObject("0x"))); + memSize = _obj.atKey("memSize").asInt(); + for (auto const& el : _obj.atKey("stack").getSubObjects()) + stack.emplace_back(el->asString()); + if (_obj.count("returnData")) + returnData = spBYTES(new BYTES(_obj.atKey("returnData"))); + else + returnData = spBYTES(new BYTES(DataObject("0x"))); + depth = _obj.atKey("depth").asInt(); + refund = _obj.atKey("refund").asInt(); + opName = _obj.atKey("opName").asString(); + error = _obj.count("error") ? _obj.atKey("error").asString() : ""; + } + + } + catch (std::exception const& _ex) + { + throw UpwardsException(string("VMLogRecord parse error: ") + _ex.what()); + } +} diff --git a/retesteth/testStructures/types/RPC/VMLogRecord.h b/retesteth/testStructures/types/RPC/VMLogRecord.h new file mode 100644 index 000000000..e58bd545f --- /dev/null +++ b/retesteth/testStructures/types/RPC/VMLogRecord.h @@ -0,0 +1,32 @@ +#pragma once +#include +#include + +namespace test::teststruct +{ + +/* + * VMTrace: (stExample/add11, fork: Istanbul, TrInfo: d: 0, g: 0, v: 0) +Transaction number: 0, hash: 0x5363f287fccaad86a0ce8d2c5b15b4b917afe6ebac6a87e61884bf18fc7af58a +{"pc":0,"op":96,"gas":"0x5c878","gasCost":"0x3","memory":"0x","memSize":0, + "stack":[],"returnStack":[],"returnData":null,"depth":1,"refund":0,"opName":"PUSH1","error":""} +*/ + +struct VMLogRecord +{ + VMLogRecord(DataObject const&); + size_t pc; + size_t op; + spVALUE gas; + spVALUE gasCost; + spBYTES memory; + long long memSize; + std::vector stack; + spBYTES returnData; + size_t depth; + spVALUE refund; + std::string opName; + std::string error; + bool isShort = false; +}; +} diff --git a/retesteth/testStructures/types/StateTests/Base/AccessList.cpp b/retesteth/testStructures/types/StateTests/Base/AccessList.cpp index 4379c3041..5cbbf8a64 100644 --- a/retesteth/testStructures/types/StateTests/Base/AccessList.cpp +++ b/retesteth/testStructures/types/StateTests/Base/AccessList.cpp @@ -15,11 +15,11 @@ AccessListElement::AccessListElement(DataObject const& _data) { auto const elStr = el->asString(); if (elStr.find("bigint") != string::npos) - m_storageKeys.push_back(spFH32(new FH32(el->asString()))); + m_storageKeys.emplace_back(spFH32(new FH32(el->asString()))); else { // TODO: This is a filler file convertion logic!!! - m_storageKeys.push_back(spFH32(new FH32(dev::toCompactHexPrefixed(dev::u256(elStr), 32)))); + m_storageKeys.emplace_back(spFH32(new FH32(dev::toCompactHexPrefixed(dev::u256(elStr), 32)))); } } } @@ -27,7 +27,7 @@ AccessListElement::AccessListElement(DataObject const& _data) AccessList::AccessList(DataObject const& _data) { for (auto const& el : _data.getSubObjects()) - m_list.push_back(spAccessListElement(new AccessListElement(el))); + m_list.emplace_back(spAccessListElement(new AccessListElement(el))); } spDataObject AccessList::asDataObject() const @@ -68,13 +68,13 @@ AccessListElement::AccessListElement(dev::RLP const& _rlp) m_address = spFH20(new FH20(_rlp[i++])); auto const& rlplist = _rlp[i++].toList(); for (auto const& key : rlplist) - m_storageKeys.push_back(spFH32(new FH32(key))); + m_storageKeys.emplace_back(spFH32(new FH32(key))); } AccessList::AccessList(dev::RLP const& _rlp) { for (auto const& accList : _rlp.toList()) - m_list.push_back(spAccessListElement(new AccessListElement(accList))); + m_list.emplace_back(spAccessListElement(new AccessListElement(accList))); } } // namespace teststruct diff --git a/retesteth/testStructures/types/StateTests/Base/StateTestEnvBase.h b/retesteth/testStructures/types/StateTests/Base/StateTestEnvBase.h index fe99ec53c..51c88e0d7 100644 --- a/retesteth/testStructures/types/StateTests/Base/StateTestEnvBase.h +++ b/retesteth/testStructures/types/StateTests/Base/StateTestEnvBase.h @@ -29,6 +29,8 @@ struct StateTestEnvBase : GCP_SPointerBase FH32 const& currentRandom() const { return m_currentRandom; } VALUE const& currentDifficulty() const { return m_currentDifficulty; } + FH32 const& currentWithdrawalsRoot() const { return m_currentWithdrawalsRoot; } + protected: StateTestEnvBase() {} spDataObject m_raw; @@ -48,6 +50,9 @@ struct StateTestEnvBase : GCP_SPointerBase // Merge spFH32 m_currentRandom; + + // Shaghai + spFH32 m_currentWithdrawalsRoot; }; diff --git a/retesteth/testStructures/types/StateTests/Base/StateTestTransactionBase.cpp b/retesteth/testStructures/types/StateTests/Base/StateTestTransactionBase.cpp index 26717ad29..021e840bc 100644 --- a/retesteth/testStructures/types/StateTests/Base/StateTestTransactionBase.cpp +++ b/retesteth/testStructures/types/StateTests/Base/StateTestTransactionBase.cpp @@ -8,6 +8,8 @@ using namespace test::teststruct; spDataObject StateTestTransactionBase::asDataObject() const { + // Saves serialization time because processed in the constructor + // TODO: double check this return m_rawData; } @@ -16,15 +18,14 @@ std::vector StateTestTransactionBase::buildTransact { // Construct vector of all transactions that are described int data std::vector out; + out.reserve(m_databox.size() * m_gasLimit.size() * m_value.size()); for (size_t dIND = 0; dIND < m_databox.size(); dIND++) { for (size_t gIND = 0; gIND < m_gasLimit.size(); gIND++) { for (size_t vIND = 0; vIND < m_value.size(); vIND++) { - if (ExitHandler::receivedExitSignal()) - return out; - + CHECKEXITR(out) Databox const& databox = m_databox.at(dIND); spDataObject trData; @@ -60,8 +61,7 @@ std::vector StateTestTransactionBase::buildTransact if (!databox.m_accessList.isEmpty()) (*trData).atKeyPointer("accessList") = databox.m_accessList->asDataObject(); - out.push_back( - TransactionInGeneralSection(dataobject::move(trData), dIND, gIND, vIND, databox.m_dataRawPreview, databox.m_dataLabel)); + out.emplace_back(TransactionInGeneralSection(dataobject::move(trData), dIND, gIND, vIND, databox.m_dataRawPreview, databox.m_dataLabel)); } } } diff --git a/retesteth/testStructures/types/StateTests/Base/TransactionInGeneralSection.cpp b/retesteth/testStructures/types/StateTests/Base/TransactionInGeneralSection.cpp index 6e9df93b9..f57edd32a 100644 --- a/retesteth/testStructures/types/StateTests/Base/TransactionInGeneralSection.cpp +++ b/retesteth/testStructures/types/StateTests/Base/TransactionInGeneralSection.cpp @@ -1,6 +1,6 @@ #include "TransactionInGeneralSection.h" #include -#include +#include using namespace std; using namespace test::teststruct; diff --git a/retesteth/testStructures/types/StateTests/Base/TransactionInGeneralSection.h b/retesteth/testStructures/types/StateTests/Base/TransactionInGeneralSection.h index bcdf55ecc..a27f5f212 100644 --- a/retesteth/testStructures/types/StateTests/Base/TransactionInGeneralSection.h +++ b/retesteth/testStructures/types/StateTests/Base/TransactionInGeneralSection.h @@ -1,5 +1,5 @@ #pragma once -#include "../../Ethereum/Transaction.h" +#include "../../Ethereum/Transactions/Transaction.h" #include namespace test::teststruct diff --git a/retesteth/testStructures/types/StateTests/Filled/Info.cpp b/retesteth/testStructures/types/StateTests/Filled/Info.cpp index 8fbf97d03..2d2e34295 100644 --- a/retesteth/testStructures/types/StateTests/Filled/Info.cpp +++ b/retesteth/testStructures/types/StateTests/Filled/Info.cpp @@ -1,35 +1,54 @@ #include "Info.h" +#include #include +using namespace std; +using namespace test::teststruct; -namespace test +namespace { -namespace teststruct + void requireInfoFields(DataObject const& _data) + { + if (_data.count("filledwith")) + { + REQUIRE_JSONFIELDS(_data, "InfoLegacy " + _data.getKey(), + {{"comment", {{DataType::String}, jsonField::Required}}, + {"filledwith", {{DataType::String}, jsonField::Required}}, + {"lllcversion", {{DataType::String}, jsonField::Required}}, + {"source", {{DataType::String}, jsonField::Required}}, + {"sourceHash", {{DataType::String}, jsonField::Optional}}, + {"source", {{DataType::String}, jsonField::Required}}, + {"sourceHash", {{DataType::String}, jsonField::Required}}}); + } + else + { + REQUIRE_JSONFIELDS(_data, "Info " + _data.getKey(), + {{"comment", {{DataType::String}, jsonField::Required}}, + {"filling-block-build-tool", {{DataType::String}, jsonField::Optional}}, + {"filling-transition-tool", {{DataType::String}, jsonField::Optional}}, + {"filling-rpc-server", {{DataType::String}, jsonField::Required}}, + {"filling-tool-version", {{DataType::String}, jsonField::Required}}, + {"lllcversion", {{DataType::String}, jsonField::Required}}, + {"solidity", {{DataType::String}, jsonField::Required}}, + {"generatedTestHash", {{DataType::String}, jsonField::Required}}, + {"source", {{DataType::String}, jsonField::Required}}, + {"sourceHash", {{DataType::String}, jsonField::Required}}, + {"labels", {{DataType::Object}, jsonField::Optional}}}); + } + } +} + +namespace test::teststruct { + Info::Info(DataObject const& _data) { - if (_data.count("filledwith")) + try { - REQUIRE_JSONFIELDS(_data, "InfoLegacy " + _data.getKey(), - {{"comment", {{DataType::String}, jsonField::Required}}, - {"filledwith", {{DataType::String}, jsonField::Required}}, - {"lllcversion", {{DataType::String}, jsonField::Required}}, - {"source", {{DataType::String}, jsonField::Required}}, - {"sourceHash", {{DataType::String}, jsonField::Optional}}, - {"source", {{DataType::String}, jsonField::Required}}, - {"sourceHash", {{DataType::String}, jsonField::Required}}}); + requireInfoFields(_data); } - else + catch (std::exception const& _ex) { - REQUIRE_JSONFIELDS(_data, "Info " + _data.getKey(), - {{"comment", {{DataType::String}, jsonField::Required}}, - {"filling-rpc-server", {{DataType::String}, jsonField::Required}}, - {"filling-tool-version", {{DataType::String}, jsonField::Required}}, - {"lllcversion", {{DataType::String}, jsonField::Required}}, - {"solidity", {{DataType::String}, jsonField::Required}}, - {"generatedTestHash", {{DataType::String}, jsonField::Required}}, - {"source", {{DataType::String}, jsonField::Required}}, - {"sourceHash", {{DataType::String}, jsonField::Required}}, - {"labels", {{DataType::Object}, jsonField::Optional}}}); + ETH_WARNING(string() + "Info section verification failed: " + _ex.what()); } if (_data.count("labels")) @@ -40,4 +59,3 @@ Info::Info(DataObject const& _data) } } // namespace teststruct -} // namespace test diff --git a/retesteth/testStructures/types/StateTests/Filled/StateTestEnv.cpp b/retesteth/testStructures/types/StateTests/Filled/StateTestEnv.cpp index 11e273a8a..efb88fbe2 100644 --- a/retesteth/testStructures/types/StateTests/Filled/StateTestEnv.cpp +++ b/retesteth/testStructures/types/StateTests/Filled/StateTestEnv.cpp @@ -1,6 +1,7 @@ #include "StateTestEnv.h" #include #include +#include using namespace std; using namespace dataobject; @@ -41,8 +42,8 @@ void StateTestEnv::initializeFields(DataObject const& _data) DataObject tmpD; tmpD = "0x00"; // State Tests extra data is 0x00 m_currentExtraData = spBYTES(new BYTES(tmpD)); - m_currentNonce = spFH8(new FH8(FH8::zero())); - m_currentMixHash = spFH32(new FH32(FH32::zero())); + m_currentNonce = spFH8(FH8::zero().copy()); + m_currentMixHash = spFH32(FH32::zero().copy()); // 1559 m_currentDifficulty = spVALUE(new VALUE(DataObject("0x00"))); @@ -57,6 +58,8 @@ void StateTestEnv::initializeFields(DataObject const& _data) m_currentRandom = spFH32(FH32::zero().copy()); if (_data.count("currentRandom")) m_currentRandom = spFH32(new FH32(_data.atKey("currentRandom"))); + + m_currentWithdrawalsRoot = spFH32(new FH32(DataObject(C_WITHDRAWALS_EMPTY_ROOT))); } diff --git a/retesteth/testStructures/types/StateTests/Filled/StateTestTransaction.cpp b/retesteth/testStructures/types/StateTests/Filled/StateTestTransaction.cpp index b7ef9fe49..c36d20fa7 100644 --- a/retesteth/testStructures/types/StateTests/Filled/StateTestTransaction.cpp +++ b/retesteth/testStructures/types/StateTests/Filled/StateTestTransaction.cpp @@ -61,9 +61,9 @@ StateTestTransaction::StateTestTransaction(DataObject const& _data) for (auto const& el : _data.atKey("accessLists").getSubObjects()) { if (el->type() == DataType::Null) - accessLists.push_back(spAccessList(0)); + accessLists.emplace_back(spAccessList(0)); else - accessLists.push_back(spAccessList(new AccessList(el))); + accessLists.emplace_back(spAccessList(new AccessList(el))); } } @@ -72,26 +72,29 @@ StateTestTransaction::StateTestTransaction(DataObject const& _data) if (accessLists.size() != _data.atKey("data").getSubObjects().size()) ETH_ERROR_MESSAGE("`AccessLists` array length must match `data` array length!"); - for (auto const& el : _data.atKey("data").getSubObjects()) + string const c_data = "data"; + m_databox.reserve(_data.atKey(c_data).getSubObjects().size()); + for (auto const& el : _data.atKey(c_data).getSubObjects()) { BYTES dataInKey = BYTES(el.getCContent()); string const sDataPreview = el->asString().substr(0, 8); if (accessLists.size()) { if (accessLists.at(index).isEmpty()) - m_databox.push_back(Databox(dataInKey, string(), sDataPreview)); + m_databox.emplace_back(Databox(dataInKey, string(), sDataPreview)); else - m_databox.push_back(Databox(dataInKey, string(), sDataPreview, accessLists.at(index))); + m_databox.emplace_back(Databox(dataInKey, string(), sDataPreview, accessLists.at(index))); } else - m_databox.push_back(Databox(dataInKey, string(), sDataPreview)); + m_databox.emplace_back(Databox(dataInKey, string(), sDataPreview)); index++; } + for (auto const& el : _data.atKey("gasLimit").getSubObjects()) - m_gasLimit.push_back(el.getCContent()); + m_gasLimit.emplace_back(el.getCContent()); for (auto const& el : _data.atKey("value").getSubObjects()) - m_value.push_back(el.getCContent()); + m_value.emplace_back(el.getCContent()); } catch (std::exception const& _ex) { diff --git a/retesteth/testStructures/types/StateTests/Filler/StateTestFillerEnv.cpp b/retesteth/testStructures/types/StateTests/Filler/StateTestFillerEnv.cpp index 67b433688..554e2f220 100644 --- a/retesteth/testStructures/types/StateTests/Filler/StateTestFillerEnv.cpp +++ b/retesteth/testStructures/types/StateTests/Filler/StateTestFillerEnv.cpp @@ -1,6 +1,7 @@ #include "StateTestFillerEnv.h" #include #include +#include using namespace std; using namespace dataobject; @@ -64,8 +65,8 @@ void StateTestFillerEnv::initializeFields(spDataObject const& _data) spDataObject tmpD(new DataObject("0x00")); // State Tests extra data is 0x00 m_currentExtraData = spBYTES(new BYTES(tmpD)); - m_currentNonce = spFH8(new FH8(FH8::zero())); - m_currentMixHash = spFH32(new FH32(FH32::zero())); + m_currentNonce = spFH8(FH8::zero().copy()); + m_currentMixHash = spFH32(FH32::zero().copy()); m_currentGasLimit = spVALUE(new VALUE(_data->atKey("currentGasLimit"))); if (m_currentGasLimit.getCContent() > dev::bigint("0x7fffffffffffffff")) throw test::UpwardsException("currentGasLimit > 0x7fffffffffffffff"); @@ -86,6 +87,9 @@ void StateTestFillerEnv::initializeFields(spDataObject const& _data) if (_data->count("currentRandom")) m_currentRandom = spFH32(new FH32(_data->atKey("currentRandom"))); + + // Shanghai + m_currentWithdrawalsRoot = spFH32(new FH32(DataObject(C_WITHDRAWALS_EMPTY_ROOT))); } spDataObject const& StateTestFillerEnv::asDataObject() const diff --git a/retesteth/testStructures/types/StateTests/Filler/StateTestFillerExpectSection.cpp b/retesteth/testStructures/types/StateTests/Filler/StateTestFillerExpectSection.cpp index eda6e8be0..32213991a 100644 --- a/retesteth/testStructures/types/StateTests/Filler/StateTestFillerExpectSection.cpp +++ b/retesteth/testStructures/types/StateTests/Filler/StateTestFillerExpectSection.cpp @@ -21,7 +21,7 @@ spDataObject ReplaceValueToIndexesInDataList(spStateTestFillerTransaction const& for (auto const& el : dVector) { if (el.m_dataLabel == _data.asString()) - indexes.push_back(i); + indexes.emplace_back(i); i++; } diff --git a/retesteth/testStructures/types/StateTests/Filler/StateTestFillerTransaction.cpp b/retesteth/testStructures/types/StateTests/Filler/StateTestFillerTransaction.cpp index 2382913c6..acd7e35eb 100644 --- a/retesteth/testStructures/types/StateTests/Filler/StateTestFillerTransaction.cpp +++ b/retesteth/testStructures/types/StateTests/Filler/StateTestFillerTransaction.cpp @@ -16,6 +16,7 @@ void require1559TransactionScheme(spDataObject const& _data) {"nonce", {{DataType::String}, jsonField::Required}}, {"value", {{DataType::Array}, jsonField::Required}}, {"to", {{DataType::String}, jsonField::Required}}, + {"sender", {{DataType::String}, jsonField::Optional}}, {"maxFeePerGas", {{DataType::String}, jsonField::Required}}, {"maxPriorityFeePerGas", {{DataType::String}, jsonField::Required}}, {"secretKey", {{DataType::String}, jsonField::Required}}}); @@ -31,6 +32,7 @@ void requireLegacyTransctionScheme(spDataObject const& _data) {"nonce", {{DataType::String}, jsonField::Required}}, {"value", {{DataType::Array}, jsonField::Required}}, {"to", {{DataType::String}, jsonField::Required}}, + {"sender", {{DataType::String}, jsonField::Optional}}, {"secretKey", {{DataType::String}, jsonField::Required}}}); } } @@ -68,7 +70,9 @@ StateTestFillerTransaction::StateTestFillerTransaction(spDataObjectMove _data) (*m_rawData)["sender"] = m_publicKey->asString(); m_nonce = spVALUE(new VALUE(m_rawData->atKey("nonce"))); - for (auto& dataEl : (*m_rawData).atKeyUnsafe("data").getSubObjectsUnsafe()) + string const c_data = "data"; + m_databox.reserve(m_rawData->atKey(c_data).getSubObjects().size()); + for (auto& dataEl : (*m_rawData).atKeyUnsafe(c_data).getSubObjectsUnsafe()) { spAccessList accessList; spDataObject actualDataField; @@ -106,12 +110,12 @@ StateTestFillerTransaction::StateTestFillerTransaction(spDataObjectMove _data) } (*actualDataField).setString(test::compiler::replaceCode(rawData)); // --- - m_databox.push_back(Databox(BYTES(actualDataField.getContent()), label, rawData.substr(0, 20), accessList)); + m_databox.emplace_back(Databox(BYTES(actualDataField.getContent()), label, rawData.substr(0, 30), accessList)); } for (auto const& el : m_rawData->atKey("gasLimit").getSubObjects()) - m_gasLimit.push_back(el.getCContent()); + m_gasLimit.emplace_back(el.getCContent()); for (auto const& el : m_rawData->atKey("value").getSubObjects()) - m_value.push_back(el.getCContent()); + m_value.emplace_back(el.getCContent()); if (m_rawData->count("maxFeePerGas") || m_rawData->count("maxPriorityFeePerGas")) { diff --git a/retesteth/testStructures/types/StateTests/GeneralStateTest.cpp b/retesteth/testStructures/types/StateTests/GeneralStateTest.cpp index d26133cbd..589e2a86e 100644 --- a/retesteth/testStructures/types/StateTests/GeneralStateTest.cpp +++ b/retesteth/testStructures/types/StateTests/GeneralStateTest.cpp @@ -49,10 +49,12 @@ GeneralStateTest::GeneralStateTest(spDataObject& _data) TestOutputHelper::get().get().testFile().string() + " A test file must contain an object value (json/yaml)."); ETH_ERROR_REQUIRE_MESSAGE(_data->getSubObjects().size() == 1, TestOutputHelper::get().get().testFile().string() + " A test file must contain exactly one test!"); + + m_tests.reserve(_data.getContent().getSubObjects().size()); for (auto& el : _data.getContent().getSubObjectsUnsafe()) { TestOutputHelper::get().setCurrentTestInfo(TestInfo("GeneralStateTest", el->getKey())); - m_tests.push_back(StateTestInFilled(el)); + m_tests.emplace_back(StateTestInFilled(el)); } } catch (DataObjectException const& _ex) @@ -75,7 +77,7 @@ StateTestInFilled::StateTestInFilled(spDataObject& _data) if (_data->count("exceptions")) { for (size_t i = _data->atKey("exceptions").getSubObjects().size(); i > 0; i--) - m_exceptions.push_back(_data->atKey("exceptions").getSubObjects().at(i - 1)->asString()); + m_exceptions.emplace_back(_data->atKey("exceptions").getSubObjects().at(i - 1)->asString()); } m_info = GCP_SPointer(new Info(_data->atKey("_info"))); @@ -98,8 +100,9 @@ StateTestInFilled::StateTestInFilled(spDataObject& _data) for (auto const& elFork : _data->atKey("post").getSubObjects()) { StateTestPostResults res; + res.reserve(elFork->getSubObjects().size()); for (auto const& elForkResults : elFork->getSubObjects()) - res.push_back(StateTestPostResult(elForkResults)); + res.emplace_back(StateTestPostResult(elForkResults)); if (m_post.count(FORK(elFork->getKey()))) ETH_ERROR_MESSAGE("StateTest post section has multiple results for the same fork!"); m_post[FORK(elFork->getKey())] = res; diff --git a/retesteth/testStructures/types/StateTests/GeneralStateTestFiller.cpp b/retesteth/testStructures/types/StateTests/GeneralStateTestFiller.cpp index 800721bfa..4d66bf16f 100644 --- a/retesteth/testStructures/types/StateTests/GeneralStateTestFiller.cpp +++ b/retesteth/testStructures/types/StateTests/GeneralStateTestFiller.cpp @@ -56,7 +56,7 @@ void checkRedundantExpectSection(std::vector const for (int v : _newExpectSection.getValInd()) { if (readExpect.checkIndexes(d, g, v)) - ETH_ERROR_MESSAGE("StateTestFiller read redundant expect section: \n" + _newExpectSection.initialData().asJson()); + ETH_ERROR_MESSAGE("Test filler read redundant expect section: \n" + _newExpectSection.initialData().asJson()); } } } @@ -74,7 +74,7 @@ GeneralStateTestFiller::GeneralStateTestFiller(spDataObject& _data) for (auto& el : _data.getContent().getSubObjectsUnsafe()) { TestOutputHelper::get().setCurrentTestInfo(TestInfo("GeneralStateTestFiller", el->getKey())); - m_tests.push_back(StateTestInFiller(el)); + m_tests.emplace_back(StateTestInFiller(el)); } } catch (DataObjectException const& _ex) @@ -102,7 +102,7 @@ StateTestInFiller::StateTestInFiller(spDataObject& _data) if (_data->count("exceptions")) { for (size_t i = _data->atKey("exceptions").getSubObjects().size(); i > 0; i--) - m_exceptions.push_back(_data->atKey("exceptions").getSubObjects().at(i - 1)->asString()); + m_exceptions.emplace_back(_data->atKey("exceptions").getSubObjects().at(i - 1)->asString()); } TestOutputHelper::get().setUnitTestExceptions(m_exceptions); @@ -120,12 +120,14 @@ StateTestInFiller::StateTestInFiller(spDataObject& _data) m_pre = spState(new State(MOVE(_data, "pre"))); m_transaction = spStateTestFillerTransaction(new StateTestFillerTransaction(MOVE(_data, "transaction"))); - for (auto& el : (*_data).atKeyUnsafe("expect").getSubObjectsUnsafe()) + string const c_expect = "expect"; + m_expectSections.reserve((*_data).atKey(c_expect).getSubObjects().size()); + for (auto& el : (*_data).atKeyUnsafe(c_expect).getSubObjectsUnsafe()) { StateTestFillerExpectSection newSection(dataobject::move(el), m_transaction); checkRedundantExpectSection(m_expectSections, newSection); checkCoinbaseInExpectSection(newSection, m_env); - m_expectSections.push_back(newSection); + m_expectSections.emplace_back(newSection); } ETH_ERROR_REQUIRE_MESSAGE(m_expectSections.size() > 0, "StateTestFiller require expect sections!"); diff --git a/retesteth/testStructures/types/TransactionTests/TransactionTest.cpp b/retesteth/testStructures/types/TransactionTests/TransactionTest.cpp index 0c34f1adc..6210b4780 100644 --- a/retesteth/testStructures/types/TransactionTests/TransactionTest.cpp +++ b/retesteth/testStructures/types/TransactionTests/TransactionTest.cpp @@ -1,5 +1,6 @@ #include #include +#include #include "EthChecks.h" #include "TransactionTest.h" @@ -15,10 +16,11 @@ TransactionTest::TransactionTest(spDataObject& _data) TestOutputHelper::get().get().testFile().string() + " A test file must contain an object value (json/yaml)."); ETH_ERROR_REQUIRE_MESSAGE(_data->getSubObjects().size() >= 1, TestOutputHelper::get().get().testFile().string() + " A test file must contain at least one test!"); + m_tests.reserve(_data->getSubObjects().size()); for (auto& el : _data.getContent().getSubObjectsUnsafe()) { TestOutputHelper::get().setCurrentTestInfo(TestInfo("TransactionTestFiller", el->getKey())); - m_tests.push_back(TransactionTestInFilled(el)); + m_tests.emplace_back(TransactionTestInFilled(el)); } } catch (DataObjectException const& _ex) @@ -45,7 +47,8 @@ TransactionTestInFilled::TransactionTestInFilled(spDataObject& _data) } catch (...) { - ETH_WARNING("Unable to read transaction from 'txbytes'"); + if (Options::get().filltests) + ETH_WARNING("Unable to read transaction from 'txbytes'"); m_readTransaction = spTransaction(0); } diff --git a/retesteth/testStructures/types/TransactionTests/TransactionTest.h b/retesteth/testStructures/types/TransactionTests/TransactionTest.h index 86ddb8e30..f6f3835d5 100644 --- a/retesteth/testStructures/types/TransactionTests/TransactionTest.h +++ b/retesteth/testStructures/types/TransactionTests/TransactionTest.h @@ -1,7 +1,7 @@ #pragma once #include #include -#include +#include #include namespace test::teststruct diff --git a/retesteth/testStructures/types/TransactionTests/TransactionTestFiller.cpp b/retesteth/testStructures/types/TransactionTests/TransactionTestFiller.cpp index 7ca6c89ab..83f77807f 100644 --- a/retesteth/testStructures/types/TransactionTests/TransactionTestFiller.cpp +++ b/retesteth/testStructures/types/TransactionTests/TransactionTestFiller.cpp @@ -15,10 +15,11 @@ TransactionTestFiller::TransactionTestFiller(spDataObject& _data) TestOutputHelper::get().get().testFile().string() + " A test file must contain an object value (json/yaml)."); ETH_ERROR_REQUIRE_MESSAGE(_data->getSubObjects().size() >= 1, TestOutputHelper::get().get().testFile().string() + " A test file must contain at least one test!"); + m_tests.reserve(_data->getSubObjects().size()); for (auto& el : _data.getContent().getSubObjectsUnsafe()) { TestOutputHelper::get().setCurrentTestInfo(TestInfo("TransactionTestFiller", el->getKey())); - m_tests.push_back(TransactionTestInFiller(el)); + m_tests.emplace_back(TransactionTestInFiller(el)); } } catch (DataObjectException const& _ex) @@ -42,10 +43,13 @@ TransactionTestInFiller::TransactionTestInFiller(spDataObject& _data) if (_data->count("_info")) m_info = GCP_SPointer(new InfoIncomplete(MOVE(_data, "_info"))); - if (_data->count("additionalForks")) + string const c_additionalForks = "additionalForks"; + if (_data->count(c_additionalForks)) { - for (auto const& additionalFork : _data->atKey("additionalForks").getSubObjects()) - m_additionalForks.push_back(FORK(additionalFork)); + auto const& forkObjects = _data->atKey(c_additionalForks).getSubObjects(); + m_additionalForks.reserve(forkObjects.size()); + for (auto const& additionalFork : forkObjects) + m_additionalForks.emplace_back(FORK(additionalFork)); } readExpectExceptions(_data->atKey("expectException"), m_expectExceptions); diff --git a/retesteth/testStructures/types/TransactionTests/TransactionTestFiller.h b/retesteth/testStructures/types/TransactionTests/TransactionTestFiller.h index 412e08f9d..68294d929 100644 --- a/retesteth/testStructures/types/TransactionTests/TransactionTestFiller.h +++ b/retesteth/testStructures/types/TransactionTests/TransactionTestFiller.h @@ -2,7 +2,7 @@ #include "../StateTests/Filler/InfoIncomplete.h" #include #include -#include +#include #include namespace test::teststruct diff --git a/retesteth/testStructures/types/ethereum.h b/retesteth/testStructures/types/ethereum.h index d47e77ce9..87138b7ba 100644 --- a/retesteth/testStructures/types/ethereum.h +++ b/retesteth/testStructures/types/ethereum.h @@ -4,4 +4,4 @@ #include "Ethereum/State.h" #include "Ethereum/StateIncomplete.h" #include "Ethereum/Storage.h" -#include "Ethereum/Transaction.h" +#include "Ethereum/Transactions/Transaction.h" diff --git a/retesteth/testSuiteRunner/TestSuite.cpp b/retesteth/testSuiteRunner/TestSuite.cpp index bb256468d..fc79888b6 100644 --- a/retesteth/testSuiteRunner/TestSuite.cpp +++ b/retesteth/testSuiteRunner/TestSuite.cpp @@ -46,18 +46,17 @@ string getTestNameFromFillerFilename(fs::path const& _fillerTestFilePath) size_t pos = fillerName.rfind(c_fillerPostf); if (pos != string::npos) return fillerName.substr(0, pos); - else - { - pos = fillerName.rfind(c_copierPostf); - if (pos != string::npos) - return fillerName.substr(0, pos); - else - { - static string const requireStr = " require: Filler.json/Filler.yml/Copier.json"; - ETH_FAIL_REQUIRE_MESSAGE( - false, "Incorrect file suffix in the filler folder! " + _fillerTestFilePath.string() + requireStr); - } - } + + pos = fillerName.rfind(c_copierPostf); + if (pos != string::npos) + return fillerName.substr(0, pos); + + if (_fillerTestFilePath.extension() == c_pythonPostf) + return fillerName; + + static string const requireStr = " require: Filler.json/Filler.yml/Copier.json/.py"; + ETH_FAIL_REQUIRE_MESSAGE( + false, "Incorrect file suffix in the filler folder! " + _fillerTestFilePath.string() + requireStr); return fillerName; } } // namespace @@ -68,30 +67,22 @@ namespace test void TestSuite::runAllTestsInFolder(string const& _testFolder) const { Options::getDynamicOptions().getClientConfigs(); - if (ExitHandler::receivedExitSignal()) - return; + CHECKEXIT - // check that destination folder test files has according Filler file in src folder - string filter; - std::vector outdatedTests; - try - { - TestOutputHelper::get().setCurrentTestInfo(TestInfo("checkFillerExistance", _testFolder)); - outdatedTests = checkFillerExistance(_testFolder, filter); - } - catch (std::exception const&) - { - TestOutputHelper::get().initTest(1); - TestOutputHelper::get().finishTest(); + clearGeneratedTestNamesMap(); + std::vector outdatedTestFillers; + std::vector allTestFillers; + if (!verifyFillers(_testFolder, outdatedTestFillers, allTestFillers)) return; - } // run all tests AbsoluteFillerPath fillerPath = getFullPathFiller(_testFolder); if (!fs::exists(fillerPath.path())) ETH_WARNING(string(fillerPath.path().c_str()) + " does not exist!"); - vector const testFillers = - Options::get().filloutdated ? outdatedTests : test::getFiles(fillerPath.path(), {".json", ".yml"}, filter); + + vector const& testFillers = Options::get().filloutdated ? + outdatedTestFillers : allTestFillers; + if (testFillers.size() == 0) { TestOutputHelper::get().currentTestRunPP(); @@ -177,14 +168,28 @@ void TestSuite::_executeTest(string const& _testFolder, fs::path const& _fillerT wereFillerErrors = _fillTest(_opt, _fillerTestFilePath, filledTestPath.path()); bool disableSecondRun = false; - if (!Options::get().getGStateTransactionFilter().empty() && Options::get().filltests) + auto noSecondRunConditions = [](){ + bool condition = true; + auto const& opt = Options::get(); + condition = condition && opt.getGStateTransactionFilter().empty(); + condition = condition && !opt.vmtrace.initialized(); + condition = condition && !opt.singleTestNet.initialized(); + condition = condition && !opt.poststate.initialized(); + condition = condition && !opt.statediff.initialized(); + return !condition; + }; + if (noSecondRunConditions() && Options::get().filltests) { - ETH_WARNING("GState transaction filter is set. Disabling generated test run!"); + ETH_WARNING("Test filter or log is set. Disabling generated test run!"); disableSecondRun = true; } if (!wereFillerErrors && !disableSecondRun) - _runTest(filledTestPath); + { + auto const generatedFiles = getGeneratedTestNames(_fillerTestFilePath); + for (auto const& name : generatedFiles) + _runTest(filledTestPath.path().parent_path() / (name + ".json")); + } RPCSession::sessionEnd(TestOutputHelper::getThreadID(), RPCSession::SessionStatus::HasFinished); } @@ -222,7 +227,7 @@ void TestSuite::executeFile(boost::filesystem::path const& _file) const opt.isLegacyTests = isLegacy || legacyTestSuiteFlag(); if (_file.extension() != ".json") - ETH_ERROR_MESSAGE("The generated test must have `.json` format!"); + ETH_ERROR_MESSAGE("The generated test must have `.json` format! (forgot --filltests?)"); ETH_DC_MESSAGE(DC::TESTLOG, "Read json structure " + string(_file.filename().c_str())); spDataObject res = test::readJsonData(_file); diff --git a/retesteth/testSuiteRunner/TestSuite.h b/retesteth/testSuiteRunner/TestSuite.h index 462a09bb6..6c8f43709 100644 --- a/retesteth/testSuiteRunner/TestSuite.h +++ b/retesteth/testSuiteRunner/TestSuite.h @@ -28,6 +28,7 @@ namespace test { extern std::string const c_fillerPostf; extern std::string const c_copierPostf; +extern std::string const c_pythonPostf; class TestSuite { @@ -37,7 +38,12 @@ class TestSuite private: // Execute Test.json file void executeFile(boost::filesystem::path const& _file) const; - std::vector checkFillerExistance(std::string const& _testFolder, std::string& testFilter) const; + bool verifyFillers(std::string const& _testFolder, + std::vector& _outdated, + std::vector& _all) const; + void checkFillerExistance(std::string const& _testFolder, + std::vector& _outdated, + std::vector& _all) const; struct BoostPath { @@ -131,6 +137,7 @@ class TestSuite AbsoluteFilledTestPath const& _outputTestFilePath) const; bool _fillJsonYml(testsuite::TestFileData& _testData, boost::filesystem::path const& _fillerTestFilePath, AbsoluteFilledTestPath const& _outputTestFilePath, TestSuite::TestSuiteOptions& _opt) const; + bool _fillPython(testsuite::TestFileData& _testData, boost::filesystem::path const&, AbsoluteFilledTestPath const&) const; }; } // namespace test diff --git a/retesteth/testSuiteRunner/TestSuiteHelperFunctions.cpp b/retesteth/testSuiteRunner/TestSuiteHelperFunctions.cpp index 02d0b5b86..29a8f4706 100644 --- a/retesteth/testSuiteRunner/TestSuiteHelperFunctions.cpp +++ b/retesteth/testSuiteRunner/TestSuiteHelperFunctions.cpp @@ -3,6 +3,8 @@ #include #include #include +#include +#include using namespace dev; using namespace std; @@ -28,8 +30,10 @@ TestFileData readTestFile(fs::path const& _testFileName) testData.data = test::readJsonData(_testFileName, string(), bSortOnLoad); else if (_testFileName.extension() == ".yml") testData.data = test::readYamlData(_testFileName, bSortOnLoad); + else if (_testFileName.extension() == ".py") + testData.data = spDataObject(new DataObject(dev::contentsString(_testFileName))); else - ETH_ERROR_MESSAGE("Unknown test format!" + test::TestOutputHelper::get().testFile().string()); + ETH_ERROR_MESSAGE("Unknown test format! \n" + _testFileName.string()); ETH_DC_MESSAGE(DC::TESTLOG, "Read json structure finish"); // Do not calculate the hash on Legacy tests unless --checkhash option provided @@ -78,7 +82,7 @@ void removeComments(spDataObject& _obj) { if (element->getKey().substr(0, 2) == "//") { - removeKeysList.push_back(element->getKey()); + removeKeysList.emplace_back(element->getKey()); continue; } removeComments(element); @@ -93,4 +97,73 @@ void removeComments(spDataObject& _obj) } } + +typedef vector VectorString; +std::map C_GeneratedTestsMAP; +std::mutex G_GeneratedTestsMap_Mutex; +void clearGeneratedTestNamesMap() +{ + std::lock_guard lock(G_GeneratedTestsMap_Mutex); + C_GeneratedTestsMAP.clear(); +} + +void checkDoubleGeneratedTestNames() +{ + std::lock_guard lock(G_GeneratedTestsMap_Mutex); + std::set checkedNames; + for (auto const& test : C_GeneratedTestsMAP) + { + for (auto const& name : test.second) + { + if (checkedNames.count(name)) + ETH_ERROR_MESSAGE("Filler will produce test name collision (change the name): `" + name + "` in test filler `" + test.first); + checkedNames.emplace(name); + } + } +} + +vector const& getGeneratedTestNames(fs::path const& _filler) +{ + std::lock_guard lock(G_GeneratedTestsMap_Mutex); + if (C_GeneratedTestsMAP.count(_filler.stem().string())) + return C_GeneratedTestsMAP.at(_filler.stem().string()); + + vector generatedTestNames; + if (_filler.extension() == ".json" || _filler.extension() == ".yml") + { + string fillerName = _filler.stem().string(); + if (fillerName.find(c_fillerPostf) != string::npos) + fillerName = fillerName.substr(0, fillerName.length() - c_fillerPostf.size()); + else if (fillerName.find(c_copierPostf) != string::npos) + fillerName = fillerName.substr(0, fillerName.length() - c_copierPostf.size()); + generatedTestNames.emplace_back(fillerName); + } + else if (_filler.extension() == ".py") + { + // Get filled test names from .py filler + size_t pos = 0; + string pythonSrc = dev::contentsString(_filler); + size_t foundPos = pythonSrc.find("def test_", pos); + while (foundPos != string::npos) + { + size_t endSelectionPos = pythonSrc.find("(", foundPos); + if (endSelectionPos != string::npos) + { + string pythonTestname = pythonSrc.substr(foundPos + 9, endSelectionPos - foundPos - 9); + generatedTestNames.emplace_back(pythonTestname); + } + pos = foundPos + 1; + foundPos = pythonSrc.find("def test_", pos); + } + } + else + { + ETH_ERROR_MESSAGE("getGeneratedTestNames:: unknown filler extension: \n" + _filler.string()); + } + + C_GeneratedTestsMAP.emplace(_filler.stem().string(), generatedTestNames); + return C_GeneratedTestsMAP.at(_filler.stem().string()); +} + + } // namespace testsuite diff --git a/retesteth/testSuiteRunner/TestSuiteHelperFunctions.h b/retesteth/testSuiteRunner/TestSuiteHelperFunctions.h index 1bc280ccf..96f673d27 100644 --- a/retesteth/testSuiteRunner/TestSuiteHelperFunctions.h +++ b/retesteth/testSuiteRunner/TestSuiteHelperFunctions.h @@ -13,6 +13,7 @@ struct TestFileData bool hashCalculated = true; }; + bool addClientInfoIfUpdate(DataObject& _filledTest, boost::filesystem::path const& _testSource, dev::h256 const& _testSourceHash, boost::filesystem::path const& _existingFilledTest); @@ -20,4 +21,8 @@ TestFileData readTestFile(boost::filesystem::path const& _testFileName); void removeComments(spDataObject& _obj); bool checkFillerHash(boost::filesystem::path const& _compiledTest, boost::filesystem::path const& _sourceTest); +void clearGeneratedTestNamesMap(); +void checkDoubleGeneratedTestNames(); +std::vector const& getGeneratedTestNames(boost::filesystem::path const& _filler); + } // namespace testsuite diff --git a/retesteth/testSuiteRunner/checkFillerExistance.cpp b/retesteth/testSuiteRunner/checkFillerExistance.cpp index ba3d546c1..16eecbc35 100644 --- a/retesteth/testSuiteRunner/checkFillerExistance.cpp +++ b/retesteth/testSuiteRunner/checkFillerExistance.cpp @@ -5,6 +5,9 @@ #include "TestSuiteHelperFunctions.h" #include +#include + + using namespace std; using namespace test; using namespace test::debug; @@ -37,146 +40,164 @@ TestSuite::AbsoluteFilledTestPath createPathIfNotExist(TestSuite::AbsoluteFilled } return _path; } +} // namespace -std::vector checkIfThereAreUnfilledTests( - fs::path const& _fullPathToFillers, vector const& _compiledTests, string const& _testNameFilter) +namespace test { - std::vector notFilledTests; - vector fillerFiles = test::getFiles(_fullPathToFillers, {".json", ".yml"}, _testNameFilter); - if (fillerFiles.size() > _compiledTests.size()) + +void checkGeneratedTest(fs::path const& _filledPath, std::vector const& _fillers, + std::vector& _outdatedTestFillers, + std::vector& _verifiedGeneratedTests) +{ + auto const& opt = Options::get(); + string message = "Tests are not generated: "; + for (auto const& filler : _fillers) { - string message = "Tests are not generated: "; - for (auto const& filler : fillerFiles) + TestInfo errorInfo("CheckFiller", filler.stem().string()); + TestOutputHelper::get().setCurrentTestInfo(errorInfo); + + bool outdatedFillerRegistered = false; + vector generatedTestNames = getGeneratedTestNames(filler); + for (auto const& testName : generatedTestNames) { - bool found = false; - for (auto const& filled : _compiledTests) + fs::path generatedTestPath = _filledPath / (testName + ".json"); + if (fs::exists(generatedTestPath)) { - string const fillerName = filler.stem().string(); - if (fillerName.substr(0, fillerName.size() - 6) == filled.stem().string()) + // if --filltests is set, mark all tests as outdated + if ((opt.filltests && !opt.filloutdated) || checkFillerHash(generatedTestPath, filler)) { - found = true; - break; + if (!opt.filloutdated) + message += "\n " + filler.string() + " => " + generatedTestPath.string(); + if (!outdatedFillerRegistered) + { + _outdatedTestFillers.emplace_back(filler); + outdatedFillerRegistered = true; + } } + _verifiedGeneratedTests.emplace_back(generatedTestPath); } - if (!found) + else { - if (!Options::get().filloutdated) - message += "\n " + string(filler.c_str()); - notFilledTests.push_back(filler); + if (!opt.filloutdated) + message += "\n " + filler.string() + " => " + generatedTestPath.string(); + if (!outdatedFillerRegistered) + { + _outdatedTestFillers.emplace_back(filler); + outdatedFillerRegistered = true; + } } } - if (!Options::get().filloutdated) - ETH_ERROR_MESSAGE(message + "\n"); } - return notFilledTests; + + if (!opt.filloutdated && _outdatedTestFillers.size() > 0 && !opt.filltests) + { + message += "\n"; + ETH_ERROR_MESSAGE(message); + } } -bool fakeFilledTestsIfThereAreNone( - vector& _compiledTests, string const& _testNameFilter, fs::path const& _fullPathToFillers) +void checkFillersSelection(std::vector const& _allTestFillers, string const& _testNameFilter) { - if (_testNameFilter.empty()) + if (!_testNameFilter.empty() && _allTestFillers.size() == 0) + ETH_ERROR_MESSAGE("Could not find a filler for provided --singletest filter: '" + _testNameFilter + "'"); + + std::set fillerNames; + std::vector fillersWithSameName; + for (auto const& test : _allTestFillers) { - // No tests generated, check at least one filler existence - vector existingFillers = test::getFiles(_fullPathToFillers, {".json", ".yml"}); - for (auto const& filler : existingFillers) - { - // put filler names as if it was actual tests - string fillerName(filler.stem().c_str()); - string fillerSuffix = fillerName.substr(fillerName.size() - 6); - if (fillerSuffix == c_fillerPostf || fillerSuffix == c_copierPostf) - _compiledTests.push_back(fillerName.substr(0, fillerName.size() - 6)); - } - return false; + if (fillerNames.count(test.stem().string())) + fillersWithSameName.emplace_back(test); + fillerNames.emplace(test.stem().string()); } - else + + if (fillersWithSameName.size() > 0) { - // No tests generated and filter is set, check that filler for filter is exist - _compiledTests.push_back(fs::path(_testNameFilter)); // put the test name as if it was compiled. - return true; + string ambiguousTests; + for (auto const& test : fillersWithSameName) + ambiguousTests += test.string() + "\n"; + ETH_ERROR_MESSAGE("Found multiple fillers with the same name. Ambiguous: \n" + ambiguousTests); } - return false; } -} // namespace - -namespace test +void checkTestsWithoutFiller(std::vector const& _verifiedGeneratedTests, fs::path const& _filledTestsPath) { -std::vector TestSuite::checkFillerExistance(string const& _testFolder, string& testNameFilter) const + vector compiledTests = test::getFiles(_filledTestsPath, {".json"}); + for (auto const& verifiedTest : _verifiedGeneratedTests) + { + auto removed = std::remove_if(compiledTests.begin(), compiledTests.end(), + [&verifiedTest](fs::path const& x) { return (x.stem() == verifiedTest.stem());} ); + compiledTests.erase(removed, compiledTests.end()); + } + if (compiledTests.size() > 0) + { + string message = "Compiled test folder contains tests without Filler: "; + for (auto const& test : compiledTests) + message += "\n " + test.string(); + message += "\n"; + ETH_ERROR_MESSAGE(message); + } +} + +void TestSuite::checkFillerExistance(string const& _testFolder, + std::vector& _outdatedTestFillers, + std::vector& _allTestFillers) const { - testNameFilter = getTestNameFilter(); - std::vector outdatedTests; + TestInfo errorInfo("CheckFillers", ""); + TestOutputHelper::get().setCurrentTestInfo(errorInfo); + + string testNameFilter = getTestNameFilter(); AbsoluteFilledTestPath filledTestsPath = createPathIfNotExist(getFullPathFilled(_testFolder)); - vector compiledTests = test::getFiles(filledTestsPath.path(), {".json", ".yml"}, testNameFilter); AbsoluteFillerPath fullPathToFillers = getFullPathFiller(_testFolder); - auto const& opt = Options::get(); - if (opt.checkhash || opt.filloutdated) - outdatedTests = checkIfThereAreUnfilledTests(fullPathToFillers.path(), compiledTests, testNameFilter); - - bool checkFillerWhenFilterIsSetButNoTestsFilled = false; - if (compiledTests.size() == 0) - checkFillerWhenFilterIsSetButNoTestsFilled = - fakeFilledTestsIfThereAreNone(compiledTests, testNameFilter, fullPathToFillers.path()); - - for (auto const& test : compiledTests) + _allTestFillers = test::getFiles(fullPathToFillers.path(), {".json", ".yml", ".py"}, testNameFilter); + if (!testNameFilter.empty()) { - fs::path const expectedFillerName = fullPathToFillers.path() / fs::path(test.stem().string() + c_fillerPostf + ".json"); - fs::path const expectedFillerName2 = fullPathToFillers.path() / fs::path(test.stem().string() + c_fillerPostf + ".yml"); - fs::path const expectedCopierName = fullPathToFillers.path() / fs::path(test.stem().string() + c_copierPostf + ".json"); + auto fillerSuffixSelect = test::getFiles(fullPathToFillers.path(), {".json", ".yml"}, testNameFilter + "Filler"); + for (auto const& el : fillerSuffixSelect) + _allTestFillers.emplace_back(el); + } - string const exceptionStr = - checkFillerWhenFilterIsSetButNoTestsFilled ? - "Could not find a filler for provided --singletest filter: '" + test.filename().string() + "'" : - "Compiled test folder contains test without Filler: " + test.filename().string(); + auto removed = std::remove_if(_allTestFillers.begin(), _allTestFillers.end(), + [](fs::path const& x) { return (x.stem() == "__init__");} ); + _allTestFillers.erase(removed, _allTestFillers.end()); - { - TestInfo errorInfo("CheckFillers", test.stem().string()); - TestOutputHelper::get().setCurrentTestInfo(errorInfo); - } + checkFillersSelection(_allTestFillers, testNameFilter); - ETH_ERROR_REQUIRE_MESSAGE( - fs::exists(expectedFillerName) || fs::exists(expectedFillerName2) || fs::exists(expectedCopierName), exceptionStr); - ETH_ERROR_REQUIRE_MESSAGE( - !(fs::exists(expectedFillerName) && fs::exists(expectedFillerName2) && fs::exists(expectedCopierName)), - "Src test could either be Filler.json, Filler.yml or Copier.json: " + test.filename().string()); + auto const& opt = Options::get(); + if (!opt.forceupdate) + { + std::vector verifiedGeneratedTests; + checkGeneratedTest(filledTestsPath.path(), _allTestFillers, _outdatedTestFillers, verifiedGeneratedTests); - // Check that filled tests created from actual fillers depenging on a test type + if (testNameFilter.empty()) + checkTestsWithoutFiller(verifiedGeneratedTests, filledTestsPath.path()); + } - auto fillerVerifier = [&testNameFilter, &outdatedTests]( - fs::path const& _test, fs::path const& _expectedFillerName, string const& _addPostfix) { - auto const& opt = Options::get(); - if (!opt.filltests || opt.filloutdated) - { - if (checkFillerHash(_test, _expectedFillerName)) - outdatedTests.push_back(_expectedFillerName); - } - if (!testNameFilter.empty()) - { - testNameFilter += _addPostfix; - return true; - } - return false; - }; + // Fill the names map and check double test names + for (auto const& filler : _allTestFillers) + getGeneratedTestNames(filler); + checkDoubleGeneratedTestNames(); +} - if (fs::exists(expectedFillerName)) - { - if (fillerVerifier(test, expectedFillerName, c_fillerPostf)) - return outdatedTests; - } - else if (fs::exists(expectedFillerName2)) - { - if (fillerVerifier(test, expectedFillerName2, c_fillerPostf)) - return outdatedTests; - } - else if (fs::exists(expectedCopierName)) - { - if (fillerVerifier(test, expectedCopierName, c_copierPostf)) - return outdatedTests; - } - } - // No compiled test files. Filter is empty - return outdatedTests; +bool TestSuite::verifyFillers(string const& _testFolder, + std::vector& _outdatedTestFillers, + std::vector& _allTestFillers) const +{ + // check that destination folder test files has according Filler file in src folder + try + { + TestOutputHelper::get().setCurrentTestInfo(TestInfo("checkFillerExistance", _testFolder)); + checkFillerExistance(_testFolder, _outdatedTestFillers, _allTestFillers); + } + catch (std::exception const&) + { + TestOutputHelper::get().initTest(1); + TestOutputHelper::get().finishTest(); + return false; + } + return true; } + } // namespace test diff --git a/retesteth/testSuiteRunner/checkFillerHash.cpp b/retesteth/testSuiteRunner/checkFillerHash.cpp index e620bb5e8..a4c751ced 100644 --- a/retesteth/testSuiteRunner/checkFillerHash.cpp +++ b/retesteth/testSuiteRunner/checkFillerHash.cpp @@ -28,11 +28,11 @@ void checkTestVersion(DataObject const& _info, fs::path const& _compiledTest) if (testVersion > retestethVersion()) ETH_WARNING("Test was filled with newer version of retesteth! " "(test: `" + strippedVersion + "` vs retesteth: `" + test::fto_string(retestethVersion()) + "`)" - " This might cause failures, please update retesteth!"); + " This might cause failures, please update retesteth!\n" + _compiledTest.string()); else if (testVersion < retestethVersion() - 1) ETH_WARNING("Test filled with older version of retesteth! " "(test: `" + strippedVersion + "` vs retesteth: `" + test::fto_string(retestethVersion()) + "`) " - "This might cause failures, please regenerate the test!"); + "This might cause failures, please regenerate the test!\n" + _compiledTest.string()); } } // namespace diff --git a/retesteth/testSuiteRunner/fillTest.cpp b/retesteth/testSuiteRunner/fillTest.cpp index 6bdf1c73d..2df1de0c3 100644 --- a/retesteth/testSuiteRunner/fillTest.cpp +++ b/retesteth/testSuiteRunner/fillTest.cpp @@ -9,6 +9,7 @@ #include #include #include +#include using namespace std; using namespace dev; @@ -41,12 +42,73 @@ fs::path prepareOutputFileName(fs::path const& _file) outPath = _file.parent_path() / fileName; return outPath; } + +void updatePythonTestInfo(TestFileData& _testData, fs::path const& _pythonFiller, fs::path const& _filledFolder) +{ + // TODO double calling this function (getGeneratedTestNames) + // can make a global map + auto const testNames = getGeneratedTestNames(_pythonFiller); + for (auto const& generatedTest : testNames) + { + fs::path const outputTestFilePath = _filledFolder / (generatedTest + ".json"); + string const res = dev::contentsString(outputTestFilePath); + if (res.empty()) + ETH_ERROR_MESSAGE("Can't open expected python produced test: " + outputTestFilePath.string()); + spDataObject output = dataobject::ConvertJsoncppStringToData(res); + bool update = + addClientInfoIfUpdate(output.getContent(), _pythonFiller, _testData.hash, outputTestFilePath); + if (update) + { + (*output).performModifier(mod_sortKeys, DataObject::ModifierOption::NONRECURSIVE); + writeFile(outputTestFilePath, asBytes(output->asJson())); + } + } +} + } // namespace namespace test { string const c_fillerPostf = "Filler"; string const c_copierPostf = "Copier"; +string const c_pythonPostf = ".py"; + +bool TestSuite::_fillPython(TestFileData& _testData, fs::path const& _fillerTestFilePath, AbsoluteFilledTestPath const& _filledPath) const +{ + bool wereErrors = false; + auto const& currentConfig = Options::getCurrentConfig(); + auto const& specsScript = currentConfig.getPySpecsStartScript(); + if (fs::exists(specsScript)) + { + string const fillerName = _fillerTestFilePath.stem().string(); + TestOutputHelper::get().setCurrentTestName(fillerName); + + string runcmd = specsScript.c_str(); + runcmd += " " + _fillerTestFilePath.parent_path().parent_path().string(); // SRCPATH + runcmd += " " + fillerName; // FILLER NAME + runcmd += " " + _filledPath.path().parent_path().string(); // OUTPATH + runcmd += " " + Options::get().getCurrentConfig().getStartScript().string(); // T8N start + ETH_DC_MESSAGEC(DC::STATS, string("Generate Python test: ") + _fillerTestFilePath.stem().string(), LogColor::YELLOW); + ETH_DC_MESSAGE(DC::RPC, string("Generate Python test: ") + runcmd); + + int exitcode; + string out = test::executeCmd(runcmd, exitcode, ExecCMDWarning::NoWarningNoError); + fs::remove_all(_fillerTestFilePath.parent_path() / "__pycache__"); + fs::remove_all(_filledPath.path().parent_path() / "__pycache__"); + ETH_DC_MESSAGE(DC::RPC, out); + if (exitcode != 0) + { + wereErrors = true; + ETH_ERROR_MESSAGE("Python spec failed filling the test: \n" + out); + return wereErrors; + } + else + updatePythonTestInfo(_testData, _fillerTestFilePath, _filledPath.path().parent_path()); + return wereErrors; + } + else + return wereErrors; +} void TestSuite::_fillCopier( TestFileData& _testData, fs::path const& _fillerTestFilePath, AbsoluteFilledTestPath const& _outputTestFilePath) const @@ -106,10 +168,18 @@ bool TestSuite::_fillTest(TestSuite::TestSuiteOptions& _opt, fs::path const& _fi bool wereErrors = false; _opt.doFilling = true; TestOutputHelper::get().setCurrentTestFile(_fillerTestFilePath); + + // TODO we already read this file when checking filler hash updated + // maybe store it in some map ?? but then a lot of tests in memory TestFileData testData = readTestFile(_fillerTestFilePath); + + bool const isPy = (_fillerTestFilePath.extension() == ".py"); + bool const isCopier = (_fillerTestFilePath.stem().string().rfind(c_copierPostf) != string::npos); + if (isPy) + return _fillPython(testData, _fillerTestFilePath, _outputTestFilePath); + fs::path const testFillerPathRelative = _opt.calculateRelativeSrcPath ? fs::relative(_fillerTestFilePath, getTestPath()) : _fillerTestFilePath; - bool const isCopier = (_fillerTestFilePath.stem().string().rfind(c_copierPostf) != string::npos); if (isCopier) { _fillCopier(testData, testFillerPathRelative, _outputTestFilePath); diff --git a/retesteth/testSuites/Common.cpp b/retesteth/testSuites/Common.cpp index 2d4431cb4..c8daf9b22 100644 --- a/retesteth/testSuites/Common.cpp +++ b/retesteth/testSuites/Common.cpp @@ -70,14 +70,14 @@ void printVmTrace(VMtraceinfo const& _info) if (!Options::get().vmtraceraw.outpath.empty()) { auto outpath = fs::path(Options::get().vmtraceraw.outpath); - ETH_DC_MESSAGE(DC::TESTLOG, "Export vmtraceraw to " + (outpath / _info.trName).string()); + ETH_DC_MESSAGEC(DC::TESTLOG, "Export vmtraceraw to " + (outpath / _info.trName).string(), LogColor::LIME); ret.exportLogs(outpath / _info.trName); } else ret.print(); } else - ret.printNice(); + ret.print(); DataObject state; state["stateRoot"] = _info.stateRoot.asString(); @@ -89,7 +89,8 @@ void compareTransactionException(spTransaction const& _tr, MineBlocksResult cons { if (!_mRes.isRejectData() && !_testException.empty()) { - ETH_WARNING("Looks like client does not support rejected transaction information!"); + if (Options::get().filltests) + ETH_WARNING("Looks like client does not support rejected transaction information!"); return; } // Mine a block, execute transaction @@ -190,7 +191,18 @@ void verifyFilledTestRecursive(DataObject const& _want, DataObject const& _have, void modifyTransactionChainIDByNetwork(test::Transaction const& _tr, FORK const& _fork) { - auto const& genesisChainID = Options::getDynamicOptions().getCurrentConfig().getGenesisTemplateChainID(); + if (Options::get().chainid.initialized()) + { + VALUE const chainID((size_t)Options::get().chainid); + if (_tr.getChainID() != chainID) + { + auto& tr = const_cast(_tr); + tr.setChainID(chainID); + } + return; + } + + auto const& genesisChainID = Options::getCurrentConfig().getGenesisTemplateChainID(); if (genesisChainID.count(_fork)) { VALUE const& chainID = genesisChainID.at(_fork); @@ -241,7 +253,7 @@ spDataObject storageDiff(Storage const& _pre, Storage const& _post) spDataObject stateDiff(State const& _pre, State const& _post) { - spDataObject res; + spDataObject res(new DataObject(DataType::Object)); for (auto const& postAcc : _post.accounts()) { if (_pre.hasAccount(postAcc.first)) @@ -297,4 +309,22 @@ spDataObject stateDiff(State const& _pre, State const& _post) return res; } +bool hasSkipFork(std::set const& _allforks) +{ + Options const& opt = Options::get(); + auto const& skipforks = opt.getCurrentConfig().cfgFile().fillerSkipForks(); + for (auto const& skipfork : skipforks) + { + if (_allforks.count(skipfork)) + { + ETH_WARNING(string("Test has unsupported fork `") + skipfork.asString() + + "` allowed to skip, skipping the test from filling!" + + TestOutputHelper::get().testInfo().errorDebug()); + return true; + } + } + return false; +} + + } // namespace diff --git a/retesteth/testSuites/Common.h b/retesteth/testSuites/Common.h index 17d83b5f5..a7f6aa7cc 100644 --- a/retesteth/testSuites/Common.h +++ b/retesteth/testSuites/Common.h @@ -45,7 +45,7 @@ struct StateTooBig : UpwardsException { StateTooBig() : UpwardsException("StateTooBig") {} }; -State getRemoteState(test::session::SessionInterface& _session); +spState getRemoteState(test::session::SessionInterface& _session); // Check that test has data object void checkDataObject(DataObject const& _input); @@ -94,4 +94,5 @@ void verifyFilledTestRecursive(DataObject const& _want, DataObject const& _have, // Configure transaction chainID by current client config void modifyTransactionChainIDByNetwork(test::Transaction const& _tr, FORK const& _fork); +bool hasSkipFork(std::set const& _allforks); } diff --git a/retesteth/testSuites/CompareStates.cpp b/retesteth/testSuites/CompareStates.cpp index f3dafe86d..b7f948f4d 100644 --- a/retesteth/testSuites/CompareStates.cpp +++ b/retesteth/testSuites/CompareStates.cpp @@ -1,5 +1,6 @@ #include "Common.h" #include +#include using namespace std; using namespace test::debug; using namespace test::session; @@ -37,9 +38,9 @@ State::Account remoteGetAccount(SessionInterface& _session, VALUE const& _bNumbe } // Get full remote state from the client -State getRemoteState(SessionInterface& _session) +spState getRemoteState(SessionInterface& _session) { - VALUE recentBNumber(_session.eth_blockNumber()); + VALUE const recentBNumber = _session.eth_blockNumber(); EthGetBlockBy recentBlock(_session.eth_getBlockByNumber(recentBNumber, Request::LESSOBJECTS)); VALUE trIndex(recentBlock.transactions().size()); @@ -51,7 +52,7 @@ State getRemoteState(SessionInterface& _session) DebugAccountRange range(_session.debug_accountRange(recentBNumber, trIndex, nextKey, 10)); for (auto const& el : range.addresses()) { - accountList.push_back(el); + accountList.emplace_back(el); if (!Options::get().fullstate && accountList.size() > 50) throw StateTooBig(); } @@ -76,7 +77,7 @@ State getRemoteState(SessionInterface& _session) throw StateTooBig(); } } - return State(stateAccountMap); + return spState(new State(stateAccountMap)); } // Compare expected state with session asking post state data on the fly @@ -155,8 +156,11 @@ CompareResult compareStorage(Storage const& _expectStorage, Storage const& _remo VALUE const& remoteVal = _remoteStorage.atKey(expKey); if (remoteVal != expVal) { - ETH_MARK_ERROR(message + "has incorrect storage [" + expKey.asString() + "] = `" + remoteVal.asString() + - "`, test expected [" + expKey.asString() + "] = `" + expVal.asString() + "`"); + ETH_MARK_ERROR(message + "has incorrect storage [" + expKey.asString() + "] = `" + + remoteVal.asString() + "(" + remoteVal.asDecString() + ")" + + "`, test expected [" + expKey.asString() + "] = `" + + expVal.asString() + "(" + expVal.asDecString() + ")" + + "`"); result = CompareResult::IncorrectStorage; } } @@ -169,9 +173,11 @@ CompareResult compareStorage(Storage const& _expectStorage, Storage const& _remo for (auto const& el : _remoteStorage.getKeys()) { if (!_expectStorage.hasKey(VALUE(el.first))) - keys.push_back(el.first); + keys.emplace_back(el.first); } - storage += "\n [" + keys.at(0) + "] = " + _remoteStorage.atKey(VALUE(keys.at(0))).asString(); + auto const& remVal = _remoteStorage.atKey(VALUE(keys.at(0))); + storage += "\n [" + keys.at(0) + "] = " + remVal.asString(); + storage += "(" + remVal.asDecString() + ")\n"; ETH_MARK_ERROR(storage); result = CompareResult::IncorrectStorage; @@ -254,8 +260,11 @@ void compareStates(StateBase const& _stateExpect, State const& _statePost) if (accountCompareResult != CompareResult::Success) result = accountCompareResult; } - if (Options::get().poststate) - ETH_DC_MESSAGE(DC::STATE, "State Dump: \n" + _statePost.asDataObject()->asJson()); + auto const& opt = Options::get(); + if (opt.poststate && !opt.poststate.isBlockSelected) + ETH_DC_MESSAGE(DC::STATE, "Compare States State Dump: " + + test::TestOutputHelper::get().testInfo().errorDebug() + cDefault + + " \n" + _statePost.asDataObject()->asJson()); if (result != CompareResult::Success) ETH_ERROR_MESSAGE("CompareStates failed with errors: " + CompareResultToString(result)); } diff --git a/retesteth/testSuites/EOFTest.cpp b/retesteth/testSuites/EOFTest.cpp new file mode 100644 index 000000000..a31221771 --- /dev/null +++ b/retesteth/testSuites/EOFTest.cpp @@ -0,0 +1,264 @@ +#include "EOFTest.h" +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace test; +using namespace dataobject; +using namespace test::teststruct; +namespace fs = boost::filesystem; + +const FH20 C_CREATE_ACC("0x6295ee1b4f6dd65047762f924ecd367c17eabf8f"); + +namespace +{ +void makeBasicSections(DataObject& _test) +{ + // Make ENV section + _test["env"]["currentCoinbase"] = "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"; + _test["env"]["currentDifficulty"] = "0x20000"; + _test["env"]["currentGasLimit"] = "0x2233445566"; + _test["env"]["currentNumber"] = "1"; + _test["env"]["currentTimestamp"] = "1000"; + _test["env"]["previousHash"] = "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"; + + // Make Pre section + spDataObject preState(new DataObject(DataType::Object)); + spDataObject account(new DataObject(DataType::Object)); + (*account)["balance"] = "1000000000000000000"; + (*account)["code"] = "0x"; + (*account)["nonce"] = "0"; + (*account).atKeyPointer("storage") = spDataObject(new DataObject(DataType::Object)); + (*account).setKey("a94f5374fce5edbc8e2a8697c15331677e6ebf0b"); + (*preState).addSubObject(account); + (*preState).setKey("pre"); + _test.atKeyPointer("pre") = preState; +} + +spDataObject makeTransactionWithoutData() +{ + spDataObject transaction(new DataObject(DataType::Object)); + (*transaction)["gasLimit"].addArrayObject(spDataObject(new DataObject("400000"))); + (*transaction)["gasPrice"] = "10"; + (*transaction)["nonce"] = "0"; + (*transaction)["secretKey"] = "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8"; + (*transaction)["to"] = ""; + (*transaction)["value"].addArrayObject(spDataObject(new DataObject("1000"))); + (*transaction).setKey("transaction"); + return transaction; +} + +spDataObject makeValidResultExpect() +{ + spDataObject result; + spDataObject account(new DataObject(DataType::Object)); + (*account)["balance"] = "1000"; + (*account).setKey(C_CREATE_ACC.asString()); + (*result).addSubObject(account); + return result; +} + +spDataObject makeInvalidResultExpect() +{ + spDataObject result; + spDataObject account(new DataObject(DataType::Object)); + (*account)["shouldnotexist"] = "1"; + (*account).setKey(C_CREATE_ACC.asString()); + (*result).addSubObject(account); + return result; +} + +void convertEOFTestFillerToStateTestFiller(spDataObject& _input) +{ + DataObject& test = (*_input).atUnsafe(0); + makeBasicSections(test); + + // Make Transaction section + spDataObject transaction = makeTransactionWithoutData(); + (*transaction).atKeyPointer("data") = test.atKeyPointerUnsafe("data"); + test.removeKey("data"); + test.atKeyPointer("transaction") = transaction; + + // Make expect section + for (auto& expect : test.atKeyUnsafe("expect").getSubObjectsUnsafe()) + { + if (!expect->count("result") && expect->atKey("result").type() != DataType::Bool) + throw UpwardsException("Expect section required to have 'result' field of type bool!"); + + bool const valid = expect->atKey("result").asBool(); + expect.getContent().removeKey("result"); + if (valid) + (*expect).atKeyPointer("result") = makeValidResultExpect(); + else + (*expect).atKeyPointer("result") = makeInvalidResultExpect(); + } +} + +spDataObject makeGeneratedEOFTest(DataObject& _stateTestFiller) +{ + spDataObject expectSectionArray = _stateTestFiller.atKeyPointer("expect"); + + // Copy transaction section data and initialize the reader + auto const trJsonCopy = _stateTestFiller.atKey("transaction").asJson(); + spDataObject transactionCpy = ConvertJsoncppStringToData(trJsonCopy); + spStateTestFillerTransaction spTr(new StateTestFillerTransaction(MOVE(transactionCpy, "transaction"))); + + // Copy expect section data and initialize the reader + vector expects; + expects.reserve(expectSectionArray->getSubObjects().size()); + for (auto const& expect : expectSectionArray->getSubObjects()) + { + spDataObject expectCpy = ConvertJsoncppStringToData(expect->asJson()); + StateTestFillerExpectSection expectSecion(dataobject::move(expectCpy), spTr); + expects.emplace_back(expectSecion); + } + + spDataObject eofTest; + string const testName = _stateTestFiller.getKey(); + + size_t number = 0; + for (auto const& data : spTr->databoxVector()) + { + spDataObject testVector; + (*testVector).setKey(testName + "_" + test::fto_string(number)); + (*testVector)["code"] = data.m_data.asString(); + + for (auto const& expect : expects) + { + if (expect.checkIndexes(number, -1, -1)) + { + auto const& acc = expect.result().accounts().at(C_CREATE_ACC.asString()); + bool valid = !acc->shouldNotExist(); + for (auto const& fork : expect.forks()) + { + spDataObject result; + (*result).setKey(fork.asString()); + (*result)["result"].setBool(valid); + (*testVector)["results"].addSubObject(result); + } + } + } + + number++; + (*eofTest)[testName]["vectors"].addSubObject(testVector); + } + return eofTest; +} + +class ExpectSection +{ +public: + ExpectSection(bool _expectedresult) + { + if (_expectedresult) + (*m_data).atKeyPointer("result") = makeValidResultExpect(); + else + (*m_data).atKeyPointer("result") = makeInvalidResultExpect(); + } + bool isEmpty() const + { + return m_indexes.size() == 0 || m_nets.size() == 0; + } + void addNet(string const& _net) + { + m_nets.emplace(_net); + } + void addIndex(size_t _ind) + { + m_indexes.emplace(_ind); + } + spDataObject getObject() + { + for (auto const& net : m_nets) + { + spDataObject netObj(new DataObject(net)); + (*m_data)["network"].addArrayObject(netObj); + } + for (auto const& ind : m_indexes) + { + auto& dataIndexes = (*m_data)["indexes"]["data"]; + dataIndexes.addArrayObject(spDataObject(new DataObject(ind))); + } + return m_data; + } +public: + std::set m_nets; + std::set m_indexes; + spDataObject m_data; +}; + +void convertEOFTestToStateTestFiller(spDataObject& _input) +{ + auto& test = (*_input).atUnsafe(0); + makeBasicSections(test); + spDataObject transaction = makeTransactionWithoutData(); + + size_t index = 0; + ExpectSection expectValid(true); + ExpectSection expectInValid(false); + for (auto& vectr : test.atKeyUnsafe("vectors").getSubObjectsUnsafe()) + { + (*transaction)["data"].addArrayObject((*vectr).atKeyPointerUnsafe("code")); + for (auto const& res : vectr->atKey("results").getSubObjects()) + { + if (res->atKey("result").asBool()) + { + expectValid.addNet(res->getKey()); + expectValid.addIndex(index); + } + else + { + expectInValid.addNet(res->getKey()); + expectInValid.addIndex(index); + } + } + index++; + } + + spDataObject expectSection(new DataObject(DataType::Array)); + if (!expectValid.isEmpty()) + (*expectSection).addArrayObject(expectValid.getObject()); + if (!expectInValid.isEmpty()) + (*expectSection).addArrayObject(expectInValid.getObject()); + ETH_ERROR_REQUIRE_MESSAGE(expectSection->getSubObjects().size() > 0, "Expect section construction error!"); + + test.atKeyPointer("expect") = expectSection; + test.atKeyPointer("transaction") = transaction; + test.removeKey("vectors"); + test.removeKey("_info"); +} + +} // namespace + +spDataObject EOFTestSuite::doTests(spDataObject& _input, TestSuiteOptions& _opt) const +{ + if (_opt.doFilling) + { + auto& test = _input.getContent().atUnsafe(0); + convertEOFTestFillerToStateTestFiller(_input); + auto eofTest = makeGeneratedEOFTest(test); + StateTestSuite::doTests(_input, _opt); + return eofTest; + } + else + { + convertEOFTestToStateTestFiller(_input); + _opt.doFilling = true; + + // Cheat the file name to look like its filler for internal checks + fs::path const& c_file = TestOutputHelper::get().testFile(); + fs::path& file = const_cast(c_file); + string sFile = c_file.string(); + size_t pos = sFile.find(".json"); + sFile.insert(pos, "Filler"); + file = sFile; + + StateTestSuite::doTests(_input, _opt); + } + return spDataObject(0); +} diff --git a/retesteth/testSuites/EOFTest.h b/retesteth/testSuites/EOFTest.h new file mode 100644 index 000000000..54bb2a9c6 --- /dev/null +++ b/retesteth/testSuites/EOFTest.h @@ -0,0 +1,18 @@ +#pragma once +#include +#include +#include +#include + +namespace test +{ +class EOFTestSuite : public StateTestSuite +{ +public: + EOFTestSuite() : StateTestSuite(){}; + dataobject::spDataObject doTests(dataobject::spDataObject& _input, TestSuiteOptions& _opt) const override; + TestSuite::TestPath suiteFolder() const override; + TestSuite::FillerPath suiteFillerFolder() const override; +}; + +} // namespace test diff --git a/retesteth/testSuites/TestFixtures.cpp b/retesteth/testSuites/TestFixtures.cpp index a642da652..56afa9b34 100644 --- a/retesteth/testSuites/TestFixtures.cpp +++ b/retesteth/testSuites/TestFixtures.cpp @@ -6,6 +6,7 @@ //Suites #include +#include #include #include #include @@ -34,7 +35,17 @@ test_suite* getSuiteByPathName(std::string const& _suiteName) { auto const suiteid = suite->get(suiteName); if (suiteid != INV_TEST_UNIT_ID) - suite = &framework::get(suiteid); + { + try { + suite = &framework::get(suiteid); + } + catch (std::exception const&) + { + ETH_WARNING("Pathname `" + _suiteName + "` is not a suite!"); + return nullptr; + } + + } else return nullptr; } @@ -72,7 +83,7 @@ test_unit_id registerNewTestCase( string const fullCaseName = string(suiteName) + "/" + _caseName; ETH_DC_MESSAGEC(DC::STATS2, "Registering new test case: " + fullCaseName, LogColor::YELLOW); - allTestNames.push_back(fullCaseName); + allTestNames.emplace_back(fullCaseName); test_case* tcase = BOOST_TEST_CASE(boost::bind(&TestFixtureBase::execute, fixture.get())); tcase->p_name.value = _caseName; @@ -90,7 +101,7 @@ void registerNewTestSuite( string const newSuiteName = _path.stem().string(); string const fullSuiteName = string(suiteName) + "/" + newSuiteName; ETH_DC_MESSAGEC(DC::STATS2, "Registering new test suite: " + fullSuiteName, LogColor::YELLOW); - allTestNames.push_back(fullSuiteName); + allTestNames.emplace_back(fullSuiteName); test_suite* tsuite = BOOST_TEST_SUITE(newSuiteName); for (auto const& path : subFolders) @@ -105,7 +116,7 @@ void registerNewTestSuite( fixToSuite.second = fullSuiteName; registerNewTestCase(allTestNames, fixToSuite, tsuite, casename); - g_dynamic_test_suite_fixtures.push_back(std::move(fixToSuite)); + g_dynamic_test_suite_fixtures.emplace_back(std::move(fixToSuite)); } _suite->add(tsuite); } @@ -163,8 +174,7 @@ bool TestChecker::isTimeConsumingTest(std::string const& _testName) FixtureRegistrator::FixtureRegistrator(TestFixtureBase* _fixture, string&& _suiteName) { uPtrTestFixtureBase ptr(_fixture); - auto p = std::make_pair(std::move(ptr), std::move(_suiteName)); - g_dynamic_test_search_fixtures.push_back(std::move(p)); + g_dynamic_test_search_fixtures.push_back(std::make_pair(std::move(ptr), std::move(_suiteName))); delete this; } @@ -233,28 +243,42 @@ TestFixture::TestFixture(std::set const& _execFlags) : m_ex _execute(_execFlags); } + +#define REGISTER_TEMPLATE(SUITE, FLAG) \ + template TestFixture::TestFixture(std::set const& _execFlags); + // Difficulty links -template TestFixture::TestFixture(std::set const& _execFlags); +REGISTER_TEMPLATE(DifficultyTestSuite, DefaultFlags) +REGISTER_TEMPLATE(TransactionTestSuite, DefaultFlags) // Legacy links -template TestFixture::TestFixture(std::set const& _execFlags); -template TestFixture::TestFixture(std::set const& _execFlags); -template TestFixture::TestFixture(std::set const& _execFlags); -template TestFixture::TestFixture(std::set const& _execFlags); +REGISTER_TEMPLATE(LegacyConstantinopleBlockchainValidTestSuite, NotRefillable) +REGISTER_TEMPLATE(LegacyConstantinopleBlockchainInvalidTestSuite, NotRefillable) +REGISTER_TEMPLATE(LegacyConstantinopleBCGeneralStateTestsSuite, NotRefillable) +REGISTER_TEMPLATE(LegacyConstantinopleStateTestSuite, NotRefillable) // BC links -template TestFixture::TestFixture(std::set const& _execFlags); -template TestFixture::TestFixture(std::set const& _execFlags); -template TestFixture::TestFixture(std::set const& _execFlags); -template TestFixture::TestFixture(std::set const& _execFlags); -template TestFixture::TestFixture(std::set const& _execFlags); -template TestFixture::TestFixture(std::set const& _execFlags); +REGISTER_TEMPLATE(BCGeneralStateTestsSuite, RequireOptionAllNotRefillable) +REGISTER_TEMPLATE(BCEIPStateTestsSuite, RequireOptionAllNotRefillable) +REGISTER_TEMPLATE(BCEIPStateTestsEOFSuite, RequireOptionAll) -// State link -template TestFixture::TestFixture(std::set const& _execFlags); -template TestFixture::TestFixture(std::set const& _execFlags); -template TestFixture::TestFixture(std::set const& _execFlags); +REGISTER_TEMPLATE(BCGeneralStateTestsVMSuite, RequireOptionAll) +REGISTER_TEMPLATE(BCGeneralStateTestsShanghaiSuite, RequireOptionAll) -template TestFixture::TestFixture(std::set const& _execFlags); +REGISTER_TEMPLATE(BlockchainTestTransitionSuite, DefaultFlags) +REGISTER_TEMPLATE(BlockchainTestInvalidSuite, RequireOptionFill) +REGISTER_TEMPLATE(BlockchainTestInvalidSuite, DefaultFlags) +REGISTER_TEMPLATE(BlockchainTestEIPSuite, DefaultFlags) +REGISTER_TEMPLATE(BlockchainTestValidSuite, DefaultFlags) + +// State link +REGISTER_TEMPLATE(StateTestSuite, RequireOptionFill) +REGISTER_TEMPLATE(StateTestSuite, DefaultFlags) +REGISTER_TEMPLATE(EOFTestSuite, DefaultFlags) +REGISTER_TEMPLATE(StateTestVMSuite, DefaultFlags) +REGISTER_TEMPLATE(StateTestShanghaiSuite, DefaultFlags) + +REGISTER_TEMPLATE(EIPStateTestSuite, DefaultFlags) +REGISTER_TEMPLATE(EIPStateTestEOFSuite, DefaultFlags) diff --git a/retesteth/testSuites/TransactionTest.cpp b/retesteth/testSuites/TransactionTest.cpp index 75a73ec62..1227ccdaf 100644 --- a/retesteth/testSuites/TransactionTest.cpp +++ b/retesteth/testSuites/TransactionTest.cpp @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include #include #include @@ -32,7 +32,8 @@ spDataObject FillTest(TransactionTestInFiller const& _test) for (auto const& fork : _test.additionalForks()) { - if (Options::getCurrentConfig().checkForkAllowed(fork)) + auto const& opt = Options::getCurrentConfig(); + if (opt.checkForkAllowed(fork) && !opt.checkForkSkipOnFiller(fork)) executionForks.emplace(fork); else ETH_WARNING("Client config does not support fork `" + fork.asString() + "`, skipping test generation!"); @@ -80,7 +81,8 @@ void RunTest(TransactionTestInFilled const& _test) if (!opt.singleTestNet.empty() && FORK(opt.singleTestNet) != fork) continue; - if (!Options::getDynamicOptions().getCurrentConfig().checkForkAllowed(fork)) + auto const& cfg = Options::getCurrentConfig(); + if (!cfg.checkForkAllowed(fork) || cfg.checkForkSkipOnFiller(fork)) { ETH_WARNING("Client config does not support fork `" + fork.asString() + "`, skipping test!"); continue; diff --git a/retesteth/testSuites/blockchain/BlockchainTestLogic.cpp b/retesteth/testSuites/blockchain/BlockchainTestLogic.cpp index eb90bc254..3e77c87ea 100644 --- a/retesteth/testSuites/blockchain/BlockchainTestLogic.cpp +++ b/retesteth/testSuites/blockchain/BlockchainTestLogic.cpp @@ -1,230 +1,50 @@ #include "BlockchainTestLogic.h" +#include "BlockchainTestRunner.h" +#include #include #include -#include -#include -#include "fillers/TestBlockchain.h" +#include using namespace std; +using namespace test; using namespace test::debug; using namespace test::session; + namespace test { /// Read and execute the test from the file void RunTest(BlockchainTestInFilled const& _test, TestSuite::TestSuiteOptions const& _opt) { - ETH_DC_MESSAGE(DC::TESTLOG, "Running " + _test.testName()); - - ClientConfig const& cfg = Options::get().getDynamicOptions().getCurrentConfig(); - bool fillerSkipFork = cfg.checkForkSkipOnFiller(_test.network()); - if (!cfg.validateForkAllowed(_test.network(), false) || fillerSkipFork) - { - if (fillerSkipFork) - ETH_WARNING("Skipping unsupported fork: " + _test.network().asString() + " in " + _test.testName()); + if (!BlockchainTestRunner::validateFork(_test.testName(), _test.network())) return; - } - TestOutputHelper::get().setCurrentTestName(_test.testName()); - TestOutputHelper::get().setUnitTestExceptions(_test.unitTestExceptions()); - SessionInterface& session = RPCSession::instance(TestOutputHelper::getThreadID()); + BlockchainTestRunner runner(_test, _opt); + runner.setChainParams(); + runner.performOptionCommandsOnGenesis(); - TestOutputHelper::get().setCurrentTestInfo(TestInfo(_test.network().asString(), 0)); - session.test_setChainParams(prepareChainParams(_test.network(), _test.sealEngine(), _test.Pre(), _test.Env())); - - // for all blocks - size_t blockNumber = 0; for (BlockchainTestBlock const& tblock : _test.blocks()) { - if (ExitHandler::receivedExitSignal()) - return; - if (Options::get().blockLimit != 0 && blockNumber + 1 >= Options::get().blockLimit) + CHECKEXIT + if (runner.abortBlock()) break; - TestOutputHelper::get().setCurrentTestInfo(TestInfo(_test.network().asString(), blockNumber++)); - - // Transaction sequence validation - ETH_DC_MESSAGEC(DC::LOWLOG, "PERFORM TRANSACTION SEQUENCE VALIDATION...", LogColor::YELLOW); + runner.incrementBlockAndSetTestInfo(); + runner.validateTransactionSequence(tblock); - bool atLeastOnceSequence = false; - typedef std::tuple SpTrException; - std::map expectedExceptions; - if (tblock.transactionSequence().size()) - { - if (tblock.header()->number() > session.eth_blockNumber()) - { - atLeastOnceSequence = true; - session.test_modifyTimestamp(tblock.header()->timestamp()); - } - else - ETH_WARNING("Skipping invalid transaction exception check in reorg block! (calling rewind not good when running the test, use filltests instead)"); - } - for (auto const& el : tblock.transactionSequence()) - { - spTransaction const& tr = std::get<0>(el); - string const& sException = std::get<1>(el); - modifyTransactionChainIDByNetwork(tr, _test.network()); - session.eth_sendRawTransaction(tr->getRawBytes(), tr->getSecret()); - SpTrException info = {tr, sException}; - expectedExceptions.emplace(tr->hash(), info); - } - if (atLeastOnceSequence) - { - VALUE const& origNumber = session.eth_blockNumber(); - MineBlocksResult const miningRes = session.test_mineBlocks(1); - for (auto const& el : expectedExceptions) - { - SpTrException const& res = el.second; - spTransaction resTransaction = std::get<0>(res); - string const& testException = std::get<1>(res); - compareTransactionException(resTransaction, miningRes, testException); - } - session.test_rewindToBlock(origNumber); - } - // transaction sequence validation - - FH32 const blHash(session.test_importRawBlock(tblock.rlp())); - - if (!session.getLastRPCError().empty()) - { - // and options does NOT allow invalid blocks or this block was expected to be valid - // BCValidBlocks does not allow invalid blocks! - if (!_opt.allowInvalidBlocks || !tblock.expectedInvalid()) - ETH_ERROR_MESSAGE( - "Importing raw RLP block, block was expected to be valid! (if it was intended, check that it is not in Valid blocks test suite) " + session.getLastRPCError().message()); - - if (Options::getDynamicOptions().getCurrentConfig().cfgFile().socketType() == ClientConfgSocketType::TransitionTool) - { - string const& sBlockException = tblock.getExpectException(); - if (!sBlockException.empty()) - blockchainfiller::TestBlockchain::checkBlockException(session, sBlockException); - } + auto const blHash = runner.mineBlock(tblock.rlp()); + if (runner.checkLastRPCBlockException(tblock)) continue; - } - else - ETH_ERROR_REQUIRE_MESSAGE(!tblock.expectedInvalid(), - "Running blockchain test: Block #" + to_string(blockNumber) + " expected to be invalid!"); - - // Check imported block against the fields in test - // Check Blockheader - EthGetBlockBy latestBlock(session.eth_getBlockByHash(blHash, Request::FULLOBJECTS)); - - for (auto const& tr : tblock.transactions()) - { - if (Options::get().vmtrace) - { - string const testNameOut = _test.testName() + "_" + tr->hash().asString() + ".txt"; - VMtraceinfo info(session, tr->hash(), latestBlock.header()->stateRoot(), testNameOut); - printVmTrace(info); - } - } - - spDataObject remoteHeader = latestBlock.header()->asDataObject(); - spDataObject testHeader = tblock.header()->asDataObject(); - bool condition = remoteHeader->asJson(0, false) == testHeader->asJson(0, false); - /*if (_opt.isLegacyTests) - { - inTestHeader = bdata.atKey("blockHeader"); // copy!!! - if (latestBlock.getBlockHeader().atKey("nonce").asString() == "0x0000000000000000") - { - // because on NoProof mixHash is returned as 0x00 by other client, even if block - // imported with mixHash/nonce ??? who returned 0x00 as mixHash??? wtf - inTestHeader["mixHash"] = - "0x0000000000000000000000000000000000000000000000000000000000000000"; - inTestHeader["nonce"] = "0x0000000000000000"; - } - inTestHeader["hash"] = latestBlock.getBlockHeader().atKey("hash"); - condition = latestBlock.getBlockHeader() == inTestHeader; - }*/ - - // string const jsonHeader = inTestHeader.type() == DataType::Null ? - // bdata.atKey("blockHeader").asJson() : - // "(adjusted)" + inTestHeader.asJson(); - string message; - if (!condition) - { - string errField; - message = "Client return HEADER vs Test HEADER: \n"; - message += compareBlockHeaders(remoteHeader.getCContent(), testHeader.getCContent(), errField); - } - ETH_ERROR_REQUIRE_MESSAGE( - condition, "Client report different blockheader after importing the rlp than expected by test! \n" + message); - // Verify uncles to one described in the fields - size_t ind = 0; - message = "Client return UNCLES: " + to_string(latestBlock.uncles().size()) + " vs " + - "Test UNCLES: " + to_string(tblock.uncles().size()); - ETH_ERROR_REQUIRE_MESSAGE(latestBlock.uncles().size() == tblock.uncles().size(), - "Client report different uncle count after importing the rlp than expected by test! \n" + message); - for (spBlockHeader const& tuncle : tblock.uncles()) - { - FH32 clientUncleHash = latestBlock.uncles().at(ind++); // EthGetBlockBy return only hashes - if (clientUncleHash != tuncle->hash()) - ETH_ERROR_MESSAGE("Remote client returned block with unclehash that is not expected by test! " + message); - } - - // Check Transaction count - message = "Client return TRANSACTIONS: " + to_string(latestBlock.transactions().size()) + " vs " + - "Test TRANSACTIONS: " + to_string(tblock.transactions().size()); - ETH_ERROR_REQUIRE_MESSAGE(latestBlock.transactions().size() == tblock.transactions().size(), - "Client report different transaction count after importing the rlp than expected by test! \n" + message); - - // Verify transactions to one described in the fields - ind = 0; - for (spTransaction const& tr : tblock.transactions()) - { - if (ExitHandler::receivedExitSignal()) - return; - EthGetBlockByTransaction const& clientTr = latestBlock.transactions().at(ind++); - ETH_ERROR_REQUIRE_MESSAGE(clientTr.blockHash() == tblock.header()->hash(), - "Error checking remote transaction, remote tr `blockHash` is different to one described in test block! " - "(" + - clientTr.blockHash().asString() + " != " + tblock.header()->hash().asString() + ")"); - - ETH_ERROR_REQUIRE_MESSAGE(clientTr.blockNumber() == tblock.header()->number(), - "Error checking remote transaction, remote tr `blockNumber` is different to one described in test block! " - "(" + - clientTr.blockNumber().asDecString() + " != " + tblock.header()->number().asDecString() + ")"); - - BYTES const testTr = tr->getRawBytes(); - BYTES const remoteTr = clientTr.transaction()->getRawBytes(); - - ETH_ERROR_REQUIRE_MESSAGE(remoteTr == testTr, "Error checking remote transaction, remote tr `" + - remoteTr.asString() + "` is different to test tr `" + - testTr.asString() + "`)"); - } + auto const blockFull = runner.requestBlock(blHash); + runner.performOptionCommands(tblock, blockFull); + runner.validateBlockHeader(tblock, blockFull); + runner.validateUncles(tblock, blockFull); + runner.validateTransactions(tblock, blockFull); } - EthGetBlockBy latestBlock(session.eth_getBlockByNumber(session.eth_blockNumber(), Request::LESSOBJECTS)); - if (_test.isFullState()) - compareStates(_test.Post(), session); - else - ETH_ERROR_REQUIRE_MESSAGE(_test.PostHash() == latestBlock.header()->stateRoot(), - "postStateHash mismatch! remote: " + latestBlock.header()->stateRoot().asString() + " != test " = - _test.PostHash().asString()); - - if (_test.lastBlockHash() != latestBlock.header()->hash()) - ETH_ERROR_MESSAGE("lastblockhash does not match! remote: '" + latestBlock.header()->hash().asString() + - "', test: '" + _test.lastBlockHash().asString() + "'"); - - bool skipGenesisCheck = false; - if (_opt.isLegacyTests) - { - // Skip old generated tests (Legacy) genesis check on aleth - // because mixHash and nonce return is different to geth - if (Options::getDynamicOptions().getCurrentConfig().cfgFile().path().parent_path().filename() == "aleth") - skipGenesisCheck = true; - - if (_test.genesisRLP().asString() == "0x00") - skipGenesisCheck = true; - } - - if (!skipGenesisCheck) - { - EthGetBlockBy genesis(session.eth_getBlockByNumber(0, Request::LESSOBJECTS)); - if (_test.genesisRLP() != genesis.getRLPHeaderTransactions()) - ETH_ERROR_MESSAGE("genesisRLP in test != genesisRLP on remote client! (" + _test.genesisRLP().asString() + - "' != '" + genesis.getRLPHeaderTransactions().asString() + "'"); - } + auto const lastBlockLess = runner.requestBlock(runner.session().eth_blockNumber()); + runner.checkPostState(lastBlockLess); + runner.checkGenesis(); } spDataObject DoTests(spDataObject& _input, TestSuite::TestSuiteOptions& _opt) diff --git a/retesteth/testSuites/blockchain/BlockchainTestLogic.h b/retesteth/testSuites/blockchain/BlockchainTestLogic.h index f055943dd..b59d77efb 100644 --- a/retesteth/testSuites/blockchain/BlockchainTestLogic.h +++ b/retesteth/testSuites/blockchain/BlockchainTestLogic.h @@ -4,6 +4,7 @@ #pragma once #include +#include #include #include #include diff --git a/retesteth/testSuites/blockchain/BlockchainTestRunner.cpp b/retesteth/testSuites/blockchain/BlockchainTestRunner.cpp new file mode 100644 index 000000000..1efe64e74 --- /dev/null +++ b/retesteth/testSuites/blockchain/BlockchainTestRunner.cpp @@ -0,0 +1,334 @@ +#include "BlockchainTestRunner.h" +#include "Common.h" +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace test; +using namespace test::debug; +using namespace test::session; + +BlockchainTestRunner::BlockchainTestRunner(BlockchainTestInFilled const& _test, TestSuite::TestSuiteOptions const& _opt) + : m_test(_test), m_opt(_opt), m_session(RPCSession::instance(TestOutputHelper::getThreadID())) +{ + ETH_DC_MESSAGE(DC::TESTLOG, "Running " + _test.testName()); +} + +bool BlockchainTestRunner::validateFork(string const& _testName, FORK const& _net) +{ + ClientConfig const& cfg = Options::get().getDynamicOptions().getCurrentConfig(); + bool fillerSkipFork = cfg.checkForkSkipOnFiller(_net); + if (!cfg.validateForkAllowed(_net, false) || fillerSkipFork) + { + if (fillerSkipFork) + ETH_WARNING("Skipping unsupported fork: " + _net.asString() + " in " + _testName); + return false; + } + return true; +} + +bool BlockchainTestRunner::abortBlock() const +{ + auto const& opt = Options::get(); + return (opt.blockLimit != 0 && m_blockNumber + 1 >= opt.blockLimit); +} + +void BlockchainTestRunner::setChainParams() +{ + TestOutputHelper::get().setCurrentTestName(m_test.testName()); + TestOutputHelper::get().setUnitTestExceptions(m_test.unitTestExceptions()); + TestOutputHelper::get().setCurrentTestInfo(TestInfo(m_test.network().asString(), 0)); + m_session.test_setChainParams(prepareChainParams(m_test.network(), m_test.sealEngine(), m_test.Pre(), m_test.Env())); +} + +void BlockchainTestRunner::incrementBlockAndSetTestInfo() +{ + m_blockNumber++; + TestOutputHelper::get().setCurrentTestInfo(TestInfo(m_test.network().asString(), m_blockNumber)); +} + +void BlockchainTestRunner::validateTransactionSequence(BlockchainTestBlock const& _tblock) +{ + ETH_DC_MESSAGEC(DC::LOWLOG, "PERFORM TRANSACTION SEQUENCE VALIDATION...", LogColor::YELLOW); + + bool atLeastOnceSequence = false; + typedef std::tuple SpTrException; + std::map expectedExceptions; + if (_tblock.transactionSequence().size()) + { + if (_tblock.header()->number() > m_session.eth_blockNumber()) + { + atLeastOnceSequence = true; + m_session.test_modifyTimestamp(_tblock.header()->timestamp()); + } + else + ETH_WARNING( + "Skipping invalid transaction exception check in reorg block! (calling rewind not good when running the test, " + "use filltests instead)"); + } + for (auto const& el : _tblock.transactionSequence()) + { + spTransaction const& tr = std::get<0>(el); + string const& sException = std::get<1>(el); + modifyTransactionChainIDByNetwork(tr, m_test.network()); + m_session.eth_sendRawTransaction(tr->getRawBytes(), tr->getSecret()); + SpTrException info = {tr, sException}; + expectedExceptions.emplace(tr->hash(), info); + } + if (atLeastOnceSequence) + { + VALUE const& origNumber = m_session.eth_blockNumber(); + MineBlocksResult const miningRes = m_session.test_mineBlocks(1); + for (auto const& el : expectedExceptions) + { + SpTrException const& res = el.second; + spTransaction resTransaction = std::get<0>(res); + string const& testException = std::get<1>(res); + compareTransactionException(resTransaction, miningRes, testException); + } + m_session.test_rewindToBlock(origNumber); + } +} + +teststruct::FH32 BlockchainTestRunner::mineBlock(BYTES const& _rlp) +{ + return m_session.test_importRawBlock(_rlp); +} + +teststruct::EthGetBlockBy BlockchainTestRunner::requestBlock(teststruct::FH32 const& _hash) +{ + return m_session.eth_getBlockByHash(_hash, Request::FULLOBJECTS); +} + +teststruct::EthGetBlockBy BlockchainTestRunner::requestBlock(teststruct::VALUE const& _number) +{ + return m_session.eth_getBlockByNumber(_number, Request::LESSOBJECTS); +} + +bool BlockchainTestRunner::checkLastRPCBlockException(BlockchainTestBlock const& _tblock) +{ + if (!m_session.getLastRPCError().empty()) + { + // and options does NOT allow invalid blocks or this block was expected to be valid + // BCValidBlocks does not allow invalid blocks! + if (!m_opt.allowInvalidBlocks || !_tblock.expectedInvalid()) + ETH_ERROR_MESSAGE( + "Importing raw RLP block, block was expected to be valid! (if it was intended, check that it is not in Valid " + "blocks test suite) " + + m_session.getLastRPCError().message()); + + if (Options::getDynamicOptions().getCurrentConfig().cfgFile().socketType() == ClientConfgSocketType::TransitionTool) + { + string const& sBlockException = _tblock.getExpectException(); + if (!sBlockException.empty()) + blockchainfiller::TestBlockchain::checkBlockException(m_session, sBlockException); + } + return true; + } + else + ETH_ERROR_REQUIRE_MESSAGE(!_tblock.expectedInvalid(), + "Running blockchain test: Block #" + to_string(m_blockNumber) + " expected to be invalid!"); + return false; +} + +void BlockchainTestRunner::performOptionCommandsOnGenesis() +{ + size_t const blockNumber = 0; + auto const genesis = requestBlock(VALUE(blockNumber)); + TxContext const ctx( + m_session, m_test.testName(), spTransaction(0), genesis.header(), m_test.network(), blockNumber, 0); + performPostStateBlockOnly(ctx); + this->performStatediffBlockOnly(blockNumber); +} + +void BlockchainTestRunner::performOptionCommands(BlockchainTestBlock const& _tblock, EthGetBlockBy const& _latestBlock) +{ + size_t txIndex = 0; + for (auto const& tr : _tblock.transactions()) + { + TxContext const ctx(m_session, m_test.testName(), tr, _latestBlock.header(), m_test.network(), m_blockNumber, txIndex); + performVMTrace(ctx); + txIndex++; + } + TxContext const ctx( + m_session, m_test.testName(), spTransaction(0), _latestBlock.header(), m_test.network(), m_blockNumber, 0); + performPostStateBlockOnly(ctx); + this->performStatediffBlockOnly(m_blockNumber); +} + +void BlockchainTestRunner::validateBlockHeader(BlockchainTestBlock const& _tblock, EthGetBlockBy const& _latestBlock) +{ + spDataObject remoteHeader = _latestBlock.header()->asDataObject(); + spDataObject testHeader = _tblock.header()->asDataObject(); + bool condition = remoteHeader->asJson(0, false) == testHeader->asJson(0, false); + /*if (_opt.isLegacyTests) + { + inTestHeader = bdata.atKey("blockHeader"); // copy!!! + if (latestBlock.getBlockHeader().atKey("nonce").asString() == "0x0000000000000000") + { + // because on NoProof mixHash is returned as 0x00 by other client, even if block + // imported with mixHash/nonce ??? who returned 0x00 as mixHash??? wtf + inTestHeader["mixHash"] = + "0x0000000000000000000000000000000000000000000000000000000000000000"; + inTestHeader["nonce"] = "0x0000000000000000"; + } + inTestHeader["hash"] = latestBlock.getBlockHeader().atKey("hash"); + condition = latestBlock.getBlockHeader() == inTestHeader; + }*/ + + // string const jsonHeader = inTestHeader.type() == DataType::Null ? + // bdata.atKey("blockHeader").asJson() : + // "(adjusted)" + inTestHeader.asJson(); + string message; + if (!condition) + { + string errField; + message = "Client return HEADER vs Test HEADER: \n"; + message += compareBlockHeaders(remoteHeader.getCContent(), testHeader.getCContent(), errField); + } + ETH_ERROR_REQUIRE_MESSAGE( + condition, "Client report different blockheader after importing the rlp than expected by test! \n" + message); +} + +void BlockchainTestRunner::validateUncles(BlockchainTestBlock const& _tblock, EthGetBlockBy const& _latestBlock) +{ + // Verify uncles to one described in the fields + size_t ind = 0; + string message = "Client return UNCLES: " + to_string(_latestBlock.uncles().size()) + " vs " + + "Test UNCLES: " + to_string(_tblock.uncles().size()); + ETH_ERROR_REQUIRE_MESSAGE(_latestBlock.uncles().size() == _tblock.uncles().size(), + "Client report different uncle count after importing the rlp than expected by test! \n" + message); + for (spBlockHeader const& tuncle : _tblock.uncles()) + { + FH32 clientUncleHash = _latestBlock.uncles().at(ind++); // EthGetBlockBy return only hashes + if (clientUncleHash != tuncle->hash()) + ETH_ERROR_MESSAGE("Remote client returned block with unclehash that is not expected by test! " + message); + } +} + +void BlockchainTestRunner::validateTransactions(BlockchainTestBlock const& _tblock, EthGetBlockBy const& _latestBlock) +{ + // Check Transaction count + string message = "Client return TRANSACTIONS: " + to_string(_latestBlock.transactions().size()) + " vs " + + "Test TRANSACTIONS: " + to_string(_tblock.transactions().size()); + ETH_ERROR_REQUIRE_MESSAGE(_latestBlock.transactions().size() == _tblock.transactions().size(), + "Client report different transaction count after importing the rlp than expected by test! \n" + message); + + // Verify transactions to one described in the fields + size_t ind = 0; + for (spTransaction const& tr : _tblock.transactions()) + { + if (ExitHandler::receivedExitSignal()) + return; + EthGetBlockByTransaction const& clientTr = _latestBlock.transactions().at(ind++); + ETH_ERROR_REQUIRE_MESSAGE(clientTr.blockHash() == _tblock.header()->hash(), + "Error checking remote transaction, remote tr `blockHash` is different to one described in test block! " + "(" + + clientTr.blockHash().asString() + " != " + _tblock.header()->hash().asString() + ")"); + + ETH_ERROR_REQUIRE_MESSAGE(clientTr.blockNumber() == _tblock.header()->number(), + "Error checking remote transaction, remote tr `blockNumber` is different to one described in test block! " + "(" + + clientTr.blockNumber().asDecString() + " != " + _tblock.header()->number().asDecString() + ")"); + + BYTES const testTr = tr->getRawBytes(); + BYTES const remoteTr = clientTr.transaction()->getRawBytes(); + + ETH_ERROR_REQUIRE_MESSAGE(remoteTr == testTr, "Error checking remote transaction, remote tr `" + remoteTr.asString() + + "` is different to test tr `" + testTr.asString() + "`)"); + } +} + +void BlockchainTestRunner::checkPostState(EthGetBlockBy const& _latestBlock) +{ + performFinalPostState(_latestBlock); + performFinalStateDiff(); + + if (m_test.isFullState()) + compareStates(m_test.Post(), m_session); + else + ETH_ERROR_REQUIRE_MESSAGE(m_test.PostHash() == _latestBlock.header()->stateRoot(), + "postStateHash mismatch! remote: " + _latestBlock.header()->stateRoot().asString() + " != test " = + m_test.PostHash().asString()); + + if (m_test.lastBlockHash() != _latestBlock.header()->hash()) + ETH_ERROR_MESSAGE("lastblockhash does not match! remote: '" + _latestBlock.header()->hash().asString() + "', test: '" + + m_test.lastBlockHash().asString() + "'"); +} + +void BlockchainTestRunner::checkGenesis() +{ + bool skipGenesisCheck = false; + if (m_opt.isLegacyTests) + { + // Skip old generated tests (Legacy) genesis check on aleth + // because mixHash and nonce return is different to geth + if (Options::getDynamicOptions().getCurrentConfig().cfgFile().path().parent_path().filename() == "aleth") + skipGenesisCheck = true; + + if (m_test.genesisRLP().asString() == "0x00") + skipGenesisCheck = true; + } + + if (!skipGenesisCheck) + { + EthGetBlockBy genesis(m_session.eth_getBlockByNumber(0, Request::LESSOBJECTS)); + if (m_test.genesisRLP() != genesis.getRLPHeaderTransactions()) + ETH_ERROR_MESSAGE("genesisRLP in test != genesisRLP on remote client! (" + m_test.genesisRLP().asString() + + "' != '" + genesis.getRLPHeaderTransactions().asString() + "'"); + } +} + +void BlockchainTestRunner::performStatediffBlockOnly(size_t _blockNumber) +{ + auto const& statediff = Options::get().statediff; + if (statediff.initialized() && statediff.isBlockSelected && m_stateDiffStateB.isEmpty()) + { + m_triedStateDiff = true; + if (statediff.firstBlock == _blockNumber && m_stateDiffStateA.isEmpty()) + { + m_stateDiffStateA = getRemoteState(m_session); + if (statediff.seconBlock != statediff.firstBlock) + return; + } + + if (statediff.seconBlock == _blockNumber && m_stateDiffStateB.isEmpty() && !m_stateDiffStateA.isEmpty()) + { + m_stateDiffStateB = getRemoteState(m_session); + auto const diff = test::stateDiff(m_stateDiffStateA, m_stateDiffStateB)->asJson(); + ETH_DC_MESSAGE(DC::STATE, + "\nRunning BC test State Diff:" + TestOutputHelper::get().testInfo().errorDebug() + cDefault + " \n" + diff); + } + } +} + +void BlockchainTestRunner::performFinalStateDiff() +{ + auto const& statediff = Options::get().statediff; + if (statediff.initialized() && !statediff.isBlockSelected) + { + auto const diff = test::stateDiff(m_test.Pre(), getRemoteState(m_session))->asJson(); + ETH_DC_MESSAGE(DC::STATE, + "\nRunning BC test State Diff:" + TestOutputHelper::get().testInfo().errorDebug() + cDefault + " \n" + diff); + } +} + +void BlockchainTestRunner::performFinalPostState(EthGetBlockBy const& _latestBlock) +{ + auto const& poststate = Options::get().poststate; + if (poststate.initialized() && !poststate.isBlockSelected) + { + performPostState(m_session, m_test.testName(), m_test.network().asString(), _latestBlock.header()->stateRoot()); + } +} + +BlockchainTestRunner::~BlockchainTestRunner() +{ + if (m_triedStateDiff) + showWarningIfStatediffNotFound(m_stateDiffStateA, m_stateDiffStateB); +} diff --git a/retesteth/testSuites/blockchain/BlockchainTestRunner.h b/retesteth/testSuites/blockchain/BlockchainTestRunner.h new file mode 100644 index 000000000..356f5f716 --- /dev/null +++ b/retesteth/testSuites/blockchain/BlockchainTestRunner.h @@ -0,0 +1,50 @@ +#pragma once +#include +#include +#include +#include +#include + +namespace test +{ +class BlockchainTestRunner +{ +public: + BlockchainTestRunner(teststruct::BlockchainTestInFilled const&, TestSuite::TestSuiteOptions const&); + ~BlockchainTestRunner(); + static bool validateFork(std::string const& _testname, teststruct::FORK const& _net); + bool abortBlock() const; + void incrementBlockAndSetTestInfo(); + void setChainParams(); + void validateTransactionSequence(teststruct::BlockchainTestBlock const&); + teststruct::FH32 mineBlock(teststruct::BYTES const&); + teststruct::EthGetBlockBy requestBlock(teststruct::FH32 const&); + teststruct::EthGetBlockBy requestBlock(teststruct::VALUE const&); + bool checkLastRPCBlockException(teststruct::BlockchainTestBlock const&); + void performOptionCommandsOnGenesis(); + void performOptionCommands(teststruct::BlockchainTestBlock const&, teststruct::EthGetBlockBy const&); + void validateBlockHeader(teststruct::BlockchainTestBlock const&, teststruct::EthGetBlockBy const&); + void validateUncles(teststruct::BlockchainTestBlock const&, teststruct::EthGetBlockBy const&); + void validateTransactions(teststruct::BlockchainTestBlock const&, teststruct::EthGetBlockBy const&); + test::session::SessionInterface& session() { return m_session; } + void checkPostState(teststruct::EthGetBlockBy const&); + void checkGenesis(); + + +private: + void performFinalPostState(teststruct::EthGetBlockBy const&); + void performFinalStateDiff(); + void performStatediffBlockOnly(size_t); + +private: + teststruct::BlockchainTestInFilled const& m_test; + TestSuite::TestSuiteOptions const& m_opt; + test::session::SessionInterface& m_session; + size_t m_blockNumber = 0; + + bool m_triedStateDiff = false; + test::teststruct::spState m_stateDiffStateA; + test::teststruct::spState m_stateDiffStateB; +}; + +} // namespace test diff --git a/retesteth/testSuites/blockchain/BlockchainTests.cpp b/retesteth/testSuites/blockchain/BlockchainTests.cpp index 5bf257592..0b8ccf5fe 100644 --- a/retesteth/testSuites/blockchain/BlockchainTests.cpp +++ b/retesteth/testSuites/blockchain/BlockchainTests.cpp @@ -28,122 +28,66 @@ namespace fs = boost::filesystem; namespace test { -/// !!! DataObject return without reference!!! must be SP!!! -spDataObject BlockchainTestTransitionSuite::doTests(spDataObject& _input, TestSuiteOptions& _opt) const -{ - _opt.allowInvalidBlocks = true; - return DoTests(_input, _opt); -} - -spDataObject BlockchainTestInvalidSuite::doTests(spDataObject& _input, TestSuiteOptions& _opt) const -{ - _opt.allowInvalidBlocks = true; - return DoTests(_input, _opt); -} - -spDataObject BlockchainTestValidSuite::doTests(spDataObject& _input, TestSuiteOptions& _opt) const -{ - _opt.allowInvalidBlocks = false; - return DoTests(_input, _opt); -} - -spDataObject LegacyConstantinopleBlockchainInvalidTestSuite::doTests(spDataObject& _input, TestSuiteOptions& _opt) const -{ - _opt.allowInvalidBlocks = true; - _opt.isLegacyTests = true; - return DoTests(_input, _opt); -} - -spDataObject LegacyConstantinopleBlockchainValidTestSuite::doTests(spDataObject& _input, TestSuiteOptions& _opt) const -{ - _opt.allowInvalidBlocks = false; - _opt.isLegacyTests = true; - return DoTests(_input, _opt); -} - -spDataObject LegacyConstantinopleBCGeneralStateTestsSuite::doTests(spDataObject& _input, TestSuiteOptions& _opt) const -{ - _opt.isLegacyTests = true; - return DoTests(_input, _opt); -} - -TestSuite::TestPath BlockchainTestValidSuite::suiteFolder() const -{ - return TestSuite::TestPath(fs::path("BlockchainTests") / string("ValidBlocks" + m_fillerPathAdd)); -} - -TestSuite::FillerPath BlockchainTestValidSuite::suiteFillerFolder() const -{ - return TestSuite::FillerPath(fs::path("src") / "BlockchainTestsFiller" / string("ValidBlocks" + m_fillerPathAdd)); -} - -TestSuite::TestPath BlockchainTestInvalidSuite::suiteFolder() const -{ - return TestSuite::TestPath(fs::path("BlockchainTests") / string("InvalidBlocks" + m_fillerPathAdd)); -} - -TestSuite::FillerPath BlockchainTestInvalidSuite::suiteFillerFolder() const -{ - return TestSuite::FillerPath(fs::path("src") / "BlockchainTestsFiller" / string("InvalidBlocks" + m_fillerPathAdd)); -} - -TestSuite::TestPath BlockchainTestTransitionSuite::suiteFolder() const -{ - return TestSuite::TestPath(fs::path("BlockchainTests") / string("TransitionTests" + m_fillerPathAdd)); -} - -TestSuite::FillerPath BlockchainTestTransitionSuite::suiteFillerFolder() const -{ - return TestSuite::FillerPath(fs::path("src") / "BlockchainTestsFiller" / string("TransitionTests" + m_fillerPathAdd)); -} - -TestSuite::TestPath BCGeneralStateTestsSuite::suiteFolder() const -{ - return TestSuite::TestPath(fs::path("BlockchainTests") / string("GeneralStateTests" + m_fillerPathAdd)); -} - -TestSuite::FillerPath BCGeneralStateTestsSuite::suiteFillerFolder() const -{ - return TestSuite::FillerPath(fs::path("src") / fs::path("GeneralStateTestsFiller" + m_fillerPathAdd)); -} - -spDataObject BCGeneralStateTestsVMSuite::doTests(spDataObject& _input, TestSuiteOptions& _opt) const -{ - // Register subtest as finished test case. because each folder is treated as test case folder - test::TestOutputHelper::get().markTestFolderAsFinished(getFullPathFiller("VMTests").parent_path(), "VMTests"); - return BCGeneralStateTestsSuite::doTests(_input, _opt); -} - -spDataObject BCGeneralStateTestsSuite::doTests(spDataObject& _input, TestSuiteOptions& _opt) const -{ - // Register subtest as finished test case. because each folder is treated as test case folder - test::TestOutputHelper::get().markTestFolderAsFinished(getFullPathFiller("VMTests").parent_path(), "VMTests"); - test::TestOutputHelper::get().markTestFolderAsFinished( - getFullPathFiller("stExpectSection").parent_path(), "stExpectSection"); - return BlockchainTestValidSuite::doTests(_input, _opt); -} - -TestSuite::TestPath BCGeneralStateTestsVMSuite::suiteFolder() const -{ - return TestSuite::TestPath(fs::path("BlockchainTests") / "GeneralStateTests" / string("VMTests" + m_fillerPathAdd)); -} - -TestSuite::FillerPath BCGeneralStateTestsVMSuite::suiteFillerFolder() const -{ - return TestSuite::FillerPath(fs::path("src") / fs::path("GeneralStateTestsFiller") / string("VMTests" + m_fillerPathAdd)); -} - -TestSuite::TestPath LegacyConstantinopleBCGeneralStateTestsSuite::suiteFolder() const -{ - return TestSuite::TestPath( - fs::path("LegacyTests") / "Constantinople" / "BlockchainTests" / "GeneralStateTests"); -} -TestSuite::FillerPath LegacyConstantinopleBCGeneralStateTestsSuite::suiteFillerFolder() const -{ - return TestSuite::FillerPath(fs::path("src") / "LegacyTests" / "Constantinople" / - "BlockchainTestsFiller" / "GeneralStateTests"); -} +#define BLOCKCHAINSUITE_FOLDER_OVERRIDE(SUITE, FOLDER, FILLER) \ + TestSuite::TestPath SUITE::suiteFolder() const \ + { \ + return TestSuite::TestPath(fs::path(string("BlockchainTests" + string(FOLDER) + m_fillerPathAdd))); \ + } \ + \ + TestSuite::FillerPath SUITE::suiteFillerFolder() const \ + { \ + return TestSuite::FillerPath(fs::path(string("src" + string(FILLER) + m_fillerPathAdd))); \ + } + +BLOCKCHAINSUITE_FOLDER_OVERRIDE(BCGeneralStateTestsSuite, "/GeneralStateTests", "/GeneralStateTestsFiller") +BLOCKCHAINSUITE_FOLDER_OVERRIDE(BCGeneralStateTestsVMSuite, "/GeneralStateTests/VMTests", "/GeneralStateTestsFiller/VMTests") +BLOCKCHAINSUITE_FOLDER_OVERRIDE(BCGeneralStateTestsShanghaiSuite, "/GeneralStateTests/Shanghai", "/GeneralStateTestsFiller/Shanghai") + +BLOCKCHAINSUITE_FOLDER_OVERRIDE(BlockchainTestTransitionSuite, "/TransitionTests", "/BlockchainTestsFiller/TransitionTests") +BLOCKCHAINSUITE_FOLDER_OVERRIDE(BlockchainTestInvalidSuite, "/InvalidBlocks", "/BlockchainTestsFiller/InvalidBlocks") +BLOCKCHAINSUITE_FOLDER_OVERRIDE(BlockchainTestValidSuite, "/ValidBlocks", "/BlockchainTestsFiller/ValidBlocks") + + +#define LEGACY_BLOCKCHAINSUITE_FOLDER_OVERRIDE(SUITE, FOLDER, FILLER) \ + TestSuite::TestPath SUITE::suiteFolder() const \ + { \ + return TestSuite::TestPath(fs::path(string("LegacyTests" + string(FOLDER)))); \ + } \ + \ + TestSuite::FillerPath SUITE::suiteFillerFolder() const \ + { \ + return TestSuite::FillerPath(fs::path(string("src/LegacyTests" + string(FILLER)))); \ + } + +LEGACY_BLOCKCHAINSUITE_FOLDER_OVERRIDE(LegacyConstantinopleBCGeneralStateTestsSuite, + "/Constantinople/BlockchainTests/GeneralStateTests", + "/Constantinople/BlockchainTestsFiller/GeneralStateTests") +LEGACY_BLOCKCHAINSUITE_FOLDER_OVERRIDE(LegacyConstantinopleBlockchainInvalidTestSuite, + "/Constantinople/BlockchainTests/InvalidBlocks", + "/Constantinople/BlockchainTestsFiller/InvalidBlocks") +LEGACY_BLOCKCHAINSUITE_FOLDER_OVERRIDE(LegacyConstantinopleBlockchainValidTestSuite, + "/Constantinople/BlockchainTests/ValidBlocks", + "/Constantinople/BlockchainTestsFiller/ValidBlocks") + + +#define BLOCKCHAINSUITE_DOTESTS_OVERRIDE(SUITE, FUNC) \ + spDataObject SUITE::doTests(spDataObject& _input, TestSuiteOptions& _opt) const \ + { \ + FUNC \ + return DoTests(_input, _opt); \ + } + +BLOCKCHAINSUITE_DOTESTS_OVERRIDE(BlockchainTestTransitionSuite, _opt.allowInvalidBlocks = true;) +BLOCKCHAINSUITE_DOTESTS_OVERRIDE(BlockchainTestInvalidSuite, _opt.allowInvalidBlocks = true;) +BLOCKCHAINSUITE_DOTESTS_OVERRIDE(BlockchainTestValidSuite, _opt.allowInvalidBlocks = false;) +BLOCKCHAINSUITE_DOTESTS_OVERRIDE(LegacyConstantinopleBlockchainInvalidTestSuite, + _opt.allowInvalidBlocks = true; + _opt.isLegacyTests = true;) +BLOCKCHAINSUITE_DOTESTS_OVERRIDE(LegacyConstantinopleBlockchainValidTestSuite, + _opt.allowInvalidBlocks = false; + _opt.isLegacyTests = true;) +BLOCKCHAINSUITE_DOTESTS_OVERRIDE(LegacyConstantinopleBCGeneralStateTestsSuite, _opt.isLegacyTests = true;) } // Namespace Close @@ -282,14 +226,9 @@ BOOST_AUTO_TEST_CASE(stChainId) {} BOOST_AUTO_TEST_CASE(stSLoadTest) {} BOOST_AUTO_TEST_CASE(stSelfBalance) {} BOOST_AUTO_TEST_CASE(stStaticFlagEnabled) {} -BOOST_AUTO_TEST_CASE(stSubroutine) {} -BOOST_AUTO_TEST_CASE(stEIP2537) {} BOOST_AUTO_TEST_CASE(stEIP2930) {} BOOST_AUTO_TEST_CASE(stEIP1559) {} BOOST_AUTO_TEST_CASE(stEIP3607) {} -BOOST_AUTO_TEST_CASE(stEIP3540) {} -BOOST_AUTO_TEST_CASE(stEIP3670) {} -BOOST_AUTO_TEST_CASE(stEIP3860) {} // Heavy BOOST_AUTO_TEST_CASE(stTimeConsuming) {} @@ -306,4 +245,11 @@ BOOST_AUTO_TEST_CASE(vmPerformance) {} BOOST_AUTO_TEST_CASE(vmTests) {} BOOST_AUTO_TEST_SUITE_END() +// Shanghai tests +using BCGeneralStateTestsShanghaiFixture = TestFixture; +ETH_REGISTER_DYNAMIC_TEST_SEARCH(BCGeneralStateTestsShanghaiFixture, "BCGeneralStateTests/Shanghai") +BOOST_FIXTURE_TEST_SUITE(Shanghai, BCGeneralStateTestsShanghaiFixture) +BOOST_AUTO_TEST_SUITE_END() + + BOOST_AUTO_TEST_SUITE_END() diff --git a/retesteth/testSuites/blockchain/BlockchainTests.h b/retesteth/testSuites/blockchain/BlockchainTests.h index 93d594361..bdd30a1e2 100644 --- a/retesteth/testSuites/blockchain/BlockchainTests.h +++ b/retesteth/testSuites/blockchain/BlockchainTests.h @@ -12,96 +12,42 @@ namespace test { using namespace dataobject; -/// Suite run and check blockchain tests with valid blocks only -class BlockchainTestValidSuite : public TestSuite -{ -public: - spDataObject doTests(spDataObject& _input, TestSuiteOptions& _opt) const override; - TestPath suiteFolder() const override; - FillerPath suiteFillerFolder() const override; -}; - -/// Suite run/check generate blockchain tests that has malicious blocks -class BlockchainTestInvalidSuite : public TestSuite -{ -public: - spDataObject doTests(spDataObject& _input, TestSuiteOptions& _opt) const override; - TestPath suiteFolder() const override; - FillerPath suiteFillerFolder() const override; -}; - -/// Suite run/check blockchain tests with fork transition configurations -class BlockchainTestTransitionSuite : public TestSuite -{ -public: - spDataObject doTests(spDataObject& _input, TestSuiteOptions& _opt) const override; - TestPath suiteFolder() const override; - FillerPath suiteFillerFolder() const override; -}; - -/// Suite run/check stateTests converted into blockchain by testeth -class BCGeneralStateTestsSuite : public BlockchainTestValidSuite -{ -public: - test::TestSuite::TestPath suiteFolder() const override; - test::TestSuite::FillerPath suiteFillerFolder() const override; - spDataObject doTests(spDataObject& _input, TestSuiteOptions& _opt) const override; -}; - -class BCGeneralStateTestsVMSuite : public BCGeneralStateTestsSuite -{ -public: - test::TestSuite::TestPath suiteFolder() const override; - test::TestSuite::FillerPath suiteFillerFolder() const override; - spDataObject doTests(spDataObject& _input, TestSuiteOptions& _opt) const override; -}; - -/// Suite run/check stateTests converted into blockchain by testeth -class LegacyConstantinopleBCGeneralStateTestsSuite : public BlockchainTestValidSuite -{ -protected: - bool legacyTestSuiteFlag() const override { return true; } -public: - spDataObject doTests(spDataObject& _input, TestSuiteOptions& _opt) const override; - test::TestSuite::TestPath suiteFolder() const override; - test::TestSuite::FillerPath suiteFillerFolder() const override; -}; - - -class LegacyConstantinopleBlockchainInvalidTestSuite : public BlockchainTestInvalidSuite -{ -protected: - bool legacyTestSuiteFlag() const override { return true; } -public: - spDataObject doTests(spDataObject& _input, TestSuiteOptions& _opt) const override; - TestPath suiteFolder() const override - { - return TestSuite::TestPath( - boost::filesystem::path("LegacyTests/Constantinople/BlockchainTests/InvalidBlocks")); - } - FillerPath suiteFillerFolder() const override - { - return TestSuite::FillerPath( - boost::filesystem::path("/src/LegacyTests/Constantinople/BlockchainTestsFiller/InvalidBlocks")); - } -}; - -class LegacyConstantinopleBlockchainValidTestSuite : public BlockchainTestValidSuite -{ -protected: - bool legacyTestSuiteFlag() const override { return true; } -public: - spDataObject doTests(spDataObject& _input, TestSuiteOptions& _opt) const override; - TestPath suiteFolder() const override - { - return TestSuite::TestPath( - boost::filesystem::path("LegacyTests/Constantinople/BlockchainTests/ValidBlocks")); - } - FillerPath suiteFillerFolder() const override - { - return TestSuite::FillerPath( - boost::filesystem::path("/src/LegacyTests/Constantinople/BlockchainTestsFiller/ValidBlocks")); - } -}; +#define REGISTER_SUITE_OVERRIDE(SUITE, BASE, CODE) \ + class SUITE : public BASE \ + { \ + CODE \ + public: \ + spDataObject doTests(spDataObject& _input, TestSuiteOptions& _opt) const override; \ + TestPath suiteFolder() const override; \ + FillerPath suiteFillerFolder() const override; \ + }; + +#define REGISTER_SUITE(SUITE, BASE) \ + class SUITE : public BASE \ + { \ + public: \ + TestPath suiteFolder() const override; \ + FillerPath suiteFillerFolder() const override; \ + }; + +REGISTER_SUITE_OVERRIDE(BlockchainTestValidSuite, TestSuite,) +REGISTER_SUITE_OVERRIDE(BlockchainTestInvalidSuite, TestSuite,) +REGISTER_SUITE_OVERRIDE(BlockchainTestTransitionSuite, TestSuite,) + +REGISTER_SUITE(BlockchainTestEIPSuite, BlockchainTestInvalidSuite) +REGISTER_SUITE(BCGeneralStateTestsSuite, BlockchainTestValidSuite) +REGISTER_SUITE(BCGeneralStateTestsVMSuite, BCGeneralStateTestsSuite) +REGISTER_SUITE(BCGeneralStateTestsShanghaiSuite, BCGeneralStateTestsSuite) + +REGISTER_SUITE(BCEIPStateTestsSuite, BlockchainTestValidSuite) +REGISTER_SUITE(BCEIPStateTestsEOFSuite, BCEIPStateTestsSuite) + +#define LEGACYFLAG \ + protected: \ + bool legacyTestSuiteFlag() const override { return true; } + +REGISTER_SUITE_OVERRIDE(LegacyConstantinopleBCGeneralStateTestsSuite, BlockchainTestValidSuite, LEGACYFLAG) +REGISTER_SUITE_OVERRIDE(LegacyConstantinopleBlockchainInvalidTestSuite, BlockchainTestInvalidSuite, LEGACYFLAG) +REGISTER_SUITE_OVERRIDE(LegacyConstantinopleBlockchainValidTestSuite, BlockchainTestValidSuite, LEGACYFLAG) } // test diff --git a/retesteth/testSuites/blockchain/Common.cpp b/retesteth/testSuites/blockchain/Common.cpp new file mode 100644 index 000000000..ee52f958b --- /dev/null +++ b/retesteth/testSuites/blockchain/Common.cpp @@ -0,0 +1,126 @@ +#include "Common.h" +#include +#include +#include +#include +#include +#include +using namespace std; +using namespace dev; +using namespace test; +using namespace test::debug; +namespace fs = boost::filesystem; + +namespace { +string getAndPrintRemoteState(test::session::SessionInterface& _session, FH32 const& _root) +{ + auto const remStateJson = getRemoteState(_session)->asDataObject()->asJson(); + ETH_DC_MESSAGE(DC::STATE, + "\nState Dump:" + TestOutputHelper::get().testInfo().errorDebug() + cDefault + " \n" + remStateJson); + ETH_DC_MESSAGE(DC::STATE, "PostState " + TestOutputHelper::get().testInfo().errorDebug() + " : \n" + + cDefault + "Hash: " + _root.asString()); + return remStateJson; +} +} + +namespace test { + +#define CHECK_SELECTOR(opt, context) \ + if (opt.isBlockSelected) \ + { \ + if (opt.blockNumber != context.blIndex || opt.transactionNumber != context.trIndex) \ + return; \ + } + +void performVMTrace(TxContext const& _context) +{ + auto const& vmtrace = Options::get().vmtrace; + if (vmtrace.initialized()) + { + CHECK_SELECTOR(vmtrace, _context) + string const testNameOut = _context.testName + "_" + _context.tr->hash().asString() + ".txt"; + VMtraceinfo info(_context.session, _context.tr->hash(), _context.blockHeader->stateRoot(), testNameOut); + printVmTrace(info); + } +} + +void performPostState(test::session::SessionInterface& _session, string const& _testName, string const& _network, FH32 const& _root) +{ + auto const& poststate = Options::get().poststate; + if (poststate.initialized() && !poststate.isBlockSelected) + { + auto const remStateJson = getAndPrintRemoteState(_session, _root); + if (!poststate.outpath.empty()) + { + string const testNameOut = _testName + "_" + _network + ".txt"; + fs::path const pathOut = fs::path(poststate.outpath) / testNameOut; + ETH_DC_MESSAGEC(DC::STATE, "Export post state to " + pathOut.string(), LogColor::LIME); + dev::writeFile(pathOut, dev::asBytes(remStateJson)); + } + } +} + +void performPostStateBlockOnly(TxContext const& _context) +{ + auto const& poststate = Options::get().poststate; + if (poststate.initialized() && poststate.isBlockSelected) + { + if (poststate.blockNumber != _context.blIndex) + return; + + auto const remStateJson = getAndPrintRemoteState(_context.session, _context.blockHeader->stateRoot()); + if (!poststate.outpath.empty()) + { + string testNameOut = _context.testName + "_block" + test::fto_string(_context.blIndex); + testNameOut += "_" + _context.network.asString() + ".txt"; + fs::path const pathOut = fs::path(poststate.outpath) / testNameOut; + ETH_DC_MESSAGEC(DC::STATE, "Export post state to " + pathOut.string(), LogColor::LIME); + dev::writeFile(pathOut, dev::asBytes(remStateJson)); + } + } +} + +void performPostState(TxContext const& _context) +{ + auto const& poststate = Options::get().poststate; + if (poststate.initialized()) + { + CHECK_SELECTOR(poststate, _context) + auto const remStateJson = getAndPrintRemoteState(_context.session, _context.blockHeader->stateRoot()); + if (!poststate.outpath.empty()) + { + string testNameOut = _context.testName + "_block" + test::fto_string(_context.blIndex) + + "_transaction" + test::fto_string(_context.trIndex); + testNameOut += "_" + _context.network.asString() + ".txt"; + fs::path const pathOut = fs::path(poststate.outpath) / testNameOut; + ETH_DC_MESSAGEC(DC::STATE, "Export post state to " + pathOut.string(), LogColor::LIME); + dev::writeFile(pathOut, dev::asBytes(remStateJson)); + } + } +} + +void showWarningIfStatediffNotFound(spState const& _stateA, spState const& _stateB) +{ + auto const& statediff = Options::get().statediff; + if (statediff.initialized() && statediff.isBlockSelected) + { + if (statediff.isTransSelected) + { + if (_stateA.isEmpty()) + ETH_WARNING("--statediff unable to get intermidiate state for block: `" + test::fto_string(statediff.firstBlock) + + "`, tx: `" + test::fto_string(statediff.firstTrnsx) + "`"); + else if (_stateB.isEmpty()) + ETH_WARNING("--statediff unable to get intermidiate state for block: `" + test::fto_string(statediff.seconBlock) + + "`, tx: `" + test::fto_string(statediff.seconTrnsx) + "`"); + } + else + { + if (_stateA.isEmpty()) + ETH_WARNING("--statediff unable to get state for block: `" + test::fto_string(statediff.firstBlock)); + else if (_stateB.isEmpty()) + ETH_WARNING("--statediff unable to get state for block: `" + test::fto_string(statediff.seconBlock)); + } + } +} + +} diff --git a/retesteth/testSuites/blockchain/Common.h b/retesteth/testSuites/blockchain/Common.h new file mode 100644 index 000000000..546563473 --- /dev/null +++ b/retesteth/testSuites/blockchain/Common.h @@ -0,0 +1,30 @@ +#pragma once +#include +#include +#include +#include + + +namespace test { +struct TxContext { + TxContext(test::session::SessionInterface& _session, std::string const& _testName, + test::teststruct::spTransaction const& _tr, test::teststruct::spBlockHeader const& _header, + test::teststruct::FORK const& _fork, size_t _blIndex, size_t _trIndex) + : session(_session), testName(_testName), tr(_tr), blockHeader(_header), + network(_fork), blIndex(_blIndex), trIndex(_trIndex) {} + test::session::SessionInterface& session; + std::string const& testName; + test::teststruct::spTransaction const& tr; + test::teststruct::spBlockHeader const& blockHeader; + test::teststruct::FORK const& network; + size_t blIndex; + size_t trIndex; +}; + +void performVMTrace(TxContext const& _context); +void performPostState(test::session::SessionInterface& _session, std::string const& _testName, + std::string const& _net, test::teststruct::FH32 const&); +void performPostState(TxContext const& _context); +void performPostStateBlockOnly(TxContext const& _context); +void showWarningIfStatediffNotFound(test::teststruct::spState const&, test::teststruct::spState const&); +} diff --git a/retesteth/testSuites/blockchain/fillers/BlockchainTestFillerLogic.cpp b/retesteth/testSuites/blockchain/fillers/BlockchainTestFillerLogic.cpp index 5385133b4..95a27375e 100644 --- a/retesteth/testSuites/blockchain/fillers/BlockchainTestFillerLogic.cpp +++ b/retesteth/testSuites/blockchain/fillers/BlockchainTestFillerLogic.cpp @@ -1,4 +1,5 @@ #include "TestBlockchainManager.h" +#include "BlockchainTestFillerRunner.h" #include #include #include @@ -16,15 +17,18 @@ namespace test spDataObject FillTest(BlockchainTestInFiller const& _test, TestSuite::TestSuiteOptions const& _opt) { (void)_opt; - ETH_DC_MESSAGE(DC::TESTLOG, "Filling " + _test.testName()); - spDataObject result; - if (ExitHandler::receivedExitSignal()) - return result; - SessionInterface& session = RPCSession::instance(TestOutputHelper::getThreadID()); - for (FORK const& net : _test.getAllForksFromExpectSections()) + BlockchainTestFillerRunner filler(_test); + CHECKEXITR(result); + + auto const allForks = _test.getAllForksFromExpectSections(); + if (hasSkipFork(allForks)) + return spDataObject(new DataObject(DataType::Null)); + + for (FORK const& net : allForks) { - if (!Options::get().singleTestNet.empty() && net.asString() != Options::get().singleTestNet) + CHECKEXITR(result) + if (filler.checkSinglenet(net)) continue; for (auto const& expect : _test.expects()) @@ -32,34 +36,20 @@ spDataObject FillTest(BlockchainTestInFiller const& _test, TestSuite::TestSuiteO // if expect is for this network, generate the test if (expect.hasFork(net)) { - // Construct filled blockchain test - spDataObject _filledTest; - DataObject& filledTest = _filledTest.getContent(); - string const newtestname = _test.testName() + "_" + net.asString(); - TestOutputHelper::get().setCurrentTestName(newtestname); - filledTest.setKey(newtestname); - if (_test.hasInfo()) - (*_filledTest).atKeyPointer("_info") = _test.Info().rawData(); - filledTest["sealEngine"] = sealEngineToStr(_test.sealEngine()); - filledTest["network"] = net.asString(); - filledTest.atKeyPointer("pre") = _test.Pre().asDataObject(); - - // Initialise chain manager - ETH_DC_MESSAGEC(DC::TESTLOG, "FILL GENESIS INFO: ", LogColor::LIME); - TestBlockchainManager testchain(_test.Env(), _test.Pre(), _test.sealEngine(), net); - TestBlock const& genesis = testchain.getLastBlock(); - filledTest.atKeyPointer("genesisBlockHeader") = genesis.getTestHeader()->asDataObject(); - filledTest["genesisRLP"] = genesis.getRawRLP().asString(); - - TestOutputHelper::get().setUnitTestExceptions(_test.unitTestExceptions()); - - size_t blocks = 0; + auto filledTest = filler.makeNewBCTestForNet(net); + auto testchain = filler.makeTestChainManager(net); + + filler.makeGenesis(filledTest, testchain); + filler.setTestInfoAndExpectExceptions(net); + + testchain.performOptionCommandsOnGenesis(); + + size_t blockNumber = 0; for (auto const& block : _test.blocks()) { - if (ExitHandler::receivedExitSignal()) - return _filledTest; - // Debug - if (Options::get().blockLimit != 0 && blocks++ >= Options::get().blockLimit) + CHECKEXITR(result) + + if (filler.optionsLimitBlock(blockNumber++)) break; // Generate a test block from filler block section @@ -69,41 +59,22 @@ spDataObject FillTest(BlockchainTestInFiller const& _test, TestSuite::TestSuiteO // If block is not disabled for testing purposes // Get the json output of a constructed block for the test (includes rlp) if (!testchain.getLastBlock().isDoNotExport()) - filledTest["blocks"].addArrayObject(testchain.getLastBlock().asDataObject()); + (*filledTest)["blocks"].addArrayObject(testchain.getLastBlock().asDataObject()); } // Import blocks that have been rewinded with the chain switch // This makes some block invalid. Because block can be mined as valid on side chain // So just import all block ever generated with test filler - testchain.syncOnRemoteClient(filledTest["blocks"]); - - // Fill info about the lastblockhash - EthGetBlockBy finalBlock(session.eth_getBlockByNumber(session.eth_blockNumber(), Request::LESSOBJECTS)); - - try - { - State remoteState(getRemoteState(session)); - compareStates(expect.result(), remoteState); - filledTest.atKeyPointer("postState") = remoteState.asDataObject(); - if (Options::get().poststate) - ETH_DC_MESSAGE(DC::STATE, "\nState Dump:" + TestOutputHelper::get().testInfo().errorDebug() + cDefault + - " \n" + filledTest.atKey("postState").asJson()); - } - catch (StateTooBig const&) - { - compareStates(expect.result(), session); - filledTest["postStateHash"] = finalBlock.header()->stateRoot().asString(); - } + testchain.syncOnRemoteClient((*filledTest)["blocks"]); - if (Options::get().poststate) - ETH_DC_MESSAGE(DC::STATE, "PostState " + TestOutputHelper::get().testInfo().errorDebug() + " : \n" + - cDefault + "Hash: " + finalBlock.header()->stateRoot().asString()); + EthGetBlockBy finalBlock = filler.getLastBlock(); + filler.performOptionsOnFinalState(finalBlock); + filler.compareFinalState(filledTest, expect.result(), finalBlock); - filledTest["lastblockhash"] = finalBlock.header()->hash().asString(); - (*result).addSubObject(_filledTest); + (*result).addSubObject(filledTest); - verifyFilledTest(_test.unitTestVerify(), _filledTest, net); + verifyFilledTest(_test.unitTestVerify(), filledTest, net); for (auto const& ex : TestOutputHelper::get().getUnitTestExceptions()) ETH_FAIL_MESSAGE("Expected exception didn't occur: \n`" + ex + "`"); diff --git a/retesteth/testSuites/blockchain/fillers/BlockchainTestFillerRunner.cpp b/retesteth/testSuites/blockchain/fillers/BlockchainTestFillerRunner.cpp new file mode 100644 index 000000000..175cce102 --- /dev/null +++ b/retesteth/testSuites/blockchain/fillers/BlockchainTestFillerRunner.cpp @@ -0,0 +1,111 @@ +#include "TestBlockchainManager.h" +#include "BlockchainTestFillerRunner.h" +#include +#include +#include +#include +#include +using namespace test; +using namespace test::session; +using namespace test::debug; +using namespace teststruct; +using namespace std; +using namespace test::blockchainfiller; + +BlockchainTestFillerRunner::BlockchainTestFillerRunner(BlockchainTestInFiller const& _test) + : m_test(_test), m_session(RPCSession::instance(TestOutputHelper::getThreadID())) +{ + ETH_DC_MESSAGE(DC::TESTLOG, "Filling " + _test.testName()); +} + +bool BlockchainTestFillerRunner::checkSinglenet(FORK const& _net) const +{ + auto const& opt = Options::get(); + return (!opt.singleTestNet.empty() && _net.asString() != opt.singleTestNet); +} + +spDataObject BlockchainTestFillerRunner::makeNewBCTestForNet(FORK const& _net) +{ + // Construct filled blockchain test fields + + spDataObject _filledTest; + DataObject& filledTest = _filledTest.getContent(); + + string const newtestname = m_test.testName() + "_" + _net.asString(); + TestOutputHelper::get().setCurrentTestName(newtestname); + + filledTest.setKey(newtestname); + if (m_test.hasInfo()) + (*_filledTest).atKeyPointer("_info") = m_test.Info().rawData(); + filledTest["sealEngine"] = sealEngineToStr(m_test.sealEngine()); + filledTest["network"] = _net.asString(); + filledTest.atKeyPointer("pre") = m_test.Pre().asDataObject(); + + return _filledTest; +} + +TestBlockchainManager BlockchainTestFillerRunner::makeTestChainManager(teststruct::FORK const& _net) +{ + ETH_DC_MESSAGEC(DC::RPC, "FILL GENESIS INFO: ", LogColor::LIME); + return TestBlockchainManager(m_test.Env(), m_test.Pre(), m_test.sealEngine(), _net); +} + +void BlockchainTestFillerRunner::makeGenesis(spDataObject& _filledTest, TestBlockchainManager& _testchain) const +{ + TestBlock const& genesis = _testchain.getLastBlock(); + (*_filledTest).atKeyPointer("genesisBlockHeader") = genesis.getTestHeader()->asDataObject(); + (*_filledTest)["genesisRLP"] = genesis.getRawRLP().asString(); +} + +void BlockchainTestFillerRunner::setTestInfoAndExpectExceptions(FORK const& _net) const +{ + auto& helper = TestOutputHelper::get(); + helper.setUnitTestExceptions(m_test.unitTestExceptions()); + helper.setCurrentTestInfo(TestInfo(_net.asString(), 0)); +} + +bool BlockchainTestFillerRunner::optionsLimitBlock(size_t _block) const +{ + auto const& opt = Options::get(); + return (opt.blockLimit != 0 && _block >= opt.blockLimit); +} + +void BlockchainTestFillerRunner::performOptionsOnFinalState(EthGetBlockBy const& _finalBlock) +{ + auto const& opt = Options::get(); + + // Perform --statediff without selector + if (opt.statediff.initialized() && !opt.statediff.isBlockSelected) + { + auto const diff = test::stateDiff(m_test.Pre(), getRemoteState(m_session))->asJson(); + ETH_DC_MESSAGE(DC::STATE, + "\nFilling BC test State Diff:" + TestOutputHelper::get().testInfo().errorDebug() + cDefault + " \n" + diff); + } + + // Perform --poststate without selector + if (opt.poststate && !opt.poststate.isBlockSelected) + ETH_DC_MESSAGE(DC::STATE, "PostState " + TestOutputHelper::get().testInfo().errorDebug() + " : \n" + + cDefault + "Hash: " + _finalBlock.header()->stateRoot().asString()); +} + +void BlockchainTestFillerRunner::compareFinalState(spDataObject& _filledTest, StateIncomplete const& _expectState, EthGetBlockBy const& _finalBlock) +{ + try + { + spState remoteState = getRemoteState(m_session); + compareStates(_expectState, remoteState); + (*_filledTest).atKeyPointer("postState") = remoteState->asDataObject(); + } + catch (StateTooBig const&) + { + compareStates(_expectState, m_session); + (*_filledTest)["postStateHash"] = _finalBlock.header()->stateRoot().asString(); + } + + (*_filledTest)["lastblockhash"] = _finalBlock.header()->hash().asString(); +} + +EthGetBlockBy BlockchainTestFillerRunner::getLastBlock() +{ + return m_session.eth_getBlockByNumber(m_session.eth_blockNumber(), Request::LESSOBJECTS); +} diff --git a/retesteth/testSuites/blockchain/fillers/BlockchainTestFillerRunner.h b/retesteth/testSuites/blockchain/fillers/BlockchainTestFillerRunner.h new file mode 100644 index 000000000..123d79473 --- /dev/null +++ b/retesteth/testSuites/blockchain/fillers/BlockchainTestFillerRunner.h @@ -0,0 +1,32 @@ +#pragma once +#include +#include +#include +#include "TestBlockchainManager.h" + +namespace test::blockchainfiller +{ +class BlockchainTestFillerRunner +{ +public: + BlockchainTestFillerRunner(teststruct::BlockchainTestInFiller const&); + ~BlockchainTestFillerRunner() {}; + dataobject::spDataObject result() { return m_result; } + + bool checkSinglenet(teststruct::FORK const& _net) const; + dataobject::spDataObject makeNewBCTestForNet(teststruct::FORK const& _net); + TestBlockchainManager makeTestChainManager(teststruct::FORK const& _net); + void makeGenesis(spDataObject& _filler, TestBlockchainManager& _testchain) const; + void setTestInfoAndExpectExceptions(teststruct::FORK const& _net) const; + bool optionsLimitBlock(size_t _block) const; + void performOptionsOnFinalState(EthGetBlockBy const&); + void compareFinalState(spDataObject& _filledTest, StateIncomplete const& _expectState, EthGetBlockBy const&); + EthGetBlockBy getLastBlock(); + +private: + test::teststruct::BlockchainTestInFiller const& m_test; + test::session::SessionInterface& m_session; + dataobject::spDataObject m_result; +}; + +} // namespace test diff --git a/retesteth/testSuites/blockchain/fillers/TestBlock.cpp b/retesteth/testSuites/blockchain/fillers/TestBlock.cpp index 335ff05b3..253e64663 100644 --- a/retesteth/testSuites/blockchain/fillers/TestBlock.cpp +++ b/retesteth/testSuites/blockchain/fillers/TestBlock.cpp @@ -33,6 +33,13 @@ spDataObject TestBlock::asDataObject() const for (auto const& tr : m_block->transactions()) res["transactions"].addArrayObject(tr->asDataObject()); + if (isBlockExportWithdrawals(m_block->header())) + res.atKeyPointer("withdrawals") = spDataObject(new DataObject(DataType::Array)); + + // Print withdrawals anyway if it's present + for (auto const& wt : m_block->withdrawals()) + res["withdrawals"].addArrayObject((wt->asDataObject())); + for (auto const& trSequence : m_transactionExecOrder) { spDataObject _trInfo; diff --git a/retesteth/testSuites/blockchain/fillers/TestBlock.h b/retesteth/testSuites/blockchain/fillers/TestBlock.h index e5f2723f4..63478fbfc 100644 --- a/retesteth/testSuites/blockchain/fillers/TestBlock.h +++ b/retesteth/testSuites/blockchain/fillers/TestBlock.h @@ -20,11 +20,14 @@ class TestBlock void registerTestTransaction(spTransaction const& _tr) { m_block.getContent().addTransaction(_tr); } // Attach Transaction to transaction Execution Order section - void registerTransactionSequence(TransactBytesException const& _trTuple) { m_transactionExecOrder.push_back(_trTuple); } + void registerTransactionSequence(TransactBytesException const& _trTuple) { m_transactionExecOrder.emplace_back(_trTuple); } void nullTransactionSequence() { m_transactionExecOrder.clear(); } // Attach Uncle header to EthereumBlock (the one described in tests) void registerTestUncle(spBlockHeader const& _uncle) { m_block.getContent().addUncle(_uncle); } + + void registerTestWithdrawal(spWithdrawal const& _w) { m_block.getContent().addWithdrawal(_w); } + bool isThereTestHeader() const { return !m_block.isEmpty(); } std::vector const& getUncles() const { return m_block->uncles(); } diff --git a/retesteth/testSuites/blockchain/fillers/TestBlockchain.cpp b/retesteth/testSuites/blockchain/fillers/TestBlockchain.cpp index 6e4cdce7c..6b6351304 100644 --- a/retesteth/testSuites/blockchain/fillers/TestBlockchain.cpp +++ b/retesteth/testSuites/blockchain/fillers/TestBlockchain.cpp @@ -3,6 +3,7 @@ #include #include #include +#include "../Common.h" using namespace std; using namespace test::debug; @@ -26,135 +27,42 @@ TestBlockchain::TestBlockchain(BlockchainTestFillerEnv const& _testEnv, State co TestBlock genesisBlock(latestBlock.getRLPHeaderTransactions(), "genesis", m_network, 0); genesisBlock.registerTestHeader(latestBlock.header()); genesisBlock.setNextBlockForked(mineNextBlockAndRevert()); - m_blocks.push_back(genesisBlock); + m_blocks.emplace_back(genesisBlock); } -void TestBlockchain::generateBlock( - BlockchainTestFillerBlock const& _block, vectorOfSchemeBlock const& _uncles, bool _generateUncles) +bool clientSupportWithdrawalsRPC() { - // If block is raw RLP block - if (_block.isRawRLP()) - { - FH32 const blHash(m_session.test_importRawBlock(_block.rawRLP())); - checkBlockException(m_session, _block.getExpectException(m_network)); - if (!blHash.isZero()) - ETH_ERROR_MESSAGE("rawBlock rlp appered to be valid. Unable to contruct objects from RLP!"); - else - { - TestBlock newBlock(_block.rawRLP(), m_chainName, m_network, m_blocks.size()); - newBlock.registerTestExceptios(_block.getExpectException(m_network)); - m_blocks.push_back(newBlock); - } - return; - } - - // Import known transactions to remote client - ETH_DC_MESSAGEC(DC::TESTLOG, "Import transactions: " + m_sDebugString, LogColor::YELLOW); - for (auto const& tr : _block.transactions()) - { - modifyTransactionChainIDByNetwork(tr.tr(), m_network); - m_session.eth_sendRawTransaction(tr.tr().getRawBytes(), tr.tr().getSecret()); - } - - // Remote client generate block with transactions - // And if it has uncles or blockheader overwrite we perform manual overwrite and reimport block again - // Then construct this RLP of a modifed block (with new header and uncles) - // if block mining failed this will be the rawRLP of import - BYTES rawRLP(DataObject("0x")); - GCP_SPointer minedBlock = mineBlock(_block, _uncles, rawRLP); + return Options::getCurrentConfig().cfgFile().socketType() == ClientConfgSocketType::TransitionTool; +} - if (minedBlock.isEmpty()) - { - // if block mining failed, the block is invalid - FORK const& newBlockNet = _block.hasChainNet() ? _block.chainNet() : m_network; - TestBlock newBlock(rawRLP, _block.chainName(), newBlockNet, m_blocks.size()); - newBlock.registerTestExceptios(_block.getExpectException(m_network)); - newBlock.setDoNotExport(_block.isDoNotImportOnClient()); - m_blocks.push_back(newBlock); - } - else +void TestBlockchain::_mineBlock_importWithdrawals(BlockchainTestFillerBlock const& _blockInTest) +{ + if (clientSupportWithdrawalsRPC() && _blockInTest.getExpectException(m_network).empty()) { - // if block mining succeed. the block is valid. - FORK const& newBlockNet = _block.hasChainNet() ? _block.chainNet() : m_network; - TestBlock newBlock(rawRLP, _block.chainName(), newBlockNet, m_blocks.size()); - newBlock.registerTestExceptios(_block.getExpectException(m_network)); - newBlock.registerTestHeader(minedBlock->header()); - newBlock.setDoNotExport(_block.isDoNotImportOnClient()); - - // ------- - // Register all test transactions (the one described in test) - // In the same order as on remote block has returned after mining - typedef std::tuple testTrInfo; - std::map testTransactionMap; - bool hasAtLeastOneInvalid = false; - for (auto const& tr : _block.transactions()) - { - string const& exception = tr.getExpectException(m_network); - bool hasException = !exception.empty(); - testTransactionMap[tr.tr().hash()] = {tr.trPointer(), hasException}; - hasAtLeastOneInvalid = hasAtLeastOneInvalid || hasException; - newBlock.registerTransactionSequence({tr.tr().getRawBytes(), exception}); - } - - // Only export the order if we have rejected transactions. to save space in tests - if (!hasAtLeastOneInvalid) - newBlock.nullTransactionSequence(); - - for (auto const& remoteTr : minedBlock->transactions()) + if (_blockInTest.withdrawals().size() > 0) { - if (Options::get().vmtrace) + for (auto const& wt : _blockInTest.withdrawals()) { - string const testNameOut = TestOutputHelper::get().testName() + "_" + remoteTr.hash().asString() + ".txt"; - VMtraceinfo info(m_session, remoteTr.hash(), minedBlock->header()->stateRoot(), testNameOut); - printVmTrace(info); + auto const str = dev::toHexPrefixed(wt.withdrawal()->asRLPStream().out()); + BYTES rlp(str); + m_session.test_registerWithdrawal(rlp); } - - if (testTransactionMap.count(remoteTr.hash())) - { - bool isMarkedInvalid = std::get<1>(testTransactionMap.at(remoteTr.hash())); - spTransaction const& spTr = std::get<0>(testTransactionMap.at(remoteTr.hash())); - - if (!isMarkedInvalid) - newBlock.registerTestTransaction(spTr); - - testTransactionMap.erase(remoteTr.hash()); - } - else - ETH_ERROR_MESSAGE("Remote client returned block with transaction that is not registered in test!"); } - - // Register all the transactions that have not been repoted by remote client - // Perhaps it dropped some of the valid transactions.. - for (auto const& leftoverTr : testTransactionMap) - { - bool isMarkedInvalid = std::get<1>(leftoverTr.second); - spTransaction const& spTr = std::get<0>(leftoverTr.second); - if (!isMarkedInvalid) - newBlock.registerTestTransaction(spTr); - } - // ------- - - // Register all test uncles (the one described in test) - for (auto const& uncle : _uncles) - newBlock.registerTestUncle(uncle); - - // Ask remote client to generate a parallel blockheader that will later be used for uncles - if (_generateUncles) - newBlock.setNextBlockForked(mineNextBlockAndRevert()); - - m_blocks.push_back(newBlock); } } GCP_SPointer TestBlockchain::mineBlock( - BlockchainTestFillerBlock const& _blockInTest, vectorOfSchemeBlock const& _preparedUncleBlocks, BYTES& _rawRLP) + BlockchainTestFillerBlock const& _blockInTest, vectorOfSchemeBlock const& _preparedUncleBlocks, BYTES& _rawRLP, bool _isTest) { - ETH_DC_MESSAGEC(DC::TESTLOG, "MINE BLOCK: " + m_sDebugString, LogColor::YELLOW); + ETH_DC_MESSAGEC(DC::RPC, "MINE BLOCK: " + m_sDebugString, LogColor::YELLOW); + + _mineBlock_importWithdrawals(_blockInTest); MineBlocksResult const miningRes = m_session.test_mineBlocks(1); VALUE latestBlockNumber(m_session.eth_blockNumber()); spFH32 minedBlockHash; - if (_blockInTest.hasBlockHeaderOverwrite(m_network) || _blockInTest.uncles().size() > 0) + if (_blockInTest.hasBlockHeaderOverwrite(m_network) || _blockInTest.uncles().size() > 0 || + !clientSupportWithdrawalsRPC()) { // Need to overwrite the blockheader of a mined block with either blockHeader or uncles // Then import it again and see what client says, because mining with uncles not supported @@ -188,6 +96,9 @@ GCP_SPointer TestBlockchain::mineBlock( _rawRLP = remoteBlock->getRLPHeaderTransactions(); } + if (_isTest) + return remoteBlock; + // check that transactions are good for (auto const& trInTest : _blockInTest.transactions()) { @@ -237,7 +148,7 @@ GCP_SPointer TestBlockchain::mineBlock( // Ask remote client to generate a blockheader that will later used for uncles spBlockHeader TestBlockchain::mineNextBlockAndRevert() { - ETH_DC_MESSAGEC(DC::TESTLOG, "Mine uncle block (next block) and revert: " + m_sDebugString, LogColor::YELLOW); + ETH_DC_MESSAGEC(DC::RPC, "Mine uncle block (next block) and revert: " + m_sDebugString, LogColor::YELLOW); { VALUE latestBlockNumber(m_session.eth_blockNumber()); EthGetBlockBy const latestBlock(m_session.eth_getBlockByNumber(latestBlockNumber, Request::LESSOBJECTS)); @@ -266,7 +177,7 @@ string TestBlockchain::prepareDebugInfoString(string const& _newBlockChainName) if (test::debug::Debug::get().flag(DC::TESTLOG)) sBlockNumber = fto_string(newBlockNumber); // very heavy m_sDebugString = "(bl: " + sBlockNumber + ", ch: " + _newBlockChainName + ", net: " + m_network.asString() + ")"; - ETH_DC_MESSAGEC(DC::TESTLOG, "Generating a test block: " + m_sDebugString, LogColor::YELLOW); + ETH_DC_MESSAGEC(DC::RPC, "Generating a test block: " + m_sDebugString, LogColor::YELLOW); return m_sDebugString; } @@ -345,16 +256,25 @@ FH32 TestBlockchain::postmineBlockHeader(BlockchainTestFillerBlock const& _block EthGetBlockBy remoteBlock(m_session.eth_getBlockByNumber(_latestBlockNumber, Request::FULLOBJECTS)); EthereumBlock managedBlock(remoteBlock.header()); for (auto const& tr : remoteBlock.transactions()) // + invalid transactions? - managedBlock.addTransaction(tr.transaction()); + managedBlock.addTransaction(tr->transaction()); // Attach test-generated uncle to a block and then reimport it again for (auto const& un : _uncles) managedBlock.addUncle(un); + if (_blockInTest.withdrawals().size() > 0) + managedBlock.forceWithdrawalsRLP(); + for (auto const& wt : _blockInTest.withdrawals()) + managedBlock.addWithdrawal(wt.withdrawal()); + bool weOverwriteHashFields = false; if (_blockInTest.hasBlockHeaderOverwrite(m_network)) { BlockHeaderOverwrite const& headerOverwrite = _blockInTest.getHeaderOverwrite(m_network); + + if (headerOverwrite.forceNoWithdrawalsRLP()) + managedBlock.forceNoWithdrawalsRLP(); + if (headerOverwrite.hasBlockHeader()) managedBlock.replaceHeader(headerOverwrite.header().overwriteBlockHeader(managedBlock.header())); @@ -376,7 +296,6 @@ FH32 TestBlockchain::postmineBlockHeader(BlockchainTestFillerBlock const& _block if (!weOverwriteHashFields) managedBlock.recalculateUncleHash(); - m_session.test_rewindToBlock(_latestBlockNumber - 1); _rawRLP = BYTES(managedBlock.getRLP().asString()); return FH32(m_session.test_importRawBlock(_rawRLP)); @@ -395,7 +314,7 @@ bool TestBlockchain::checkBlockException(SessionInterface const& _session, strin else { std::string const& clientExceptionString = - Options::get().getDynamicOptions().getCurrentConfig().translateException(_sBlockException); + Options::get().getCurrentConfig().translateException(_sBlockException); size_t pos = _session.getLastRPCError().message().find(clientExceptionString); if (clientExceptionString.empty()) pos = string::npos; @@ -414,4 +333,30 @@ void TestBlockchain::resetChainParams() const m_session.test_setChainParams(prepareChainParams(m_network, m_sealEngine, m_genesisState, m_testEnv)); } +void TestBlockchain::performOptionCommandsOnGenesis() +{ + auto const& poststate = Options::get().poststate; + if (poststate.initialized() && poststate.isBlockSelected && poststate.blockNumber == 0) + { + auto const genesis = m_session.eth_getBlockByNumber(0, Request::LESSOBJECTS); + auto const& testname = TestOutputHelper::get().testName(); + TxContext const ctx(m_session, testname, spTransaction(0), genesis->header(), m_network, 0, 0); + performPostState(ctx); + } + + auto const& statediff = Options::get().statediff; + if (statediff.initialized() && statediff.isBlockSelected && statediff.firstBlock == 0) + { + m_triedStateDiff = true; + m_stateDiffStateA = getRemoteState(m_session); + } +} + +TestBlockchain::~TestBlockchain() +{ + if (m_triedStateDiff) + showWarningIfStatediffNotFound(m_stateDiffStateA, m_stateDiffStateB); +} + + } // namespace blockchainfiller diff --git a/retesteth/testSuites/blockchain/fillers/TestBlockchain.h b/retesteth/testSuites/blockchain/fillers/TestBlockchain.h index fdd5bbeca..7e3f96f46 100644 --- a/retesteth/testSuites/blockchain/fillers/TestBlockchain.h +++ b/retesteth/testSuites/blockchain/fillers/TestBlockchain.h @@ -23,6 +23,7 @@ class TestBlockchain // Using _env, _pre, _engine, _network settings TestBlockchain(BlockchainTestFillerEnv const& _testEnv, State const& _genesisState, SealEngine _engine, FORK const& _network, std::string const& _chainName, RegenerateGenesis _regenerateGenesis); + ~TestBlockchain(); // Need to call resetChainParams because TestBLockchainManager could have chains with different networks void resetChainParams() const; @@ -46,6 +47,8 @@ class TestBlockchain // Return true if block is valid, false if block is not valid static bool checkBlockException(session::SessionInterface const& _session, std::string const& _sBlockException); + void performOptionCommandsOnGenesis(); + private: // Ask remote client to generate a blockheader that will later used for uncles spBlockHeader mineNextBlockAndRevert(); @@ -53,7 +56,8 @@ class TestBlockchain // Mine the test block on remote client. // if blockheader is tweaked or there are uncles, postmine tweak this and reimport GCP_SPointer mineBlock( - BlockchainTestFillerBlock const& _block, vectorOfSchemeBlock const& _preparedUncleBlocks, BYTES& _rawRLP); + BlockchainTestFillerBlock const& _block, vectorOfSchemeBlock const& _preparedUncleBlocks, BYTES& _rawRLP, + bool _isTest = false); // After test_mineBlock we can change the blockheader or add uncles. that will require to tweak // the block And reimport it again, then check exceptions @@ -71,6 +75,22 @@ class TestBlockchain std::string m_chainName; // Name of this chain std::vector m_blocks; // List of blocks // std::vector m_knownBlocks; // List of fork block RLPs +private: + void _tryIntermidiatePostState(BlockchainTestFillerBlock const&, vectorOfSchemeBlock const&); + void _performStatediff(size_t _blockNumber, size_t _txNumber); + + void _generateBlock_RawBlock(BlockchainTestFillerBlock const& _block); + void _generateBlock_ImportTransactionsOnRemoteClient(BlockchainTestFillerBlock const& _block, + vectorOfSchemeBlock const& _uncles); + void _generateBlock_RegisterInvalidBlock(BlockchainTestFillerBlock const& _block, BYTES const& _rawRLP); + void _generateBlock_RegisterTestTransactions(BlockchainTestFillerBlock const& _block, TestBlock& _newBlock, spEthGetBlockBy); + + void _mineBlock_importWithdrawals(BlockchainTestFillerBlock const&); + +private: + bool m_triedStateDiff = false; + spState m_stateDiffStateA; + spState m_stateDiffStateB; }; } // namespace test::blockchainfiller diff --git a/retesteth/testSuites/blockchain/fillers/TestBlockchainGenerateBlock.cpp b/retesteth/testSuites/blockchain/fillers/TestBlockchainGenerateBlock.cpp new file mode 100644 index 000000000..f7ba1d6d4 --- /dev/null +++ b/retesteth/testSuites/blockchain/fillers/TestBlockchainGenerateBlock.cpp @@ -0,0 +1,257 @@ +#include "TestBlockchain.h" +#include +#include +#include +#include +using namespace std; +using namespace test::debug; +using namespace test::session; + +namespace test::blockchainfiller { + +void TestBlockchain::generateBlock( + BlockchainTestFillerBlock const& _block, vectorOfSchemeBlock const& _uncles, bool _generateUncles) +{ + if (_block.isRawRLP()) + { + _generateBlock_RawBlock(_block); + return; + } + + _generateBlock_ImportTransactionsOnRemoteClient(_block, _uncles); + + // Remote client generate block with transactions + // And if it has uncles or blockheader overwrite we perform manual overwrite and reimport block again + // Then construct this RLP of a modifed block (with new header and uncles) + // if block mining failed this will be the rawRLP of import + BYTES rawRLP(DataObject("0x")); + spEthGetBlockBy minedBlock = mineBlock(_block, _uncles, rawRLP); + + if (minedBlock.isEmpty()) + _generateBlock_RegisterInvalidBlock(_block, rawRLP); + else + { + if (!Options::get().statediff.isTransSelected) + _performStatediff((size_t)minedBlock->header()->number().asBigInt(), 0); + + // if block mining succeed. the block is valid. + FORK const& newBlockNet = _block.hasChainNet() ? _block.chainNet() : m_network; + TestBlock newBlock(rawRLP, _block.chainName(), newBlockNet, m_blocks.size()); + newBlock.registerTestExceptios(_block.getExpectException(m_network)); + newBlock.registerTestHeader(minedBlock->header()); + newBlock.setDoNotExport(_block.isDoNotImportOnClient()); + + _generateBlock_RegisterTestTransactions(_block, newBlock, minedBlock); + + // Register all test uncles (the one described in test) + for (auto const& uncle : _uncles) + newBlock.registerTestUncle(uncle); + + for (auto const& with : _block.withdrawals()) + newBlock.registerTestWithdrawal(with.withdrawal()); + + // Ask remote client to generate a parallel blockheader that will later be used for uncles + if (_generateUncles) + newBlock.setNextBlockForked(mineNextBlockAndRevert()); + + m_blocks.emplace_back(newBlock); + } +} + +void TestBlockchain::_generateBlock_RawBlock(BlockchainTestFillerBlock const& _block) +{ + FH32 const blHash(m_session.test_importRawBlock(_block.rawRLP())); + checkBlockException(m_session, _block.getExpectException(m_network)); + if (!blHash.isZero()) + ETH_ERROR_MESSAGE("rawBlock rlp appered to be valid. Unable to contruct objects from RLP!"); + else + { + TestBlock newBlock(_block.rawRLP(), m_chainName, m_network, m_blocks.size()); + newBlock.registerTestExceptios(_block.getExpectException(m_network)); + m_blocks.emplace_back(newBlock); + } +} + +void TestBlockchain::_generateBlock_ImportTransactionsOnRemoteClient(BlockchainTestFillerBlock const& _block, + vectorOfSchemeBlock const& _uncles) +{ + // Import known transactions to remote client + ETH_DC_MESSAGEC(DC::RPC, "Import transactions: " + m_sDebugString, LogColor::YELLOW); + _tryIntermidiatePostState(_block, _uncles); + for (auto const& tr : _block.transactions()) + { + modifyTransactionChainIDByNetwork(tr.tr(), m_network); + m_session.eth_sendRawTransaction(tr.tr().getRawBytes(), tr.tr().getSecret()); + } +} + +void TestBlockchain::_generateBlock_RegisterInvalidBlock(BlockchainTestFillerBlock const& _block, BYTES const& _rawRLP) +{ + // if block mining failed, the block is invalid + FORK const& newBlockNet = _block.hasChainNet() ? _block.chainNet() : m_network; + TestBlock newBlock(_rawRLP, _block.chainName(), newBlockNet, m_blocks.size()); + newBlock.registerTestExceptios(_block.getExpectException(m_network)); + newBlock.setDoNotExport(_block.isDoNotImportOnClient()); + m_blocks.emplace_back(newBlock); +} + +void TestBlockchain::_generateBlock_RegisterTestTransactions(BlockchainTestFillerBlock const& _block, + TestBlock& _newBlock, spEthGetBlockBy _minedBlock) +{ + // Register all test transactions (the one described in test) + // In the same order as on remote block has returned after mining + typedef std::tuple testTrInfo; + std::map testTransactionMap; + bool hasAtLeastOneInvalid = false; + for (auto const& tr : _block.transactions()) + { + string const& exception = tr.getExpectException(m_network); + bool hasException = !exception.empty(); + testTransactionMap[tr.tr().hash()] = {tr.trPointer(), hasException}; + hasAtLeastOneInvalid = hasAtLeastOneInvalid || hasException; + _newBlock.registerTransactionSequence({tr.tr().getRawBytes(), exception}); + } + + // Only export the order if we have rejected transactions. to save space in tests + if (!hasAtLeastOneInvalid) + _newBlock.nullTransactionSequence(); + + size_t txIndex = 0; + for (auto const& remoteTr : _minedBlock->transactions()) + { + TxContext const ctx(m_session, TestOutputHelper::get().testName(), remoteTr->transaction(), _minedBlock->header(), + m_network, (size_t)_minedBlock->header()->number().asBigInt(), txIndex); + performVMTrace(ctx); + txIndex++; + + if (testTransactionMap.count(remoteTr->hash())) + { + bool isMarkedInvalid = std::get<1>(testTransactionMap.at(remoteTr->hash())); + spTransaction const& spTr = std::get<0>(testTransactionMap.at(remoteTr->hash())); + + if (!isMarkedInvalid) + _newBlock.registerTestTransaction(spTr); + + testTransactionMap.erase(remoteTr->hash()); + } + else + ETH_ERROR_MESSAGE("Remote client returned block with transaction that is not registered in test!"); + } + + // Register all the transactions that have not been repoted by remote client + // Perhaps it dropped some of the valid transactions.. + for (auto const& leftoverTr : testTransactionMap) + { + bool isMarkedInvalid = std::get<1>(leftoverTr.second); + spTransaction const& spTr = std::get<0>(leftoverTr.second); + if (!isMarkedInvalid) + _newBlock.registerTestTransaction(spTr); + } +} + + +void TestBlockchain::_tryIntermidiatePostState(BlockchainTestFillerBlock const& _block, vectorOfSchemeBlock const& _uncles) +{ + auto runForOption = [this, &_block, &_uncles] + (auto const& _option, size_t _blockNumber, size_t _transNumber) + { + bool const optionInitialized = _option.initialized() && _option.isBlockSelected; + auto const optionBlockNumber = _blockNumber; + auto const optionTransNumber = _transNumber; + + if (optionInitialized) + { + auto const currentBlockNumber = m_session.eth_blockNumber(); + if (optionBlockNumber != (size_t)currentBlockNumber.asBigInt() + 1) + return; + + bool thereisTransactionIndex = optionTransNumber < _block.transactions().size(); + if (!thereisTransactionIndex) + return; + + size_t txIndex = 0; + for (auto const& tr : _block.transactions()) + { + modifyTransactionChainIDByNetwork(tr.tr(), m_network); + m_session.eth_sendRawTransaction(tr.tr().getRawBytes(), tr.tr().getSecret()); + + if (txIndex == optionTransNumber) + { + BYTES rawRLP(DataObject("0x")); + GCP_SPointer minedBlock = mineBlock(_block, _uncles, rawRLP, true); + if (!minedBlock.isEmpty()) + { + TxContext const ctx(m_session, TestOutputHelper::get().testName(), tr.trPointer(), minedBlock->header(), + m_network, (size_t)minedBlock->header()->number().asBigInt(), txIndex); + performPostState(ctx); + _performStatediff((size_t)(currentBlockNumber.asBigInt()+1), txIndex); + } + else + ETH_WARNING("Tying to get intermidiate tx state for block#" + test::fto_string(optionBlockNumber) + ", but block mining failed!"); + + m_session.test_rewindToBlock(currentBlockNumber); + { + VALUE latestBlockNumber(m_session.eth_blockNumber()); + EthGetBlockBy const latestBlock(m_session.eth_getBlockByNumber(latestBlockNumber, Request::LESSOBJECTS)); + m_session.test_modifyTimestamp(latestBlock.header()->timestamp() + 1000); + } + return; + } + txIndex++; + } + } + }; + + auto const& opt = Options::get(); + runForOption(opt.poststate, opt.poststate.blockNumber, opt.poststate.transactionNumber); + + auto runForStatediff = [this, &opt, &runForOption](){ + if (m_stateDiffStateA.isEmpty()) + runForOption(opt.statediff, opt.statediff.firstBlock, opt.statediff.firstTrnsx); + else if (m_stateDiffStateB.isEmpty()) + runForOption(opt.statediff, opt.statediff.seconBlock, opt.statediff.seconTrnsx); + }; + + if (opt.statediff.firstBlock == opt.statediff.seconBlock) + { + // attempt to capture the intermidiate state from different txs + runForStatediff(); + runForStatediff(); + } + else + runForStatediff(); + +} + +void TestBlockchain::_performStatediff(size_t _blockNumber, size_t _txNumber) +{ + m_triedStateDiff = true; + auto const& statediff = Options::get().statediff; + if (statediff.initialized() && statediff.isBlockSelected && m_stateDiffStateB.isEmpty()) + { + bool selector = statediff.firstBlock == _blockNumber; + if (statediff.isTransSelected) + selector = selector && statediff.firstTrnsx == _txNumber; + + if (selector && m_stateDiffStateA.isEmpty()) + { + m_stateDiffStateA = getRemoteState(m_session); + } + else + { + bool selector = statediff.seconBlock == _blockNumber; + if (statediff.isTransSelected) + selector = selector && statediff.seconTrnsx == _txNumber; + + if (selector && m_stateDiffStateB.isEmpty() && !m_stateDiffStateA.isEmpty()) + { + m_stateDiffStateB = getRemoteState(m_session); + auto const diff = test::stateDiff(m_stateDiffStateA, m_stateDiffStateB)->asJson(); + ETH_DC_MESSAGE(DC::STATE, + "\nFilling BC test State Diff:" + TestOutputHelper::get().testInfo().errorDebug() + cDefault + " \n" + diff); + } + } + } +} + +} diff --git a/retesteth/testSuites/blockchain/fillers/TestBlockchainManager.cpp b/retesteth/testSuites/blockchain/fillers/TestBlockchainManager.cpp index 4eb1856e4..50e5517fd 100644 --- a/retesteth/testSuites/blockchain/fillers/TestBlockchainManager.cpp +++ b/retesteth/testSuites/blockchain/fillers/TestBlockchainManager.cpp @@ -30,7 +30,7 @@ TestBlockchainManager::TestBlockchainManager( // Generate block using a client from the filler information void TestBlockchainManager::parseBlockFromFiller(BlockchainTestFillerBlock const& _block, bool _generateUncles) { - ETH_DC_MESSAGEC(DC::TESTLOG, "STARTING A NEW BLOCK: ", LogColor::LIME); + ETH_DC_MESSAGEC(DC::RPC, "STARTING A NEW BLOCK: ", LogColor::LIME); // See if chain reorg is needed. ex: new fork, or remine block reorgChains(_block); @@ -59,7 +59,7 @@ void TestBlockchainManager::parseBlockFromFiller(BlockchainTestFillerBlock const // Get this block exception on canon chain to later verify it FORK const& canonNet = getDefaultChain().getNetwork(); - m_testBlockRLPs.push_back(std::make_tuple(lastBlock.getRawRLP(), _block.getExpectException(canonNet))); + m_testBlockRLPs.emplace_back(std::make_tuple(lastBlock.getRawRLP(), _block.getExpectException(canonNet))); } TestBlockchain& TestBlockchainManager::getDefaultChain() @@ -88,7 +88,7 @@ void TestBlockchainManager::syncOnRemoteClient(DataObject& _exportBlocksSection) if (m_wasAtLeastOneFork) { // !!! RELY ON _exportBlocksSection has the same block order as m_testBlockRLPs - ETH_DC_MESSAGEC(DC::TESTLOG, "IMPORT KNOWN BLOCKS ", LogColor::LIME); + ETH_DC_MESSAGEC(DC::RPC, "IMPORT KNOWN BLOCKS ", LogColor::LIME); TestBlockchain const& chain = m_mapOfKnownChain.at(m_sDefaultChainName); chain.resetChainParams(); // restore canon chain of the test size_t ind = 0; @@ -117,11 +117,11 @@ void TestBlockchainManager::syncOnRemoteClient(DataObject& _exportBlocksSection) vectorOfSchemeBlock TestBlockchainManager::prepareUncles(BlockchainTestFillerBlock const& _block, string const& _debug) { - ETH_DC_MESSAGEC(DC::TESTLOG, "Prepare Uncles for the block: " + _debug, LogColor::YELLOW); + ETH_DC_MESSAGEC(DC::RPC, "Prepare Uncles for the block: " + _debug, LogColor::YELLOW); vectorOfSchemeBlock preparedUncleBlocks; // Prepared uncles for the current block // return block header using uncle overwrite section on uncles array from test for (auto const& uncle : _block.uncles()) - preparedUncleBlocks.push_back(prepareUncle(uncle, preparedUncleBlocks)); + preparedUncleBlocks.emplace_back(prepareUncle(uncle, preparedUncleBlocks)); return preparedUncleBlocks; } @@ -162,7 +162,7 @@ void TestBlockchainManager::reorgChains(BlockchainTestFillerBlock const& _block) if (!sameChain || blockNumberHasDecreased) { m_wasAtLeastOneFork = true; - ETH_DC_MESSAGEC(DC::TESTLOG, + ETH_DC_MESSAGEC(DC::RPC, "PERFORM REWIND HISTORY: (current: " + m_sCurrentChainName + ", new: " + newBlockChainName + ")", LogColor::YELLOW); @@ -277,5 +277,11 @@ spBlockHeader TestBlockchainManager::prepareUncle( return uncleBlockHeader; } +void TestBlockchainManager::performOptionCommandsOnGenesis() +{ + TestBlockchain& currentChainMining = getCurrentChain(); + currentChainMining.performOptionCommandsOnGenesis(); +} + } // namespace blockchainfiller } // namespace test diff --git a/retesteth/testSuites/blockchain/fillers/TestBlockchainManager.h b/retesteth/testSuites/blockchain/fillers/TestBlockchainManager.h index 6f3569c94..073a3cdbc 100644 --- a/retesteth/testSuites/blockchain/fillers/TestBlockchainManager.h +++ b/retesteth/testSuites/blockchain/fillers/TestBlockchainManager.h @@ -25,6 +25,8 @@ class TestBlockchainManager // Import all generated blocks at the same order as they are in tests void syncOnRemoteClient(DataObject& _exportBlocksSection) const; + void performOptionCommandsOnGenesis(); + private: // Reorg chains on the client if needed for _newBlock that potentially comes from another chain void reorgChains(BlockchainTestFillerBlock const& _newBlock); diff --git a/retesteth/testSuites/statetests/EOFTestBoost.cpp b/retesteth/testSuites/statetests/EOFTestBoost.cpp new file mode 100644 index 000000000..a208eecd7 --- /dev/null +++ b/retesteth/testSuites/statetests/EOFTestBoost.cpp @@ -0,0 +1,27 @@ +#include "retesteth/testSuites/TestFixtures.h" +#include +#include + +using namespace std; +using namespace test; +using namespace boost::unit_test; +namespace fs = boost::filesystem; + + +TestSuite::TestPath EOFTestSuite::suiteFolder() const +{ + return TestSuite::TestPath(fs::path("EOFTests" + m_fillerPathAdd)); +} + +TestSuite::FillerPath EOFTestSuite::suiteFillerFolder() const +{ + return TestSuite::FillerPath(fs::path("src") / string("EOFTestsFiller" + m_fillerPathAdd)); +} + +using EOFTestsFixture = TestFixture; +ETH_REGISTER_DYNAMIC_TEST_SEARCH(EOFTestsFixture, "EOFTests") +BOOST_FIXTURE_TEST_SUITE(EOFTests, EOFTestsFixture) + +BOOST_AUTO_TEST_CASE(efExample) {} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/retesteth/testSuites/statetests/FillStateTest.cpp b/retesteth/testSuites/statetests/FillStateTest.cpp index dc5a6606c..589e7c66f 100644 --- a/retesteth/testSuites/statetests/FillStateTest.cpp +++ b/retesteth/testSuites/statetests/FillStateTest.cpp @@ -116,7 +116,7 @@ spDataObject performTransaction(StateTestFillerExecInfo const& _info) auto const remState = getRemoteState(session); compareStates(expect.result(), remState); if (Options::get().poststate) - (*transactionResults).atKeyPointer("postState") = remState.asDataObject(); + (*transactionResults).atKeyPointer("postState") = remState->asDataObject(); } catch (StateTooBig const&) { @@ -193,7 +193,7 @@ spDataObject FillTest(StateTestInFiller const& _test) TestOutputHelper::get().setCurrentTestInfo(errorInfo); auto const p = prepareChainParams(fork, SealEngine::NoReward, _test.Pre(), _test.Env(), ParamsContext::StateTests); - session.test_setChainParams(p); + session.test_setChainParamsNoGenesis(p); // Run transactions for defined expect sections only for (auto const& expect : _test.Expects()) diff --git a/retesteth/testSuites/statetests/FillStateTestAsChain.cpp b/retesteth/testSuites/statetests/FillStateTestAsChain.cpp index 3d32787f4..1d15c3045 100644 --- a/retesteth/testSuites/statetests/FillStateTestAsChain.cpp +++ b/retesteth/testSuites/statetests/FillStateTestAsChain.cpp @@ -21,7 +21,6 @@ spDataObject FillTestAsBlockchain(StateTestInFiller const& _test) SessionInterface& session = RPCSession::instance(TestOutputHelper::getThreadID()); std::vector txs = _test.GeneralTr().buildTransactions(); - auto const allforks = _test.getAllForksFromExpectSections(); if (hasSkipFork(allforks)) return spDataObject(new DataObject(DataType::Null)); @@ -83,9 +82,9 @@ spDataObject FillTestAsBlockchain(StateTestInFiller const& _test) try { - State postState(getRemoteState(session)); + spState postState = getRemoteState(session); compareStates(mexpect, postState); - (*aBlockchainTest).atKeyPointer("postState") = postState.asDataObject(); + (*aBlockchainTest).atKeyPointer("postState") = postState->asDataObject(); } catch (StateTooBig const&) { @@ -110,6 +109,8 @@ spDataObject FillTestAsBlockchain(StateTestInFiller const& _test) (*block)["transactions"].atLastElementUnsafe()["sender"] = sender->asString(); } (*block).atKeyPointer("uncleHeaders") = spDataObject(new DataObject(DataType::Array)); + if (isBlockExportWithdrawals(remoteBlock.header())) + (*block).atKeyPointer("withdrawals") = spDataObject(new DataObject(DataType::Array)); if (!testException.empty()) { @@ -125,7 +126,7 @@ spDataObject FillTestAsBlockchain(StateTestInFiller const& _test) dataPostfix += "_" + fork.asString(); if (filledTest->count(_test.testName() + dataPostfix)) - ETH_ERROR_MESSAGE("The test filler contain redundant expect section: " + _test.testName() + + ETH_ERROR_MESSAGE("Test filler read redundant expect section: " + _test.testName() + dataPostfix + " (" + tr.transaction()->dataLabel() + ")"); verifyFilledTest(_test.unitTestVerifyBC(), aBlockchainTest, fork); diff --git a/retesteth/testSuites/statetests/RunStateTest.cpp b/retesteth/testSuites/statetests/RunStateTest.cpp index fe81b22de..42addb13f 100644 --- a/retesteth/testSuites/statetests/RunStateTest.cpp +++ b/retesteth/testSuites/statetests/RunStateTest.cpp @@ -63,9 +63,19 @@ void performValidations(StateTestExecInfo const& _info, FH32 const& _trHash) if (!expectedBytesPtr.isEmpty()) { if (tr.transaction()->getRawBytes().asString() != expectedBytesPtr->asString()) - ETH_ERROR_MESSAGE(string("TxBytes mismatch: test transaction section does not match txbytes in post section! ") + - "\n Constructed: " + expectedBytesPtr->asString() + "\n vs \n " + - tr.transaction()->getRawBytes().asString()); + { + string const msg = string("TxBytes mismatch: test transaction section does not match txbytes in post section! ") + + "\n Constructed: " + expectedBytesPtr->asString() + "\n vs \n " + + tr.transaction()->getRawBytes().asString(); + if (Options::get().chainid.initialized()) + { + ETH_DC_MESSAGE(DC::LOWLOG, msg); + } + else + { + ETH_ERROR_MESSAGE(msg); + } + } } // Validate log hash @@ -88,7 +98,7 @@ void performPostState(StateTestExecInfo const& _info) auto& tr = _info.tr; // Built transaction auto const& network = _info.network; // Current network (forkname) - auto const remStateJson = getRemoteState(session).asDataObject()->asJson(); + auto const remStateJson = getRemoteState(session)->asDataObject()->asJson(); ETH_DC_MESSAGE(DC::STATE, "\nRunning test State Dump:" + TestOutputHelper::get().testInfo().errorDebug() + cDefault + " \n" + remStateJson); if (!Options::get().poststate.outpath.empty()) @@ -143,7 +153,7 @@ void performTransaction(StateTestExecInfo const& _info) if (actualHash != expectedPostHash) { - ETH_DC_MESSAGE(DC::TESTLOG, "\nState Dump: \n" + getRemoteState(session).asDataObject()->asJson()); + ETH_DC_MESSAGE(DC::TESTLOG, "\nState Dump: \n" + getRemoteState(session)->asDataObject()->asJson()); ETH_ERROR_MESSAGE("Post hash mismatch remote: " + actualHash.asString() + ", expected: " + expectedPostHash.asString()); } performValidations(_info, trHash); @@ -190,7 +200,7 @@ void RunTest(StateTestInFilled const& _test) TestOutputHelper::get().setCurrentTestInfo(errorInfo); auto p = prepareChainParams(network, SealEngine::NoReward, _test.Pre(), _test.Env(), ParamsContext::StateTests); - session.test_setChainParams(p); + session.test_setChainParamsNoGenesis(p); // Read all results for a specific fork for (StateTestPostResult const& result : post.second) diff --git a/retesteth/testSuites/statetests/StateTests.cpp b/retesteth/testSuites/statetests/StateTests.cpp index 9a0754f7f..82685fb9c 100644 --- a/retesteth/testSuites/statetests/StateTests.cpp +++ b/retesteth/testSuites/statetests/StateTests.cpp @@ -43,10 +43,6 @@ namespace test spDataObject StateTestSuite::doTests(spDataObject& _input, TestSuiteOptions& _opt) const { TestOutputHelper::get().setCurrentTestInfo(TestInfo("StateTestSuite::doTests init")); - - // Register subtest as finished test case. because each folder is treated as test case folder - test::TestOutputHelper::get().markTestFolderAsFinished(getFullPathFiller("VMTests").parent_path(), "VMTests"); - if (_opt.doFilling) { spDataObject filledTest; diff --git a/retesteth/testSuites/statetests/StateTests.h b/retesteth/testSuites/statetests/StateTests.h index 491c6dcf5..6a89f3743 100644 --- a/retesteth/testSuites/statetests/StateTests.h +++ b/retesteth/testSuites/statetests/StateTests.h @@ -25,6 +25,7 @@ along with cpp-ethereum. If not, see . namespace test { + class StateTestSuite : public TestSuite { public: @@ -43,11 +44,18 @@ class LegacyConstantinopleStateTestSuite : public StateTestSuite TestSuite::FillerPath suiteFillerFolder() const override; }; -class StateTestVMSuite : public StateTestSuite -{ -public: - TestSuite::TestPath suiteFolder() const override; - TestSuite::FillerPath suiteFillerFolder() const override; -}; + +#define REGISTER_STATESUITE(NAME) \ + class NAME : public StateTestSuite \ + { \ + public: \ + TestSuite::TestPath suiteFolder() const override; \ + TestSuite::FillerPath suiteFillerFolder() const override;\ + }; + +REGISTER_STATESUITE(StateTestVMSuite) +REGISTER_STATESUITE(StateTestShanghaiSuite) +REGISTER_STATESUITE(EIPStateTestSuite) +REGISTER_STATESUITE(EIPStateTestEOFSuite) } // namespace test diff --git a/retesteth/testSuites/statetests/StateTestsBoost.cpp b/retesteth/testSuites/statetests/StateTestsBoost.cpp index f512fbc59..b35f65c73 100644 --- a/retesteth/testSuites/statetests/StateTestsBoost.cpp +++ b/retesteth/testSuites/statetests/StateTestsBoost.cpp @@ -2,6 +2,7 @@ #include "retesteth/TestOutputHelper.h" #include "retesteth/testSuites/TestFixtures.h" #include "retesteth/testSuites/statetests/StateTests.h" +#include "libdataobj/DataObject.h" #include #include #include @@ -9,33 +10,42 @@ using namespace std; using namespace dev; using namespace test; +using namespace dataobject; using namespace boost::unit_test; namespace fs = boost::filesystem; -// Most Recent StateTestSuite -TestSuite::TestPath StateTestSuite::suiteFolder() const -{ - if (Options::get().fillchain) - return TestSuite::TestPath(fs::path("BlockchainTests") / string("GeneralStateTests" + m_fillerPathAdd)); - return TestSuite::TestPath(fs::path("GeneralStateTests" + m_fillerPathAdd)); -} +#define STATESUITE_FOLDER_OVERRIDE(SUITE, FOLDER) \ + TestSuite::TestPath SUITE::suiteFolder() const \ + { \ + if (Options::get().fillchain) \ + return TestSuite::TestPath(fs::path(string("BlockchainTests/GeneralStateTests") + string(FOLDER + m_fillerPathAdd))); \ + return TestSuite::TestPath(fs::path(string("GeneralStateTests") + string(FOLDER + m_fillerPathAdd))); \ + } \ + \ + TestSuite::FillerPath SUITE::suiteFillerFolder() const \ + { \ + return TestSuite::FillerPath(fs::path(string("src/GeneralStateTestsFiller") + string(FOLDER + m_fillerPathAdd))); \ + } + +#define EIPSUITE_FOLDER_OVERRIDE(SUITE, FOLDER) \ + TestSuite::TestPath SUITE::suiteFolder() const \ + { \ + if (Options::get().fillchain) \ + return TestSuite::TestPath(fs::path(string("EIPTests/BlockchainTests") + string(FOLDER + m_fillerPathAdd))); \ + return TestSuite::TestPath(fs::path(string("EIPTests") + string(FOLDER + m_fillerPathAdd))); \ + } \ + \ + TestSuite::FillerPath SUITE::suiteFillerFolder() const \ + { \ + return TestSuite::FillerPath(fs::path(string("src/EIPTestsFiller") + string(FOLDER + m_fillerPathAdd))); \ + } + +STATESUITE_FOLDER_OVERRIDE(StateTestSuite, "") +STATESUITE_FOLDER_OVERRIDE(StateTestVMSuite, "/VMTests") +STATESUITE_FOLDER_OVERRIDE(StateTestShanghaiSuite, "/Shanghai") +EIPSUITE_FOLDER_OVERRIDE(EIPStateTestSuite, "/StateTests") +EIPSUITE_FOLDER_OVERRIDE(EIPStateTestEOFSuite, "/StateTests/stEOF") -TestSuite::FillerPath StateTestSuite::suiteFillerFolder() const -{ - return TestSuite::FillerPath(fs::path("src") / string("GeneralStateTestsFiller" + m_fillerPathAdd)); -} - -TestSuite::TestPath StateTestVMSuite::suiteFolder() const -{ - if (Options::get().fillchain) - return TestSuite::TestPath(fs::path("BlockchainTests") / "GeneralStateTests" / string("VMTests" + m_fillerPathAdd)); - return TestSuite::TestPath(fs::path("GeneralStateTests") / string("VMTests" + m_fillerPathAdd)); -} - -TestSuite::FillerPath StateTestVMSuite::suiteFillerFolder() const -{ - return TestSuite::FillerPath(fs::path("src") / "GeneralStateTestsFiller" / string("VMTests" + m_fillerPathAdd)); -} // Legacy Constantinople TestSuite::TestPath LegacyConstantinopleStateTestSuite::suiteFolder() const @@ -123,14 +133,9 @@ BOOST_AUTO_TEST_CASE(stSLoadTest) {} BOOST_AUTO_TEST_CASE(stChainId) {} BOOST_AUTO_TEST_CASE(stSelfBalance) {} BOOST_AUTO_TEST_CASE(stStaticFlagEnabled) {} -BOOST_AUTO_TEST_CASE(stSubroutine) {} -BOOST_AUTO_TEST_CASE(stEIP2537) {} BOOST_AUTO_TEST_CASE(stEIP2930) {} BOOST_AUTO_TEST_CASE(stEIP1559) {} BOOST_AUTO_TEST_CASE(stEIP3607) {} -BOOST_AUTO_TEST_CASE(stEIP3540) {} -BOOST_AUTO_TEST_CASE(stEIP3670) {} -BOOST_AUTO_TEST_CASE(stEIP3860) {} // Heavy BOOST_AUTO_TEST_CASE(stTimeConsuming) {} @@ -141,6 +146,12 @@ BOOST_FIXTURE_TEST_SUITE(Retesteth, StateTestsRetestethUnit) BOOST_AUTO_TEST_CASE(stExpectSection) {} BOOST_AUTO_TEST_SUITE_END() +// Shanghai tests suite +using GeneralStateTestsShanghaiFixture = TestFixture; +ETH_REGISTER_DYNAMIC_TEST_SEARCH(GeneralStateTestsShanghaiFixture, "GeneralStateTests/Shanghai") +BOOST_FIXTURE_TEST_SUITE(Shanghai, GeneralStateTestsShanghaiFixture) +BOOST_AUTO_TEST_SUITE_END() + // Converted VMTests using GeneralStateTestsVMFixture = TestFixture; ETH_REGISTER_DYNAMIC_TEST_SEARCH(GeneralStateTestsVMFixture, "GeneralStateTests/VMTests") @@ -154,3 +165,55 @@ BOOST_AUTO_TEST_CASE(vmTests) {} BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END() + + +#include +#define BCEIPSUITE_FOLDER_OVERRIDE(SUITE, FOLDER, FILLER) \ + TestSuite::TestPath SUITE::suiteFolder() const \ + { \ + return TestSuite::TestPath(fs::path(string("EIPTests" + string(FOLDER) + m_fillerPathAdd))); \ + } \ + \ + TestSuite::FillerPath SUITE::suiteFillerFolder() const \ + { \ + return TestSuite::FillerPath(fs::path(string("src/EIPTestsFiller" + string(FILLER) + m_fillerPathAdd))); \ + } + +BCEIPSUITE_FOLDER_OVERRIDE(BCEIPStateTestsSuite, "/BlockchainTests/StateTests", "/StateTests") +BCEIPSUITE_FOLDER_OVERRIDE(BCEIPStateTestsEOFSuite, "/BlockchainTests/StateTests/stEOF", "/StateTests/stEOF") +BCEIPSUITE_FOLDER_OVERRIDE(BlockchainTestEIPSuite, "/BlockchainTests", "/BlockchainTests") + +//EIP TESTS +BOOST_AUTO_TEST_SUITE(EIPTests) + +using EIPTestsFixture = TestFixture; +ETH_REGISTER_DYNAMIC_TEST_SEARCH(EIPTestsFixture, "EIPTests/StateTests") +BOOST_FIXTURE_TEST_SUITE(StateTests, EIPTestsFixture) + using EIPStateTestsEOFFixture = TestFixture; + ETH_REGISTER_DYNAMIC_TEST_SEARCH(EIPStateTestsEOFFixture, "EIPTests/StateTests/stEOF") + BOOST_FIXTURE_TEST_SUITE(stEOF, EIPStateTestsEOFFixture) + BOOST_AUTO_TEST_CASE(stEIP3540) {} + BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() + + +using BCEIPSuiteFixture = TestFixture; +ETH_REGISTER_DYNAMIC_TEST_SEARCH(BCEIPSuiteFixture, "EIPTests/BlockchainTests") +BOOST_FIXTURE_TEST_SUITE(BlockchainTests, BCEIPSuiteFixture) + + using BCEIPStateSuiteFixture = TestFixture; + ETH_REGISTER_DYNAMIC_TEST_SEARCH(BCEIPStateSuiteFixture, "EIPTests/BlockchainTests/StateTests") + BOOST_FIXTURE_TEST_SUITE(StateTests, BCEIPStateSuiteFixture) + BOOST_AUTO_TEST_CASE(stEIP3855) {} + BOOST_AUTO_TEST_CASE(stEIP3860) {} + + using BCEIPStateTestsEOFFixture = TestFixture; + ETH_REGISTER_DYNAMIC_TEST_SEARCH(BCEIPStateTestsEOFFixture, "EIPTests/BlockchainTests/StateTests/stEOF") + BOOST_FIXTURE_TEST_SUITE(stEOF, BCEIPStateTestsEOFFixture) + BOOST_AUTO_TEST_CASE(stEIP3540) {} + BOOST_AUTO_TEST_SUITE_END() + BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE_END() // EIPTESTS + diff --git a/retesteth/testSuites/statetests/StateTestsHelper.cpp b/retesteth/testSuites/statetests/StateTestsHelper.cpp index f28831479..751cea529 100644 --- a/retesteth/testSuites/statetests/StateTestsHelper.cpp +++ b/retesteth/testSuites/statetests/StateTestsHelper.cpp @@ -69,22 +69,4 @@ void checkUnexecutedTransactions(std::vector const& } } -bool hasSkipFork(std::set const& _allforks) -{ - Options const& opt = Options::get(); - auto const& skipforks = opt.getCurrentConfig().cfgFile().fillerSkipForks(); - for (auto const& skipfork : skipforks) - { - if (_allforks.count(skipfork)) - { - ETH_WARNING(string("Test has unsupported fork `") + skipfork.asString() + - "` allowed to skip, skipping the test from filling!" - + TestOutputHelper::get().testInfo().errorDebug()); - return true; - } - } - return false; -} - - } // namespace test::statetests diff --git a/retesteth/testSuites/statetests/StateTestsHelper.h b/retesteth/testSuites/statetests/StateTestsHelper.h index bdec184be..87f24c74c 100644 --- a/retesteth/testSuites/statetests/StateTestsHelper.h +++ b/retesteth/testSuites/statetests/StateTestsHelper.h @@ -12,7 +12,6 @@ enum class Report extern std::string const c_trHashNotFound; bool OptionsAllowTransaction(TransactionInGeneralSection const& _tr); void checkUnexecutedTransactions(std::vector const& _txs, Report _report = Report::WARNING); -bool hasSkipFork(std::set const& _allforks); void RunTest(StateTestInFilled const& _test); spDataObject FillTest(StateTestInFiller const& _test); diff --git a/retesteth/unitTests/structTests.cpp b/retesteth/unitTests/structTests.cpp index 5d61cffd9..e59a465e5 100644 --- a/retesteth/unitTests/structTests.cpp +++ b/retesteth/unitTests/structTests.cpp @@ -2,7 +2,7 @@ #include #include #include -#include +#include using namespace std; using namespace dev; diff --git a/web/memlogpid.py b/web/memlogpid.py index f7ba7f7c7..986def371 100755 --- a/web/memlogpid.py +++ b/web/memlogpid.py @@ -26,7 +26,7 @@ def get_cpumem(pid): argLogFile = sys.argv[3] my_env = os.environ.copy() - my_env["JAVA_HOME"] = "/usr/lib/jvm/java-11-openjdk-amd64" + my_env["JAVA_HOME"] = "/usr/lib/jvm/java-17-oracle" logfile = open(argLogFile, 'w') proc = subprocess.Popen([argCommand], shell=True, stdout=logfile, stderr=logfile, env = my_env) diff --git a/web/script.sh b/web/script.sh index 6ab7a9cb3..414c6d2b6 100755 --- a/web/script.sh +++ b/web/script.sh @@ -55,11 +55,15 @@ if [ "$1" = "besu" ] || [ -z "$1" ]; then rm ./build/install/besu/bin/besu BESU_HEAD=$(git rev-parse HEAD | cut -c1-7) echo "Build besu: " - export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64 - # export JAVA_HOME=/usr/lib/jvm/java-14-oracle + #export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64 + #export JAVA_HOME=/usr/lib/jvm/java-14-oracle + export JAVA_HOME=/usr/lib/jvm/java-17-oracle + ./gradlew clean distZip -x test + ./gradlew clean ./gradlew build #./gradlew integrationTest ./gradlew installDist + ./gradlew ethereum:evmtool:installDist killall java fi @@ -77,6 +81,19 @@ if [ "$1" = "ethereumjs" ] || [ -z "$1" ]; then npm run build --workspaces fi +if [ "$1" = "nimbus" ] || [ -z "$1" ]; then + echo "Fetch nimbus: " + cd $BUILDPATH/nimbus-eth1 + git reset --hard HEAD~1 + git fetch origin + git checkout master + git pull + rm ./tools/t8n/t8n + NIMBUS_HEAD=$(git rev-parse HEAD | cut -c1-7) + echo "Build nimbus: " + make t8n -j2 +fi + #if [ "$1" = "oewrap" ] || [ -z "$1" ]; then # echo "Fetch open-ethereum: " # cd $BUILDPATH/openethereum @@ -156,6 +173,9 @@ runCmd() { if [ "$client" = "oewrap" ]; then headinfo="OEWrapper: #$OEWR_HEAD" fi + if [ "$client" = "nimbus" ]; then + headinfo="Nimbus: #$NIMBUS_HEAD" + fi if [ "$client" = "retesteth" ]; then clientcfg="" fi @@ -272,6 +292,20 @@ if [ "$cname" = "besu" ] || [ -z "$cname" ]; then fi fi +if [ "$cname" = "nimbus" ] || [ -z "$cname" ]; then + sleep 10 + threads=2 + client="nimbus" + CMD="-t GeneralStateTests -- --all -j$threads $arg2" + runCmd + CMD="-t BlockchainTests -- --all -j$threads $arg2" + runCmd +# if [ "$arg2" != "--filltests" ]; then +# CMD="-t LegacyTests/Constantinople -- --all --lowcpu -j$threads $arg2" +# runCmd +# fi +fi + if [ "$cname" = "testeth" ] || [ -z "$cname" ]; then threads=1 client="testeth" diff --git a/web/testoption.sh b/web/testoption.sh new file mode 100755 index 000000000..304daf9eb --- /dev/null +++ b/web/testoption.sh @@ -0,0 +1,100 @@ +#!/bin/bash +retesteth -t BlockchainTests/ValidBlocks/bcExample -- --singletest optionsTest --filltests &>/dev/null + +function findsubstr() +{ + local STR=$1 + local SUB=$2 + if [[ "$STR" == *"$SUB"* ]]; then + echo 1 + return + fi + echo 0 +} + +function countsubstr() +{ + local STR=$1 + local SUB=$2 + local s=${STR//"$SUB"} + echo "$(((${#STR} - ${#s}) / ${#SUB}))" +} + +# Test --poststate without block selection +echo "Testing --poststate 2:10 in Fill mode" +out=$(retesteth -t BlockchainTests/ValidBlocks/bcExample -- --singletest optionsTest --poststate 2:10 --filltests --singlenet London 2>/dev/null) +out=$(echo $out) + +if (( $(countsubstr "$out" "State Dump:") != 0 ));then + echo "ERROR: Expected no State Dump!" +fi + +# Test --poststate without block selection +echo "Testing --poststate 3:0 in Fill mode" +out=$(retesteth -t BlockchainTests/ValidBlocks/bcExample -- --singletest optionsTest --poststate 3:0 --filltests --singlenet London 2>/dev/null) +out=$(echo $out) + +if (( $(countsubstr "$out" "State Dump:") != 0 ));then + echo "ERROR: Expected no State Dump!" +fi + +# Test --poststate without block selection +echo "Testing --poststate 2:0 in Fill mode" +out=$(retesteth -t BlockchainTests/ValidBlocks/bcExample -- --singletest optionsTest --poststate 2:0 --filltests --singlenet London 2>/dev/null) +out=$(echo $out) + +if (( $(findsubstr "$out" "storage\" : { \"0x01\" : \"0x01\", \"0x02\" : \"0x01\" }") != 1 ));then + echo "ERROR: Final post not found!" +fi +if (( $(findsubstr "$out" "nonce\" : \"0x02\"") != 1 ));then + echo "ERROR: Nonce expected to have sent 2 txs" +fi +if (( $(countsubstr "$out" "State Dump:") != 1 ));then + echo "ERROR: Expected only one State Dump!" +fi + +# Test --poststate without block selection +echo "Testing --poststate in Fill mode" +out=$(retesteth -t BlockchainTests/ValidBlocks/bcExample -- --singletest optionsTest --poststate --filltests --singlenet London 2>/dev/null) +out=$(echo $out) + +if (( $(findsubstr "$out" "storage\" : { \"0x01\" : \"0x01\", \"0x02\" : \"0x01\", \"0x03\" : \"0x01\", \"0x05\" : \"0x01\" }") != 1 ));then + echo "ERROR: Final post not found!" +fi +if (( $(findsubstr "$out" "nonce\" : \"0x04\"") != 1 ));then + echo "ERROR: Nonce expected to have sent 4 txs" +fi +if (( $(countsubstr "$out" "State Dump:") != 1 ));then + echo "ERROR: Expected only one State Dump!" +fi + +# Test --poststate without block selection +echo "Testing --poststate in Run mode" +out=$(retesteth -t BlockchainTests/ValidBlocks/bcExample -- --singletest optionsTest --poststate --singlenet London 2>/dev/null) +out=$(echo $out) + +if (( $(findsubstr "$out" "storage\" : { \"0x01\" : \"0x01\", \"0x02\" : \"0x01\", \"0x03\" : \"0x01\", \"0x05\" : \"0x01\" }") != 1 ));then + echo "ERROR: Final post not found!" +fi +if (( $(findsubstr "$out" "nonce\" : \"0x04\"") != 1 ));then + echo "ERROR: Nonce expected to have sent 4 txs" +fi +if (( $(countsubstr "$out" "State Dump:") != 1 ));then + echo "ERROR: Expected only one State Dump!" +fi + +# Test --poststate with block selection +echo "Testing --poststate x:y in Run mode" +out=$(retesteth -t BlockchainTests/ValidBlocks/bcExample -- --singletest optionsTest --poststate 2:0 --singlenet London 2>/dev/null) +out=$(echo $out) + +if (( $(findsubstr "$out" "storage\" : { \"0x01\" : \"0x01\", \"0x02\" : \"0x01\", \"0x03\" : \"0x01\" }") != 1 ));then + echo "ERROR: Final post not found!" +fi +if (( $(findsubstr "$out" "nonce\" : \"0x03\"") != 1 ));then + echo "ERROR: Nonce expected to have sent 3 txs" +fi +if (( $(countsubstr "$out" "State Dump:") != 1 ));then + echo "ERROR: Expected only one State Dump!" +fi +