diff --git a/.github/workflows/functional-tests.yml b/.github/workflows/functional-tests.yml index 489c82421..4042e3a05 100644 --- a/.github/workflows/functional-tests.yml +++ b/.github/workflows/functional-tests.yml @@ -24,6 +24,7 @@ with: token: ${{ secrets.PERSONAL_ACCESS_TOKEN }} repository: skalenetwork/skale-ci-integration_tests + ref: v3.18.0 submodules: recursive - name: Set up Node uses: actions/setup-node@v3.4.0 @@ -65,8 +66,8 @@ - name: skaled+load_python+all run: SKALED_PROVIDER=skaled_providers/binary_from_container ./run_tests.sh skaled+load_python+all - # - name: skaled+load_js+run_angry_cats - # run: SKALED_PROVIDER=skaled_providers/endpoint_by_container ./run_tests.sh skaled+load_js+run_angry_cats + - name: skaled+load_js+run_angry_cats + run: SKALED_PROVIDER=skaled_providers/endpoint_by_container ./run_tests.sh skaled+load_js+run_angry_cats - name: skaled+internals+test_snapshot_api run: SKALED_PROVIDER=skaled_providers/binary_from_container ./run_tests.sh skaled+internals+test_snapshot_api diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 63ae10fc6..372bc11a6 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -150,6 +150,7 @@ jobs: export VERSION=$(cat VERSION) export VERSION=$(bash ./scripts/calculate_version.sh $BRANCH $VERSION) echo "::set-env name=VERSION::$VERSION" + echo "::set-env name=VERSION_ORIG::$VERSION" echo "Version $VERSION" ( test $BRANCH = "stable" && export PRERELEASE=false ) || export PRERELEASE=true echo "PRERELEASE=$PRERELEASE" >> $GITHUB_ENV @@ -191,6 +192,7 @@ jobs: echo "Branch $BRANCH" export VERSION=$VERSION-historic echo "::set-env name=VERSION::$VERSION" + echo "::set-env name=VERSION_HISTORIC::$VERSION" echo "Version $VERSION" export RELEASE=true echo "::set-env name=RELEASE::$RELEASE" @@ -214,12 +216,21 @@ jobs: asset_name: skaled-debug-historic asset_content_type: application/octet-stream outputs: - version: ${{ env.VERSION }} + version_orig: ${{ env.VERSION_ORIG }} + version_historic: ${{ env.VERSION_HISTORIC }} functional-tests: uses: ./.github/workflows/functional-tests.yml name: Functional testing for build needs: [build] with: - version: ${{ needs.build.outputs.version }} + version: ${{ needs.build.outputs.version_orig }} + secrets: inherit + + functional-tests-historic: + uses: ./.github/workflows/functional-tests.yml + name: Functional testing for build + needs: [build] + with: + version: ${{ needs.build.outputs.version_historic }} secrets: inherit diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 49803f389..2ec07ee36 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -122,7 +122,6 @@ jobs: ccache --show-stats - name: Build dependencies run: | - export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" export CC=gcc-9 export CXX=g++-9 @@ -134,6 +133,7 @@ jobs: rm -f ./libwebsockets-from-git.tar.gz ./build.sh DEBUG=1 PARALLEL_COUNT=$(nproc) cd .. + - name: Configure all run: | export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" @@ -166,55 +166,57 @@ jobs: ccache --show-stats - name: Testeth verbosity 1 run : | + mkdir -p /tmp/tests/ + sudo rm -rf /tmp/tests/* #first run with verbosity 1. If test fails, rerun with verbosity 4 cd build/test export NO_NTP_CHECK=1 - export NO_ULIMIT_CHECK=1 + export NO_ULIMIT_CHECK=1 # we specifically run each test for easier log review - ./testeth -t BlockchainTests -- --express && touch /tmp/BlockchainTestsPassed - ./testeth -t TransitionTests -- --express && touch /tmp/TransitionTestsPassed - ./testeth -t TransactionTests -- --express && touch /tmp/TransactionTestsPassed - ./testeth -t VMTests -- --express && touch /tmp/VMTestsPassed - ./testeth -t LevelDBTests -- --express && touch /tmp/LevelDBTestsPassed - ./testeth -t CoreLibTests -- --express && touch /tmp/CoreLibTestsPassed - ./testeth -t RlpTests -- --express && touch /tmp/RlpTestsPassed - ./testeth -t SharedSpaceTests -- --express && touch /tmp/SharedSpaceTestsPassed - ./testeth -t EthashTests -- --express && touch /tmp/EthashTestsPassed - ./testeth -t SealEngineTests -- --express && touch /tmp/SealEngineTestsPassed - ./testeth -t DifficultyTests -- --express && touch /tmp/DifficultyTestsPassed - ./testeth -t BlockSuite -- --express && touch /tmp/BlockSuitePassed - ./testeth -t BlockChainMainNetworkSuite -- --express && touch /tmp/BlockChainMainNetworkSuitePassed - ./testeth -t BlockChainFrontierSuite -- --express && touch /tmp/BlockChainFrontierSuitePassed - ./testeth -t BlockQueueSuite -- --express && touch /tmp/BlockQueueSuitePassed - ./testeth -t ClientBase -- --express && touch /tmp/ClientBasePassed - ./testeth -t EstimateGas -- --express && touch /tmp/EstimateGasPassed - ./testeth -t IMABLSPublicKey -- --express && touch /tmp/IMABLSPublicKeyPassed - ./testeth -t ExtVmSuite -- --express && touch /tmp/ExtVmSuitePassed - ./testeth -t GasPricer -- --express && touch /tmp/GasPricerPassed - ./testeth -t BasicTests -- --express && touch /tmp/BasicTestsPassed - ./testeth -t InstanceMonitorSuite -- --express && touch /tmp/InstanceMonitorSuitePassed - ./testeth -t PrecompiledTests -- --express && touch /tmp/PrecompiledTestsPassed - ./testeth -t SkaleHostSuite -- --express && touch /tmp/SkaleHostSuitePassed - ./testeth -t StateUnitTests -- --express && touch /tmp/StateUnitTestsPassed - ./testeth -t libethereum -- --express && touch /tmp/libethereumPassed - ./testeth -t TransactionQueueSuite -- --express && touch /tmp/TransactionQueueSuitePassed - ./testeth -t LegacyVMSuite -- --express && touch /tmp/LegacyVMSuitePassed - ./testeth -t SkaleInterpreterSuite -- --express && touch /tmp/SkaleInterpreterSuitePassed - ./testeth -t SnapshotSigningTestSuite -- --express && touch /tmp/SnapshotSigningTestSuitePassed - ./testeth -t SkUtils -- --express && touch /tmp/SkUtilsPassed - ./testeth -t BlockChainTestSuite -- --express && touch /tmp/BlockChainTestSuitePassed - ./testeth -t TestHelperSuite -- --express && touch /tmp/TestHelperSuitePassed - ./testeth -t LevelDBHashBase -- --express && touch /tmp/LevelDBHashBasePassed - ./testeth -t memDB -- --express && touch /tmp/memDBPassed - ./testeth -t OverlayDBTests -- --express && touch /tmp/OverlayDBTestsPassed - ./testeth -t AccountHolderTest -- --express && touch /tmp/AccountHolderTestPassed - ./testeth -t ClientTests -- --express && touch /tmp/ClientTestsPassed - ./testeth -t JsonRpcSuite -- --express && touch /tmp/JsonRpcSuitePassed - ./testeth -t SingleConsensusTests -- --express && touch /tmp/SingleConsensusTestsPassed - ./testeth -t ConsensusTests -- --express && touch /tmp/ConsensusTestsPassed - sudo ./testeth -t BtrfsTestSuite -- --all && touch /tmp/BtrfsTestSuitePassed - sudo ./testeth -t HashSnapshotTestSuite -- --all && touch /tmp/HashSnapshotTestSuitePassed - sudo ./testeth -t ClientSnapshotsSuite -- --all && touch /tmp/ClientSnapshotsSuitePassed + ./testeth -t BlockchainTests -- --express && touch /tmp/tests/BlockchainTestsPassed + ./testeth -t TransitionTests -- --express && touch /tmp/tests/TransitionTestsPassed + ./testeth -t TransactionTests -- --express && touch /tmp/tests/TransactionTestsPassed + ./testeth -t VMTests -- --express && touch /tmp/tests/VMTestsPassed + ./testeth -t LevelDBTests -- --express && touch /tmp/tests/LevelDBTestsPassed + ./testeth -t CoreLibTests -- --express && touch /tmp/tests/CoreLibTestsPassed + ./testeth -t RlpTests -- --express && touch /tmp/tests/RlpTestsPassed + ./testeth -t SharedSpaceTests -- --express && touch /tmp/tests/SharedSpaceTestsPassed + ./testeth -t EthashTests -- --express && touch /tmp/tests/EthashTestsPassed + ./testeth -t SealEngineTests -- --express && touch /tmp/tests/SealEngineTestsPassed + ./testeth -t DifficultyTests -- --express && touch /tmp/tests/DifficultyTestsPassed + ./testeth -t BlockSuite -- --express && touch /tmp/tests/BlockSuitePassed + ./testeth -t BlockChainMainNetworkSuite -- --express && touch /tmp/tests/BlockChainMainNetworkSuitePassed + ./testeth -t BlockChainFrontierSuite -- --express && touch /tmp/tests/BlockChainFrontierSuitePassed + ./testeth -t BlockQueueSuite -- --express && touch /tmp/tests/BlockQueueSuitePassed + ./testeth -t ClientBase -- --express && touch /tmp/tests/ClientBasePassed + ./testeth -t EstimateGas -- --express && touch /tmp/tests/EstimateGasPassed + ./testeth -t getHistoricNodesData -- --express && touch /tmp/tests/getHistoricNodesDataPassed + ./testeth -t ExtVmSuite -- --express && touch /tmp/tests/ExtVmSuitePassed + ./testeth -t GasPricer -- --express && touch /tmp/tests/GasPricerPassed + ./testeth -t BasicTests -- --express && touch /tmp/tests/BasicTestsPassed + ./testeth -t InstanceMonitorSuite -- --express && touch /tmp/tests/InstanceMonitorSuitePassed + ./testeth -t PrecompiledTests -- --express && touch /tmp/tests/PrecompiledTestsPassed + ./testeth -t SkaleHostSuite -- --express && touch /tmp/tests/SkaleHostSuitePassed + ./testeth -t StateUnitTests -- --express && touch /tmp/tests/StateUnitTestsPassed + ./testeth -t libethereum -- --express && touch /tmp/tests/libethereumPassed + ./testeth -t TransactionQueueSuite -- --express && touch /tmp/tests/TransactionQueueSuitePassed + ./testeth -t LegacyVMSuite -- --express && touch /tmp/tests/LegacyVMSuitePassed + ./testeth -t SkaleInterpreterSuite -- --express && touch /tmp/tests/SkaleInterpreterSuitePassed + ./testeth -t SnapshotSigningTestSuite -- --express && touch /tmp/tests/SnapshotSigningTestSuitePassed + ./testeth -t SkUtils -- --express && touch /tmp/tests/SkUtilsPassed + ./testeth -t BlockChainTestSuite -- --express && touch /tmp/tests/BlockChainTestSuitePassed + ./testeth -t TestHelperSuite -- --express && touch /tmp/tests/TestHelperSuitePassed + ./testeth -t LevelDBHashBase -- --express && touch /tmp/tests/LevelDBHashBasePassed + ./testeth -t memDB -- --express && touch /tmp/tests/memDBPassed + ./testeth -t OverlayDBTests -- --express && touch /tmp/tests/OverlayDBTestsPassed + ./testeth -t AccountHolderTest -- --express && touch /tmp/tests/AccountHolderTestPassed + ./testeth -t ClientTests -- --express && touch /tmp/tests/ClientTestsPassed + ./testeth -t JsonRpcSuite -- --express && touch /tmp/tests/JsonRpcSuitePassed + ./testeth -t SingleConsensusTests -- --express && touch /tmp/tests/SingleConsensusTestsPassed + ./testeth -t ConsensusTests -- --express && touch /tmp/tests/ConsensusTestsPassed + sudo ./testeth -t BtrfsTestSuite -- --all && touch /tmp/tests/BtrfsTestSuitePassed + sudo ./testeth -t HashSnapshotTestSuite -- --all && touch /tmp/tests/HashSnapshotTestSuitePassed + sudo ./testeth -t ClientSnapshotsSuite -- --all && touch /tmp/tests/ClientSnapshotsSuitePassed cd .. - name: Testeth verbosity 4 run : | @@ -222,50 +224,50 @@ jobs: cd build/test export NO_NTP_CHECK=1 export NO_ULIMIT_CHECK=1 - ls /tmp/BlockchainTestsPassed || ./testeth -t BlockchainTests -- --express --verbosity 4 - ls /tmp/TransitionTestsPassed || ./testeth -t TransitionTests -- --express --verbosity 4 - ls /tmp/TransactionTestsPassed || ./testeth -t TransactionTests -- --express --verbosity 4 - ls /tmp/VMTestsPassed || ./testeth -t VMTests -- --express --verbosity 4 - ls /tmp/LevelDBTestsPassed || ./testeth -t LevelDBTests -- --express --verbosity 4 - ls /tmp/CoreLibTestsPassed || ./testeth -t CoreLibTests -- --express --verbosity 4 - ls /tmp/RlpTestsPassed || ./testeth -t RlpTests -- --express --verbosity 4 - ls /tmp/SharedSpaceTestsPassed || ./testeth -t SharedSpaceTests -- --express --verbosity 4 - ls /tmp/EthashTestsPassed || ./testeth -t EthashTests -- --express --verbosity 4 - ls /tmp/SealEngineTestsPassed || ./testeth -t SealEngineTests -- --express --verbosity 4 - ls /tmp/DifficultyTestsPassed || ./testeth -t DifficultyTests -- --express --verbosity 4 - ls /tmp/BlockSuitePassed || ./testeth -t BlockSuite -- --express --verbosity 4 - ls /tmp/BlockChainMainNetworkSuitePassed || ./testeth -t BlockChainMainNetworkSuite -- --express --verbosity 4 - ls /tmp/BlockChainFrontierSuitePassed || ./testeth -t BlockChainFrontierSuite -- --express --verbosity 4 - ls /tmp/BlockQueueSuitePassed || ./testeth -t BlockQueueSuite -- --express --verbosity 4 - ls /tmp/ClientBasePassed || ./testeth -t ClientBase -- --express --verbosity 4 - ls /tmp/EstimateGasPassed || ./testeth -t EstimateGas -- --express --verbosity 4 - ls /tmp/IMABLSPublicKeyPassed || ./testeth -t IMABLSPublicKey -- --express --verbosity 4 - ls /tmp/ExtVmSuitePassed || ./testeth -t ExtVmSuite -- --express --verbosity 4 - ls /tmp/GasPricerPassed || ./testeth -t GasPricer -- --express --verbosity 4 - ls /tmp/BasicTestsPassed || ./testeth -t BasicTests -- --express --verbosity 4 - ls /tmp/InstanceMonitorSuitePassed || ./testeth -t InstanceMonitorSuite -- --express --verbosity 4 - ls /tmp/PrecompiledTestsPassed || ./testeth -t PrecompiledTests -- --express --verbosity 4 - ls /tmp/SkaleHostSuitePassed || ./testeth -t SkaleHostSuite -- --express --verbosity 4 - ls /tmp/StateUnitTestsPassed || ./testeth -t StateUnitTests -- --express --verbosity 4 - ls /tmp/libethereumPassed || ./testeth -t libethereum -- --express --verbosity 4 - ls /tmp/TransactionQueueSuitePassed || ./testeth -t TransactionQueueSuite -- --express --verbosity 4 - ls /tmp/LegacyVMSuitePassed || ./testeth -t LegacyVMSuite -- --express --verbosity 4 - ls /tmp/SkaleInterpreterSuitePassed || ./testeth -t SkaleInterpreterSuite -- --express --verbosity 4 - ls /tmp/SnapshotSigningTestSuitePassed || ./testeth -t SnapshotSigningTestSuite -- --express --verbosity 4 - ls /tmp/SkUtilsPassed || ./testeth -t SkUtils -- --express --verbosity 4 - ls /tmp/BlockChainTestSuitePassed || ./testeth -t BlockChainTestSuite -- --express --verbosity 4 - ls /tmp/TestHelperSuitePassed || ./testeth -t TestHelperSuite -- --express --verbosity 4 - ls /tmp/LevelDBHashBasePassed || ./testeth -t LevelDBHashBase -- --express --verbosity 4 - ls /tmp/memDBPassed || ./testeth -t memDB -- --express --verbosity 4 - ls /tmp/OverlayDBTestsPassed || ./testeth -t OverlayDBTests -- --express --verbosity 4 - ls /tmp/AccountHolderTestPassed || ./testeth -t AccountHolderTest -- --express --verbosity 4 - ls /tmp/ClientTestsPassed || ./testeth -t ClientTests -- --express --verbosity 4 - ls /tmp/JsonRpcSuitePassed || ./testeth -t JsonRpcSuite -- --express --verbosity 4 - ls /tmp/SingleConsensusTestsPassed || ./testeth -t SingleConsensusTests -- --express --verbosity 4 - ls /tmp/ConsensusTestsPassed || ./testeth -t ConsensusTests -- --express --verbosity 4 - ls /tmp/BtrfsTestSuitePassed || sudo NO_ULIMIT_CHECK=1 NO_NTP_CHECK=1 ./testeth -t BtrfsTestSuite -- --all --verbosity 4 - ls /tmp/HashSnapshotTestSuitePassed || sudo NO_ULIMIT_CHECK=1 NO_NTP_CHECK=1 ./testeth -t HashSnapshotTestSuite -- --all --verbosity 4 - ls /tmp/ClientSnapshotsSuitePassed || sudo NO_ULIMIT_CHECK=1 NO_NTP_CHECK=1 ./testeth -t ClientSnapshotsSuite -- --all --verbosity 4 + ls /tmp/tests/BlockchainTestsPassed || ./testeth -t BlockchainTests -- --express --verbosity 4 + ls /tmp/tests/TransitionTestsPassed || ./testeth -t TransitionTests -- --express --verbosity 4 + ls /tmp/tests/TransactionTestsPassed || ./testeth -t TransactionTests -- --express --verbosity 4 + ls /tmp/tests/VMTestsPassed || ./testeth -t VMTests -- --express --verbosity 4 + ls /tmp/tests/LevelDBTestsPassed || ./testeth -t LevelDBTests -- --express --verbosity 4 + ls /tmp/tests/CoreLibTestsPassed || ./testeth -t CoreLibTests -- --express --verbosity 4 + ls /tmp/tests/RlpTestsPassed || ./testeth -t RlpTests -- --express --verbosity 4 + ls /tmp/tests/SharedSpaceTestsPassed || ./testeth -t SharedSpaceTests -- --express --verbosity 4 + ls /tmp/tests/EthashTestsPassed || ./testeth -t EthashTests -- --express --verbosity 4 + ls /tmp/tests/SealEngineTestsPassed || ./testeth -t SealEngineTests -- --express --verbosity 4 + ls /tmp/tests/DifficultyTestsPassed || ./testeth -t DifficultyTests -- --express --verbosity 4 + ls /tmp/tests/BlockSuitePassed || ./testeth -t BlockSuite -- --express --verbosity 4 + ls /tmp/tests/BlockChainMainNetworkSuitePassed || ./testeth -t BlockChainMainNetworkSuite -- --express --verbosity 4 + ls /tmp/tests/BlockChainFrontierSuitePassed || ./testeth -t BlockChainFrontierSuite -- --express --verbosity 4 + ls /tmp/tests/BlockQueueSuitePassed || ./testeth -t BlockQueueSuite -- --express --verbosity 4 + ls /tmp/tests/ClientBasePassed || ./testeth -t ClientBase -- --express --verbosity 4 + ls /tmp/tests/EstimateGasPassed || ./testeth -t EstimateGas -- --express --verbosity 4 + ls /tmp/tests/getHistoricNodesDataPassed || ./testeth -t getHistoricNodesData -- --express --verbosity 4 + ls /tmp/tests/ExtVmSuitePassed || ./testeth -t ExtVmSuite -- --express --verbosity 4 + ls /tmp/tests/GasPricerPassed || ./testeth -t GasPricer -- --express --verbosity 4 + ls /tmp/tests/BasicTestsPassed || ./testeth -t BasicTests -- --express --verbosity 4 + ls /tmp/tests/InstanceMonitorSuitePassed || ./testeth -t InstanceMonitorSuite -- --express --verbosity 4 + ls /tmp/tests/PrecompiledTestsPassed || ./testeth -t PrecompiledTests -- --express --verbosity 4 + ls /tmp/tests/SkaleHostSuitePassed || ./testeth -t SkaleHostSuite -- --express --verbosity 4 + ls /tmp/tests/StateUnitTestsPassed || ./testeth -t StateUnitTests -- --express --verbosity 4 + ls /tmp/tests/libethereumPassed || ./testeth -t libethereum -- --express --verbosity 4 + ls /tmp/tests/TransactionQueueSuitePassed || ./testeth -t TransactionQueueSuite -- --express --verbosity 4 + ls /tmp/tests/LegacyVMSuitePassed || ./testeth -t LegacyVMSuite -- --express --verbosity 4 + ls /tmp/tests/SkaleInterpreterSuitePassed || ./testeth -t SkaleInterpreterSuite -- --express --verbosity 4 + ls /tmp/tests/SnapshotSigningTestSuitePassed || ./testeth -t SnapshotSigningTestSuite -- --express --verbosity 4 + ls /tmp/tests/SkUtilsPassed || ./testeth -t SkUtils -- --express --verbosity 4 + ls /tmp/tests/BlockChainTestSuitePassed || ./testeth -t BlockChainTestSuite -- --express --verbosity 4 + ls /tmp/tests/TestHelperSuitePassed || ./testeth -t TestHelperSuite -- --express --verbosity 4 + ls /tmp/tests/LevelDBHashBasePassed || ./testeth -t LevelDBHashBase -- --express --verbosity 4 + ls /tmp/tests/memDBPassed || ./testeth -t memDB -- --express --verbosity 4 + ls /tmp/tests/OverlayDBTestsPassed || ./testeth -t OverlayDBTests -- --express --verbosity 4 + ls /tmp/tests/AccountHolderTestPassed || ./testeth -t AccountHolderTest -- --express --verbosity 4 + ls /tmp/tests/ClientTestsPassed || ./testeth -t ClientTests -- --express --verbosity 4 + ls /tmp/tests/JsonRpcSuitePassed || ./testeth -t JsonRpcSuite -- --express --verbosity 4 + ls /tmp/tests/SingleConsensusTestsPassed || ./testeth -t SingleConsensusTests -- --express --verbosity 4 + ls /tmp/tests/ConsensusTestsPassed || ./testeth -t ConsensusTests -- --express --verbosity 4 + ls /tmp/tests/BtrfsTestSuitePassed || sudo NO_ULIMIT_CHECK=1 NO_NTP_CHECK=1 ./testeth -t BtrfsTestSuite -- --all --verbosity 4 + ls /tmp/tests/HashSnapshotTestSuitePassed || sudo NO_ULIMIT_CHECK=1 NO_NTP_CHECK=1 ./testeth -t HashSnapshotTestSuite -- --all --verbosity 4 + ls /tmp/tests/ClientSnapshotsSuitePassed || sudo NO_ULIMIT_CHECK=1 NO_NTP_CHECK=1 ./testeth -t ClientSnapshotsSuite -- --all --verbosity 4 cd .. - name: Create lcov report @@ -282,7 +284,7 @@ jobs: with: token: ${{ secrets.CODECOV_TOKEN }} files: ./coverage.info - + - name: Configure all as historic run: | export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" @@ -291,8 +293,8 @@ jobs: export TARGET=all export CMAKE_BUILD_TYPE=Debug export CODE_COVERAGE=ON - mkdir -p build - cd build + mkdir -p build_historic + cd build_historic # -DCMAKE_C_FLAGS=-O3 -DCMAKE_CXX_FLAGS=-O3 cmake -DCMAKE_BUILD_TYPE=$CMAKE_BUILD_TYPE -DCOVERAGE=$CODE_COVERAGE -DHISTORIC_STATE=1 .. cd .. @@ -304,9 +306,15 @@ jobs: export TARGET=all export CMAKE_BUILD_TYPE=Debug export CODE_COVERAGE=ON - cd build + cd build_historic make testeth -j$(nproc) cd .. - name: Print ccache stats after full historic build run : | ccache --show-stats + - name: Testeth historic + run : | + cd build_historic/test + export NO_NTP_CHECK=1 + export NO_ULIMIT_CHECK=1 + ./testeth -t JsonRpcSuite -- --express --verbosity 4 diff --git a/VERSION b/VERSION index 58baf7b99..c5b45eb7b 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.17.1 +3.18.0 diff --git a/deps/build.sh b/deps/build.sh index 16f35d527..664c42448 100755 --- a/deps/build.sh +++ b/deps/build.sh @@ -1223,7 +1223,7 @@ then # #CMAKE_ARGS_FOR_LIB_WEB_SOCKETS="$CMAKE_ARGS_FOR_LIB_WEB_SOCKETS -DLWS_WITH_LIBEV=ON" # LWS_WITH_LIBEV=ON # fi - #else + #else ## #CMAKE_ARGS_FOR_LIB_WEB_SOCKETS="$CMAKE_ARGS_FOR_LIB_WEB_SOCKETS -DLWS_WITH_LIBEV=OFF" # echo " " #fi @@ -1383,7 +1383,7 @@ then if [ ! -f "boost_1_68_0.tar.bz2" ]; then echo -e "${COLOR_INFO}downloading it${COLOR_DOTS}...${COLOR_RESET}" - eval "$WGET" https://boostorg.jfrog.io/artifactory/main/release/1.68.0/source/boost_1_68_0.tar.bz2 + eval "$WGET" https://sourceforge.net/projects/boost/files/boost/1.68.0/boost_1_68_0.tar.bz2 fi echo -e "${COLOR_INFO}unpacking it${COLOR_DOTS}...${COLOR_RESET}" eval tar -xf boost_1_68_0.tar.bz2 diff --git a/libconsensus b/libconsensus index 5a9b85d8f..ddde155ee 160000 --- a/libconsensus +++ b/libconsensus @@ -1 +1 @@ -Subproject commit 5a9b85d8f171e1ba5f7dfe244cff70e0e39aa5f4 +Subproject commit ddde155ee8ca1e9dbc8adcccab62d9f85a48f1c0 diff --git a/libdevcore/CMakeLists.txt b/libdevcore/CMakeLists.txt index 19f5f4b85..99d179d1e 100644 --- a/libdevcore/CMakeLists.txt +++ b/libdevcore/CMakeLists.txt @@ -15,8 +15,9 @@ add_library(devcore ${sources} ${headers}) add_dependencies(devcore secp256k1) target_compile_options( devcore PRIVATE - -Wno-error=deprecated-copy -Wno-error=unused-result -Wno-error=unused-parameter -Wno-error=unused-variable -Wno-error=maybe-uninitialized - ) + -Wno-error=deprecated-copy -Wno-error=unused-result -Wno-error=unused-parameter + -Wno-error=unused-variable -Wno-error=maybe-uninitialized -Wno-error=class-memaccess +) # Needed to prevent including system-level boost headers: target_include_directories(devcore SYSTEM PUBLIC ${Boost_INCLUDE_DIR} PRIVATE ../utils) diff --git a/libdevcore/Common.cpp b/libdevcore/Common.cpp index ec4c0bc53..e15bb6ae7 100644 --- a/libdevcore/Common.cpp +++ b/libdevcore/Common.cpp @@ -47,14 +47,18 @@ void ExitHandler::exitHandler( int s ) { } void ExitHandler::exitHandler( int nSignalNo, ExitHandler::exit_code_t ec ) { - std::string strMessagePrefix = ExitHandler::shouldExit() ? - cc::error( "\nStop flag was already raised on. " ) + - cc::fatal( "WILL FORCE TERMINATE." ) + - cc::error( " Caught (second) signal. " ) : - cc::error( "\nCaught (first) signal. " ); - std::cerr << strMessagePrefix << cc::error( skutils::signal::signal2str( nSignalNo ) ) - << "\n\n"; - std::cerr.flush(); + std::string strMessagePrefix; + if ( nSignalNo > 0 ) { + strMessagePrefix = ( ExitHandler::shouldExit() && s_nStopSignal > 0 ) ? + string( "\nStop flag was already raised on. " ) + + "WILL FORCE TERMINATE." + " Caught (second) signal. " : + "\nCaught (first) signal. "; + } else { + strMessagePrefix = ExitHandler::shouldExit() ? + string( "\nInternal exit requested while already exiting. " ) : + "\nInternal exit initiated. "; + } + std::cerr << strMessagePrefix << skutils::signal::signal2str( nSignalNo ) << "\n\n"; switch ( nSignalNo ) { case SIGINT: @@ -102,10 +106,10 @@ void ExitHandler::exitHandler( int nSignalNo, ExitHandler::exit_code_t ec ) { auto start_time = std::chrono::steady_clock::now(); std::thread( [nSignalNo, start_time]() { - std::cerr << ( "\n" + cc::fatal( "SELF-KILL:" ) + " " + cc::error( "Will sleep " ) + - cc::size10( ExitHandler::KILL_TIMEOUT ) + - cc::error( " seconds before force exit..." ) + "\n\n" ); - std::cerr.flush(); + std::cerr << ( "\n" + string( "SELF-KILL:" ) + " " + "Will sleep " + + cc::size10( ExitHandler::KILL_TIMEOUT ) + + " seconds before force exit..." ) + + "\n\n"; clog( VerbosityInfo, "exit" ) << "THREADS timer started"; @@ -133,11 +137,10 @@ void ExitHandler::exitHandler( int nSignalNo, ExitHandler::exit_code_t ec ) { std::this_thread::sleep_for( 100ms ); } - std::cerr << ( "\n" + cc::fatal( "SELF-KILL:" ) + " " + - cc::error( "Will force exit after sleeping " ) + + std::cerr << ( "\n" + string( "SELF-KILL:" ) + " " + + "Will force exit after sleeping " + cc::size10( ExitHandler::KILL_TIMEOUT ) + cc::error( " second(s)" ) + "\n\n" ); - std::cerr.flush(); // TODO deduplicate this with main() before return ExitHandler::exit_code_t ec = ExitHandler::requestedExitCode(); @@ -153,9 +156,9 @@ void ExitHandler::exitHandler( int nSignalNo, ExitHandler::exit_code_t ec ) { // nice exit here: - if ( ExitHandler::shouldExit() ) { - std::cerr << ( "\n" + cc::fatal( "SIGNAL-HANDLER:" ) + " " + - cc::error( "Will force exit now..." ) + "\n\n" ); + // TODO deduplicate with first if() + if ( ExitHandler::shouldExit() && s_nStopSignal > 0 && nSignalNo > 0 ) { + std::cerr << ( "\n" + string( "SIGNAL-HANDLER:" ) + " " + "Will force exit now...\n\n" ); _exit( 13 ); } diff --git a/libdevcore/LevelDB.cpp b/libdevcore/LevelDB.cpp index 2896cf4d0..b568d85da 100644 --- a/libdevcore/LevelDB.cpp +++ b/libdevcore/LevelDB.cpp @@ -22,13 +22,14 @@ #include "Assertions.h" #include "Log.h" #include -#include namespace dev { namespace db { unsigned c_maxOpenLeveldbFiles = 25; +const size_t LevelDB::BATCH_CHUNK_SIZE = 10000; + namespace { inline leveldb::Slice toLDBSlice( Slice _slice ) { return leveldb::Slice( _slice.data(), _slice.size() ); @@ -213,7 +214,6 @@ void LevelDB::forEach( std::function< bool( Slice, Slice ) > f ) const { } } - void LevelDB::forEachWithPrefix( std::string& _prefix, std::function< bool( Slice, Slice ) > f ) const { cnote << "Iterating over the LevelDB prefix: " << _prefix; @@ -238,21 +238,23 @@ h256 LevelDB::hashBase() const { if ( it == nullptr ) { BOOST_THROW_EXCEPTION( DatabaseError() << errinfo_comment( "null iterator" ) ); } + secp256k1_sha256_t ctx; secp256k1_sha256_initialize( &ctx ); for ( it->SeekToFirst(); it->Valid(); it->Next() ) { - std::string key_ = it->key().ToString(); - std::string value_ = it->value().ToString(); + std::string keyTmp = it->key().ToString(); + std::string valueTmp = it->value().ToString(); // HACK! For backward compatibility! When snapshot could happen between update of two nodes // - it would lead to stateRoot mismatch // TODO Move this logic to separate "compatiliblity layer"! - if ( key_ == "pieceUsageBytes" ) + if ( keyTmp == "pieceUsageBytes" ) continue; - std::string key_value = key_ + value_; - const std::vector< uint8_t > usc( key_value.begin(), key_value.end() ); - bytesConstRef str_key_value( usc.data(), usc.size() ); - secp256k1_sha256_write( &ctx, str_key_value.data(), str_key_value.size() ); + std::string keyValue = keyTmp + valueTmp; + const std::vector< uint8_t > usc( keyValue.begin(), keyValue.end() ); + bytesConstRef strKeyValue( usc.data(), usc.size() ); + secp256k1_sha256_write( &ctx, strKeyValue.data(), strKeyValue.size() ); } + h256 hash; secp256k1_sha256_finalize( &ctx, hash.data() ); return hash; @@ -263,16 +265,17 @@ h256 LevelDB::hashBaseWithPrefix( char _prefix ) const { if ( it == nullptr ) { BOOST_THROW_EXCEPTION( DatabaseError() << errinfo_comment( "null iterator" ) ); } + secp256k1_sha256_t ctx; secp256k1_sha256_initialize( &ctx ); for ( it->SeekToFirst(); it->Valid(); it->Next() ) { if ( it->key()[0] == _prefix ) { - std::string key_ = it->key().ToString(); - std::string value_ = it->value().ToString(); - std::string key_value = key_ + value_; - const std::vector< uint8_t > usc( key_value.begin(), key_value.end() ); - bytesConstRef str_key_value( usc.data(), usc.size() ); - secp256k1_sha256_write( &ctx, str_key_value.data(), str_key_value.size() ); + std::string keyTmp = it->key().ToString(); + std::string valueTmp = it->value().ToString(); + std::string keyValue = keyTmp + valueTmp; + const std::vector< uint8_t > usc( keyValue.begin(), keyValue.end() ); + bytesConstRef strKeyValue( usc.data(), usc.size() ); + secp256k1_sha256_write( &ctx, strKeyValue.data(), strKeyValue.size() ); } } h256 hash; @@ -280,6 +283,39 @@ h256 LevelDB::hashBaseWithPrefix( char _prefix ) const { return hash; } +bool LevelDB::hashBasePartially( secp256k1_sha256_t* ctx, std::string& lastHashedKey ) const { + std::unique_ptr< leveldb::Iterator > it( m_db->NewIterator( m_readOptions ) ); + if ( it == nullptr ) { + BOOST_THROW_EXCEPTION( DatabaseError() << errinfo_comment( "null iterator" ) ); + } + + if ( lastHashedKey != "start" ) + it->Seek( lastHashedKey ); + else + it->SeekToFirst(); + + for ( size_t counter = 0; it->Valid() && counter < BATCH_CHUNK_SIZE; it->Next() ) { + std::string keyTmp = it->key().ToString(); + std::string valueTmp = it->value().ToString(); + // HACK! For backward compatibility! When snapshot could happen between update of two nodes + // - it would lead to stateRoot mismatch + // TODO Move this logic to separate "compatiliblity layer"! + if ( keyTmp == "pieceUsageBytes" ) + continue; + std::string keyValue = keyTmp + valueTmp; + const std::vector< uint8_t > usc( keyValue.begin(), keyValue.end() ); + bytesConstRef strKeyValue( usc.data(), usc.size() ); + secp256k1_sha256_write( ctx, strKeyValue.data(), strKeyValue.size() ); + ++counter; + } + + if ( it->Valid() ) { + lastHashedKey = it->key().ToString(); + return true; + } else + return false; +} + void LevelDB::doCompaction() const { m_db->CompactRange( nullptr, nullptr ); } diff --git a/libdevcore/LevelDB.h b/libdevcore/LevelDB.h index 0a597c51e..5c314e8bf 100644 --- a/libdevcore/LevelDB.h +++ b/libdevcore/LevelDB.h @@ -26,6 +26,8 @@ #include #include +#include + namespace dev { namespace db { class LevelDB : public DatabaseFace { @@ -59,6 +61,8 @@ class LevelDB : public DatabaseFace { h256 hashBase() const override; h256 hashBaseWithPrefix( char _prefix ) const; + bool hashBasePartially( secp256k1_sha256_t* ctx, std::string& lastHashedKey ) const; + void doCompaction() const; // Return the total count of key deletes since the start @@ -74,6 +78,8 @@ class LevelDB : public DatabaseFace { leveldb::WriteOptions const m_writeOptions; leveldb::Options m_options; boost::filesystem::path const m_path; + + static const size_t BATCH_CHUNK_SIZE; }; } // namespace db diff --git a/libethcore/ChainOperationParams.h b/libethcore/ChainOperationParams.h index ec57fe4ed..678619900 100644 --- a/libethcore/ChainOperationParams.h +++ b/libethcore/ChainOperationParams.h @@ -175,7 +175,10 @@ struct SChain { time_t verifyDaSigsPatchTimestamp = 0; time_t storageDestructionPatchTimestamp = 0; time_t powCheckPatchTimestamp = 0; + time_t precompiledConfigPatchTimestamp = 0; + time_t pushZeroPatchTimestamp = 0; time_t skipInvalidTransactionsPatchTimestamp = 0; + time_t correctForkInPowPatchTimestamp = 0; SChain() { name = "TestChain"; diff --git a/libethereum/Block.cpp b/libethereum/Block.cpp index 28e17ad0f..d98705d88 100644 --- a/libethereum/Block.cpp +++ b/libethereum/Block.cpp @@ -351,7 +351,7 @@ pair< TransactionReceipts, bool > Block::sync( // caller if we hit the limit for ( Transaction& transaction : transactions ) { - transaction.checkOutExternalGas( _bc.chainParams().externalGasDifficulty ); + transaction.checkOutExternalGas( _bc.chainParams(), _bc.number() ); } assert( _bc.currentHash() == m_currentBlock.parentHash() ); @@ -631,8 +631,7 @@ u256 Block::enact( VerifiedBlockRef const& _block, BlockChain const& _bc ) { // << " (state #" // << state().getNonce( tr.from() ) << ") value = " << tr.value() << // endl; - const_cast< Transaction& >( tr ).checkOutExternalGas( - _bc.chainParams().externalGasDifficulty ); + const_cast< Transaction& >( tr ).checkOutExternalGas( _bc.chainParams(), _bc.number() ); execute( _bc.lastBlockHashes(), tr ); // cerr << "Now: " // << "State #" << state().getNonce( tr.from() ) << endl; diff --git a/libethereum/ChainParams.cpp b/libethereum/ChainParams.cpp index fb48f748d..52d3fade1 100644 --- a/libethereum/ChainParams.cpp +++ b/libethereum/ChainParams.cpp @@ -266,11 +266,25 @@ ChainParams ChainParams::loadConfig( sChainObj.at( "powCheckPatchTimestamp" ).get_int64() : 0; + s.precompiledConfigPatchTimestamp = + sChainObj.count( "precompiledConfigPatchTimestamp" ) ? + sChainObj.at( "precompiledConfigPatchTimestamp" ).get_int64() : + 0; + + s.pushZeroPatchTimestamp = sChainObj.count( "pushZeroPatchTimestamp" ) ? + sChainObj.at( "pushZeroPatchTimestamp" ).get_int64() : + 0; + s.skipInvalidTransactionsPatchTimestamp = sChainObj.count( "skipInvalidTransactionsPatchTimestamp" ) ? sChainObj.at( "skipInvalidTransactionsPatchTimestamp" ).get_int64() : 0; + s.correctForkInPowPatchTimestamp = + sChainObj.count( "correctForkInPowPatchTimestamp" ) ? + sChainObj.at( "correctForkInPowPatchTimestamp" ).get_int64() : + 0; + if ( sChainObj.count( "nodeGroups" ) ) { std::vector< NodeGroup > nodeGroups; for ( const auto& nodeGroupConf : sChainObj["nodeGroups"].get_obj() ) { @@ -284,9 +298,12 @@ ChainParams ChainParams::loadConfig( auto groupNodesObj = nodeGroupObj["nodes"].get_obj(); for ( const auto& groupNodeConf : groupNodesObj ) { auto groupNodeConfObj = groupNodeConf.second.get_array(); - u256 sChainIndex = groupNodeConfObj[0].get_uint64(); - u256 id = groupNodeConfObj[1].get_uint64(); - std::string publicKey = groupNodeConfObj[2].get_str(); + u256 sChainIndex = groupNodeConfObj.at( 0 ).get_uint64(); + u256 id = groupNodeConfObj.at( 1 ).get_uint64(); + std::string publicKey = groupNodeConfObj.at( 2 ).get_str(); + if ( publicKey.empty() ) { + BOOST_THROW_EXCEPTION( std::runtime_error( "Empty public key in config" ) ); + } groupNodes.push_back( { id, sChainIndex, publicKey } ); } std::sort( groupNodes.begin(), groupNodes.end(), diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 06cec9516..f2c34239f 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -53,7 +53,10 @@ #include #include +#include #include +#include +#include #include #include #include @@ -163,8 +166,11 @@ Client::Client( ChainParams const& _params, int _networkID, RevertableFSPatch::setTimestamp( chainParams().sChain.revertableFSPatchTimestamp ); StorageDestructionPatch::setTimestamp( chainParams().sChain.storageDestructionPatchTimestamp ); POWCheckPatch::setTimestamp( chainParams().sChain.powCheckPatchTimestamp ); + PushZeroPatch::setTimestamp( chainParams().sChain.pushZeroPatchTimestamp ); SkipInvalidTransactionsPatch::setTimestamp( this->chainParams().sChain.skipInvalidTransactionsPatchTimestamp ); + PrecompiledConfigPatch::setTimestamp( chainParams().sChain.precompiledConfigPatchTimestamp ); + CorrectForkInPowPatch::setTimestamp( chainParams().sChain.correctForkInPowPatchTimestamp ); } @@ -311,8 +317,12 @@ void Client::init( WithExisting _forceAction, u256 _networkId ) { if ( m_dbPath.size() ) Defaults::setDBPath( m_dbPath ); - if ( ChainParams().sChain.nodeGroups.size() > 0 ) - initIMABLSPublicKey(); + if ( chainParams().sChain.nodeGroups.size() > 0 ) { + initHistoricGroupIndex(); + } else { + LOG( m_logger ) << "Empty node groups in config. " + "This is OK in tests but not OK in production"; + } // init snapshots for not newly created chains if ( number() ) { @@ -323,6 +333,10 @@ void Client::init( WithExisting _forceAction, u256 _networkId ) { // HACK Needed to set env var for consensus AmsterdamFixPatch::isEnabled( *this ); + // needed for checkOutExternalGas + CorrectForkInPowPatch::lastBlockTimestamp = blockChain().info().timestamp(); + CorrectForkInPowPatch::lastBlockNumber = blockChain().number(); + initCPUUSage(); doWork( false ); @@ -592,6 +606,10 @@ size_t Client::importTransactionsAsBlock( sealUnconditionally( false ); importWorkingBlock(); + // this needs to be updated as soon as possible, as it's used in new transactions validation + CorrectForkInPowPatch::lastBlockTimestamp = blockChain().info().timestamp(); + CorrectForkInPowPatch::lastBlockNumber = blockChain().number(); + if ( !UnsafeRegion::isActive() ) { LOG( m_loggerDetail ) << "Total unsafe time so far = " << std::chrono::duration_cast< std::chrono::seconds >( @@ -619,7 +637,7 @@ size_t Client::importTransactionsAsBlock( } if ( chainParams().sChain.nodeGroups.size() > 0 ) - updateIMABLSPublicKey(); + updateHistoricGroupIndex(); m_snapshotAgent->doSnapshotIfNeeded( number(), _timestamp ); @@ -657,7 +675,12 @@ size_t Client::syncTransactions( RevertableFSPatch::lastBlockTimestamp = blockChain().info().timestamp(); StorageDestructionPatch::lastBlockTimestamp = blockChain().info().timestamp(); POWCheckPatch::lastBlockTimestamp = blockChain().info().timestamp(); + PushZeroPatch::lastBlockTimestamp = blockChain().info().timestamp(); SkipInvalidTransactionsPatch::lastBlockTimestamp = blockChain().info().timestamp(); + PrecompiledConfigPatch::lastBlockTimestamp = blockChain().info().timestamp(); + CorrectForkInPowPatch::lastBlockTimestamp = blockChain().info().timestamp(); + CorrectForkInPowPatch::lastBlockNumber = blockChain().number(); + DEV_WRITE_GUARDED( x_working ) { assert( !m_working.isSealed() ); @@ -1085,7 +1108,9 @@ Block Client::blockByNumber( BlockNumber _h ) const { auto readState = m_state.createStateReadOnlyCopy(); readState.mutableHistoricState().setRootByBlockNumber( _h ); - DEV_GUARDED( m_blockImportMutex ) { return Block( bc(), hash, readState ); } + // removed m_blockImportMutex here + // this function doesn't interact with latest block so the mutex isn't needed + return Block( bc(), hash, readState ); assert( false ); return Block( bc() ); } catch ( Exception& ex ) { @@ -1118,10 +1143,9 @@ Transactions Client::pending() const { } SyncStatus Client::syncStatus() const { - // TODO implement this when syncing will be needed - SyncStatus s; - s.startBlockNumber = s.currentBlockNumber = s.highestBlockNumber = 0; - return s; + if ( !m_skaleHost ) + BOOST_THROW_EXCEPTION( std::runtime_error( "SkaleHost was not initialized" ) ); + return m_skaleHost->syncStatus(); } TransactionSkeleton Client::populateTransactionWithDefaults( TransactionSkeleton const& _t ) const { @@ -1179,8 +1203,6 @@ h256 Client::importTransaction( Transaction const& _t ) { // the latest block in the client's blockchain. This can throw but // we'll catch the exception at the RPC level. - const_cast< Transaction& >( _t ).checkOutExternalGas( chainParams().externalGasDifficulty ); - // throws in case of error State state; u256 gasBidPrice; @@ -1188,6 +1210,10 @@ h256 Client::importTransaction( Transaction const& _t ) { DEV_GUARDED( m_blockImportMutex ) { state = this->state().createStateReadOnlyCopy(); gasBidPrice = this->gasBidPrice(); + + // We need to check external gas under mutex to be sure about current block bumber + // correctness + const_cast< Transaction& >( _t ).checkOutExternalGas( chainParams(), number() ); } Executive::verifyTransaction( _t, @@ -1244,7 +1270,7 @@ ExecutionResult Client::call( Address const& _from, u256 _value, Address _dest, Transaction t( _value, gasPrice, gas, _dest, _data, nonce ); t.forceSender( _from ); t.forceChainId( chainParams().chainID ); - t.checkOutExternalGas( ~u256( 0 ) ); + t.ignoreExternalGas(); if ( _ff == FudgeFactor::Lenient ) { historicBlock.mutableState().mutableHistoricState().addBalance( _from, ( u256 )( t.gas() * t.gasPrice() + t.value() ) ); @@ -1269,7 +1295,7 @@ ExecutionResult Client::call( Address const& _from, u256 _value, Address _dest, Transaction t( _value, gasPrice, gas, _dest, _data, nonce ); t.forceSender( _from ); t.forceChainId( chainParams().chainID ); - t.checkOutExternalGas( ~u256( 0 ) ); + t.ignoreExternalGas(); if ( _ff == FudgeFactor::Lenient ) temp.mutableState().addBalance( _from, ( u256 )( t.gas() * t.gasPrice() + t.value() ) ); ret = temp.execute( bc().lastBlockHashes(), t, skale::Permanence::Reverted ); @@ -1285,9 +1311,9 @@ ExecutionResult Client::call( Address const& _from, u256 _value, Address _dest, return ret; } -void Client::initIMABLSPublicKey() { +void Client::initHistoricGroupIndex() { if ( number() == 0 ) { - imaBLSPublicKeyGroupIndex = 0; + historicGroupIndex = 0; return; } @@ -1299,7 +1325,11 @@ void Client::initIMABLSPublicKey() { chainParams().sChain.nodeGroups.end(), [¤tBlockTimestamp]( const dev::eth::NodeGroup& ng ) { return currentBlockTimestamp <= ng.finishTs; } ); - assert( it != chainParams().sChain.nodeGroups.end() ); + + if ( it == chainParams().sChain.nodeGroups.end() ) { + BOOST_THROW_EXCEPTION( + std::runtime_error( "Assertion failed: it == chainParams().sChain.nodeGroups.end()" ) ); + } if ( it != chainParams().sChain.nodeGroups.begin() ) { auto prevIt = std::prev( it ); @@ -1308,15 +1338,18 @@ void Client::initIMABLSPublicKey() { it = prevIt; } - imaBLSPublicKeyGroupIndex = std::distance( chainParams().sChain.nodeGroups.begin(), it ); + historicGroupIndex = std::distance( chainParams().sChain.nodeGroups.begin(), it ); } -void Client::updateIMABLSPublicKey() { +void Client::updateHistoricGroupIndex() { uint64_t blockTimestamp = blockInfo( hashFromNumber( number() ) ).timestamp(); - uint64_t currentFinishTs = chainParams().sChain.nodeGroups[imaBLSPublicKeyGroupIndex].finishTs; + uint64_t currentFinishTs = chainParams().sChain.nodeGroups.at( historicGroupIndex ).finishTs; if ( blockTimestamp >= currentFinishTs ) - ++imaBLSPublicKeyGroupIndex; - assert( imaBLSPublicKeyGroupIndex < chainParams().sChain.nodeGroups.size() ); + ++historicGroupIndex; + if ( historicGroupIndex >= chainParams().sChain.nodeGroups.size() ) { + BOOST_THROW_EXCEPTION( std::runtime_error( + "Assertion failed: historicGroupIndex >= chainParams().sChain.nodeGroups.size())" ) ); + } } // new block watch diff --git a/libethereum/Client.h b/libethereum/Client.h index 2e3155612..3bf2015c4 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -297,7 +297,25 @@ class Client : public ClientBase, protected Worker { } std::array< std::string, 4 > getIMABLSPublicKey() const { - return chainParams().sChain.nodeGroups[imaBLSPublicKeyGroupIndex].blsPublicKey; + return chainParams().sChain.nodeGroups.at( historicGroupIndex ).blsPublicKey; + } + + // get node id for historic node in chain + std::string getHistoricNodeId( unsigned _id ) const { + return chainParams().sChain.nodeGroups.at( historicGroupIndex ).nodes.at( _id ).id.str(); + } + + // get schain index for historic node in chain + std::string getHistoricNodeIndex( unsigned _idx ) const { + return chainParams() + .sChain.nodeGroups.at( historicGroupIndex ) + .nodes.at( _idx ) + .schainIndex.str(); + } + + // get node owner for historic node in chain + std::string getHistoricNodePublicKey( unsigned _idx ) const { + return chainParams().sChain.nodeGroups.at( historicGroupIndex ).nodes.at( _idx ).publicKey; } void doStateDbCompaction() const { m_state.getOriginalDb()->doCompaction(); } @@ -532,10 +550,11 @@ class Client : public ClientBase, protected Worker { fs::path m_dbPath; private: - void initIMABLSPublicKey(); - void updateIMABLSPublicKey(); + void initHistoricGroupIndex(); + void updateHistoricGroupIndex(); - unsigned imaBLSPublicKeyGroupIndex = 0; + // which group corresponds to the current block timestamp on this node + unsigned historicGroupIndex = 0; public: FILE* performance_fd; diff --git a/libethereum/ClientBase.cpp b/libethereum/ClientBase.cpp index 6d646f45a..6b6d530b4 100644 --- a/libethereum/ClientBase.cpp +++ b/libethereum/ClientBase.cpp @@ -23,6 +23,7 @@ */ #include "ClientBase.h" +#include #include #include @@ -89,7 +90,7 @@ std::pair< bool, ExecutionResult > ClientBase::estimateGasStep( int64_t _gas, Bl t = Transaction( _value, _gasPrice, _gas, _data, nonce ); t.forceSender( _from ); t.forceChainId( chainId() ); - t.checkOutExternalGas( ~u256( 0 ) ); + t.ignoreExternalGas(); EnvInfo const env( _latestBlock.info(), bc().lastBlockHashes(), 0, _gas ); // Make a copy of state!! It will be deleted after step! State tempState = _latestBlock.mutableState(); @@ -115,7 +116,12 @@ std::pair< u256, ExecutionResult > ClientBase::estimateGas( Address const& _from int64_t upperBound = _maxGas; if ( upperBound == Invalid256 || upperBound > c_maxGasEstimate ) upperBound = c_maxGasEstimate; - int64_t lowerBound = Transaction::baseGasRequired( !_dest, &_data, EVMSchedule() ); + int64_t lowerBound = + CorrectForkInPowPatch::isEnabled() ? + Transaction::baseGasRequired( !_dest, &_data, + bc().sealEngine()->chainParams().scheduleForBlockNumber( bc().number() ) ) : + Transaction::baseGasRequired( !_dest, &_data, EVMSchedule() ); + Block bk = latestBlock(); if ( upperBound > bk.info().gasLimit() ) { upperBound = bk.info().gasLimit().convert_to< int64_t >(); diff --git a/libethereum/InstanceMonitor.cpp b/libethereum/InstanceMonitor.cpp index e2a6585db..ed180f6fc 100644 --- a/libethereum/InstanceMonitor.cpp +++ b/libethereum/InstanceMonitor.cpp @@ -32,7 +32,7 @@ using namespace dev; namespace fs = boost::filesystem; -const std::string InstanceMonitor::rotation_info_file_name = "rotation.txt"; +const std::string InstanceMonitor::rotation_info_file_name = "rotation.json"; void InstanceMonitor::prepareRotation() { reportExitTimeReached( true ); @@ -40,35 +40,49 @@ void InstanceMonitor::prepareRotation() { } void InstanceMonitor::initRotationParams( uint64_t _finishTimestamp ) { - nlohmann::json rotationJson = nlohmann::json::object(); - rotationJson["timestamp"] = _finishTimestamp; + try { + nlohmann::json rotationJson = nlohmann::json::object(); + rotationJson["timestamp"] = _finishTimestamp; - std::ofstream rotationInfoFile( m_rotationInfoFilePath.string() ); - rotationInfoFile << rotationJson; + std::ofstream rotationInfoFile( m_rotationInfoFilePath.string() ); + rotationInfoFile << rotationJson; - m_finishTimestamp = _finishTimestamp; - LOG( m_logger ) << "Set rotation time to " << m_finishTimestamp; + LOG( m_infoLogger ) << "Set rotation time to " << _finishTimestamp; + } catch ( ... ) { + LOG( m_errorLogger ) << "Setting rotation timestamp failed"; + throw_with_nested( std::runtime_error( "cannot save rotation timestamp" ) ); + } } -bool InstanceMonitor::isTimeToRotate( uint64_t _finishTimestamp ) { +bool InstanceMonitor::isTimeToRotate( uint64_t _blockTimestamp ) const { if ( !fs::exists( m_rotationInfoFilePath ) ) { return false; } - return m_finishTimestamp <= _finishTimestamp; + try { + auto _rotationTimestamp = rotationTimestamp(); + return _rotationTimestamp <= _blockTimestamp; + } catch ( InvalidRotationInfoFileException& ex ) { + return false; + } } -void InstanceMonitor::restoreRotationParams() { - if ( fs::exists( m_rotationInfoFilePath ) ) { - std::ifstream rotationInfoFile( m_rotationInfoFilePath.string() ); +uint64_t InstanceMonitor::rotationTimestamp() const { + std::ifstream rotationInfoFile( m_rotationInfoFilePath.string() ); + try { auto rotationJson = nlohmann::json::parse( rotationInfoFile ); - m_finishTimestamp = rotationJson["timestamp"].get< uint64_t >(); + auto timestamp = rotationJson["timestamp"].get< uint64_t >(); + LOG( m_infoLogger ) << "Rotation scheduled for " << timestamp; + return timestamp; + } catch ( ... ) { + LOG( m_errorLogger ) << "Rotation file is malformed or missing"; + throw InvalidRotationInfoFileException( m_rotationInfoFilePath ); } } void InstanceMonitor::reportExitTimeReached( bool _reached ) { if ( m_statusAndControl ) { - LOG( m_logger ) << "Setting ExitTimeReached = " << _reached; + LOG( m_infoLogger ) << "Setting ExitTimeReached = " << _reached; m_statusAndControl->setExitState( StatusAndControl::ExitTimeReached, _reached ); } else - LOG( m_logger ) << "Simulating setting ExitTimeReached = " << _reached; + LOG( m_infoLogger ) << "Simulating setting ExitTimeReached = " << _reached; } diff --git a/libethereum/InstanceMonitor.h b/libethereum/InstanceMonitor.h index 84867ddcc..688fddcbd 100644 --- a/libethereum/InstanceMonitor.h +++ b/libethereum/InstanceMonitor.h @@ -36,23 +36,18 @@ class InstanceMonitor { public: explicit InstanceMonitor( const boost::filesystem::path& _rotationInfoFileDirPath, std::shared_ptr< StatusAndControl > _statusAndControl = nullptr ) - : m_finishTimestamp( 0 ), - m_rotationInfoFilePath( _rotationInfoFileDirPath / rotation_info_file_name ), + : m_rotationInfoFilePath( _rotationInfoFileDirPath / rotation_info_file_name ), m_statusAndControl( _statusAndControl ) { - restoreRotationParams(); reportExitTimeReached( false ); } void prepareRotation(); void initRotationParams( uint64_t _finishTimestamp ); - bool isTimeToRotate( uint64_t _finishTimestamp ); + bool isTimeToRotate( uint64_t _blockTimestamp ) const; protected: - void restoreRotationParams(); - [[nodiscard]] uint64_t finishTimestamp() const { return m_finishTimestamp; } - + [[nodiscard]] uint64_t rotationTimestamp() const; [[nodiscard]] fs::path rotationInfoFilePath() const { return m_rotationInfoFilePath; } - uint64_t m_finishTimestamp; const fs::path m_rotationInfoFilePath; std::shared_ptr< StatusAndControl > m_statusAndControl; @@ -60,6 +55,21 @@ class InstanceMonitor { void reportExitTimeReached( bool _reached ); + class InvalidRotationInfoFileException : public std::exception { + protected: + std::string what_str; + + public: + boost::filesystem::path path; + + InvalidRotationInfoFileException( const boost::filesystem::path& _path ) : path( _path ) { + what_str = "File " + path.string() + " is malformed or missing"; + } + virtual const char* what() const noexcept override { return what_str.c_str(); } + }; + + private: - dev::Logger m_logger{ createLogger( dev::VerbosityInfo, "instance-monitor" ) }; + mutable dev::Logger m_infoLogger{ createLogger( dev::VerbosityInfo, "instance-monitor" ) }; + mutable dev::Logger m_errorLogger{ createLogger( dev::VerbosityError, "instance-monitor" ) }; }; diff --git a/libethereum/Precompiled.cpp b/libethereum/Precompiled.cpp index 6a0a1c63f..aecc33209 100644 --- a/libethereum/Precompiled.cpp +++ b/libethereum/Precompiled.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -36,8 +37,11 @@ #include #include #include +#include #include #include +#include +#include #include @@ -247,10 +251,20 @@ static Logger& getLogger( int a_severity = VerbosityTrace ) { static void convertBytesToString( bytesConstRef _in, size_t _startPosition, std::string& _out, size_t& _stringLength ) { + if ( _in.size() < UINT256_SIZE ) { + throw std::runtime_error( "Input is too short - invalid input in convertBytesToString()" ); + } bigint const sstringLength( parseBigEndianRightPadded( _in, _startPosition, UINT256_SIZE ) ); + if ( sstringLength < 0 ) { + throw std::runtime_error( + "Negative string length - invalid input in convertBytesToString()" ); + } _stringLength = sstringLength.convert_to< size_t >(); + if ( _startPosition + UINT256_SIZE + _stringLength > _in.size() ) { + throw std::runtime_error( "Invalid input in convertBytesToString()" ); + } vector_ref< const unsigned char > byteFilename = - _in.cropped( _startPosition + 32, _stringLength ); + _in.cropped( _startPosition + UINT256_SIZE, _stringLength ); _out = std::string( ( char* ) byteFilename.data(), _stringLength ); } @@ -673,25 +687,8 @@ ETH_REGISTER_PRECOMPILED( logTextMessage )( bytesConstRef _in ) { return { false, response }; // 1st false - means bad error occur } -static const std::list< std::string > g_listReadableConfigParts{ "sealEngine", - //"genesis.*" - //"params.*", - - "skaleConfig.nodeInfo.wallets.ima.commonBLSPublicKey*", - "skaleConfig.nodeInfo.wallets.ima.BLSPublicKey*", - - "skaleConfig.nodeInfo.nodeName", "skaleConfig.nodeInfo.nodeID", - "skaleConfig.nodeInfo.basePort*", "skaleConfig.nodeInfo.*RpcPort*", - "skaleConfig.nodeInfo.acceptors", "skaleConfig.nodeInfo.max-connections", - "skaleConfig.nodeInfo.max-http-queues", "skaleConfig.nodeInfo.ws-mode", - - "skaleConfig.contractSettings.*", - - "skaleConfig.sChain.emptyBlockIntervalMs", - - "skaleConfig.sChain.schainName", "skaleConfig.sChain.schainID", - - "skaleConfig.sChain.nodes.*" }; +static const std::list< std::string > g_listReadableConfigParts{ "skaleConfig.sChain.nodes.", + "skaleConfig.nodeInfo.wallets.ima.n" }; static bool stat_is_accessible_json_path( const std::string& strPath ) { if ( strPath.empty() ) @@ -700,7 +697,7 @@ static bool stat_is_accessible_json_path( const std::string& strPath ) { itEnd = g_listReadableConfigParts.cend(); for ( ; itWalk != itEnd; ++itWalk ) { const std::string strWildCard = ( *itWalk ); - if ( skutils::tools::wildcmp( strWildCard.c_str(), strPath.c_str() ) ) + if ( boost::algorithm::starts_with( strPath, strWildCard ) ) return true; } return false; @@ -756,6 +753,47 @@ static dev::u256 stat_parse_u256_hex_or_dec( const std::string& strValue ) { return uValue; } +static bool isCallToHistoricData( const std::string& callData ) { + // in C++ 20 there is string::starts_with, but we do not use C++ 20 yet + return boost::algorithm::starts_with( callData, "skaleConfig.sChain.nodes." ); +} + +static std::pair< std::string, unsigned > parseHistoricFieldRequest( std::string callData ) { + std::vector< std::string > splitted; + boost::split( splitted, callData, boost::is_any_of( "." ) ); + // first 3 elements are skaleConfig, sChain, nodes - it was checked before + unsigned id = std::stoul( splitted.at( 3 ) ); + std::string fieldName; + std::set< std::string > allowedValues{ "id", "schainIndex", "publicKey" }; + fieldName = splitted.at( 4 ); + if ( allowedValues.count( fieldName ) ) { + return { fieldName, id }; + } else { + BOOST_THROW_EXCEPTION( std::runtime_error( "Unknown field:" + fieldName ) ); + } + return { fieldName, id }; +} + +/* + * this precompiled contract is designed to get access to specific integer config values + * and works as key / values map + * input: bytes - length + path to config variable + * output: bytes - config variable value + * + * variables available through this precompiled contract: + * 1. id - node id for INDEX node in schain group for current block number + * 2. schainIndex - schain index for INDEX node in schain group for current block number + * to access those variables one should use the following scheme: + * prefix=skaleConfig.sChain.nodes - to access corresponding structure inside skaled + * index - node index user wants to get access to + * field - the field user wants to request + * + * example: + * to request the value for 1-st node (1 based) for the node id field the input should be + * input=skaleConfig.sChain.nodes.0.id (inside skaled node indexes are 0 based) + * so one should pass the following as calldata: + * toBytes( input.length + toBytes(input) ) + */ ETH_REGISTER_PRECOMPILED( getConfigVariableUint256 )( bytesConstRef _in ) { try { size_t lengthName; @@ -767,18 +805,33 @@ ETH_REGISTER_PRECOMPILED( getConfigVariableUint256 )( bytesConstRef _in ) { if ( !g_configAccesssor ) throw std::runtime_error( "Config accessor was not initialized" ); - nlohmann::json joConfig = g_configAccesssor->getConfigJSON(); - nlohmann::json joValue = - skutils::json_config_file_accessor::stat_extract_at_path( joConfig, rawName ); - std::string strValue = skutils::tools::trim_copy( - joValue.is_string() ? joValue.get< std::string >() : joValue.dump() ); - // dev::u256 uValue( strValue.c_str() ); - dev::u256 uValue = stat_parse_u256_hex_or_dec( strValue ); - // std::cout << "------------ Loaded config var \"" - // << rawName << "\" value is " << uValue - // << "\n"; + std::string strValue; + // call to skaleConfig.sChain.nodes means call to the historic data + // need to proccess it in a different way + if ( isCallToHistoricData( rawName ) && PrecompiledConfigPatch::isEnabled() ) { + if ( !g_skaleHost ) + throw std::runtime_error( "SkaleHost accessor was not initialized" ); + + std::string field; + unsigned id; + std::tie( field, id ) = parseHistoricFieldRequest( rawName ); + if ( field == "id" ) { + strValue = g_skaleHost->getHistoricNodeId( id ); + } else if ( field == "schainIndex" ) { + strValue = g_skaleHost->getHistoricNodeIndex( id ); + } else { + throw std::runtime_error( "Incorrect config field" ); + } + } else { + nlohmann::json joConfig = g_configAccesssor->getConfigJSON(); + nlohmann::json joValue = + skutils::json_config_file_accessor::stat_extract_at_path( joConfig, rawName ); + strValue = skutils::tools::trim_copy( + joValue.is_string() ? joValue.get< std::string >() : joValue.dump() ); + } + dev::u256 uValue = jsToInt( strValue ); bytes response = toBigEndian( uValue ); return { true, response }; } catch ( std::exception& ex ) { @@ -807,13 +860,14 @@ ETH_REGISTER_PRECOMPILED( getConfigVariableAddress )( bytesConstRef _in ) { if ( !g_configAccesssor ) throw std::runtime_error( "Config accessor was not initialized" ); + nlohmann::json joConfig = g_configAccesssor->getConfigJSON(); nlohmann::json joValue = skutils::json_config_file_accessor::stat_extract_at_path( joConfig, rawName ); std::string strValue = skutils::tools::trim_copy( joValue.is_string() ? joValue.get< std::string >() : joValue.dump() ); - dev::u256 uValue( strValue.c_str() ); + dev::u256 uValue( strValue ); bytes response = toBigEndian( uValue ); return { true, response }; } catch ( std::exception& ex ) { @@ -831,6 +885,24 @@ ETH_REGISTER_PRECOMPILED( getConfigVariableAddress )( bytesConstRef _in ) { return { false, response }; // 1st false - means bad error occur } +/* + * this precompiled contract is designed to get access to specific config values that are + * strings and works as key / values map input: bytes - length + path to config variable output: + * bytes - config variable value + * + * variables available through this precompiled contract: + * 1. publicKey - ETH public key for INDEX node in schain group for current block number + * to access those variables one should use the following scheme: + * prefix=skaleConfig.sChain.nodes - to access corresponding structure inside skaled + * index - node index user wants to get access to + * field - the field user wants to request + * + * example: + * to request the value for 2-nd node (1 based) for the publicKey field the input should be + * input=skaleConfig.sChain.nodes.1.publicKey (inside skaled node indexes are 0 based) + * so one should pass the following as calldata + * toBytes( input.length + toBytes(input) ) + */ ETH_REGISTER_PRECOMPILED( getConfigVariableString )( bytesConstRef _in ) { try { size_t lengthName; @@ -842,11 +914,29 @@ ETH_REGISTER_PRECOMPILED( getConfigVariableString )( bytesConstRef _in ) { if ( !g_configAccesssor ) throw std::runtime_error( "Config accessor was not initialized" ); - nlohmann::json joConfig = g_configAccesssor->getConfigJSON(); - nlohmann::json joValue = - skutils::json_config_file_accessor::stat_extract_at_path( joConfig, rawName ); - std::string strValue = joValue.is_string() ? joValue.get< std::string >() : joValue.dump(); - bytes response = stat_string_to_bytes_with_length( strValue ); + std::string strValue; + // call to skaleConfig.sChain.nodes means call to the historic data + // need to proccess it in a different way + if ( isCallToHistoricData( rawName ) && PrecompiledConfigPatch::isEnabled() ) { + if ( !g_skaleHost ) + throw std::runtime_error( "SkaleHost accessor was not initialized" ); + + std::string field; + unsigned id; + std::tie( field, id ) = parseHistoricFieldRequest( rawName ); + if ( field == "publicKey" ) { + strValue = g_skaleHost->getHistoricNodePublicKey( id ); + } else { + throw std::runtime_error( "Incorrect config field" ); + } + } else { + nlohmann::json joConfig = g_configAccesssor->getConfigJSON(); + nlohmann::json joValue = + skutils::json_config_file_accessor::stat_extract_at_path( joConfig, rawName ); + strValue = skutils::tools::trim_copy( + joValue.is_string() ? joValue.get< std::string >() : joValue.dump() ); + } + bytes response = dev::fromHex( strValue ); return { true, response }; } catch ( std::exception& ex ) { std::string strError = ex.what(); diff --git a/libethereum/SkaleHost.cpp b/libethereum/SkaleHost.cpp index 1f15035fe..01434a060 100644 --- a/libethereum/SkaleHost.cpp +++ b/libethereum/SkaleHost.cpp @@ -66,6 +66,8 @@ using namespace dev::eth; #define CONSENSUS 1 #endif +const int SkaleHost::REJECT_OLD_TRANSACTION_THROUGH_BROADCAST_INTERVAL_SEC = 600; + std::unique_ptr< ConsensusInterface > DefaultConsensusFactory::create( ConsensusExtFace& _extFace ) const { #if CONSENSUS @@ -325,6 +327,13 @@ void SkaleHost::logState() { } h256 SkaleHost::receiveTransaction( std::string _rlp ) { + // drop incoming transactions if skaled has an outdated state + if ( m_client.bc().info().timestamp() + REJECT_OLD_TRANSACTION_THROUGH_BROADCAST_INTERVAL_SEC < + std::time( NULL ) ) { + LOG( m_debugLogger ) << "Dropped the transaction received through broadcast"; + return h256(); + } + Transaction transaction( jsToBytes( _rlp, OnFailed::Throw ), CheckTransaction::None ); h256 sha = transaction.sha3(); @@ -571,13 +580,12 @@ void SkaleHost::createBlock( const ConsensusExtFace::transactions_vector& _appro std::lock_guard< std::recursive_mutex > lock( m_pending_createMutex ); if ( m_ignoreNewBlocks ) { - clog( VerbosityWarning, "skale-host" ) << "WARNING: skaled got new block #" << _blockID - << " after timestamp-related exit initiated!"; + LOG( m_warningLogger ) << "WARNING: skaled got new block #" << _blockID + << " after timestamp-related exit initiated!"; return; } - LOG( m_debugLogger ) << cc::debug( "createBlock " ) << cc::notice( "ID" ) << cc::debug( " = " ) - << cc::warn( "#" ) << cc::num10( _blockID ) << std::endl; + LOG( m_debugLogger ) << "createBlock ID = #" << _blockID; m_debugTracer.tracepoint( "create_block" ); // convert bytes back to transactions (using caching), delete them from q and push results into @@ -587,23 +595,18 @@ void SkaleHost::createBlock( const ConsensusExtFace::transactions_vector& _appro dev::h256 stCurrent = this->m_client.blockInfo( this->m_client.hashFromNumber( _blockID - 1 ) ).stateRoot(); - LOG( m_traceLogger ) << cc::debug( "STATE ROOT FOR BLOCK: " ) - << cc::debug( std::to_string( _blockID - 1 ) ) << ' ' - << cc::debug( stCurrent.hex() ) << std::endl; + LOG( m_traceLogger ) << "STATE ROOT FOR BLOCK: " << std::to_string( _blockID - 1 ) << " " + << stCurrent.hex(); // FATAL if mismatch in non-default if ( _winningNodeIndex != 0 && dev::h256::Arith( stCurrent ) != _stateRoot && !this->m_client.chainParams().nodeInfo.syncNode ) { - clog( VerbosityError, "skale-host" ) - << cc::fatal( "FATAL STATE ROOT MISMATCH ERROR:" ) - << cc::error( " current state root " ) - << cc::warn( dev::h256::Arith( stCurrent ).str() ) - << cc::error( " is not equal to arrived state root " ) - << cc::warn( _stateRoot.str() ) << cc::error( " with block ID " ) - << cc::notice( "#" ) << cc::num10( _blockID ) << cc::warn( ", " ) - << cc::p( "/data_dir" ) - << cc::error( " cleanup is recommended, exiting with code " ) - << cc::num10( int( ExitHandler::ec_state_root_mismatch ) ) << "..."; + LOG( m_errorLogger ) << "FATAL STATE ROOT MISMATCH ERROR: current state root " + << dev::h256::Arith( stCurrent ).str() + << " is not equal to arrived state root " << _stateRoot.str() + << " with block ID #" << _blockID + << ", /data_dir cleanup is recommended, exiting with code " + << int( ExitHandler::ec_state_root_mismatch ) << "..."; if ( AmsterdamFixPatch::stateRootCheckingEnabled( m_client ) ) { m_ignoreNewBlocks = true; m_consensus->exitGracefully(); @@ -613,16 +616,14 @@ void SkaleHost::createBlock( const ConsensusExtFace::transactions_vector& _appro // WARN if default but non-zero if ( _winningNodeIndex == 0 && _stateRoot != u256() ) - clog( VerbosityWarning, "skale-host" ) - << cc::warn( "WARNING: STATE ROOT MISMATCH!" ) - << cc::warn( " Current block is DEFAULT BUT arrived state root is " ) - << cc::warn( _stateRoot.str() ) << cc::warn( " with block ID " ) - << cc::notice( "#" ) << cc::num10( _blockID ); + LOG( m_warningLogger ) << "WARNING: STATE ROOT MISMATCH!" + << "Current block is DEFAULT BUT arrived state root is " + << _stateRoot.str() << " with block ID #" << _blockID; } std::vector< Transaction > out_txns; // resultant Transaction vector - std::atomic_bool have_consensus_born = false; // means we need to re-verify old txns + std::atomic_bool haveConsensusBorn = false; // means we need to re-verify old txns // HACK this is for not allowing new transactions in tq between deletion and block creation! // TODO decouple SkaleHost and Client!!! @@ -636,11 +637,11 @@ void SkaleHost::createBlock( const ConsensusExtFace::transactions_vector& _appro for ( auto it = _approvedTransactions.begin(); it != _approvedTransactions.end(); ++it ) { const bytes& data = *it; h256 sha = sha3( data ); - LOG( m_traceLogger ) << cc::debug( "Arrived txn: " ) << sha << std::endl; + LOG( m_traceLogger ) << "Arrived txn: " << sha; jarrProcessedTxns.push_back( toJS( sha ) ); #ifdef DEBUG_TX_BALANCE if ( sent.count( sha ) != m_transaction_cache.count( sha.asArray() ) ) { - std::cerr << cc::error( "createBlock assert" ) << std::endl; + LOG( m_errorLogger ) << "createBlock assert"; // sleep(200); assert( sent.count( sha ) == m_transaction_cache.count( sha.asArray() ) ); } @@ -652,6 +653,7 @@ void SkaleHost::createBlock( const ConsensusExtFace::transactions_vector& _appro // TODO clear occasionally this cache?! if ( m_m_transaction_cache.find( sha.asArray() ) != m_m_transaction_cache.cend() ) { Transaction t = m_m_transaction_cache.at( sha.asArray() ); + t.checkOutExternalGas( m_client.chainParams(), m_client.number(), true ); out_txns.push_back( t ); LOG( m_debugLogger ) << "Dropping good txn " << sha << std::endl; m_debugTracer.tracepoint( "drop_good" ); @@ -665,16 +667,16 @@ void SkaleHost::createBlock( const ConsensusExtFace::transactions_vector& _appro // ).detach(); } else { Transaction t( data, CheckTransaction::Everything, true ); - t.checkOutExternalGas( m_client.chainParams().externalGasDifficulty ); + t.checkOutExternalGas( m_client.chainParams(), m_client.number() ); out_txns.push_back( t ); - LOG( m_debugLogger ) << "Will import consensus-born txn!"; + LOG( m_debugLogger ) << "Will import consensus-born txn"; m_debugTracer.tracepoint( "import_consensus_born" ); - have_consensus_born = true; + haveConsensusBorn = true; } + if ( m_tq.knownTransactions().count( sha ) != 0 ) { - // TODO fix this!!? - clog( VerbosityWarning, "skale-host" ) - << "Consensus returned 'future'' transaction that we didn't yet send!!"; + LOG( m_traceLogger ) + << "Consensus returned future transaction that we didn't yet send"; m_debugTracer.tracepoint( "import_future" ); } @@ -707,35 +709,33 @@ void SkaleHost::createBlock( const ConsensusExtFace::transactions_vector& _appro boost::chrono::high_resolution_clock::time_point skaledTimeFinish = boost::chrono::high_resolution_clock::now(); if ( latestBlockTime != boost::chrono::high_resolution_clock::time_point() ) { - clog( VerbosityInfo, "skale-host" ) - << "SWT:" - << boost::chrono::duration_cast< boost::chrono::milliseconds >( - skaledTimeFinish - skaledTimeStart ) - .count() - << ':' << "BFT:" - << boost::chrono::duration_cast< boost::chrono::milliseconds >( - skaledTimeFinish - latestBlockTime ) - .count(); + LOG( m_infoLogger ) << "SWT:" + << boost::chrono::duration_cast< boost::chrono::milliseconds >( + skaledTimeFinish - skaledTimeStart ) + .count() + << ':' << "BFT:" + << boost::chrono::duration_cast< boost::chrono::milliseconds >( + skaledTimeFinish - latestBlockTime ) + .count(); } else { - clog( VerbosityInfo, "skale-host" ) - << "SWT:" - << boost::chrono::duration_cast< boost::chrono::milliseconds >( - skaledTimeFinish - skaledTimeStart ) - .count(); + LOG( m_infoLogger ) << "SWT:" + << boost::chrono::duration_cast< boost::chrono::milliseconds >( + skaledTimeFinish - skaledTimeStart ) + .count(); } latestBlockTime = skaledTimeFinish; - LOG( m_debugLogger ) << cc::success( "Successfully imported " ) << n_succeeded - << cc::success( " of " ) << out_txns.size() - << cc::success( " transactions" ) << std::endl; + LOG( m_debugLogger ) << "Successfully imported " << n_succeeded << " of " << out_txns.size() + << " transactions"; - if ( have_consensus_born ) + if ( haveConsensusBorn ) this->m_lastBlockWithBornTransactions = _blockID; logState(); - clog( VerbosityInfo, "skale-host" ) - << "TQBYTES:CTQ:" << m_tq.status().currentBytes << ":FTQ:" << m_tq.status().futureBytes - << ":TQSIZE:CTQ:" << m_tq.status().current << ":FTQ:" << m_tq.status().future; + LOG( m_infoLogger ) << "TQBYTES:CTQ:" << m_tq.status().currentBytes + << ":FTQ:" << m_tq.status().futureBytes + << ":TQSIZE:CTQ:" << m_tq.status().current + << ":FTQ:" << m_tq.status().future; if ( m_instanceMonitor != nullptr ) { if ( m_instanceMonitor->isTimeToRotate( _timeStamp ) ) { @@ -743,15 +743,15 @@ void SkaleHost::createBlock( const ConsensusExtFace::transactions_vector& _appro m_ignoreNewBlocks = true; m_consensus->exitGracefully(); ExitHandler::exitHandler( -1, ExitHandler::ec_rotation_complete ); - clog( VerbosityInfo, "skale-host" ) << "Rotation is completed. Instance is exiting"; + LOG( m_infoLogger ) << "Rotation is completed. Instance is exiting"; } } } catch ( const std::exception& ex ) { - cerror << "CRITICAL " << ex.what() << " (in createBlock)"; - cerror << "\n" << skutils::signal::generate_stack_trace() << "\n" << std::endl; + LOG( m_errorLogger ) << "CRITICAL " << ex.what() << " (in createBlock)"; + LOG( m_errorLogger ) << "\n" << skutils::signal::generate_stack_trace() << "\n"; } catch ( ... ) { - cerror << "CRITICAL unknown exception (in createBlock)"; - cerror << "\n" << skutils::signal::generate_stack_trace() << "\n" << std::endl; + LOG( m_errorLogger ) << "CRITICAL unknown exception (in createBlock)"; + LOG( m_errorLogger ) << "\n" << skutils::signal::generate_stack_trace() << "\n"; } void SkaleHost::startWorking() { @@ -762,27 +762,26 @@ void SkaleHost::startWorking() { // recursively calls this func - so working is still false!) working = true; - if ( !this->m_client.chainParams().nodeInfo.syncNode ) { - try { - m_broadcaster->startService(); - } catch ( const Broadcaster::StartupException& ) { - working = false; - std::throw_with_nested( SkaleHost::CreationException() ); - } - - auto bcast_func = std::bind( &SkaleHost::broadcastFunc, this ); - m_broadcastThread = std::thread( bcast_func ); + try { + m_broadcaster->startService(); + } catch ( const Broadcaster::StartupException& ) { + working = false; + std::throw_with_nested( SkaleHost::CreationException() ); + } catch ( ... ) { + working = false; + std::throw_with_nested( std::runtime_error( "Error in starting broadcaster service" ) ); } - auto csus_func = [&]() { + auto broadcastFunction = std::bind( &SkaleHost::broadcastFunc, this ); + m_broadcastThread = std::thread( broadcastFunction ); + + auto consensusFunction = [&]() { try { m_consensus->startAll(); - } catch ( const std::exception& ) { + } catch ( ... ) { // cleanup m_exitNeeded = true; - if ( !this->m_client.chainParams().nodeInfo.syncNode ) { - m_broadcastThread.join(); - } + m_broadcastThread.join(); ExitHandler::exitHandler( -1, ExitHandler::ec_termninated_by_signal ); return; } @@ -813,7 +812,7 @@ void SkaleHost::startWorking() { // m_consensus->setEmptyBlockIntervalMs( tmp_interval ); }; // func - m_consensusThread = std::thread( csus_func ); + m_consensusThread = std::thread( consensusFunction ); } // TODO finish all gracefully to allow all undone jobs be finished @@ -942,6 +941,21 @@ u256 SkaleHost::getBlockRandom() const { return m_consensus->getRandomForBlockId( m_client.number() ); } +dev::eth::SyncStatus SkaleHost::syncStatus() const { + if ( !m_consensus ) + BOOST_THROW_EXCEPTION( std::runtime_error( "Consensus was not initialized" ) ); + auto syncInfo = m_consensus->getSyncInfo(); + dev::eth::SyncStatus syncStatus; + // SKALE: catchup downloads blocks with transactions, then the node executes them + // we don't download state changes separately + syncStatus.state = syncInfo.isSyncing ? dev::eth::SyncState::Blocks : dev::eth::SyncState::Idle; + syncStatus.startBlockNumber = syncInfo.startingBlock; + syncStatus.currentBlockNumber = syncInfo.currentBlock; + syncStatus.highestBlockNumber = syncInfo.highestBlock; + syncStatus.majorSyncing = syncInfo.isSyncing; + return syncStatus; +} + std::map< std::string, uint64_t > SkaleHost::getConsensusDbUsage() const { return m_consensus->getConsensusDbUsage(); } @@ -950,6 +964,18 @@ std::array< std::string, 4 > SkaleHost::getIMABLSPublicKey() const { return m_client.getIMABLSPublicKey(); } +std::string SkaleHost::getHistoricNodeId( unsigned _id ) const { + return m_client.getHistoricNodeId( _id ); +} + +std::string SkaleHost::getHistoricNodeIndex( unsigned _index ) const { + return m_client.getHistoricNodeIndex( _index ); +} + +std::string SkaleHost::getHistoricNodePublicKey( unsigned _idx ) const { + return m_client.getHistoricNodePublicKey( _idx ); +} + uint64_t SkaleHost::submitOracleRequest( const string& _spec, string& _receipt, string& _errorMessage ) { return m_consensus->submitOracleRequest( _spec, _receipt, _errorMessage ); diff --git a/libethereum/SkaleHost.h b/libethereum/SkaleHost.h index bb79d5d60..8ffce7aca 100644 --- a/libethereum/SkaleHost.h +++ b/libethereum/SkaleHost.h @@ -51,6 +51,7 @@ namespace dev { namespace eth { +struct SyncStatus; class Client; class TransactionQueue; class BlockHeader; @@ -123,9 +124,19 @@ class SkaleHost { dev::u256 getGasPrice() const; dev::u256 getBlockRandom() const; + dev::eth::SyncStatus syncStatus() const; std::map< std::string, uint64_t > getConsensusDbUsage() const; std::array< std::string, 4 > getIMABLSPublicKey() const; + // get node id for historic node in chain + std::string getHistoricNodeId( unsigned _id ) const; + + // get schain index for historic node in chain + std::string getHistoricNodeIndex( unsigned _idx ) const; + + // get public key for historic node in chain + std::string getHistoricNodePublicKey( unsigned _idx ) const; + uint64_t submitOracleRequest( const string& _spec, string& _receipt, string& _errorMessage ); uint64_t checkOracleResult( const string& _receipt, string& _result ); @@ -193,6 +204,10 @@ class SkaleHost { bool m_broadcastEnabled; + + dev::Logger m_errorLogger{ dev::createLogger( dev::VerbosityError, "skale-host" ) }; + dev::Logger m_warningLogger{ dev::createLogger( dev::VerbosityWarning, "skale-host" ) }; + dev::Logger m_infoLogger{ dev::createLogger( dev::VerbosityInfo, "skale-host" ) }; dev::Logger m_debugLogger{ dev::createLogger( dev::VerbosityDebug, "skale-host" ) }; dev::Logger m_traceLogger{ dev::createLogger( dev::VerbosityTrace, "skale-host" ) }; void logState(); @@ -214,4 +229,8 @@ class SkaleHost { std::atomic_int total_sent, total_arrived; boost::chrono::high_resolution_clock::time_point latestBlockTime; + + // reject old transactions that come through broadcast + // if current ts is much bigger than currentBlock.ts + static const int REJECT_OLD_TRANSACTION_THROUGH_BROADCAST_INTERVAL_SEC; }; diff --git a/libethereum/Transaction.cpp b/libethereum/Transaction.cpp index 1645c30c3..de556a0f9 100644 --- a/libethereum/Transaction.cpp +++ b/libethereum/Transaction.cpp @@ -29,6 +29,7 @@ #include #include #include +#include using namespace std; using namespace dev; @@ -180,19 +181,32 @@ u256 Transaction::gasPrice() const { } } -void Transaction::checkOutExternalGas( u256 const& _difficulty ) { - assert( _difficulty > 0 ); - if ( !m_externalGasIsChecked && !isInvalid() ) { +void Transaction::checkOutExternalGas( const ChainParams& _cp, uint64_t _bn, bool _force ) { + u256 const& difficulty = _cp.externalGasDifficulty; + assert( difficulty > 0 ); + if ( ( _force || !m_externalGasIsChecked ) && !isInvalid() ) { h256 hash = dev::sha3( sender().ref() ) ^ dev::sha3( nonce() ) ^ dev::sha3( gasPrice() ); if ( !hash ) { hash = h256( 1 ); } - u256 externalGas = ~u256( 0 ) / u256( hash ) / _difficulty; + u256 externalGas = ~u256( 0 ) / u256( hash ) / difficulty; if ( externalGas > 0 ) ctrace << "Mined gas: " << externalGas << endl; - if ( externalGas >= baseGasRequired( ConstantinopleSchedule ) ) { - m_externalGas = externalGas; + + EVMSchedule scheduleForUse = ConstantinopleSchedule; + if ( CorrectForkInPowPatch::isEnabled() ) + scheduleForUse = _cp.scheduleForBlockNumber( _bn ); + + // never call checkOutExternalGas with non-last block + if ( _bn != CorrectForkInPowPatch::getLastBlockNumber() ) { + ctrace << _bn << " != " << CorrectForkInPowPatch::getLastBlockNumber(); + BOOST_THROW_EXCEPTION( std::runtime_error( + "Internal error: checkOutExternalGas() has invalid block number" ) ); } + + if ( externalGas >= baseGasRequired( scheduleForUse ) ) + m_externalGas = externalGas; + m_externalGasIsChecked = true; } } diff --git a/libethereum/Transaction.h b/libethereum/Transaction.h index 6764bce5a..dffadb347 100644 --- a/libethereum/Transaction.h +++ b/libethereum/Transaction.h @@ -29,6 +29,8 @@ #include #include +#include "ChainParams.h" + namespace dev { namespace eth { @@ -120,7 +122,12 @@ class Transaction : public TransactionBase { u256 gasPrice() const; - void checkOutExternalGas( u256 const& _difficulty ); + void checkOutExternalGas( const ChainParams& _cp, uint64_t _bn, bool _force = false ); + + void ignoreExternalGas() { + m_externalGasIsChecked = true; + m_externalGas = 0; + } private: bool m_externalGasIsChecked = false; diff --git a/libethereum/ValidationSchemes.cpp b/libethereum/ValidationSchemes.cpp index 38231c130..1f7243e31 100644 --- a/libethereum/ValidationSchemes.cpp +++ b/libethereum/ValidationSchemes.cpp @@ -268,8 +268,14 @@ void validateConfigJson( js::mObject const& _obj ) { { "storageDestructionPatchTimestamp", { { js::int_type }, JsonFieldPresence::Optional } }, { "powCheckPatchTimestamp", { { js::int_type }, JsonFieldPresence::Optional } }, + { "pushZeroPatchTimestamp", { { js::int_type }, JsonFieldPresence::Optional } }, + { "nodeGroups", { { js::obj_type }, JsonFieldPresence::Optional } }, { "nodeGroups", { { js::obj_type }, JsonFieldPresence::Optional } }, { "skipInvalidTransactionsPatchTimestamp", + { { js::int_type }, JsonFieldPresence::Optional } }, + { "precompiledConfigPatchTimestamp", + { { js::int_type }, JsonFieldPresence::Optional } }, + { "correctForkInPowPatchTimestamp", { { js::int_type }, JsonFieldPresence::Optional } } } ); js::mArray const& nodes = sChain.at( "nodes" ).get_array(); diff --git a/libevm/Instruction.cpp b/libevm/Instruction.cpp index 78e8eec2d..bb4f25d20 100644 --- a/libevm/Instruction.cpp +++ b/libevm/Instruction.cpp @@ -86,6 +86,10 @@ static const std::map c_instructionInfo = { Instruction::MSIZE, { "MSIZE", 0, 1, Tier::Base } }, { Instruction::GAS, { "GAS", 0, 1, Tier::Base } }, { Instruction::JUMPDEST, { "JUMPDEST", 0, 0, Tier::Special } }, + // As per EIP-3855 PUSH0 instruction tire is base (2 gas units) + // As all other PUSH instructions, it removes zero elements from stack and + // pushes 1 element to stack + { Instruction::PUSH0, { "PUSH0", 0, 1, Tier::Base } }, { Instruction::PUSH1, { "PUSH1", 0, 1, Tier::VeryLow } }, { Instruction::PUSH2, { "PUSH2", 0, 1, Tier::VeryLow } }, { Instruction::PUSH3, { "PUSH3", 0, 1, Tier::VeryLow } }, diff --git a/libevm/Instruction.h b/libevm/Instruction.h index 573b57107..0dc52bdad 100644 --- a/libevm/Instruction.h +++ b/libevm/Instruction.h @@ -94,6 +94,7 @@ enum class Instruction : uint8_t { GAS, ///< get the amount of available gas JUMPDEST, ///< set a potential jump destination + PUSH0 = 0x5f, // EIP-3855 PUSH1 = 0x60, ///< place 1 byte item on stack PUSH2, ///< place 2 byte item on stack PUSH3, ///< place 3 byte item on stack diff --git a/libevm/LegacyVM.cpp b/libevm/LegacyVM.cpp index 8a0775112..a987a3b0c 100644 --- a/libevm/LegacyVM.cpp +++ b/libevm/LegacyVM.cpp @@ -16,6 +16,7 @@ */ #include "LegacyVM.h" +#include "libskale/PushZeroPatch.h" using namespace std; using namespace dev; @@ -1355,6 +1356,21 @@ void LegacyVM::interpretCases() { } CONTINUE + // EIP-3855. Code PUSH0 is similar to PUSH1 but pushes 0 + // we need to increment program counter only by one since + // the value is not read from program code as in PUSH1 + CASE( PUSH0 ) { + if ( !PushZeroPatch::isEnabled() ) { + throwBadInstruction(); + } + ON_OP(); + updateIOGas(); + m_SPP[0] = 0; + ++m_PC; + }; + CONTINUE + + CASE( PUSH1 ) { ON_OP(); updateIOGas(); diff --git a/libevm/LegacyVMConfig.h b/libevm/LegacyVMConfig.h index 4b8bde611..9908d712c 100644 --- a/libevm/LegacyVMConfig.h +++ b/libevm/LegacyVMConfig.h @@ -254,7 +254,7 @@ namespace eth { &&BEGINDATA, \ &&BEGINSUB, \ &&INVALID, \ - &&INVALID, \ + &&PUSH0, /* EIP-3855 */ \ &&PUSH1, /* 60, */ \ &&PUSH2, \ &&PUSH3, \ diff --git a/libskale/CMakeLists.txt b/libskale/CMakeLists.txt index 73acfbbf5..1a0fb8ff1 100644 --- a/libskale/CMakeLists.txt +++ b/libskale/CMakeLists.txt @@ -20,7 +20,10 @@ set(sources OverlayFS.cpp StorageDestructionPatch.cpp POWCheckPatch.cpp + PrecompiledConfigPatch.cpp + PushZeroPatch.cpp SkipInvalidTransactionsPatch.cpp + CorrectForkInPowPatch.cpp ) set(headers @@ -39,8 +42,10 @@ set(headers AmsterdamFixPatch.h RevertableFSPatch.h POWCheckPatch.h + PrecompiledConfigPatch.h OverlayFS.h SkipInvalidTransactionsPatch.h + CorrectForkInPowPatch.h ) add_library(skale ${sources} ${headers}) diff --git a/libskale/CorrectForkInPowPatch.cpp b/libskale/CorrectForkInPowPatch.cpp new file mode 100644 index 000000000..aec18bc29 --- /dev/null +++ b/libskale/CorrectForkInPowPatch.cpp @@ -0,0 +1,12 @@ +#include "CorrectForkInPowPatch.h" + +time_t CorrectForkInPowPatch::activationTimestamp; +time_t CorrectForkInPowPatch::lastBlockTimestamp; +unsigned CorrectForkInPowPatch::lastBlockNumber; + +bool CorrectForkInPowPatch::isEnabled() { + if ( activationTimestamp == 0 ) { + return false; + } + return activationTimestamp <= lastBlockTimestamp; +} diff --git a/libskale/CorrectForkInPowPatch.h b/libskale/CorrectForkInPowPatch.h new file mode 100644 index 000000000..94c0f766e --- /dev/null +++ b/libskale/CorrectForkInPowPatch.h @@ -0,0 +1,41 @@ +#ifndef CORRECTFORKINPOWPATCH_H +#define CORRECTFORKINPOWPATCH_H + +#include + +#include + +namespace dev { +namespace eth { +class Client; +} +namespace test { +class TestBlockChain; +class TestOutputHelperFixture; +} // namespace test +} // namespace dev + +/* + * Context: use current, and not Constantinople, fork in Transaction::checkOutExternalGas() + */ +class CorrectForkInPowPatch : public SchainPatch { +public: + static bool isEnabled(); + + static void setTimestamp( time_t _timeStamp ) { + printInfo( __FILE__, _timeStamp ); + activationTimestamp = _timeStamp; + } + + static unsigned getLastBlockNumber() { return lastBlockNumber; } + +private: + friend class dev::eth::Client; + friend class dev::test::TestBlockChain; + friend class dev::test::TestOutputHelperFixture; + static time_t activationTimestamp; + static time_t lastBlockTimestamp; + static unsigned lastBlockNumber; +}; + +#endif // CORRECTFORKINPOWPATCH_H diff --git a/libskale/PrecompiledConfigPatch.cpp b/libskale/PrecompiledConfigPatch.cpp new file mode 100644 index 000000000..f36557d61 --- /dev/null +++ b/libskale/PrecompiledConfigPatch.cpp @@ -0,0 +1,11 @@ +#include "PrecompiledConfigPatch.h" + +time_t PrecompiledConfigPatch::precompiledConfigPatchTimestamp; +time_t PrecompiledConfigPatch::lastBlockTimestamp; + +bool PrecompiledConfigPatch::isEnabled() { + if ( precompiledConfigPatchTimestamp == 0 ) { + return false; + } + return precompiledConfigPatchTimestamp <= lastBlockTimestamp; +} diff --git a/libskale/PrecompiledConfigPatch.h b/libskale/PrecompiledConfigPatch.h new file mode 100644 index 000000000..776dd47cc --- /dev/null +++ b/libskale/PrecompiledConfigPatch.h @@ -0,0 +1,32 @@ +#ifndef PRECOMPILEDCONFIGPATCH_H +#define PRECOMPILEDCONFIGPATCH_H + +#include +#include + +namespace dev { +namespace eth { +class Client; +} +} // namespace dev + +/* + * Context: enable precompiled contracts to read historical config data + */ +class PrecompiledConfigPatch : public SchainPatch { +public: + static bool isEnabled(); + + static void setTimestamp( time_t _timeStamp ) { + printInfo( __FILE__, _timeStamp ); + precompiledConfigPatchTimestamp = _timeStamp; + } + +private: + friend class dev::eth::Client; + static time_t precompiledConfigPatchTimestamp; + static time_t lastBlockTimestamp; +}; + + +#endif // PRECOMPILEDCONFIGPATCH_H diff --git a/libskale/PushZeroPatch.cpp b/libskale/PushZeroPatch.cpp new file mode 100644 index 000000000..e7ef4f6c1 --- /dev/null +++ b/libskale/PushZeroPatch.cpp @@ -0,0 +1,11 @@ +#include "PushZeroPatch.h" + +time_t PushZeroPatch::pushZeroPatchTimestamp; +time_t PushZeroPatch::lastBlockTimestamp; + +bool PushZeroPatch::isEnabled() { + if ( pushZeroPatchTimestamp == 0 ) { + return false; + } + return pushZeroPatchTimestamp <= lastBlockTimestamp; +} diff --git a/libskale/PushZeroPatch.h b/libskale/PushZeroPatch.h new file mode 100644 index 000000000..6ebab4e9f --- /dev/null +++ b/libskale/PushZeroPatch.h @@ -0,0 +1,27 @@ +#include +#include + +namespace dev { +namespace eth { +class Client; +} +} // namespace dev + +/* + * Context: enable effective storage destruction + */ +class PushZeroPatch : public SchainPatch { +public: + static bool isEnabled(); + + static void setTimestamp( time_t _timeStamp ) { + printInfo( __FILE__, _timeStamp ); + pushZeroPatchTimestamp = _timeStamp; + } + + +private: + friend class dev::eth::Client; + static time_t pushZeroPatchTimestamp; + static time_t lastBlockTimestamp; +}; \ No newline at end of file diff --git a/libskale/SnapshotManager.cpp b/libskale/SnapshotManager.cpp index d3c3bc04e..8729d2a74 100644 --- a/libskale/SnapshotManager.cpp +++ b/libskale/SnapshotManager.cpp @@ -445,13 +445,25 @@ void SnapshotManager::computeDatabaseHash( BOOST_THROW_EXCEPTION( InvalidPath( _dbDir ) ); } - std::unique_ptr< dev::db::LevelDB > m_db( new dev::db::LevelDB( _dbDir.string(), - dev::db::LevelDB::defaultSnapshotReadOptions(), dev::db::LevelDB::defaultWriteOptions(), - dev::db::LevelDB::defaultSnapshotDBOptions() ) ); - dev::h256 hash_volume = m_db->hashBase(); - cnote << _dbDir << " hash is: " << hash_volume << std::endl; + secp256k1_sha256_t dbCtx; + secp256k1_sha256_initialize( &dbCtx ); - secp256k1_sha256_write( ctx, hash_volume.data(), hash_volume.size ); + std::string lastHashedKey = "start"; + bool isContinue = true; + + while ( isContinue ) { + std::unique_ptr< dev::db::LevelDB > m_db( new dev::db::LevelDB( _dbDir.string(), + dev::db::LevelDB::defaultSnapshotReadOptions(), dev::db::LevelDB::defaultWriteOptions(), + dev::db::LevelDB::defaultSnapshotDBOptions() ) ); + + isContinue = m_db->hashBasePartially( &dbCtx, lastHashedKey ); + } + + dev::h256 dbHash; + secp256k1_sha256_finalize( &dbCtx, dbHash.data() ); + cnote << _dbDir << " hash is: " << dbHash << std::endl; + + secp256k1_sha256_write( ctx, dbHash.data(), dbHash.size ); } catch ( const fs::filesystem_error& ex ) { std::throw_with_nested( CannotRead( ex.path1() ) ); } diff --git a/libskutils/src/http_pg.cpp b/libskutils/src/http_pg.cpp index fc2fb766d..83952d64c 100644 --- a/libskutils/src/http_pg.cpp +++ b/libskutils/src/http_pg.cpp @@ -203,6 +203,7 @@ void request_site::onEOM() noexcept { } else { std::string strOut = rslt.joOut_.dump(); bldr.header( "content-length", skutils::tools::format( "%zu", strOut.size() ) ); + bldr.header( "Content-Type", "application/json" ); bldr.body( strOut ); } bldr.sendWithEOM(); diff --git a/libweb3jsonrpc/Eth.cpp b/libweb3jsonrpc/Eth.cpp index 3f0c8413c..63d4a8ff3 100644 --- a/libweb3jsonrpc/Eth.cpp +++ b/libweb3jsonrpc/Eth.cpp @@ -66,6 +66,12 @@ void GappedTransactionIndexCache::ensureCached( BlockNumber _bn, _readLock.unlock(); _writeLock.lock(); + unsigned realBn = _bn; + if ( _bn == LatestBlock ) + realBn = client.number(); + else if ( _bn == PendingBlock ) + realBn = client.number() + 1; // TODO test this case and decide + assert( real2gappedCache.size() <= cacheSize ); if ( real2gappedCache.size() >= cacheSize ) { real2gappedCache.erase( real2gappedCache.begin() ); @@ -89,7 +95,7 @@ void GappedTransactionIndexCache::ensureCached( BlockNumber _bn, pair< h256, unsigned > loc = client.transactionLocation( th ); // ignore transactions with 0 gas usage OR different location! - if ( diff == 0 || client.numberFromHash( loc.first ) != _bn || loc.second != realIndex ) + if ( diff == 0 || client.numberFromHash( loc.first ) != realBn || loc.second != realIndex ) continue; // cache it @@ -135,28 +141,6 @@ Eth::Eth( const std::string& configPath, eth::Interface& _eth, eth::AccountHolde { } -bool Eth::isEnabledTransactionSending() const { - bool isEnabled = true; - try { - nlohmann::json joConfig = getConfigJSON(); - if ( joConfig.count( "skaleConfig" ) == 0 ) - throw std::runtime_error( "error config.json file, cannot find \"skaleConfig\"" ); - const nlohmann::json& joSkaleConfig = joConfig["skaleConfig"]; - if ( joSkaleConfig.count( "nodeInfo" ) == 0 ) - throw std::runtime_error( - "error config.json file, cannot find \"skaleConfig\"/\"nodeInfo\"" ); - const nlohmann::json& joSkaleConfig_nodeInfo = joSkaleConfig["nodeInfo"]; - if ( joSkaleConfig_nodeInfo.count( "syncNode" ) == 0 ) - throw std::runtime_error( - "error config.json file, cannot find " - "\"skaleConfig\"/\"nodeInfo\"/\"syncNode\"" ); - const nlohmann::json& joSkaleConfig_nodeInfo_syncNode = joSkaleConfig_nodeInfo["syncNode"]; - isEnabled = joSkaleConfig_nodeInfo_syncNode.get< bool >() ? false : true; - } catch ( ... ) { - } - return isEnabled; -} - string Eth::eth_protocolVersion() { return toJS( eth::c_protocolVersion ); } @@ -189,7 +173,10 @@ Json::Value Eth::eth_accounts() { return toJson( m_ethAccounts.allAccounts() ); } -string Eth::eth_blockNumber() { +string Eth::eth_blockNumber( const Json::Value& request ) { + if ( !request.empty() ) { + BOOST_THROW_EXCEPTION( JsonRpcException( Errors::ERROR_RPC_INVALID_PARAMS ) ); + } return toJS( client()->number() ); } @@ -381,8 +368,6 @@ void Eth::setTransactionDefaults( TransactionSkeleton& _t ) { string Eth::eth_sendTransaction( Json::Value const& _json ) { try { - if ( !isEnabledTransactionSending() ) - throw std::runtime_error( "transacton sending feature is disabled on this instance" ); TransactionSkeleton t = toTransactionSkeleton( _json ); setTransactionDefaults( t ); pair< bool, Secret > ar = m_ethAccounts.authenticate( t ); @@ -450,8 +435,6 @@ Json::Value Eth::eth_inspectTransaction( std::string const& _rlp ) { // TODO Catch exceptions for all calls other eth_-calls in outer scope! /// skale string Eth::eth_sendRawTransaction( std::string const& _rlp ) { - if ( !isEnabledTransactionSending() ) - throw JsonRpcException( "transacton sending feature is disabled on this instance" ); // Don't need to check the transaction signature (CheckTransaction::None) since it // will be checked as a part of transaction import Transaction t( jsToBytes( _rlp, OnFailed::Throw ), CheckTransaction::None ); @@ -889,15 +872,24 @@ Json::Value Eth::eth_getWork() { } Json::Value Eth::eth_syncing() { - dev::eth::SyncStatus sync = client()->syncStatus(); - if ( sync.state == SyncState::Idle || !sync.majorSyncing ) - return Json::Value( false ); - - Json::Value info( Json::objectValue ); - info["startingBlock"] = sync.startBlockNumber; - info["highestBlock"] = sync.highestBlockNumber; - info["currentBlock"] = sync.currentBlockNumber; - return info; + try { + auto client = this->client(); + if ( !client ) + BOOST_THROW_EXCEPTION( std::runtime_error( "Client was not initialized" ) ); + + // ask consensus whether the node is in catchup mode + dev::eth::SyncStatus sync = client->syncStatus(); + if ( !sync.majorSyncing ) + return Json::Value( false ); + + Json::Value info( Json::objectValue ); + info["startingBlock"] = sync.startBlockNumber; + info["highestBlock"] = sync.highestBlockNumber; + info["currentBlock"] = sync.currentBlockNumber; + return info; + } catch ( const Exception& e ) { + BOOST_THROW_EXCEPTION( jsonrpc::JsonRpcException( e.what() ) ); + } } string Eth::eth_chainId() { diff --git a/libweb3jsonrpc/Eth.h b/libweb3jsonrpc/Eth.h index a3ce404da..8059860d7 100644 --- a/libweb3jsonrpc/Eth.h +++ b/libweb3jsonrpc/Eth.h @@ -151,7 +151,7 @@ class Eth : public dev::rpc::EthFace, public skutils::json_config_file_accessor virtual bool eth_mining() override; virtual std::string eth_gasPrice() override; virtual Json::Value eth_accounts() override; - virtual std::string eth_blockNumber() override; + virtual std::string eth_blockNumber( const Json::Value& request ) override; virtual std::string eth_getBalance( std::string const& _address, std::string const& _blockNumber ) override; virtual std::string eth_getStorageAt( std::string const& _address, std::string const& _position, diff --git a/libweb3jsonrpc/EthFace.h b/libweb3jsonrpc/EthFace.h index 7c31b4f62..b7bafedd3 100644 --- a/libweb3jsonrpc/EthFace.h +++ b/libweb3jsonrpc/EthFace.h @@ -212,7 +212,7 @@ class EthFace : public ServerInterface< EthFace > { jsonrpc::JSON_OBJECT, NULL ), &dev::rpc::EthFace::eth_syncingI ); this->bindAndAddMethod( jsonrpc::Procedure( "eth_estimateGas", jsonrpc::PARAMS_BY_POSITION, - jsonrpc::JSON_STRING, "param1", jsonrpc::JSON_OBJECT, NULL ), + jsonrpc::JSON_STRING, NULL ), &dev::rpc::EthFace::eth_estimateGasI ); this->bindAndAddMethod( jsonrpc::Procedure( "eth_chainId", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, NULL ), @@ -244,8 +244,7 @@ class EthFace : public ServerInterface< EthFace > { response = this->eth_accounts(); } inline virtual void eth_blockNumberI( const Json::Value& request, Json::Value& response ) { - ( void ) request; - response = this->eth_blockNumber(); + response = this->eth_blockNumber( request ); } inline virtual void eth_getBalanceI( const Json::Value& request, Json::Value& response ) { response = this->eth_getBalance( request[0u].asString(), request[1u].asString() ); @@ -420,6 +419,9 @@ class EthFace : public ServerInterface< EthFace > { response = this->eth_syncing(); } inline virtual void eth_estimateGasI( const Json::Value& request, Json::Value& response ) { + if ( !request.isArray() || request.empty() ) + BOOST_THROW_EXCEPTION( + jsonrpc::JsonRpcException( jsonrpc::Errors::ERROR_RPC_INVALID_PARAMS ) ); response = this->eth_estimateGas( request[0u] ); } inline virtual void eth_chainIdI( const Json::Value& request, Json::Value& response ) { @@ -432,7 +434,7 @@ class EthFace : public ServerInterface< EthFace > { virtual bool eth_mining() = 0; virtual std::string eth_gasPrice() = 0; virtual Json::Value eth_accounts() = 0; - virtual std::string eth_blockNumber() = 0; + virtual std::string eth_blockNumber( const Json::Value& request ) = 0; virtual std::string eth_getBalance( const std::string& param1, const std::string& param2 ) = 0; virtual std::string eth_getStorageAt( const std::string& param1, const std::string& param2, const std::string& param3 ) = 0; diff --git a/libweb3jsonrpc/Net.cpp b/libweb3jsonrpc/Net.cpp index 8145dba5d..26ff582e6 100644 --- a/libweb3jsonrpc/Net.cpp +++ b/libweb3jsonrpc/Net.cpp @@ -35,7 +35,7 @@ Net::Net( const dev::eth::ChainParams& _chainParams ) : m_chainParams( _chainPar // TODO Ask here real values from consensus/broadcast std::string Net::net_version() { - return toJS( m_chainParams.chainID ); + return toString( m_chainParams.chainID ); } std::string Net::net_peerCount() { diff --git a/libweb3jsonrpc/Net.h b/libweb3jsonrpc/Net.h index bc53e0c2b..dbf63c355 100644 --- a/libweb3jsonrpc/Net.h +++ b/libweb3jsonrpc/Net.h @@ -44,7 +44,7 @@ class Net : public NetFace { virtual bool net_listening() override; private: - const dev::eth::ChainParams& m_chainParams; + const dev::eth::ChainParams m_chainParams; }; } // namespace rpc diff --git a/libweb3jsonrpc/Skale.cpp b/libweb3jsonrpc/Skale.cpp index 763c3af6c..27b71b1cb 100644 --- a/libweb3jsonrpc/Skale.cpp +++ b/libweb3jsonrpc/Skale.cpp @@ -158,6 +158,10 @@ nlohmann::json Skale::impl_skale_getSnapshot( const nlohmann::json& joRequest, C // TODO check unsigned blockNumber = joRequest["blockNumber"].get< unsigned >(); + if ( blockNumber != 0 && blockNumber != m_client.getLatestSnapshotBlockNumer() ) { + joResponse["error"] = "Invalid snapshot block number requested - it might be deleted."; + return joResponse; + } // exit if too early if ( currentSnapshotBlockNumber >= 0 ) { @@ -366,6 +370,11 @@ Json::Value Skale::skale_getSnapshotSignature( unsigned blockNumber ) { if ( chainParams.nodeInfo.keyShareName.empty() || chainParams.nodeInfo.sgxServerUrl.empty() ) throw jsonrpc::JsonRpcException( "Snapshot signing is not enabled" ); + if ( blockNumber != 0 && blockNumber != this->m_client.getLatestSnapshotBlockNumer() ) { + throw jsonrpc::JsonRpcException( + "Invalid snapshot block number requested - it might be deleted." ); + } + try { dev::h256 snapshot_hash = this->m_client.getSnapshotHash( blockNumber ); if ( !snapshot_hash ) diff --git a/scripts/build_and_publish.sh b/scripts/build_and_publish.sh index 366c6bc7b..f02f0b0c0 100644 --- a/scripts/build_and_publish.sh +++ b/scripts/build_and_publish.sh @@ -9,14 +9,17 @@ NAME=schain REPO_NAME=skalenetwork/$NAME IMAGE_NAME=$REPO_NAME:$VERSION -LABEL="develop" -if [ $BRANCH = "stable" ] -then - LABEL="stable" -elif [ $BRANCH = "beta" ] +# 3.17.0-develop.22 -> 3.17.0-develop +# 3.17.0-develop.22-hostoric -> 3.17.0-develop +LABEL="${VERSION%.*}" + +# 3.17.0 -> 3.17.0 +# 3.17.0-historic -> 3.17.0 +if [[ "$BRANCH" == "stable" ]] then - LABEL="beta" + LABEL=${VERSION%-historic} fi + LATEST_IMAGE_NAME=$REPO_NAME:$LABEL-latest if [[ $VERSION == *"historic" ]] @@ -44,8 +47,4 @@ echo "Built $IMAGE_NAME" echo "$DOCKER_PASSWORD" | docker login --username $DOCKER_USERNAME --password-stdin docker push $IMAGE_NAME || exit $? - -if [ $BRANCH = $LABEL ] -then - docker push $LATEST_IMAGE_NAME || exit $? -fi +docker push $LATEST_IMAGE_NAME || exit $? diff --git a/skaled/main.cpp b/skaled/main.cpp index 8118b017e..b0ad1aca8 100644 --- a/skaled/main.cpp +++ b/skaled/main.cpp @@ -274,8 +274,9 @@ void downloadSnapshot( unsigned block_number, std::shared_ptr< SnapshotManager > throw std::runtime_error( strErrorDescription ); } } catch ( ... ) { - std::throw_with_nested( - std::runtime_error( cc::error( "Exception while downloading snapshot" ) ) ); + // remove partially downloaded snapshot + boost::filesystem::remove( saveTo ); + std::throw_with_nested( std::runtime_error( "Exception while downloading snapshot" ) ); } clog( VerbosityInfo, "downloadSnapshot" ) << cc::success( "Snapshot download success for block " ) @@ -437,9 +438,9 @@ bool tryDownloadSnapshot( std::shared_ptr< SnapshotManager >& snapshotManager, try { snapshotManager->computeSnapshotHash( blockNumber, true ); } catch ( const std::exception& ) { - std::throw_with_nested( - std::runtime_error( cc::fatal( "FATAL:" ) + " " + - cc::error( "Exception while computing snapshot hash " ) ) ); + std::throw_with_nested( std::runtime_error( + std::string( "FATAL:" ) + + std::string( " Exception while computing snapshot hash " ) ) ); } dev::h256 calculated_hash = snapshotManager->getSnapshotHash( blockNumber ); @@ -448,18 +449,15 @@ bool tryDownloadSnapshot( std::shared_ptr< SnapshotManager >& snapshotManager, successfullDownload = true; if ( isRegularSnapshot ) { snapshotManager->restoreSnapshot( blockNumber ); - std::cout << cc::success( "Snapshot restore success for block " ) - << cc::u( to_string( blockNumber ) ) << std::endl; + std::cout << "Snapshot restore success for block " << to_string( blockNumber ) + << std::endl; } return successfullDownload; } else { clog( VerbosityWarning, "tryDownloadSnapshot" ) - << cc::notice( - "Downloaded snapshot with incorrect hash! Incoming " - "hash " ) - << cc::notice( votedHash.first.hex() ) - << cc::notice( " is not equal to calculated hash " ) - << cc::notice( calculated_hash.hex() ) << cc::notice( "Will try again" ); + << "Downloaded snapshot with incorrect hash! Incoming hash " + << votedHash.first.hex() << " is not equal to calculated hash " + << calculated_hash.hex() << " Will try again"; if ( isRegularSnapshot ) snapshotManager->cleanup(); else @@ -550,6 +548,7 @@ int main( int argc, char** argv ) try { cc::_on_ = false; cc::_max_value_size_ = 2048; MicroProfileSetEnableAllGroups( true ); + dev::setThreadName( "main" ); BlockHeader::useTimestampHack = false; srand( time( nullptr ) ); setCLocale(); @@ -2773,7 +2772,6 @@ int main( int argc, char** argv ) try { << cc::debug( "Done, programmatic shutdown via Web3 is disabled" ); } - dev::setThreadName( "main" ); if ( g_client ) { unsigned int n = g_client->blockChain().details().number; unsigned int mining = 0; diff --git a/storage_benchmark/CMakeLists.txt b/storage_benchmark/CMakeLists.txt index 8180d42dc..67b410f4b 100644 --- a/storage_benchmark/CMakeLists.txt +++ b/storage_benchmark/CMakeLists.txt @@ -20,6 +20,7 @@ target_link_libraries( historic skutils devcore + skale "${DEPS_INSTALL_ROOT}/lib/libunwind.a" "${DEPS_INSTALL_ROOT}/lib/liblzma.a" ) diff --git a/test/historicstate/configs/basic_config.json b/test/historicstate/configs/basic_config.json index aa5915277..ea3bbf1d6 100644 --- a/test/historicstate/configs/basic_config.json +++ b/test/historicstate/configs/basic_config.json @@ -322,10 +322,11 @@ "sChain": { "schainName": "TestChain", - "schainID": 1, + "schainID": 5, "schainOwner": "0x907cd0881E50d359bb9Fd120B1A5A143b1C97De6", "contractStorageLimit": 10000000000, "emptyBlockIntervalMs": 10000, + "pushZeroPatchTimestamp": 1, "nodes": [ { "nodeID": 1112, "ip": "127.0.0.1", "basePort": 1231, "schainIndex" : 1, "publicKey":""} ] diff --git a/test/historicstate/hardhat/contracts/Push0.sol b/test/historicstate/hardhat/contracts/Push0.sol new file mode 100644 index 000000000..e09e457b6 --- /dev/null +++ b/test/historicstate/hardhat/contracts/Push0.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +contract Push0 { + + uint256 public constant ZERO = 0; + + function getZero() public { + // this triggers compiler using push0 to stack since operations use lots of zeros + uint256 one = 0; + one = one + 1 + ZERO; + uint256 two = one * 0; + uint256 three = one * ZERO; + } +} \ No newline at end of file diff --git a/test/historicstate/hardhat/hardhat.config.js b/test/historicstate/hardhat/hardhat.config.js index d369e02ba..3ff48bfba 100644 --- a/test/historicstate/hardhat/hardhat.config.js +++ b/test/historicstate/hardhat/hardhat.config.js @@ -10,7 +10,7 @@ module.exports = { const INSECURE_PRIVATE_KEY = "bd200f4e7f597f3c2c77fb405ee7fabeb249f63f03f43d5927b4fa0c43cfe85e"; module.exports = { - solidity: "0.8.9", + solidity: "0.8.20", networks: { skaled: { url: `http://localhost:1234`, diff --git a/test/historicstate/hardhat/scripts/push0_test.ts b/test/historicstate/hardhat/scripts/push0_test.ts new file mode 100644 index 000000000..d76a0a934 --- /dev/null +++ b/test/historicstate/hardhat/scripts/push0_test.ts @@ -0,0 +1,71 @@ +const OWNER_ADDRESS: string = "0x907cd0881E50d359bb9Fd120B1A5A143b1C97De6"; +const ZERO_ADDRESS: string = "0xO000000000000000000000000000000000000000"; +const INITIAL_MINT: bigint = 10000000000000000000000000000000000000000; + +import {ethers} from "hardhat"; + +async function waitUntilNextBlock() { + + const current = await hre.ethers.provider.getBlockNumber(); + let newBlock = current; + console.log(`BLOCK_NUMBER ${current}`); + + while (newBlock == current) { + newBlock = await hre.ethers.provider.getBlockNumber(); + } + + console.log(`BLOCK_NUMBER ${newBlock}`); + + return current; + +} + +function CHECK(result: any): void { + if (!result) { + const message: string = `Check failed ${result}` + console.log(message); + throw message; + } +} + +async function getAndPrintTrace(hash: string): Promise { + + const trace = await ethers.provider.send('debug_traceTransaction', [hash, {}]); + + console.log(JSON.stringify(trace, null, 4)); + return trace; +} + +async function deployWriteAndDestroy(): Promise { + + console.log(`Deploying ...`); + + const Push0Test = await ethers.getContractFactory("Push0"); + const test = await Push0Test.deploy(); + const testContract = await test.deployed(); + + + const deployBn = await ethers.provider.getBlockNumber(); + + const hash = testContract.deployTransaction.hash; + console.log(`Gas limit ${testContract.deployTransaction.gasLimit}`); + console.log(`Contract deployed to ${testContract.address} at block ${deployBn} tx hash ${hash}`); + + console.log(`Now testing`); + + const transferReceipt = await testContract.getZero() + console.log(`Gas limit ${transferReceipt.gasLimit}`); + + +} + +async function main(): Promise { + await deployWriteAndDestroy(); +} + +// We recommend this pattern to be able to use async/await everywhere +// and properly handle errors. +main().catch((error: any) => { + console.error(error); + process.exitCode = 1; +}); \ No newline at end of file diff --git a/test/tools/libtesteth/BlockChainHelper.cpp b/test/tools/libtesteth/BlockChainHelper.cpp index fbdaf71be..757ac6169 100644 --- a/test/tools/libtesteth/BlockChainHelper.cpp +++ b/test/tools/libtesteth/BlockChainHelper.cpp @@ -21,6 +21,8 @@ * that manage block/transaction import and test mining */ +#include + #include #include #include @@ -473,6 +475,10 @@ void TestBlockChain::reset( TestBlock const& _genesisBlock ) { } bool TestBlockChain::addBlock( TestBlock const& _block ) { + + CorrectForkInPowPatch::lastBlockTimestamp = m_blockChain->info().timestamp(); + CorrectForkInPowPatch::lastBlockNumber = m_blockChain->number(); + while ( true ) { try { _block.verify( *this ); // check that block header match TestBlock contents @@ -494,6 +500,10 @@ bool TestBlockChain::addBlock( TestBlock const& _block ) { State st( block.state() ); m_lastBlock.setState( st ); + + CorrectForkInPowPatch::lastBlockTimestamp = m_blockChain->info().timestamp(); + CorrectForkInPowPatch::lastBlockNumber = m_blockChain->number(); + return true; } diff --git a/test/tools/libtesteth/ImportTest.cpp b/test/tools/libtesteth/ImportTest.cpp index 8400ed13c..7ecf2283d 100644 --- a/test/tools/libtesteth/ImportTest.cpp +++ b/test/tools/libtesteth/ImportTest.cpp @@ -111,36 +111,9 @@ void ImportTest::makeBlockchainTestFromStateTest( set< eth::Network > const& _ne TrExpectSection* search2 = &search; checkGeneralTestSectionSearch( exp.get_obj(), stateIndexesToPrint, "", search2 ); throw std::logic_error( "Skale state does not support addresses list" ); - // if (search.second.first.addresses().size() != 0) // if match in - // the expect sections - // // for this tr - // found - // { - // // replace expected mining reward (in state tests it is 0) - // json_spirit::mObject obj = - // fillJsonWithState(search2->second.first, - // search2->second.second); - // for (auto& adr : obj) - // { - // if (adr.first == toHexPrefixed(m_envInfo->author()) && - // adr.second.get_obj().count("balance")) - // { - // u256 expectCoinbaseBalance = - // toInt(adr.second.get_obj()["balance"]); - // expectCoinbaseBalance += blockReward; - // adr.second.get_obj()["balance"] = - // toCompactHexPrefixed(expectCoinbaseBalance); - // } - // } - - // json_spirit::mObject expetSectionObj; - // expetSectionObj["network"] = test::netIdToString(net); - // expetSectionObj["result"] = obj; - // expetSectionArray.push_back(expetSectionObj); - // break; - // } + } // for exp - } // for net + } // for net testObj["expect"] = expetSectionArray; @@ -225,7 +198,6 @@ bytes ImportTest::executeTest( bool _isFilling ) { continue; for ( auto& tr : m_transactions ) { - tr.transaction.checkOutExternalGas( 100 ); Options const& opt = Options::get(); if ( opt.trDataIndex != -1 && opt.trDataIndex != tr.dataInd ) continue; @@ -739,15 +711,6 @@ bool ImportTest::checkGeneralTestSectionSearch( json_spirit::mObject const& _exp _errorTransactions.push_back( i ); } } else if ( _expects.count( "hash" ) ) { - // checking filled state test against client - // BOOST_CHECK_MESSAGE(_expects.at("hash").get_str() == - // toHexPrefixed(tr.postState.globalRoot().asBytes()), - // TestOutputHelper::get().testName() + " on " + - // test::netIdToString(tr.netId) + - // ": Expected another postState hash! expected: " + - // _expects.at("hash").get_str() + " actual: " + - // toHexPrefixed(tr.postState.globalRoot().asBytes()) + - // " in " + trInfo); if ( _expects.count( "logs" ) ) BOOST_CHECK_MESSAGE( _expects.at( "logs" ).get_str() == exportLog( tr.output.second.log() ), diff --git a/test/tools/libtesteth/TestOutputHelper.cpp b/test/tools/libtesteth/TestOutputHelper.cpp index c863fa0fd..f5ec7cdf2 100644 --- a/test/tools/libtesteth/TestOutputHelper.cpp +++ b/test/tools/libtesteth/TestOutputHelper.cpp @@ -20,6 +20,7 @@ * Fixture class for boost output when running testeth */ +#include #include #include #include @@ -102,6 +103,8 @@ void TestOutputHelper::printTestExecStats() { } TestOutputHelperFixture::TestOutputHelperFixture() { TestOutputHelper::get().initTest(); + CorrectForkInPowPatch::lastBlockTimestamp = 1; + CorrectForkInPowPatch::lastBlockNumber = 0; } TestOutputHelperFixture::~TestOutputHelperFixture() { diff --git a/test/unittests/libethereum/ClientTest.cpp b/test/unittests/libethereum/ClientTest.cpp index c49302cad..81781fa7c 100644 --- a/test/unittests/libethereum/ClientTest.cpp +++ b/test/unittests/libethereum/ClientTest.cpp @@ -339,7 +339,11 @@ static std::string const c_configString = R"( "allowFutureBlocks": true, "homesteadForkBlock": "0x00", "EIP150ForkBlock": "0x00", - "EIP158ForkBlock": "0x00" + "EIP158ForkBlock": "0x00", + "byzantiumForkBlock": "0x00", + "constantinopleForkBlock": "0x00", + "constantinopleFixForkBlock": "0x00", + "istanbulForkBlock": "0x00" }, "genesis": { "nonce": "0x0000000000000042", @@ -375,6 +379,7 @@ static std::string const c_genesisInfoSkaleTest = std::string() + "byzantiumForkBlock": "0x00", "constantinopleForkBlock": "0x00", "constantinopleFixForkBlock": "0x00", + "istanbulForkBlock": "0x00", "networkID" : "12313219", "chainID": "0x01", "maximumExtraDataSize": "0x20", @@ -412,6 +417,7 @@ static std::string const c_genesisInfoSkaleTest = std::string() + "schainID": 1, "contractStorageLimit": 32000, "emptyBlockIntervalMs": -1, + "correctForkInPowPatchTimestamp": 1, "nodes": [ { "nodeID": 1112, "ip": "127.0.0.1", "basePort": )E"+std::to_string( rand_port ) + R"E(, "schainIndex" : 1, "publicKey": "0xfa"} ] @@ -439,6 +445,25 @@ static std::string const c_genesisInfoSkaleTest = std::string() + BOOST_AUTO_TEST_SUITE( EstimateGas ) +BOOST_AUTO_TEST_CASE( transactionWithData ) { + TestClientFixture fixture( c_genesisInfoSkaleTest ); + ClientTest* testClient = asClientTest( fixture.ethereum() ); + + dev::eth::simulateMining( *( fixture.ethereum() ), 10 ); + + Address addr( "0xca4409573a5129a72edf85d6c51e26760fc9c903" ); + + bytes data = + jsToBytes( "0x11223344556600770000" ); + + u256 estimate = testClient + ->estimateGas( addr, 0, addr, data, 10000000, 1000000, + GasEstimationCallback() ) + .first; + + BOOST_CHECK_EQUAL( estimate, u256( 21000+7*16+3*4 ) ); +} + BOOST_AUTO_TEST_CASE( constantConsumption ) { TestClientFixture fixture( c_genesisInfoSkaleTest ); ClientTest* testClient = asClientTest( fixture.ethereum() ); @@ -475,7 +500,8 @@ BOOST_AUTO_TEST_CASE( constantConsumption ) { GasEstimationCallback() ) .first; - BOOST_CHECK_EQUAL( estimate, u256( 71800 ) ); + // 71488 checked in reall call under Istanbul fork + BOOST_CHECK_EQUAL( estimate, u256( 71488 ) ); } BOOST_AUTO_TEST_CASE( linearConsumption ) { @@ -513,7 +539,7 @@ BOOST_AUTO_TEST_CASE( linearConsumption ) { GasEstimationCallback() ) .first; - BOOST_CHECK_EQUAL( estimate, u256( 2367016 ) ); + BOOST_CHECK_EQUAL( estimate, u256( 2366934 ) ); } BOOST_AUTO_TEST_CASE( exceedsGasLimit ) { @@ -589,7 +615,7 @@ BOOST_AUTO_TEST_CASE( runsInterference ) { GasEstimationCallback() ) .first; - BOOST_CHECK_EQUAL( estimate, u256( 41684 ) ); + BOOST_CHECK_EQUAL( estimate, u256( 41424 ) ); } BOOST_AUTO_TEST_CASE( consumptionWithRefunds ) { @@ -810,12 +836,12 @@ BOOST_AUTO_TEST_CASE( consumptionWithReverts ) { GasEstimationCallback() ) .first; - BOOST_CHECK_EQUAL( estimate, u256( 121944 ) ); + BOOST_CHECK_EQUAL( estimate, u256( 121632 ) ); } BOOST_AUTO_TEST_SUITE_END() -BOOST_AUTO_TEST_SUITE( IMABLSPublicKey ) +BOOST_AUTO_TEST_SUITE( getHistoricNodesData ) static std::string const c_genesisInfoSkaleIMABLSPublicKeyTest = std::string() + R"E( @@ -829,6 +855,7 @@ static std::string const c_genesisInfoSkaleIMABLSPublicKeyTest = std::string() + "byzantiumForkBlock": "0x00", "constantinopleForkBlock": "0x00", "constantinopleFixForkBlock": "0x00", + "istanbulForkBlock": "0x00", "networkID" : "12313219", "chainID": "0x01", "maximumExtraDataSize": "0x20", @@ -865,6 +892,7 @@ static std::string const c_genesisInfoSkaleIMABLSPublicKeyTest = std::string() + "schainName": "TestChain", "schainID": 1, "emptyBlockIntervalMs": -1, + "precompiledConfigPatchTimestamp": 1, "nodeGroups": { "1": { "nodes": { @@ -917,15 +945,16 @@ static std::string const c_genesisInfoSkaleIMABLSPublicKeyTest = std::string() + } )E"; -BOOST_AUTO_TEST_CASE( initAndUpdateIMABLSPUblicKey ) { +BOOST_AUTO_TEST_CASE( initAndUpdateHistoricConfigFields ) { TestClientFixture fixture( c_genesisInfoSkaleIMABLSPublicKeyTest ); ClientTest* testClient = asClientTest( fixture.ethereum() ); std::array< std::string, 4 > imaBLSPublicKeyOnStartUp = { "12457351342169393659284905310882617316356538373005664536506840512800919345414", "11573096151310346982175966190385407867176668720531590318594794283907348596326", "13929944172721019694880576097738949215943314024940461401664534665129747139387", "7375214420811287025501422512322868338311819657776589198925786170409964211914" }; - BOOST_REQUIRE( testClient->getIMABLSPublicKey() == imaBLSPublicKeyOnStartUp ); - + BOOST_REQUIRE( testClient->getHistoricNodePublicKey( 0 ) == "0x3a581d62b12232dade30c3710215a271984841657449d1f474295a13737b778266f57e298f123ae80cbab7cc35ead1b62a387556f94b326d5c65d4a7aa2abcba" ); + BOOST_REQUIRE( testClient->getHistoricNodeId( 0 ) == "26" ); + BOOST_REQUIRE( testClient->getHistoricNodeIndex( 0 ) == "3" ); BOOST_REQUIRE( testClient->mineBlocks( 1 ) ); @@ -934,6 +963,9 @@ BOOST_AUTO_TEST_CASE( initAndUpdateIMABLSPUblicKey ) { std::array< std::string, 4 > imaBLSPublicKeyAfterBlock = { "10860211539819517237363395256510340030868592687836950245163587507107792195621", "2419969454136313127863904023626922181546178935031521540751337209075607503568", "3399776985251727272800732947224655319335094876742988846345707000254666193993", "16982202412630419037827505223148517434545454619191931299977913428346639096984" }; BOOST_REQUIRE( testClient->getIMABLSPublicKey() == imaBLSPublicKeyAfterBlock ); + BOOST_REQUIRE( testClient->getHistoricNodePublicKey( 0 ) == "0x6180cde2cbbcc6b6a17efec4503a7d4316f8612f411ee171587089f770335f484003ad236c534b9afa82befc1f69533723abdb6ec2601e582b72dcfd7919338b" ); + BOOST_REQUIRE( testClient->getHistoricNodeId( 0 ) == "30" ); + BOOST_REQUIRE( testClient->getHistoricNodeIndex( 0 ) == "0" ); } BOOST_AUTO_TEST_SUITE_END() @@ -948,7 +980,11 @@ static std::string const c_skaleConfigString = R"E( "allowFutureBlocks": true, "homesteadForkBlock": "0x00", "EIP150ForkBlock": "0x00", - "EIP158ForkBlock": "0x00" + "EIP158ForkBlock": "0x00", + "byzantiumForkBlock": "0x00", + "constantinopleForkBlock": "0x00", + "constantinopleFixForkBlock": "0x00", + "istanbulForkBlock": "0x00" }, "genesis": { "nonce": "0x0000000000000042", diff --git a/test/unittests/libethereum/InstanceMonitorTest.cpp b/test/unittests/libethereum/InstanceMonitorTest.cpp index 760cf3f58..137b70555 100644 --- a/test/unittests/libethereum/InstanceMonitorTest.cpp +++ b/test/unittests/libethereum/InstanceMonitorTest.cpp @@ -17,10 +17,6 @@ class InstanceMonitorMock: public InstanceMonitor { public: explicit InstanceMonitorMock(fs::path const &rotationFlagFilePath, std::shared_ptr statusAndControl) : InstanceMonitor(rotationFlagFilePath, statusAndControl) {}; - uint64_t getFinishTimestamp() { - return this->finishTimestamp(); - }; - fs::path getRotationInfoFilePath() { return this->rotationInfoFilePath(); } @@ -32,6 +28,10 @@ class InstanceMonitorMock: public InstanceMonitor { void removeFlagFileTest(){ this->reportExitTimeReached( false ); } + + uint64_t getRotationTimestamp() const { + return this->rotationTimestamp(); + } }; class InstanceMonitorTestFixture : public TestOutputHelperFixture { @@ -70,7 +70,7 @@ BOOST_AUTO_TEST_CASE( test_initRotationParams ) { uint64_t ts = 100; BOOST_REQUIRE( !fs::exists(instanceMonitor->getRotationInfoFilePath() ) ); instanceMonitor->initRotationParams(ts); - BOOST_CHECK_EQUAL(instanceMonitor->getFinishTimestamp(), ts); + BOOST_CHECK_EQUAL(instanceMonitor->getRotationTimestamp(), ts); BOOST_REQUIRE( fs::exists(instanceMonitor->getRotationInfoFilePath() ) ); @@ -80,6 +80,15 @@ BOOST_AUTO_TEST_CASE( test_initRotationParams ) { BOOST_CHECK_EQUAL(rotateJson["timestamp"].get< uint64_t >(), ts); } + +BOOST_AUTO_TEST_CASE( test_isTimeToRotate_invalid_file ) { + uint64_t currentTime = 100; + std::ofstream rotationInfoFile(instanceMonitor->getRotationInfoFilePath().string() ); + rotationInfoFile << "Broken file"; + BOOST_REQUIRE( !instanceMonitor->isTimeToRotate( currentTime ) ); +} + + BOOST_AUTO_TEST_CASE( test_isTimeToRotate_false ) { uint64_t currentTime = 100; uint64_t finishTime = 200; @@ -98,6 +107,9 @@ BOOST_AUTO_TEST_CASE( test_isTimeToRotate_true ) { instanceMonitor->initRotationParams(50); BOOST_REQUIRE( instanceMonitor->isTimeToRotate( currentTime ) ); + + currentTime = 49; + BOOST_REQUIRE( !instanceMonitor->isTimeToRotate( currentTime ) ); } BOOST_AUTO_TEST_CASE( test_rotation ) { diff --git a/test/unittests/libethereum/PrecompiledConfig.json b/test/unittests/libethereum/PrecompiledConfig.json new file mode 100644 index 000000000..b7b4901f0 --- /dev/null +++ b/test/unittests/libethereum/PrecompiledConfig.json @@ -0,0 +1,109 @@ +{ + "sealEngine": "Ethash", + "params": { + "accountStartNonce": "0x00", + "homesteadForkBlock": "0x00", + "EIP150ForkBlock": "0x00", + "EIP158ForkBlock": "0x00", + "byzantiumForkBlock": "0x00", + "constantinopleForkBlock": "0x00", + "constantinopleFixForkBlock": "0x00", + "networkID" : "12313219", + "chainID": "0x01", + "maximumExtraDataSize": "0x20", + "tieBreakingGas": false, + "minGasLimit": "0x1388", + "maxGasLimit": "7fffffffffffffff", + "gasLimitBoundDivisor": "0x0400", + "minimumDifficulty": "0x020000", + "difficultyBoundDivisor": "0x0800", + "durationLimit": "0x0d", + "blockReward": "0x4563918244F40000" + }, + "genesis": { + "nonce": "0x0000000000000042", + "difficulty": "0x020000", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "author": "0x0000000000000000000000000000000000000000", + "timestamp": "0x00", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "extraData": "0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa", + "gasLimit": "0x47E7C4" + }, + "skaleConfig": { + "nodeInfo": { + "nodeName": "Node1", + "nodeID": 1112, + "bindIP": "127.0.0.1", + "basePort": 1234, + "logLevel": "trace", + "logLevelProposal": "trace", + "ecdsaKeyName": "NEK:fa112", + "wallets": { + "ima": { + "n": 1 + } + } + }, + "sChain": { + "schainName": "TestChain", + "schainID": 1, + "contractStorageLimit": 32000, + "precompiledConfigPatchTimestamp": 1, + "emptyBlockIntervalMs": -1, + "nodeGroups": { + "1": { + "nodes": { + "30": [ + 0, + 30, + "0x6180cde2cbbcc6b6a17efec4503a7d4316f8612f411ee171587089f770335f484003ad236c534b9afa82befc1f69533723abdb6ec2601e582b72dcfd7919338b" + ] + }, + "finish_ts": null, + "bls_public_key": { + "blsPublicKey0": "10860211539819517237363395256510340030868592687836950245163587507107792195621", + "blsPublicKey1": "2419969454136313127863904023626922181546178935031521540751337209075607503568", + "blsPublicKey2": "3399776985251727272800732947224655319335094876742988846345707000254666193993", + "blsPublicKey3": "16982202412630419037827505223148517434545454619191931299977913428346639096984" + } + }, + "0": { + "nodes": { + "26": [ + 3, + 26, + "0x3a581d62b12232dade30c3710215a271984841657449d1f474295a13737b778266f57e298f123ae80cbab7cc35ead1b62a387556f94b326d5c65d4a7aa2abcba" + ] + }, + "finish_ts": 4294967290, + "bls_public_key": { + "blsPublicKey0": "12457351342169393659284905310882617316356538373005664536506840512800919345414", + "blsPublicKey1": "11573096151310346982175966190385407867176668720531590318594794283907348596326", + "blsPublicKey2": "13929944172721019694880576097738949215943314024940461401664534665129747139387", + "blsPublicKey3": "7375214420811287025501422512322868338311819657776589198925786170409964211914" + } + } + }, + "nodes": [ + { "nodeID": 1112, "ip": "127.0.0.1", "basePort": 1234, "schainIndex" : 1, "publicKey": "0xfa", "owner": "0x21abd6db4e347b4e8c937c1c8370e4b5ed3f0dd3db69cbdb7a38e1e50b1b82fc"} + ] + } + }, + "accounts": { + "0000000000000000000000000000000000000001": { "precompiled": { "name": "ecrecover", "linear": { "base": 3000, "word": 0 } } }, + "0000000000000000000000000000000000000002": { "precompiled": { "name": "sha256", "linear": { "base": 60, "word": 12 } } }, + "0000000000000000000000000000000000000003": { "precompiled": { "name": "ripemd160", "linear": { "base": 600, "word": 120 } } }, + "0000000000000000000000000000000000000004": { "precompiled": { "name": "identity", "linear": { "base": 15, "word": 3 } } }, + "0000000000000000000000000000000000000005": { "precompiled": { "name": "modexp", "startingBlock" : "0x2dc6c0" } }, + "0000000000000000000000000000000000000006": { "precompiled": { "name": "alt_bn128_G1_add", "startingBlock" : "0x2dc6c0", "linear": { "base": 500, "word": 0 } } }, + "0000000000000000000000000000000000000007": { "precompiled": { "name": "alt_bn128_G1_mul", "startingBlock" : "0x2dc6c0", "linear": { "base": 40000, "word": 0 } } }, + "0000000000000000000000000000000000000008": { "precompiled": { "name": "alt_bn128_pairing_product", "startingBlock" : "0x2dc6c0" } }, + "0xca4409573a5129a72edf85d6c51e26760fc9c903": { "balance": "100000000000000000000000" }, + "0xD2001300000000000000000000000000000000D2": { "balance": "0", "nonce": "0", "storage": {}, "code":"0x6080604052348015600f57600080fd5b506004361060325760003560e01c8063815b8ab41460375780638273f754146062575b600080fd5b606060048036036020811015604b57600080fd5b8101908080359060200190929190505050606a565b005b60686081565b005b60005a90505b815a82031015607d576070565b5050565b60005a9050609660028281609157fe5b04606a565b5056fea165627a7a72305820f5fb5a65e97cbda96c32b3a2e1497cd6b7989179b5dc29e9875bcbea5a96c4520029"}, + "0xD2001300000000000000000000000000000000D4": { "balance": "0", "nonce": "0", "storage": {}, "code":"0x608060405234801561001057600080fd5b506004361061004c5760003560e01c80632098776714610051578063b8bd717f1461007f578063d37165fa146100ad578063fdde8d66146100db575b600080fd5b61007d6004803603602081101561006757600080fd5b8101908080359060200190929190505050610109565b005b6100ab6004803603602081101561009557600080fd5b8101908080359060200190929190505050610136565b005b6100d9600480360360208110156100c357600080fd5b8101908080359060200190929190505050610170565b005b610107600480360360208110156100f157600080fd5b8101908080359060200190929190505050610191565b005b60005a90505b815a8203101561011e5761010f565b600080fd5b815a8203101561013257610123565b5050565b60005a90505b815a8203101561014b5761013c565b600060011461015957600080fd5b5a90505b815a8203101561016c5761015d565b5050565b60005a9050600081830390505b805a8303101561018c5761017d565b505050565b60005a90505b815a820310156101a657610197565b60016101b157600080fd5b5a90505b815a820310156101c4576101b5565b505056fea264697066735822122089b72532621e7d1849e444ee6efaad4fb8771258e6f79755083dce434e5ac94c64736f6c63430006000033"}, + "0xd40B3c51D0ECED279b1697DbdF45d4D19b872164": { "balance": "0", "nonce": "0", "storage": {}, "code":"0x6080604052348015600f57600080fd5b506004361060325760003560e01c80636057361d146037578063b05784b8146062575b600080fd5b606060048036036020811015604b57600080fd5b8101908080359060200190929190505050607e565b005b60686088565b6040518082815260200191505060405180910390f35b8060008190555050565b6000805490509056fea2646970667358221220e5ff9593bfa9540a34cad5ecbe137dcafcfe1f93e3c4832610438d6f0ece37db64736f6c63430006060033"}, + "0xD2001300000000000000000000000000000000D3": { "balance": "0", "nonce": "0", "storage": {}, "code":"0x608060405234801561001057600080fd5b50600436106100365760003560e01c8063ee919d501461003b578063f0fdf83414610069575b600080fd5b6100676004803603602081101561005157600080fd5b81019080803590602001909291905050506100af565b005b6100956004803603602081101561007f57600080fd5b8101908080359060200190929190505050610108565b604051808215151515815260200191505060405180910390f35b600160008083815260200190815260200160002060006101000a81548160ff021916908315150217905550600080600083815260200190815260200160002060006101000a81548160ff02191690831515021790555050565b60006020528060005260406000206000915054906101000a900460ff168156fea2646970667358221220cf479cb746c4b897c88be4ad8e2612a14e27478f91928c49619c98da374a3bf864736f6c63430006000033"}, + "0xD40b89C063a23eb85d739f6fA9B14341838eeB2b": { "balance": "0", "nonce": "0", "storage": {"0x101e368776582e57ab3d116ffe2517c0a585cd5b23174b01e275c2d8329c3d83": "0x0000000000000000000000000000000000000000000000000000000000000001"}, "code":"0x608060405234801561001057600080fd5b506004361061004c5760003560e01c80634df7e3d014610051578063d82cf7901461006f578063ee919d501461009d578063f0fdf834146100cb575b600080fd5b610059610111565b6040518082815260200191505060405180910390f35b61009b6004803603602081101561008557600080fd5b8101908080359060200190929190505050610117565b005b6100c9600480360360208110156100b357600080fd5b810190808035906020019092919050505061017d565b005b6100f7600480360360208110156100e157600080fd5b81019080803590602001909291905050506101ab565b604051808215151515815260200191505060405180910390f35b60015481565b60008082815260200190815260200160002060009054906101000a900460ff16151560011515141561017a57600080600083815260200190815260200160002060006101000a81548160ff02191690831515021790555060018054016001819055505b50565b600160008083815260200190815260200160002060006101000a81548160ff02191690831515021790555050565b60006020528060005260406000206000915054906101000a900460ff168156fea264697066735822122000af6f9a0d5c9b8b642648557291c9eb0f9732d60094cf75e14bb192abd97bcc64736f6c63430006000033"} + } +} diff --git a/test/unittests/libethereum/PrecompiledTest.cpp b/test/unittests/libethereum/PrecompiledTest.cpp index 861cbb595..20498f3d9 100644 --- a/test/unittests/libethereum/PrecompiledTest.cpp +++ b/test/unittests/libethereum/PrecompiledTest.cpp @@ -21,13 +21,19 @@ */ #include +#include #include #include #include +#include +#include +#include +#include #include #include #include #include +#include #include @@ -37,6 +43,21 @@ using namespace dev::eth; using namespace dev::test; namespace ut = boost::unit_test; +std::string numberToHex( size_t inputNumber ) { + std::stringstream sstream; + sstream << std::hex << inputNumber; + std::string hexNumber = sstream.str(); + hexNumber.insert( hexNumber.begin(), 64 - hexNumber.length(), '0' ); + return hexNumber; +} + +std::string stringToHex( std::string inputString ) { + size_t strLength = ( ( inputString.size() * 2 + 63 ) / 64 ) * 64; + std::string hexString = toHex( inputString.begin(), inputString.end(), "" ); + hexString.insert( hexString.begin() + hexString.length(), strLength - hexString.length(), '0' ); + return hexString; +} + BOOST_FIXTURE_TEST_SUITE( PrecompiledTests, TestOutputHelperFixture ) BOOST_AUTO_TEST_CASE( modexpFermatTheorem, @@ -1557,20 +1578,285 @@ BOOST_AUTO_TEST_CASE( ecpairingCost ) { BOOST_CHECK_EQUAL( static_cast< int >( costIstanbul ), in.size() / 192 * 34000 + 45000 ); } -std::string numberToHex( size_t inputNumber ) { - std::stringstream sstream; - sstream << std::hex << inputNumber; - std::string hexNumber = sstream.str(); - hexNumber.insert( hexNumber.begin(), 64 - hexNumber.length(), '0' ); - return hexNumber; +static std::string const genesisInfoSkaleConfigTest = std::string() + + R"E( +{ + "sealEngine": "Ethash", + "params": { + "accountStartNonce": "0x00", + "homesteadForkBlock": "0x00", + "EIP150ForkBlock": "0x00", + "EIP158ForkBlock": "0x00", + "byzantiumForkBlock": "0x00", + "constantinopleForkBlock": "0x00", + "constantinopleFixForkBlock": "0x00", + "networkID" : "12313219", + "chainID": "0x01", + "maximumExtraDataSize": "0x20", + "tieBreakingGas": false, + "minGasLimit": "0x1388", + "maxGasLimit": "7fffffffffffffff", + "gasLimitBoundDivisor": "0x0400", + "minimumDifficulty": "0x020000", + "difficultyBoundDivisor": "0x0800", + "durationLimit": "0x0d", + "blockReward": "0x4563918244F40000" + }, + "genesis": { + "nonce": "0x0000000000000042", + "difficulty": "0x020000", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "author": "0x0000000000000000000000000000000000000000", + "timestamp": "0x00", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "extraData": "0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa", + "gasLimit": "0x47E7C4" + }, + "skaleConfig": { + "nodeInfo": { + "nodeName": "Node1", + "nodeID": 1112, + "bindIP": "127.0.0.1", + "basePort": 1234, + "logLevel": "trace", + "logLevelProposal": "trace", + "ecdsaKeyName": "NEK:fa112", + "wallets": { + "ima": { + "n": 1 + } + } + }, + "sChain": { + "schainName": "TestChain", + "schainID": 1, + "contractStorageLimit": 32000, + "precompiledConfigPatchTimestamp": 1, + "emptyBlockIntervalMs": -1, + "nodeGroups": { + "1": { + "nodes": { + "30": [ + 13, + 30, + "0x6180cde2cbbcc6b6a17efec4503a7d4316f8612f411ee171587089f770335f484003ad236c534b9afa82befc1f69533723abdb6ec2601e582b72dcfd7919338b" + ] + }, + "finish_ts": null, + "bls_public_key": { + "blsPublicKey0": "10860211539819517237363395256510340030868592687836950245163587507107792195621", + "blsPublicKey1": "2419969454136313127863904023626922181546178935031521540751337209075607503568", + "blsPublicKey2": "3399776985251727272800732947224655319335094876742988846345707000254666193993", + "blsPublicKey3": "16982202412630419037827505223148517434545454619191931299977913428346639096984" + } + }, + "0": { + "nodes": { + "26": [ + 3, + 26, + "0x3a581d62b12232dade30c3710215a271984841657449d1f474295a13737b778266f57e298f123ae80cbab7cc35ead1b62a387556f94b326d5c65d4a7aa2abcba" + ] + }, + "finish_ts": 4294967290, + "bls_public_key": { + "blsPublicKey0": "12457351342169393659284905310882617316356538373005664536506840512800919345414", + "blsPublicKey1": "11573096151310346982175966190385407867176668720531590318594794283907348596326", + "blsPublicKey2": "13929944172721019694880576097738949215943314024940461401664534665129747139387", + "blsPublicKey3": "7375214420811287025501422512322868338311819657776589198925786170409964211914" + } + } + }, + "nodes": [ + { "nodeID": 1112, "ip": "127.0.0.1", "basePort": 1234, "schainIndex" : 1, "publicKey": "0xfa", "owner": "0x21abd6db4e347b4e8c937c1c8370e4b5ed3f0dd3db69cbdb7a38e1e50b1b82fc"} + ] + } + }, + "accounts": { + "0000000000000000000000000000000000000001": { "precompiled": { "name": "ecrecover", "linear": { "base": 3000, "word": 0 } } }, + "0000000000000000000000000000000000000002": { "precompiled": { "name": "sha256", "linear": { "base": 60, "word": 12 } } }, + "0000000000000000000000000000000000000003": { "precompiled": { "name": "ripemd160", "linear": { "base": 600, "word": 120 } } }, + "0000000000000000000000000000000000000004": { "precompiled": { "name": "identity", "linear": { "base": 15, "word": 3 } } }, + "0000000000000000000000000000000000000005": { "precompiled": { "name": "modexp", "startingBlock" : "0x2dc6c0" } }, + "0000000000000000000000000000000000000006": { "precompiled": { "name": "alt_bn128_G1_add", "startingBlock" : "0x2dc6c0", "linear": { "base": 500, "word": 0 } } }, + "0000000000000000000000000000000000000007": { "precompiled": { "name": "alt_bn128_G1_mul", "startingBlock" : "0x2dc6c0", "linear": { "base": 40000, "word": 0 } } }, + "0000000000000000000000000000000000000008": { "precompiled": { "name": "alt_bn128_pairing_product", "startingBlock" : "0x2dc6c0" } }, + "0xca4409573a5129a72edf85d6c51e26760fc9c903": { "balance": "100000000000000000000000" }, + "0xD2001300000000000000000000000000000000D2": { "balance": "0", "nonce": "0", "storage": {}, "code":"0x6080604052348015600f57600080fd5b506004361060325760003560e01c8063815b8ab41460375780638273f754146062575b600080fd5b606060048036036020811015604b57600080fd5b8101908080359060200190929190505050606a565b005b60686081565b005b60005a90505b815a82031015607d576070565b5050565b60005a9050609660028281609157fe5b04606a565b5056fea165627a7a72305820f5fb5a65e97cbda96c32b3a2e1497cd6b7989179b5dc29e9875bcbea5a96c4520029"}, + "0xD2001300000000000000000000000000000000D4": { "balance": "0", "nonce": "0", "storage": {}, "code":"0x608060405234801561001057600080fd5b506004361061004c5760003560e01c80632098776714610051578063b8bd717f1461007f578063d37165fa146100ad578063fdde8d66146100db575b600080fd5b61007d6004803603602081101561006757600080fd5b8101908080359060200190929190505050610109565b005b6100ab6004803603602081101561009557600080fd5b8101908080359060200190929190505050610136565b005b6100d9600480360360208110156100c357600080fd5b8101908080359060200190929190505050610170565b005b610107600480360360208110156100f157600080fd5b8101908080359060200190929190505050610191565b005b60005a90505b815a8203101561011e5761010f565b600080fd5b815a8203101561013257610123565b5050565b60005a90505b815a8203101561014b5761013c565b600060011461015957600080fd5b5a90505b815a8203101561016c5761015d565b5050565b60005a9050600081830390505b805a8303101561018c5761017d565b505050565b60005a90505b815a820310156101a657610197565b60016101b157600080fd5b5a90505b815a820310156101c4576101b5565b505056fea264697066735822122089b72532621e7d1849e444ee6efaad4fb8771258e6f79755083dce434e5ac94c64736f6c63430006000033"}, + "0xd40B3c51D0ECED279b1697DbdF45d4D19b872164": { "balance": "0", "nonce": "0", "storage": {}, "code":"0x6080604052348015600f57600080fd5b506004361060325760003560e01c80636057361d146037578063b05784b8146062575b600080fd5b606060048036036020811015604b57600080fd5b8101908080359060200190929190505050607e565b005b60686088565b6040518082815260200191505060405180910390f35b8060008190555050565b6000805490509056fea2646970667358221220e5ff9593bfa9540a34cad5ecbe137dcafcfe1f93e3c4832610438d6f0ece37db64736f6c63430006060033"}, + "0xD2001300000000000000000000000000000000D3": { "balance": "0", "nonce": "0", "storage": {}, "code":"0x608060405234801561001057600080fd5b50600436106100365760003560e01c8063ee919d501461003b578063f0fdf83414610069575b600080fd5b6100676004803603602081101561005157600080fd5b81019080803590602001909291905050506100af565b005b6100956004803603602081101561007f57600080fd5b8101908080359060200190929190505050610108565b604051808215151515815260200191505060405180910390f35b600160008083815260200190815260200160002060006101000a81548160ff021916908315150217905550600080600083815260200190815260200160002060006101000a81548160ff02191690831515021790555050565b60006020528060005260406000206000915054906101000a900460ff168156fea2646970667358221220cf479cb746c4b897c88be4ad8e2612a14e27478f91928c49619c98da374a3bf864736f6c63430006000033"}, + "0xD40b89C063a23eb85d739f6fA9B14341838eeB2b": { "balance": "0", "nonce": "0", "storage": {"0x101e368776582e57ab3d116ffe2517c0a585cd5b23174b01e275c2d8329c3d83": "0x0000000000000000000000000000000000000000000000000000000000000001"}, "code":"0x608060405234801561001057600080fd5b506004361061004c5760003560e01c80634df7e3d014610051578063d82cf7901461006f578063ee919d501461009d578063f0fdf834146100cb575b600080fd5b610059610111565b6040518082815260200191505060405180910390f35b61009b6004803603602081101561008557600080fd5b8101908080359060200190929190505050610117565b005b6100c9600480360360208110156100b357600080fd5b810190808035906020019092919050505061017d565b005b6100f7600480360360208110156100e157600080fd5b81019080803590602001909291905050506101ab565b604051808215151515815260200191505060405180910390f35b60015481565b60008082815260200190815260200160002060009054906101000a900460ff16151560011515141561017a57600080600083815260200190815260200160002060006101000a81548160ff02191690831515021790555060018054016001819055505b50565b600160008083815260200190815260200160002060006101000a81548160ff02191690831515021790555050565b60006020528060005260406000206000915054906101000a900460ff168156fea264697066735822122000af6f9a0d5c9b8b642648557291c9eb0f9732d60094cf75e14bb192abd97bcc64736f6c63430006000033"} + } } +)E"; -std::string stringToHex( std::string inputString ) { - std::string hexString = toHex( inputString.begin(), inputString.end(), "" ); - hexString.insert( hexString.begin() + hexString.length(), 64 - hexString.length(), '0' ); - return hexString; +BOOST_AUTO_TEST_CASE( getConfigVariable ) { + ChainParams chainParams; + chainParams = chainParams.loadConfig( genesisInfoSkaleConfigTest ); + chainParams.sealEngineName = NoProof::name(); + chainParams.allowFutureBlocks = true; + + dev::eth::g_configAccesssor.reset( new skutils::json_config_file_accessor( "../../test/unittests/libethereum/PrecompiledConfig.json" ) ); + + std::unique_ptr client; + dev::TransientDirectory m_tmpDir; + auto monitor = make_shared< InstanceMonitor >("test"); + setenv("DATA_DIR", m_tmpDir.path().c_str(), 1); + client.reset( new eth::ClientTest( chainParams, ( int ) chainParams.networkID, + shared_ptr< GasPricer >(), nullptr, monitor, m_tmpDir.path(), dev::WithExisting::Kill ) ); + + client->injectSkaleHost(); + client->startWorking(); + + client->setAuthor( Address("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF") ); + + ClientTest* testClient = asClientTest( client.get() ); + + testClient->mineBlocks( 1 ); + testClient->importTransactionsAsBlock( dev::eth::Transactions(), 1000, 4294967294 ); + dev::eth::g_skaleHost = testClient->skaleHost(); + + PrecompiledExecutor exec = PrecompiledRegistrar::executor( "getConfigVariableUint256" ); + std::string input = stringToHex( "skaleConfig.sChain.nodes.0.id" ); + input = input.substr(0, 58); // remove 0s in the end + + bytes in = fromHex( numberToHex( 29 ) + input ); + auto res = exec( bytesConstRef( in.data(), in.size() ) ); + + BOOST_REQUIRE( res.first ); + BOOST_REQUIRE( dev::fromBigEndian( res.second ) == 30 ); + + input = stringToHex( "skaleConfig.sChain.nodes.0.schainIndex" ); + input = input.substr(0, 76); // remove 0s in the end + in = fromHex( numberToHex( 38 ) + input ); + res = exec( bytesConstRef( in.data(), in.size() ) ); + + BOOST_REQUIRE( res.first ); + BOOST_REQUIRE( dev::fromBigEndian( res.second ) == 13 ); + + input = stringToHex( "skaleConfig.sChain.nodes.0.publicKey" ); + input = input.substr(0, 72); // remove 0s in the end + in = fromHex( numberToHex( 36 ) + input ); + res = exec( bytesConstRef( in.data(), in.size() ) ); + + BOOST_REQUIRE( !res.first ); + + input = stringToHex( "skaleConfig.sChain.nodes.0.unknownField" ); + input = input.substr(0, 78); // remove 0s in the end + in = fromHex( numberToHex( 39 ) + input ); + res = exec( bytesConstRef( in.data(), in.size() ) ); + + BOOST_REQUIRE( !res.first ); + + input = stringToHex( "skaleConfig.nodeInfo.wallets.ima.n" ); + input = input.substr(0, 68); // remove 0s in the end + in = fromHex( numberToHex( 34 ) + input ); + res = exec( bytesConstRef( in.data(), in.size() ) ); + + BOOST_REQUIRE( res.first ); + BOOST_REQUIRE( dev::fromBigEndian( res.second ) == 1 ); + + input = stringToHex( "skaleConfig.nodeInfo.wallets.ima.t" ); + input = input.substr(0, 68); // remove 0s in the end + in = fromHex( numberToHex( 34 ) + input ); + res = exec( bytesConstRef( in.data(), in.size() ) ); + + BOOST_REQUIRE( !res.first ); + + exec = PrecompiledRegistrar::executor( "getConfigVariableString" ); + + input = stringToHex( "skaleConfig.sChain.nodes.0.publicKey" ); + input = input.substr(0, 72); // remove 0s in the end + in = fromHex( numberToHex( 36 ) + input ); + res = exec( bytesConstRef( in.data(), in.size() ) ); + + BOOST_REQUIRE( res.first ); + BOOST_REQUIRE( res.second == fromHex("0x6180cde2cbbcc6b6a17efec4503a7d4316f8612f411ee171587089f770335f484003ad236c534b9afa82befc1f69533723abdb6ec2601e582b72dcfd7919338b") ); + + input = stringToHex( "skaleConfig.sChain.nodes.0.id" ); + input = input.substr(0, 58); // remove 0s in the end + + in = fromHex( numberToHex( 29 ) + input ); + res = exec( bytesConstRef( in.data(), in.size() ) ); + + BOOST_REQUIRE( !res.first ); + + input = stringToHex( "skaleConfig.sChain.nodes.0.schainIndex" ); + input = input.substr(0, 76); // remove 0s in the end + in = fromHex( numberToHex( 38 ) + input ); + res = exec( bytesConstRef( in.data(), in.size() ) ); + + BOOST_REQUIRE( !res.first ); + + input = stringToHex( "skaleConfig.sChain.nodes.0.unknownField" ); + input = input.substr(0, 78); // remove 0s in the end + in = fromHex( numberToHex( 39 ) + input ); + res = exec( bytesConstRef( in.data(), in.size() ) ); + + BOOST_REQUIRE( !res.first ); } +// temporary merge tests for getConfigVariable +// because of the specifics in test design +//BOOST_AUTO_TEST_CASE( getConfigVariableAddress ) { +// ChainParams chainParams; +// chainParams = chainParams.loadConfig( genesisInfoSkaleConfigTest ); +// chainParams.sealEngineName = NoProof::name(); +// chainParams.allowFutureBlocks = true; + +// dev::eth::g_configAccesssor.reset( new skutils::json_config_file_accessor( "../../test/unittests/libethereum/PrecompiledConfig.json" ) ); + +// std::unique_ptr client; +// dev::TransientDirectory m_tmpDir; +// auto monitor = make_shared< InstanceMonitor >("test"); +// setenv("DATA_DIR", m_tmpDir.path().c_str(), 1); +// client.reset( new eth::ClientTest( chainParams, ( int ) chainParams.networkID, +// shared_ptr< GasPricer >(), nullptr, monitor, m_tmpDir.path(), dev::WithExisting::Kill ) ); + +// client->injectSkaleHost(); +// client->startWorking(); + +// client->setAuthor( Address("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF") ); + +// ClientTest* testClient = asClientTest( client.get() ); + +// testClient->mineBlocks( 1 ); +// testClient->importTransactionsAsBlock( dev::eth::Transactions(), 1000, 4294967294 ); +// dev::eth::g_skaleHost = testClient->skaleHost(); + +// PrecompiledExecutor exec = PrecompiledRegistrar::executor( "getConfigVariableAddress" ); + +// std::string input = stringToHex( "skaleConfig.sChain.nodes.0.owner" ); +// bytes in = fromHex( numberToHex( 32 ) + input ); +// auto res = exec( bytesConstRef( in.data(), in.size() ) ); + +// BOOST_REQUIRE( res.first ); +// BOOST_REQUIRE( res.second == fromHex("0x23bbe8db4e347b4e8c937c1c8350e4b5ed33adb3db69cbdb7a38e1f40a1b82fe") ); + +// input = stringToHex( "skaleConfig.sChain.nodes.0.id" ); +// input = input.substr(0, 58); // remove 0s in the end + +// in = fromHex( numberToHex( 29 ) + input ); +// res = exec( bytesConstRef( in.data(), in.size() ) ); + +// BOOST_REQUIRE( !res.first ); + +// input = stringToHex( "skaleConfig.sChain.nodes.0.schainIndex" ); +// input = input.substr(0, 76); // remove 0s in the end +// in = fromHex( numberToHex( 38 ) + input ); +// res = exec( bytesConstRef( in.data(), in.size() ) ); + +// BOOST_REQUIRE( !res.first ); + +// input = stringToHex( "skaleConfig.sChain.nodes.0.unknownField" ); +// input = input.substr(0, 78); // remove 0s in the end +// in = fromHex( numberToHex( 39 ) + input ); +// res = exec( bytesConstRef( in.data(), in.size() ) ); + +// BOOST_REQUIRE( !res.first ); +//} + struct FilestorageFixture : public TestOutputHelperFixture { FilestorageFixture() { ownerAddress = Address( "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" ); diff --git a/test/unittests/libethereum/SkaleHost.cpp b/test/unittests/libethereum/SkaleHost.cpp index 1e5590e4a..930339da0 100644 --- a/test/unittests/libethereum/SkaleHost.cpp +++ b/test/unittests/libethereum/SkaleHost.cpp @@ -89,13 +89,18 @@ class ConsensusTestStub : public ConsensusInterface { } uint64_t checkOracleResult( const string& - /*_receipt*/, string& /*_result */) { + /*_receipt*/, string& /*_result */) override { return 0; } - map< string, uint64_t > getConsensusDbUsage() const { + map< string, uint64_t > getConsensusDbUsage() const override { return map< string, uint64_t >(); }; + + virtual ConsensusInterface::SyncInfo getSyncInfo() override { + return ConsensusInterface::SyncInfo{}; + }; + }; class ConsensusTestStubFactory : public ConsensusFactory { @@ -118,7 +123,7 @@ struct SkaleHostFixture : public TestOutputHelperFixture { chainParams.allowFutureBlocks = true; chainParams.difficulty = chainParams.minimumDifficulty; chainParams.gasLimit = chainParams.maxGasLimit; - chainParams.byzantiumForkBlock = 0; + chainParams.istanbulForkBlock = 0; // add random extra data to randomize genesis hash and get random DB path, // so that tests can be run in parallel // TODO: better make it use ethemeral in-memory databases @@ -128,7 +133,7 @@ struct SkaleHostFixture : public TestOutputHelperFixture { chainParams.sChain.nodes[0].port = chainParams.sChain.nodes[0].port6 = rand_port; // not 0-timestamp genesis - to test patch - chainParams.timestamp = 1; + chainParams.timestamp = std::time( NULL ) - 5; if( params.count("multiTransactionMode") && stoi( params.at( "multiTransactionMode" ) ) ) chainParams.sChain.multiTransactionMode = true; @@ -908,7 +913,7 @@ BOOST_AUTO_TEST_CASE( transactionDropReceive // 1st tx Transaction tx1 = tx_from_json( json ); - tx1.checkOutExternalGas( client->chainParams().difficulty ); + tx1.checkOutExternalGas( client->chainParams(), client->number() ); // submit it! tq->import( tx1 ); @@ -965,7 +970,7 @@ BOOST_AUTO_TEST_CASE( transactionDropQueue, // 1st tx Transaction tx1 = tx_from_json( json ); - tx1.checkOutExternalGas( client->chainParams().difficulty ); + tx1.checkOutExternalGas( client->chainParams(), client->number() ); // submit it! tq->import( tx1 ); @@ -1022,7 +1027,7 @@ BOOST_AUTO_TEST_CASE( transactionDropByGasPrice // 1st tx Transaction tx1 = tx_from_json( json ); - tx1.checkOutExternalGas( client->chainParams().difficulty ); + tx1.checkOutExternalGas( client->chainParams(), client->number() ); // submit it! tq->import( tx1 ); @@ -1085,7 +1090,7 @@ BOOST_AUTO_TEST_CASE( transactionDropByGasPriceReceive // 1st tx Transaction tx1 = tx_from_json( json ); - tx1.checkOutExternalGas( client->chainParams().difficulty ); + tx1.checkOutExternalGas( client->chainParams(), client->number() ); RLPStream stream1; tx1.streamRLP( stream1 ); diff --git a/test/unittests/libweb3core/LevelDBHash.cpp b/test/unittests/libweb3core/LevelDBHash.cpp index 67dde80cb..f7c444dcd 100644 --- a/test/unittests/libweb3core/LevelDBHash.cpp +++ b/test/unittests/libweb3core/LevelDBHash.cpp @@ -9,44 +9,96 @@ BOOST_AUTO_TEST_SUITE( LevelDBHashBase ) BOOST_AUTO_TEST_CASE( hash ) { dev::TransientDirectory td; + std::vector< std::pair< std::string, std::string > > randomKeysValues(123); + dev::h256 hash; { std::unique_ptr< dev::db::LevelDB > db( new dev::db::LevelDB( td.path() ) ); BOOST_REQUIRE( db ); + db->insert( dev::db::Slice( "PieceUsageBytes" ), dev::db::Slice( "123456789" ) ); + db->insert( dev::db::Slice( "ppieceUsageBytes" ), dev::db::Slice( "123456789" ) ); + for ( size_t i = 0; i < 123; ++i ) { - std::string key = std::to_string( 43 + i ); - std::string value = std::to_string( i ); + std::string key = dev::h256::random().hex(); + std::string value = dev::h256::random().hex(); db->insert( dev::db::Slice(key), dev::db::Slice(value) ); + + randomKeysValues[i] = { key, value }; } hash = db->hashBase(); } + boost::filesystem::remove_all( td.path() ); + BOOST_REQUIRE( !boost::filesystem::exists( td.path() ) ); + dev::h256 hash_same; { std::unique_ptr< dev::db::LevelDB > db_copy( new dev::db::LevelDB( td.path() ) ); BOOST_REQUIRE( db_copy ); for ( size_t i = 0; i < 123; ++i ) { - std::string key = std::to_string( 43 + i ); - std::string value = std::to_string( i ); + std::string key = randomKeysValues[i].first; + std::string value = randomKeysValues[i].second; db_copy->insert( dev::db::Slice(key), dev::db::Slice(value) ); } + db_copy->insert( dev::db::Slice( "PieceUsageBytes" ), dev::db::Slice( "123456789" ) ); + db_copy->insert( dev::db::Slice( "ppieceUsageBytes" ), dev::db::Slice( "123456789" ) ); hash_same = db_copy->hashBase(); } BOOST_REQUIRE( hash == hash_same ); + boost::filesystem::remove_all( td.path() ); + BOOST_REQUIRE( !boost::filesystem::exists( td.path() ) ); + + dev::h256 hashPartially; + { + { + std::unique_ptr< dev::db::LevelDB > db_copy( new dev::db::LevelDB( td.path() ) ); + BOOST_REQUIRE( db_copy ); + + for ( size_t i = 0; i < 123; ++i ) { + std::string key = randomKeysValues[i].first; + std::string value = randomKeysValues[i].second; + db_copy->insert( dev::db::Slice(key), dev::db::Slice(value) ); + } + + db_copy->insert( dev::db::Slice( "PieceUsageBytes" ), dev::db::Slice( "123456789" ) ); + db_copy->insert( dev::db::Slice( "ppieceUsageBytes" ), dev::db::Slice( "123456789" ) ); + } + + secp256k1_sha256_t dbCtx; + secp256k1_sha256_initialize( &dbCtx ); + + std::string lastHashedKey = "start"; + bool isContinue = true; + while ( isContinue ) { + std::unique_ptr< dev::db::LevelDB > m_db( new dev::db::LevelDB( td.path(), + dev::db::LevelDB::defaultSnapshotReadOptions(), dev::db::LevelDB::defaultWriteOptions(), + dev::db::LevelDB::defaultSnapshotDBOptions() ) ); + + isContinue = m_db->hashBasePartially( &dbCtx, lastHashedKey ); + } + + secp256k1_sha256_finalize( &dbCtx, hashPartially.data() ); + } + + BOOST_REQUIRE( hash == hashPartially ); + + boost::filesystem::remove_all( td.path() ); + BOOST_REQUIRE( !boost::filesystem::exists( td.path() ) ); + dev::h256 hash_diff; { std::unique_ptr< dev::db::LevelDB > db_diff( new dev::db::LevelDB( td.path() ) ); BOOST_REQUIRE( db_diff ); for ( size_t i = 0; i < 123; ++i ) { - std::string key = std::to_string( 42 + i ); - std::string value = std::to_string( i ); + std::string key = dev::h256::random().hex(); + std::string value = dev::h256::random().hex(); db_diff->insert( dev::db::Slice(key), dev::db::Slice(value) ); } diff --git a/test/unittests/libweb3jsonrpc/WebThreeStubClient.cpp b/test/unittests/libweb3jsonrpc/WebThreeStubClient.cpp index 597104bf2..acdebbf42 100644 --- a/test/unittests/libweb3jsonrpc/WebThreeStubClient.cpp +++ b/test/unittests/libweb3jsonrpc/WebThreeStubClient.cpp @@ -396,9 +396,11 @@ std::string WebThreeStubClient::eth_sendTransaction( const Json::Value& param1 ) jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString() ); } -std::string WebThreeStubClient::eth_estimateGas( const Json::Value& param1 ) { +std::string WebThreeStubClient::eth_estimateGas( const Json::Value& param1, const std::string& param2 ) { Json::Value p; p.append( param1 ); + if(!param2.empty()) + p.append( param2 ); Json::Value result = this->CallMethod( "eth_estimateGas", p ); if ( result.isString() ) return result.asString(); diff --git a/test/unittests/libweb3jsonrpc/WebThreeStubClient.h b/test/unittests/libweb3jsonrpc/WebThreeStubClient.h index d6acd634c..5f56db895 100644 --- a/test/unittests/libweb3jsonrpc/WebThreeStubClient.h +++ b/test/unittests/libweb3jsonrpc/WebThreeStubClient.h @@ -57,7 +57,7 @@ class WebThreeStubClient : public jsonrpc::Client { std::string eth_call( const Json::Value& param1, const std::string& param2 ) noexcept( false ); std::string eth_callEIP1898( const Json::Value& param1, const Json::Value& param2 ) noexcept( false ); bool eth_flush() noexcept( false ); - std::string eth_estimateGas( const Json::Value& param1 ) noexcept( false ); + std::string eth_estimateGas( const Json::Value& param1, const std::string& param2 = "latest" ) noexcept( false ); Json::Value eth_getBlockByHash( const std::string& param1, bool param2 ) noexcept( false ); Json::Value eth_getBlockByNumber( const std::string& param1, bool param2 ) noexcept( false ); Json::Value eth_getTransactionByHash( const std::string& param1 ) noexcept( false ); diff --git a/test/unittests/libweb3jsonrpc/jsonrpc.cpp b/test/unittests/libweb3jsonrpc/jsonrpc.cpp index 1da3f94a9..714bb525e 100644 --- a/test/unittests/libweb3jsonrpc/jsonrpc.cpp +++ b/test/unittests/libweb3jsonrpc/jsonrpc.cpp @@ -40,7 +40,7 @@ #include #include #include -// SKALE #include +#include #include #include #include @@ -78,6 +78,7 @@ static std::string const c_genesisConfigString = "EIP158ForkBlock": "0x00", "byzantiumForkBlock": "0x00", "constantinopleForkBlock": "0x00", + "istanbulForkBlock": "0x00", "skaleDisableChainIdCheck": true, "externalGasDifficulty": "0x1" }, @@ -245,7 +246,9 @@ class TestIpcClient : public jsonrpc::IClientConnector { }; struct JsonRpcFixture : public TestOutputHelperFixture { - JsonRpcFixture( const std::string& _config = "", bool _owner = true, bool _deploymentControl = true, bool _generation2 = false, bool _mtmEnabled = false ) { + JsonRpcFixture( const std::string& _config = "", bool _owner = true, + bool _deploymentControl = true, bool _generation2 = false, + bool _mtmEnabled = false, bool _isSyncNode = false, int _emptyBlockIntervalMs = -1 ) { dev::p2p::NetworkPreferences nprefs; ChainParams chainParams; @@ -280,11 +283,15 @@ struct JsonRpcFixture : public TestOutputHelperFixture { chainParams.byzantiumForkBlock = 0; chainParams.EIP158ForkBlock = 0; chainParams.constantinopleForkBlock = 0; + chainParams.istanbulForkBlock = 0; chainParams.externalGasDifficulty = 1; chainParams.sChain.contractStorageLimit = 128; // 615 + 1430 is experimentally-derived block size + average extras size chainParams.sChain.dbStorageLimit = 320.5*( 615 + 1430 ); chainParams.sChain.contractStoragePatchTimestamp = 1; + powPatchActivationTimestamp = time(nullptr) + 60; + chainParams.sChain.correctForkInPowPatchTimestamp = powPatchActivationTimestamp; // 10 guessed seconds + chainParams.sChain.emptyBlockIntervalMs = _emptyBlockIntervalMs; // add random extra data to randomize genesis hash and get random DB path, // so that tests can be run in parallel // TODO: better make it use ethemeral in-memory databases @@ -293,6 +300,7 @@ struct JsonRpcFixture : public TestOutputHelperFixture { chainParams.sChain.nodes[0].port = chainParams.sChain.nodes[0].port6 = rand_port; } chainParams.sChain.multiTransactionMode = _mtmEnabled; + chainParams.nodeInfo.syncNode = _isSyncNode; // web3.reset( new WebThreeDirect( // "eth tests", tempDir.path(), "", chainParams, WithExisting::Kill, {"eth"}, @@ -313,23 +321,24 @@ struct JsonRpcFixture : public TestOutputHelperFixture { client->setAuthor( coinbase.address() ); // wait for 1st block - because it's always empty - std::promise< void > block_promise; + std::promise< void > blockPromise; auto importHandler = client->setOnBlockImport( - [&block_promise]( BlockHeader const& ) { - block_promise.set_value(); + [&blockPromise]( BlockHeader const& ) { + blockPromise.set_value(); } ); client->injectSkaleHost(); client->startWorking(); - block_promise.get_future().wait(); + if ( !_isSyncNode ) + blockPromise.get_future().wait(); if ( !_generation2 ) client->setAuthor( coinbase.address() ); else client->setAuthor( chainParams.sChain.blockAuthor ); - using FullServer = ModularServer< rpc::EthFace, /* rpc::NetFace,*/ rpc::Web3Face, + using FullServer = ModularServer< rpc::EthFace, rpc::NetFace, rpc::Web3Face, rpc::AdminEthFace /*, rpc::AdminNetFace*/, rpc::DebugFace, rpc::TestFace >; accountHolder.reset( new FixedAccountHolder( [&]() { return client.get(); }, {} ) ); @@ -343,7 +352,7 @@ struct JsonRpcFixture : public TestOutputHelperFixture { gasPricer = make_shared< eth::TrivialGasPricer >( 0, DefaultGasPrice ); - rpcServer.reset( new FullServer( ethFace /*, new rpc::Net(*web3)*/, + rpcServer.reset( new FullServer( ethFace , new rpc::Net( chainParams ), new rpc::Web3( /*web3->clientVersion()*/ ), // TODO Add real version? new rpc::AdminEth( *client, *gasPricer, keyManager, *sessionManager.get() ), /*new rpc::AdminNet(*web3, *sessionManager), */ new rpc::Debug( *client ), @@ -410,6 +419,7 @@ struct JsonRpcFixture : public TestOutputHelperFixture { unique_ptr< WebThreeStubClient > rpcClient; std::string adminSession; SkaleServerOverride* skale_server_connector; + time_t powPatchActivationTimestamp; }; struct RestrictedAddressFixture : public JsonRpcFixture { @@ -502,6 +512,23 @@ BOOST_AUTO_TEST_CASE( jsonrpc_number ) { // BOOST_CHECK_EQUAL(web3->isNetworkStarted(), false); //} +BOOST_AUTO_TEST_CASE( jsonrpc_netVersion ) +{ + std::string _config = c_genesisConfigString; + Json::Value ret; + Json::Reader().parse( _config, ret ); + + // Set chainID = 65535 + ret["params"]["chainID"] = "0xffff"; + + Json::FastWriter fastWriter; + std::string config = fastWriter.write( ret ); + JsonRpcFixture fixture( config ); + + auto version = fixture.rpcClient->net_version(); + BOOST_CHECK_EQUAL( version, "65535" ); +} + BOOST_AUTO_TEST_CASE( jsonrpc_setMining ) { JsonRpcFixture fixture; fixture.rpcClient->admin_eth_setMining( true, fixture.adminSession ); @@ -724,6 +751,41 @@ BOOST_AUTO_TEST_CASE( eth_sendRawTransaction_errorDuplicateTransaction ) { "Same transaction already exists in the pending transaction queue." ); } +BOOST_AUTO_TEST_CASE( send_raw_tx_sync ) { + // Enable sync mode + JsonRpcFixture fixture( c_genesisConfigString, true, true, true, false, true ); + Address senderAddress = fixture.coinbase.address(); + fixture.client->setAuthor( senderAddress ); + + // contract test { + // function f(uint a) returns(uint d) { return a * 7; } + // } + + string compiled = + "6080604052341561000f57600080fd5b60b98061001d6000396000f300" + "608060405260043610603f576000357c01000000000000000000000000" + "00000000000000000000000000000000900463ffffffff168063b3de64" + "8b146044575b600080fd5b3415604e57600080fd5b606a600480360381" + "019080803590602001909291905050506080565b604051808281526020" + "0191505060405180910390f35b60006007820290509190505600a16562" + "7a7a72305820f294e834212334e2978c6dd090355312a3f0f9476b8eb9" + "8fb480406fc2728a960029"; + + Json::Value create; + create["code"] = compiled; + create["gas"] = "180000"; + + BOOST_REQUIRE( fixture.client->transactionQueueStatus().current == 0); + + // Sending tx to sync node + string txHash = fixture.rpcClient->eth_sendTransaction( create ); + + auto pendingTransactions = fixture.client->pending(); + BOOST_REQUIRE( pendingTransactions.size() == 1); + auto txHashFromQueue = "0x" + pendingTransactions[0].sha3().hex(); + BOOST_REQUIRE( txHashFromQueue == txHash ); +} + BOOST_AUTO_TEST_CASE( eth_signTransaction ) { JsonRpcFixture fixture; auto address = fixture.coinbase.address(); @@ -1246,7 +1308,11 @@ BOOST_AUTO_TEST_CASE( eth_estimateGas ) { testPositive["to"] = "0xD2001300000000000000000000000000000000D4"; testPositive["data"] = "0xfdde8d66000000000000000000000000000000000000000000000000000000000000c350"; response = fixture.rpcClient->eth_estimateGas( testPositive ); - BOOST_CHECK( response == "0x1dc58" ); + string response2 = fixture.rpcClient->eth_estimateGas( testPositive, "latest" ); + string response3 = fixture.rpcClient->eth_estimateGas( testPositive, "1" ); + BOOST_CHECK_EQUAL( response, "0x1db20" ); + BOOST_CHECK_EQUAL( response2, "0x1db20" ); + BOOST_CHECK_EQUAL( response3, "0x1db20" ); } BOOST_AUTO_TEST_CASE( eth_sendRawTransaction_gasLimitExceeded ) { @@ -1536,6 +1602,78 @@ BOOST_AUTO_TEST_CASE( call_from_parameter ) { responseString, "0x000000000000000000000000112233445566778899aabbccddeeff0011223344" ); } +BOOST_AUTO_TEST_CASE( simplePoWTransaction ) { + // 1s empty block interval + JsonRpcFixture fixture( "", true, true, false, false, false, 1000 ); + dev::eth::simulateMining( *( fixture.client ), 1 ); + + auto senderAddress = fixture.coinbase.address(); + + Json::Value transact; + transact["from"] = toJS( senderAddress ); + transact["to"] = toJS( senderAddress ); + // 1k + ostringstream ss("0x"); + for(int i=0; i<1024/16; ++i) + ss << "112233445566778899aabbccddeeff11"; + transact["data"] = ss.str(); + + string gasEstimateStr = fixture.rpcClient->eth_estimateGas(transact); + u256 gasEstimate = jsToU256(gasEstimateStr); + + // old estimate before patch + BOOST_REQUIRE_EQUAL(gasEstimate, u256(21000+1024*68)); + + u256 powGasPrice = 0; + u256 correctEstimate = u256(21000+1024*16); + do { + const u256 GAS_PER_HASH = 1; + u256 candidate = h256::random(); + h256 hash = dev::sha3( senderAddress ) ^ dev::sha3( u256( 0 ) ) ^ dev::sha3( candidate ); + u256 externalGas = ~u256( 0 ) / u256( hash ) * GAS_PER_HASH; + if ( externalGas >= correctEstimate && externalGas < correctEstimate + correctEstimate/10 ) { + powGasPrice = candidate; + } + } while ( !powGasPrice ); + // Account balance is too low will mean that PoW didn't work out + transact["gasPrice"] = toJS( powGasPrice ); + + // wait for patch turning on and see how it happens + string txHash; + BlockHeader badInfo, goodInfo; + for(;;) { + string gasEstimateStr = fixture.rpcClient->eth_estimateGas(transact); + u256 gasEstimate = jsToU256(gasEstimateStr); + // old + if(gasEstimate == u256(21000+1024*68)){ + try{ + fixture.rpcClient->eth_sendTransaction( transact ); + BOOST_REQUIRE(false); + } catch(const std::exception& ex) { + assert(string(ex.what()).find("balance is too low") != string::npos); + badInfo = fixture.client->blockInfo(fixture.client->hashFromNumber(LatestBlock)); + dev::eth::mineTransaction( *( fixture.client ), 1 ); // empty block + } // catch + } + // new + else { + BOOST_REQUIRE_EQUAL(gasEstimate, correctEstimate); + txHash = fixture.rpcClient->eth_sendTransaction( transact ); + goodInfo = fixture.client->blockInfo(fixture.client->hashFromNumber(LatestBlock)); + break; + } // else + } // for + + BOOST_REQUIRE_LT(badInfo.timestamp(), fixture.powPatchActivationTimestamp); + BOOST_REQUIRE_GE(goodInfo.timestamp(), fixture.powPatchActivationTimestamp); + BOOST_REQUIRE_EQUAL(badInfo.number()+1, goodInfo.number()); + + dev::eth::mineTransaction( *( fixture.client ), 1 ); + + Json::Value receipt = fixture.rpcClient->eth_getTransactionReceipt( txHash ); + BOOST_REQUIRE_EQUAL(receipt["status"], "0x1"); +} + BOOST_AUTO_TEST_CASE( transactionWithoutFunds ) { JsonRpcFixture fixture; dev::eth::simulateMining( *( fixture.client ), 1 ); @@ -1579,22 +1717,26 @@ BOOST_AUTO_TEST_CASE( transactionWithoutFunds ) { string balanceString = fixture.rpcClient->eth_getBalance( toJS( address2 ), "latest" ); BOOST_REQUIRE_EQUAL( toJS( 0 ), balanceString ); + Json::Value transact; + transact["from"] = toJS( address2 ); + transact["to"] = contractAddress; + transact["data"] = "0x15b2eec30000000000000000000000000000000000000000000000000000000000000003"; + + string gasEstimateStr = fixture.rpcClient->eth_estimateGas(transact); + u256 gasEstimate = jsToU256(gasEstimateStr); + u256 powGasPrice = 0; do { const u256 GAS_PER_HASH = 1; u256 candidate = h256::random(); h256 hash = dev::sha3( address2 ) ^ dev::sha3( u256( 0 ) ) ^ dev::sha3( candidate ); u256 externalGas = ~u256( 0 ) / u256( hash ) * GAS_PER_HASH; - if ( externalGas >= 21000 + 21000 ) { + if ( externalGas >= gasEstimate && externalGas < gasEstimate + gasEstimate/10 ) { powGasPrice = candidate; } } while ( !powGasPrice ); - - Json::Value transact; - transact["from"] = toJS( address2 ); - transact["to"] = contractAddress; transact["gasPrice"] = toJS( powGasPrice ); - transact["data"] = "0x15b2eec30000000000000000000000000000000000000000000000000000000000000003"; + fixture.rpcClient->eth_sendTransaction( transact ); dev::eth::mineTransaction( *( fixture.client ), 1 ); @@ -1848,7 +1990,8 @@ contract TestEstimateGas { txStore1["data"] = "0x6057361d0000000000000000000000000000000000000000000000000000000000000001"; txStore1["from"] = toJS( senderAddress ); txStore1["gasPrice"] = fixture.rpcClient->eth_gasPrice(); - string txHash = fixture.rpcClient->eth_call( txStore1, "latest" ); + fixture.rpcClient->eth_sendTransaction( txStore1 ); + dev::eth::mineTransaction( *( fixture.client ), 1 ); Json::Value estimateGasCall; // call clear(0) estimateGasCall["to"] = contractAddress; @@ -1858,11 +2001,25 @@ contract TestEstimateGas { string estimatedGas = fixture.rpcClient->eth_estimateGas( estimateGasCall ); dev::bytes data = dev::jsToBytes( estimateGasCall["data"].asString() ); - BOOST_REQUIRE( dev::jsToU256( estimatedGas ) > dev::eth::TransactionBase::baseGasRequired( false, &data, fixture.client->chainParams().scheduleForBlockNumber( fixture.client->number() ) ) ); - BOOST_REQUIRE( dev::jsToU256( estimatedGas ) == 21871 ); + + // try to send with this gas + estimateGasCall["gas"] = toJS( jsToInt( estimatedGas ) ); + string clearHash = fixture.rpcClient->eth_sendTransaction( estimateGasCall ); + dev::eth::mineTransaction( *( fixture.client ), 1 ); + Json::Value clearReceipt = fixture.rpcClient->eth_getTransactionReceipt( clearHash ); + BOOST_REQUIRE_EQUAL(clearReceipt["status"], "0x1"); + BOOST_REQUIRE_LT(jsToInt(clearReceipt["gasUsed"].asString()), 21000); + + // try to lower gas + estimateGasCall["gas"] = toJS( jsToInt( estimatedGas ) - 1 ); + clearHash = fixture.rpcClient->eth_sendTransaction( estimateGasCall ); + dev::eth::mineTransaction( *( fixture.client ), 1 ); + clearReceipt = fixture.rpcClient->eth_getTransactionReceipt( clearHash ); + BOOST_REQUIRE_EQUAL(clearReceipt["status"], "0x0"); + BOOST_REQUIRE_GT(jsToInt(clearReceipt["gasUsed"].asString()), 21000); } BOOST_AUTO_TEST_CASE( storage_limit_contract ) { @@ -2942,15 +3099,36 @@ BOOST_AUTO_TEST_CASE( skip_invalid_transactions ) { #ifdef HISTORIC_STATE // 3 check that historic node sees only 3 txns + string explicitNumberStr = to_string(fixture.client->number()); + // 1 Block Json::Value block = fixture.rpcClient->eth_getBlockByNumber("latest", "false"); + string bh = block["hash"].asString(); + + // 2 transaction count + Json::Value cnt = fixture.rpcClient->eth_getBlockTransactionCountByNumber("latest"); + BOOST_REQUIRE_EQUAL(cnt.asString(), "0x3"); + cnt = fixture.rpcClient->eth_getBlockTransactionCountByNumber(explicitNumberStr); + BOOST_REQUIRE_EQUAL(cnt.asString(), "0x3"); + cnt = fixture.rpcClient->eth_getBlockTransactionCountByHash(bh); + BOOST_REQUIRE_EQUAL(cnt.asString(), "0x3"); + + + BOOST_REQUIRE_EQUAL(block["transactions"].size(), 3); + BOOST_REQUIRE_EQUAL(block["transactions"][0]["transactionIndex"], "0x0"); + BOOST_REQUIRE_EQUAL(block["transactions"][1]["transactionIndex"], "0x1"); + BOOST_REQUIRE_EQUAL(block["transactions"][2]["transactionIndex"], "0x2"); + + // same with explicit number + block = fixture.rpcClient->eth_getBlockByNumber(explicitNumberStr, "false"); + BOOST_REQUIRE_EQUAL(block["transactions"].size(), 3); BOOST_REQUIRE_EQUAL(block["transactions"][0]["transactionIndex"], "0x0"); BOOST_REQUIRE_EQUAL(block["transactions"][1]["transactionIndex"], "0x1"); BOOST_REQUIRE_EQUAL(block["transactions"][2]["transactionIndex"], "0x2"); - // 2 receipts + // 3 receipts Json::Value r1,r3,r4; BOOST_REQUIRE_NO_THROW(r1 = fixture.rpcClient->eth_getTransactionReceipt(toJS(h1))); BOOST_REQUIRE_THROW (fixture.rpcClient->eth_getTransactionReceipt(toJS(h2)), jsonrpc::JsonRpcException); @@ -2961,16 +3139,24 @@ BOOST_AUTO_TEST_CASE( skip_invalid_transactions ) { BOOST_REQUIRE_EQUAL(r3["transactionIndex"], "0x1"); BOOST_REQUIRE_EQUAL(r4["transactionIndex"], "0x2"); - // 3 transaction by index + // 4 transaction by index Json::Value t0 = fixture.rpcClient->eth_getTransactionByBlockNumberAndIndex("latest", "0"); Json::Value t1 = fixture.rpcClient->eth_getTransactionByBlockNumberAndIndex("latest", "1"); Json::Value t2 = fixture.rpcClient->eth_getTransactionByBlockNumberAndIndex("latest", "2"); + BOOST_REQUIRE_EQUAL(jsToFixed<32>(t0["hash"].asString()), h1); + BOOST_REQUIRE_EQUAL(jsToFixed<32>(t1["hash"].asString()), h3); + BOOST_REQUIRE_EQUAL(jsToFixed<32>(t2["hash"].asString()), h4); + // same with explicit block number + + t0 = fixture.rpcClient->eth_getTransactionByBlockNumberAndIndex(explicitNumberStr, "0"); + t1 = fixture.rpcClient->eth_getTransactionByBlockNumberAndIndex(explicitNumberStr, "1"); + t2 = fixture.rpcClient->eth_getTransactionByBlockNumberAndIndex(explicitNumberStr, "2"); BOOST_REQUIRE_EQUAL(jsToFixed<32>(t0["hash"].asString()), h1); BOOST_REQUIRE_EQUAL(jsToFixed<32>(t1["hash"].asString()), h3); BOOST_REQUIRE_EQUAL(jsToFixed<32>(t2["hash"].asString()), h4); - string bh = r1["blockHash"].asString(); + BOOST_REQUIRE_EQUAL(bh, r1["blockHash"].asString()); t0 = fixture.rpcClient->eth_getTransactionByBlockHashAndIndex(bh, "0"); t1 = fixture.rpcClient->eth_getTransactionByBlockHashAndIndex(bh, "1"); @@ -2980,15 +3166,9 @@ BOOST_AUTO_TEST_CASE( skip_invalid_transactions ) { BOOST_REQUIRE_EQUAL(jsToFixed<32>(t1["hash"].asString()), h3); BOOST_REQUIRE_EQUAL(jsToFixed<32>(t2["hash"].asString()), h4); - // 4 transaction by hash + // 5 transaction by hash BOOST_REQUIRE_THROW (fixture.rpcClient->eth_getTransactionByHash(toJS(h2)), jsonrpc::JsonRpcException); - // 5 transaction count - Json::Value cnt = fixture.rpcClient->eth_getBlockTransactionCountByNumber("latest"); - BOOST_REQUIRE_EQUAL(cnt.asString(), "0x3"); - cnt = fixture.rpcClient->eth_getBlockTransactionCountByHash(bh); - BOOST_REQUIRE_EQUAL(cnt.asString(), "0x3"); - // send it successfully // make money @@ -3234,7 +3414,7 @@ BOOST_AUTO_TEST_CASE( test_transactions ) { Transaction valid( fromHex( "0xf86c808504a817c80083015f90943d7112ee86223baf0a506b9d2a77595cbbba51d1872386f26fc10000801ca0655757fd0650a65a373c48a4dc0f3d6ac5c3831aa0cc2cb863a5909dc6c25f72a071882ee8633466a243c0ea64dadb3120c1ca7a5cc7433c6c0b1c861a85322265" ), CheckTransaction::None ); - valid.checkOutExternalGas( 1 ); + valid.ignoreExternalGas(); client->importTransactionsAsBlock(Transactions{invalid, valid}, 1); @@ -3262,7 +3442,7 @@ BOOST_AUTO_TEST_CASE( test_exceptions ) { Transaction valid( fromHex( "0xf86c808504a817c80083015f90943d7112ee86223baf0a506b9d2a77595cbbba51d1872386f26fc10000801ca0655757fd0650a65a373c48a4dc0f3d6ac5c3831aa0cc2cb863a5909dc6c25f72a071882ee8633466a243c0ea64dadb3120c1ca7a5cc7433c6c0b1c861a85322265" ), CheckTransaction::None ); - valid.checkOutExternalGas( 1 ); + valid.ignoreExternalGas(); client->importTransactionsAsBlock(Transactions{invalid, valid}, 1);