diff --git a/.cicd/defaults.json b/.cicd/defaults.json index fd637bc48a..3ec177b341 100644 --- a/.cicd/defaults.json +++ b/.cicd/defaults.json @@ -4,6 +4,6 @@ "prerelease":false }, "eossystemcontracts":{ - "ref":"release/3.1" + "ref":"release/3.2" } } diff --git a/.cicd/platforms.json b/.cicd/platforms.json deleted file mode 100644 index fccc8dbc00..0000000000 --- a/.cicd/platforms.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "ubuntu20": { - "dockerfile": ".cicd/platforms/ubuntu20.Dockerfile" - }, - "ubuntu22": { - "dockerfile": ".cicd/platforms/ubuntu22.Dockerfile" - } -} diff --git a/.cicd/platforms/ubuntu20.Dockerfile b/.cicd/platforms/ubuntu20.Dockerfile index 56bf2c8a54..fe7aaea80e 100644 --- a/.cicd/platforms/ubuntu20.Dockerfile +++ b/.cicd/platforms/ubuntu20.Dockerfile @@ -9,7 +9,6 @@ RUN apt-get update && apt-get upgrade -y && \ jq \ libcurl4-openssl-dev \ libgmp-dev \ - libssl-dev \ llvm-11-dev \ ninja-build \ python3-numpy \ diff --git a/.cicd/platforms/ubuntu22.Dockerfile b/.cicd/platforms/ubuntu22.Dockerfile index 57d49fe026..275d52a4c7 100644 --- a/.cicd/platforms/ubuntu22.Dockerfile +++ b/.cicd/platforms/ubuntu22.Dockerfile @@ -8,7 +8,6 @@ RUN apt-get update && apt-get upgrade -y && \ jq \ libcurl4-openssl-dev \ libgmp-dev \ - libssl-dev \ llvm-11-dev \ ninja-build \ python3-numpy \ diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 6739f7eec2..4dccdddd5b 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -31,23 +31,25 @@ defaults: shell: bash jobs: - platforms: - name: Run Platforms Workflow - uses: ./.github/workflows/platforms.yaml + platform-cache: + name: Platform Cache + uses: AntelopeIO/platform-cache-workflow/.github/workflows/platformcache.yaml@v1 permissions: packages: write contents: read + with: + runs-on: '["self-hosted", "enf-x86-beefy"]' + platform-files: | + .cicd/platforms + tools/reproducible.Dockerfile:builder build-base: name: Run Build Workflow uses: ./.github/workflows/build_base.yaml - needs: [platforms] + needs: [platform-cache] with: - p: ${{needs.platforms.outputs.p}} - platform-matrix: ${{needs.platforms.outputs.platform-matrix}} - permissions: - packages: write - contents: read + platforms: ${{needs.platform-cache.outputs.platforms}} + platform-list: ${{needs.platform-cache.outputs.platform-list}} v: name: Discover Versions @@ -77,16 +79,15 @@ jobs: echo eos-system-contracts-ref=${{inputs.override-eos-system-contracts}} >> $GITHUB_OUTPUT fi - dev-package: - name: Build leap-dev package - needs: [platforms, build-base] - if: always() && needs.platforms.result == 'success' && needs.build-base.result == 'success' + package: + name: Build deb packages + needs: [platform-cache, build-base] strategy: fail-fast: false matrix: - platform: [ubuntu20, ubuntu22] + platform: [ubuntu20, ubuntu22, reproducible] runs-on: ubuntu-latest - container: ${{fromJSON(needs.platforms.outputs.p)[matrix.platform].image}} + container: ${{fromJSON(needs.platform-cache.outputs.platforms)[matrix.platform].image}} steps: - uses: actions/checkout@v3 with: @@ -95,42 +96,55 @@ jobs: uses: actions/download-artifact@v3 with: name: ${{matrix.platform}}-build - - name: Build dev package + - name: Build packages run: | zstdcat build.tar.zst | tar x cd build cpack + ../tools/tweak-deb.sh leap_*.deb - name: Install dev package + if: matrix.platform != 'reproducible' run: | apt-get update && apt-get upgrade -y apt-get install -y ./build/leap_*.deb ./build/leap-dev*.deb - name: Test using TestHarness + if: matrix.platform != 'reproducible' run: | python3 -c "from TestHarness import Cluster" - name: Upload dev package uses: actions/upload-artifact@v3 + if: matrix.platform != 'reproducible' with: name: leap-dev-${{matrix.platform}}-amd64 path: build/leap-dev*.deb + - name: Upload leap package + uses: actions/upload-artifact@v3 + if: matrix.platform == 'reproducible' + with: + name: leap-deb-amd64 + path: build/leap_*.deb tests: - name: Tests - needs: [platforms, build-base] - if: always() && needs.platforms.result == 'success' && needs.build-base.result == 'success' + name: Tests (${{matrix.cfg.name}}) + needs: [platform-cache, build-base] strategy: fail-fast: false matrix: - platform: [ubuntu20, ubuntu22] + include: + - cfg: {name: 'ubuntu20', base: 'ubuntu20', builddir: 'ubuntu20'} + - cfg: {name: 'ubuntu22', base: 'ubuntu22', builddir: 'ubuntu22'} + - cfg: {name: 'ubuntu20repro', base: 'ubuntu20', builddir: 'reproducible'} + - cfg: {name: 'ubuntu22repro', base: 'ubuntu22', builddir: 'reproducible'} runs-on: ["self-hosted", "enf-x86-hightier"] container: - image: ${{fromJSON(needs.platforms.outputs.p)[matrix.platform].image}} + image: ${{fromJSON(needs.platform-cache.outputs.platforms)[matrix.cfg.base].image}} options: --security-opt seccomp=unconfined steps: - uses: actions/checkout@v3 - name: Download builddir uses: actions/download-artifact@v3 with: - name: ${{matrix.platform}}-build + name: ${{matrix.cfg.builddir}}-build - name: Run Parallel Tests run: | # https://github.com/actions/runner/issues/2033 -- need this because of full version label test looking at git revs @@ -142,76 +156,81 @@ jobs: run: awk 'BEGIN {err = 1} /bmi2/ && /adx/ {err = 0} END {exit err}' /proc/cpuinfo np-tests: - name: NP Tests - needs: [platforms, build-base] - if: always() && needs.platforms.result == 'success' && needs.build-base.result == 'success' + name: NP Tests (${{matrix.cfg.name}}) + needs: [platform-cache, build-base] strategy: fail-fast: false matrix: - platform: [ubuntu20, ubuntu22] + include: + - cfg: {name: 'ubuntu20', base: 'ubuntu20', builddir: 'ubuntu20'} + - cfg: {name: 'ubuntu22', base: 'ubuntu22', builddir: 'ubuntu22'} + - cfg: {name: 'ubuntu20repro', base: 'ubuntu20', builddir: 'reproducible'} + - cfg: {name: 'ubuntu22repro', base: 'ubuntu22', builddir: 'reproducible'} runs-on: ["self-hosted", "enf-x86-midtier"] steps: - uses: actions/checkout@v3 - name: Download builddir uses: actions/download-artifact@v3 with: - name: ${{matrix.platform}}-build + name: ${{matrix.cfg.builddir}}-build - name: Run tests in parallel containers uses: ./.github/actions/parallel-ctest-containers with: - container: ${{fromJSON(needs.platforms.outputs.p)[matrix.platform].image}} + container: ${{fromJSON(needs.platform-cache.outputs.platforms)[matrix.cfg.base].image}} error-log-paths: '["build/etc", "build/var", "build/leap-ignition-wd", "build/TestLogs"]' - log-tarball-prefix: ${{matrix.platform}} + log-tarball-prefix: ${{matrix.cfg.name}} tests-label: nonparallelizable_tests test-timeout: 420 - name: Upload logs from failed tests uses: actions/upload-artifact@v3 if: failure() with: - name: ${{matrix.platform}}-np-logs + name: ${{matrix.cfg.name}}-np-logs path: '*-logs.tar.gz' lr-tests: - name: LR Tests - needs: [platforms, build-base] - if: always() && needs.platforms.result == 'success' && needs.build-base.result == 'success' + name: LR Tests (${{matrix.cfg.name}}) + needs: [platform-cache, build-base] strategy: fail-fast: false matrix: - platform: [ubuntu20, ubuntu22] + include: + - cfg: {name: 'ubuntu20', base: 'ubuntu20', builddir: 'ubuntu20'} + - cfg: {name: 'ubuntu22', base: 'ubuntu22', builddir: 'ubuntu22'} + - cfg: {name: 'ubuntu20repro', base: 'ubuntu20', builddir: 'reproducible'} + - cfg: {name: 'ubuntu22repro', base: 'ubuntu22', builddir: 'reproducible'} runs-on: ["self-hosted", "enf-x86-lowtier"] steps: - uses: actions/checkout@v3 - name: Download builddir uses: actions/download-artifact@v3 with: - name: ${{matrix.platform}}-build + name: ${{matrix.cfg.builddir}}-build - name: Run tests in parallel containers uses: ./.github/actions/parallel-ctest-containers with: - container: ${{fromJSON(needs.platforms.outputs.p)[matrix.platform].image}} + container: ${{fromJSON(needs.platform-cache.outputs.platforms)[matrix.cfg.base].image}} error-log-paths: '["build/etc", "build/var", "build/leap-ignition-wd", "build/TestLogs"]' - log-tarball-prefix: ${{matrix.platform}} + log-tarball-prefix: ${{matrix.cfg.name}} tests-label: long_running_tests test-timeout: 1800 - name: Upload logs from failed tests uses: actions/upload-artifact@v3 if: failure() with: - name: ${{matrix.platform}}-lr-logs + name: ${{matrix.cfg.name}}-lr-logs path: '*-logs.tar.gz' libtester-tests: name: libtester tests - needs: [platforms, build-base, v, dev-package] - if: always() && needs.platforms.result == 'success' && needs.v.result == 'success' && needs.dev-package.result == 'success' + needs: [platform-cache, build-base, v, package] strategy: fail-fast: false matrix: platform: [ubuntu20, ubuntu22] test: [build-tree, make-dev-install, deb-install] runs-on: ["self-hosted", "enf-x86-midtier"] - container: ${{ matrix.test != 'deb-install' && fromJSON(needs.platforms.outputs.p)[matrix.platform].image || matrix.platform == 'ubuntu20' && 'ubuntu:focal' || 'ubuntu:jammy' }} + container: ${{ matrix.test != 'deb-install' && fromJSON(needs.platform-cache.outputs.platforms)[matrix.platform].image || matrix.platform == 'ubuntu20' && 'ubuntu:focal' || 'ubuntu:jammy' }} env: DEBIAN_FRONTEND: noninteractive TZ: Etc/UTC @@ -295,9 +314,9 @@ jobs: all-passing: name: All Required Tests Passed - needs: [dev-package, tests, np-tests, libtester-tests] + needs: [tests, np-tests, libtester-tests] if: always() runs-on: ubuntu-latest steps: - - if: needs.dev-package.result != 'success' || needs.tests.result != 'success' || needs.np-tests.result != 'success' || needs.libtester-tests.result != 'success' + - if: needs.tests.result != 'success' || needs.np-tests.result != 'success' || needs.libtester-tests.result != 'success' run: false diff --git a/.github/workflows/build_base.yaml b/.github/workflows/build_base.yaml index 51dd5d2167..5e6639f968 100644 --- a/.github/workflows/build_base.yaml +++ b/.github/workflows/build_base.yaml @@ -3,12 +3,12 @@ name: "Build leap" on: workflow_call: inputs: - p: - description: "Discovered Build Platforms" + platforms: + description: "Platforms definitions" type: string required: true - platform-matrix: - description: "Platform Matrix" + platform-list: + description: "Array of platforms" type: string required: true @@ -26,9 +26,9 @@ jobs: strategy: fail-fast: false matrix: - platform: ${{fromJSON(inputs.platform-matrix)}} + platform: ${{fromJSON(inputs.platform-list)}} runs-on: ["self-hosted", "enf-x86-beefy"] - container: ${{fromJSON(inputs.p)[matrix.platform].image}} + container: ${{fromJSON(inputs.platforms)[matrix.platform].image}} steps: - uses: actions/checkout@v3 with: diff --git a/.github/workflows/performance_harness_run.yaml b/.github/workflows/performance_harness_run.yaml index 7282bb1316..ce037555a7 100644 --- a/.github/workflows/performance_harness_run.yaml +++ b/.github/workflows/performance_harness_run.yaml @@ -12,6 +12,16 @@ on: override-test-params: description: 'Override perf harness params' type: string + override-leap: + description: Override leap target + type: string + override-leap-prerelease: + type: choice + description: Override leap prelease + options: + - default + - true + - false permissions: packages: read @@ -28,31 +38,39 @@ jobs: runs-on: ubuntu-latest outputs: test-params: ${{steps.overrides.outputs.test-params}} + leap-target: ${{steps.overrides.outputs.leap-target}} + leap-prerelease: ${{steps.overrides.outputs.leap-prerelease}} steps: - name: Setup Input Params id: overrides run: | echo test-params=findMax testBpOpMode >> $GITHUB_OUTPUT + echo leap-target="DEFAULT" >> $GITHUB_OUTPUT + echo leap-prerelease="false" >> $GITHUB_OUTPUT if [[ "${{inputs.override-test-params}}" != "" ]]; then echo test-params=${{inputs.override-test-params}} >> $GITHUB_OUTPUT fi + if [[ "${{inputs.override-leap}}" != "" ]]; then + echo leap-target=${{inputs.override-leap}} >> $GITHUB_OUTPUT + fi + if [[ "${{inputs.override-leap-prerelease}}" == +(true|false) ]]; then + echo leap-prerelease=${{inputs.override-leap-prerelease}} >> $GITHUB_OUTPUT + fi - platforms: - name: Run Platforms Workflow - uses: ./.github/workflows/platforms.yaml - with: - override-build-matrix: ${{github.event.inputs.platform-choice}} + platform-cache: + name: Platform Cache + uses: AntelopeIO/platform-cache-workflow/.github/workflows/platformcache.yaml@v1 permissions: packages: write contents: read + with: + runs-on: '["self-hosted", "enf-x86-beefy"]' + platform-files: .cicd/platforms reuse-build: name: Reuse leap build needs: [v] - if: | - always() && - needs.v.result == 'success' runs-on: ubuntu-latest outputs: build-artifact: ${{steps.downloadBuild.outputs.downloaded-file}} @@ -77,44 +95,63 @@ jobs: build-base: name: Run Build Workflow - needs: [platforms, reuse-build] - if: always() && needs.platforms.result == 'success' && needs.reuse-build.outputs.build-artifact == '' + needs: [platform-cache, reuse-build] + if: needs.reuse-build.outputs.build-artifact == '' uses: ./.github/workflows/build_base.yaml with: - p: ${{needs.platforms.outputs.p}} - platform-matrix: ${{needs.platforms.outputs.platform-matrix}} - permissions: - packages: write - contents: read + platforms: ${{needs.platform-cache.outputs.platforms}} + platform-list: '["${{github.event.inputs.platform-choice}}"]' tests: name: Tests - needs: [v, platforms, reuse-build, build-base] - if: always() && needs.platforms.result == 'success' && (needs.build-base.result == 'success' || needs.reuse-build.result == 'success') - runs-on: ubuntu-latest + needs: [v, platform-cache, reuse-build, build-base] + if: always() && (needs.build-base.result == 'success' || needs.reuse-build.result == 'success') + runs-on: ["Leap-Perf-Ubuntu-22-16x64x600"] container: - image: ${{fromJSON(needs.platforms.outputs.p)[github.event.inputs.platform-choice].image}} + image: ${{fromJSON(needs.platform-cache.outputs.platforms)[github.event.inputs.platform-choice].image}} steps: - name: Download builddir uses: actions/download-artifact@v3 with: name: ${{github.event.inputs.platform-choice}}-build - - name: Run Performance Test + - name: Extract Build Directory run: | zstdcat build.tar.zst | tar x + - if: ${{ needs.v.outputs.leap-target != 'DEFAULT' }} + name: Download Prev Leap Version + uses: AntelopeIO/asset-artifact-download-action@v3 + with: + owner: AntelopeIO + repo: leap + target: '${{needs.v.outputs.leap-target}}' + prereleases: ${{fromJSON(needs.v.outputs.leap-prerelease)}} + file: 'leap.*${{github.event.inputs.platform-choice}}.*(x86_64|amd64).deb' + - if: ${{ needs.v.outputs.leap-target != 'DEFAULT' }} + name: Install leap & replace binaries for PH use + run: | + apt-get update + apt-get install -y ./leap*.deb + rm build/bin/nodeos + rm build/bin/cleos + cp /usr/bin/nodeos build/bin + cp /usr/bin/cleos build/bin + ./build/bin/nodeos --full-version + ./build/bin/cleos version full + - name: Run Performance Test + run: | cd build ./tests/PerformanceHarnessScenarioRunner.py ${{needs.v.outputs.test-params}} - name: Prepare results id: prep-results run: | - tar -pc build/PerformanceHarnessScenarioRunnerLogs | zstd --long -T0 -9 > PerformanceHarnessScenarioRunnerLogs.tar.zst + tar -pc build/PHSRLogs | zstd --long -T0 -9 > PHSRLogs.tar.zst - name: Upload results uses: AntelopeIO/upload-artifact-large-chunks-action@v1 with: name: performance-test-results - path: PerformanceHarnessScenarioRunnerLogs.tar.zst + path: PHSRLogs.tar.zst - name: Upload report uses: actions/upload-artifact@v3 with: name: performance-test-report - path: ./build/PerformanceHarnessScenarioRunnerLogs/**/report.json + path: ./build/PHSRLogs/**/report.json diff --git a/.github/workflows/ph_backward_compatibility.yaml b/.github/workflows/ph_backward_compatibility.yaml index 0abe6b6400..4633108821 100644 --- a/.github/workflows/ph_backward_compatibility.yaml +++ b/.github/workflows/ph_backward_compatibility.yaml @@ -12,36 +12,38 @@ defaults: shell: bash jobs: - platforms: - name: Run Platforms Workflow - uses: ./.github/workflows/platforms.yaml + platform-cache: + name: Platform Cache + uses: AntelopeIO/platform-cache-workflow/.github/workflows/platformcache.yaml@v1 permissions: - packages: write contents: read + packages: write + with: + runs-on: '["self-hosted", "enf-x86-beefy"]' + platform-files: .cicd/platforms build-base: name: Run Build Workflow uses: ./.github/workflows/build_base.yaml - needs: [platforms] + needs: [platform-cache] with: - p: ${{needs.platforms.outputs.p}} - platform-matrix: ${{needs.platforms.outputs.platform-matrix}} + platforms: ${{needs.platform-cache.outputs.platforms}} + platform-list: ${{needs.platform-cache.outputs.platform-list}} permissions: packages: write contents: read tests: name: Tests - needs: [platforms, build-base] - if: always() && needs.platforms.result == 'success' && needs.build-base.result == 'success' + needs: [platform-cache, build-base] strategy: fail-fast: false matrix: - platform: ${{fromJSON(needs.platforms.outputs.platform-matrix)}} + platform: ${{fromJSON(needs.platform-cache.outputs.platform-list)}} release: [3.1, 3.2, 4.0] runs-on: ["self-hosted", "enf-x86-lowtier"] container: - image: ${{fromJSON(needs.platforms.outputs.p)[matrix.platform].image}} + image: ${{fromJSON(needs.platform-cache.outputs.platforms)[matrix.platform].image}} options: --security-opt seccomp=unconfined steps: - uses: actions/checkout@v3 @@ -67,7 +69,8 @@ jobs: rm build/bin/cleos cp /usr/bin/nodeos build/bin cp /usr/bin/cleos build/bin - ./build/bin/nodeos --version + ./build/bin/nodeos --full-version + ./build/bin/cleos version full - if: ${{ matrix.release == '3.1' || matrix.release == '3.2' }} name: Run Performance Tests (> $GITHUB_OUTPUT - - if [[ "${{inputs.override-build-matrix}}" != "" ]]; then - echo 'platform-matrix=["${{inputs.override-build-matrix}}"]' >> $GITHUB_OUTPUT - fi diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 0000000000..dfcd19869d --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,52 @@ +name: Release Actions + +on: + release: + types: [published] + +jobs: + eb: + name: experimental-binaries + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + actions: read + steps: + - name: Get ubuntu20 leap-dev.deb + uses: AntelopeIO/asset-artifact-download-action@v3 + with: + owner: ${{github.repository_owner}} + repo: ${{github.event.repository.name}} + file: 'leap-dev.*amd64.deb' + target: ${{github.sha}} + artifact-name: leap-dev-ubuntu20-amd64 + wait-for-exact-target-workflow: true + - name: Get ubuntu22 leap-dev.deb + uses: AntelopeIO/asset-artifact-download-action@v3 + with: + owner: ${{github.repository_owner}} + repo: ${{github.event.repository.name}} + file: 'leap-dev.*amd64.deb' + target: ${{github.sha}} + artifact-name: leap-dev-ubuntu22-amd64 + wait-for-exact-target-workflow: true + - name: Create Dockerfile + run: | + cat < Dockerfile + FROM scratch + LABEL org.opencontainers.image.description="A collection of experimental Leap binary packages" + COPY *.deb / + EOF + - name: Login to ghcr + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{github.repository_owner}} + password: ${{github.token}} + - name: Build and push experimental-binaries + uses: docker/build-push-action@v3 + with: + push: true + tags: ghcr.io/${{github.repository_owner}}/experimental-binaries:${{github.ref_name}} + context: . diff --git a/.gitmodules b/.gitmodules index e4ca16a9fe..6bd697c27f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -37,3 +37,6 @@ [submodule "libraries/boost"] path = libraries/boost url = https://github.com/boostorg/boost.git +[submodule "libraries/libfc/libraries/boringssl/boringssl"] + path = libraries/libfc/libraries/boringssl/boringssl + url = https://github.com/AntelopeIO/boringssl-build diff --git a/CMakeLists.txt b/CMakeLists.txt index 3c8b0a9f46..29cc78775f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,7 +13,7 @@ set( CMAKE_CXX_STANDARD 20 ) set( CMAKE_CXX_EXTENSIONS ON ) set( CXX_STANDARD_REQUIRED ON) -set(VERSION_MAJOR 4) +set(VERSION_MAJOR 5) set(VERSION_MINOR 1) set(VERSION_PATCH 0) set(VERSION_SUFFIX dev) @@ -54,15 +54,6 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS "ON") set(BUILD_DOXYGEN FALSE CACHE BOOL "Build doxygen documentation on every make") set(ENABLE_MULTIVERSION_PROTOCOL_TEST FALSE CACHE BOOL "Enable nodeos multiversion protocol test") -# add defaults for openssl -if(APPLE AND UNIX AND "${OPENSSL_ROOT_DIR}" STREQUAL "") - if(CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") - set(OPENSSL_ROOT_DIR "/opt/homebrew/opt/openssl@3;/opt/homebrew/opt/openssl@1.1") - else() - set(OPENSSL_ROOT_DIR "/usr/local/opt/openssl@3;/usr/local/opt/openssl@1.1") - endif() -endif() - option(ENABLE_OC "Enable eosvm-oc on supported platforms" ON) # WASM runtimes to enable. Each runtime in this list will have: @@ -180,6 +171,10 @@ if( ENABLE_TCMALLOC ) set(CMAKE_CXX_STANDARD_LIBRARIES "${CMAKE_CXX_STANDARD_LIBRARIES} ${GPERFTOOLS_TCMALLOC}") endif() +# leap includes a bundled BoringSSL which conflicts with OpenSSL. Make sure any other bundled libraries (such as boost) +# do not attempt to use an external OpenSSL in any manner +set(CMAKE_DISABLE_FIND_PACKAGE_OpenSSL On) + add_subdirectory( libraries ) add_subdirectory( plugins ) add_subdirectory( programs ) @@ -226,6 +221,7 @@ configure_file(libraries/eos-vm/LICENSE licen configure_file(libraries/prometheus/prometheus-cpp/LICENSE licenses/leap/LICENSE.prom COPYONLY) configure_file(programs/cleos/LICENSE.CLI11 licenses/leap/LICENSE.CLI11 COPYONLY) configure_file(libraries/libfc/libraries/bls12-381/LICENSE licenses/leap/LICENSE.bls12-381 COPYONLY) +configure_file(libraries/libfc/libraries/boringssl/boringssl/src/LICENSE licenses/leap/LICENSE.boringssl COPYONLY) install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/licenses/leap" DESTINATION "${CMAKE_INSTALL_FULL_DATAROOTDIR}/licenses/" COMPONENT base) diff --git a/CMakeModules/EosioTester.cmake.in b/CMakeModules/EosioTester.cmake.in index b522e1be4e..155819b03f 100644 --- a/CMakeModules/EosioTester.cmake.in +++ b/CMakeModules/EosioTester.cmake.in @@ -37,6 +37,7 @@ endif ( APPLE ) set( Boost_USE_MULTITHREADED ON ) set( Boost_USE_STATIC_LIBS ON CACHE STRING "ON or OFF" ) +set( BOOST_EXCLUDE_LIBRARIES "mysql" ) add_subdirectory( @CMAKE_INSTALL_FULL_DATAROOTDIR@/leap_boost ${PROJECT_BINARY_DIR}/libraries/boost EXCLUDE_FROM_ALL) @@ -52,8 +53,8 @@ find_library(libwast WAST @CMAKE_INSTALL_FULL_LIBDIR@ NO_DEFAULT_PATH) find_library(libir IR @CMAKE_INSTALL_FULL_LIBDIR@ NO_DEFAULT_PATH) find_library(liblogging Logging @CMAKE_INSTALL_FULL_LIBDIR@ NO_DEFAULT_PATH) find_library(libsoftfloat softfloat @CMAKE_INSTALL_FULL_LIBDIR@ NO_DEFAULT_PATH) -get_filename_component(cryptodir @OPENSSL_CRYPTO_LIBRARY@ DIRECTORY) -find_library(liboscrypto crypto "${cryptodir}" NO_DEFAULT_PATH) +find_library(libbscrypto bscrypto @CMAKE_INSTALL_FULL_LIBDIR@ NO_DEFAULT_PATH) +find_library(libdecrepit decrepit @CMAKE_INSTALL_FULL_LIBDIR@ NO_DEFAULT_PATH) find_library(libchainbase chainbase @CMAKE_INSTALL_FULL_LIBDIR@ NO_DEFAULT_PATH) find_library(libbuiltins builtins @CMAKE_INSTALL_FULL_LIBDIR@ NO_DEFAULT_PATH) @@ -67,58 +68,72 @@ if("eos-vm-oc" IN_LIST EOSIO_WASM_RUNTIMES) set(WRAP_MAIN "-Wl,-wrap=main") endif() +add_library(EosioChain INTERFACE) + +target_link_libraries(EosioChain INTERFACE + ${libchain} + ${libfc} + ${libwast} + ${libwasm} + ${libir} + ${libsoftfloat} + ${libbscrypto} + ${libdecrepit} + ${liblogging} + ${libchainbase} + ${libbuiltins} + ${libsecp256k1} + ${libbn256} + ${libbls12-381} + @GMP_LIBRARY@ + + Boost::date_time + Boost::filesystem + Boost::system + Boost::chrono + Boost::multi_index + Boost::multiprecision + Boost::interprocess + Boost::asio + Boost::signals2 + Boost::iostreams + "-lz" # Needed by Boost iostreams + + ${LLVM_LIBS} + + ${PLATFORM_SPECIFIC_LIBS} + + ${WRAP_MAIN} + Threads::Threads +) + +target_include_directories(EosioChain INTERFACE + @OPENSSL_INCLUDE_DIR@ + @CMAKE_INSTALL_PREFIX@ + @CMAKE_INSTALL_FULL_INCLUDEDIR@ + @CMAKE_INSTALL_FULL_INCLUDEDIR@/wasm-jit + @CMAKE_INSTALL_FULL_INCLUDEDIR@/leapboringssl + @CMAKE_INSTALL_FULL_INCLUDEDIR@/softfloat ) + +#adds -ltr. Ubuntu eosio.contracts build breaks without this +if(UNIX AND NOT APPLE) + target_link_libraries(EosioChain INTERFACE ${LIBRT}) +endif() + +add_library(EosioTester INTERFACE) + +target_link_libraries(EosioTester INTERFACE + ${libtester} + Boost::unit_test_framework + EosioChain +) + macro(add_eosio_test_executable test_name) add_executable( ${test_name} ${ARGN} ) target_link_libraries( ${test_name} - ${libtester} - ${libchain} - ${libfc} - ${libwast} - ${libwasm} - ${libir} - ${libsoftfloat} - ${liboscrypto} - ${liblogging} - ${libchainbase} - ${libbuiltins} - ${libsecp256k1} - ${libbn256} - ${libbls12-381} - @GMP_LIBRARY@ - - Boost::date_time - Boost::filesystem - Boost::system - Boost::chrono - Boost::multi_index - Boost::multiprecision - Boost::interprocess - Boost::asio - Boost::signals2 - Boost::iostreams - "-lz" # Needed by Boost iostreams - Boost::unit_test_framework - - ${LLVM_LIBS} - - ${PLATFORM_SPECIFIC_LIBS} - - ${WRAP_MAIN} - Threads::Threads + EosioTester ) - #adds -ltr. Ubuntu eosio.contracts build breaks without this - if(UNIX AND NOT APPLE) - target_link_libraries(${test_name} ${LIBRT}) - endif() - - target_include_directories( ${test_name} PUBLIC - @OPENSSL_INCLUDE_DIR@ - @CMAKE_INSTALL_PREFIX@ - @CMAKE_INSTALL_FULL_INCLUDEDIR@ - @CMAKE_INSTALL_FULL_INCLUDEDIR@/wasm-jit - @CMAKE_INSTALL_FULL_INCLUDEDIR@/softfloat ) - endmacro() macro(add_eosio_test test_name) diff --git a/CMakeModules/EosioTesterBuild.cmake.in b/CMakeModules/EosioTesterBuild.cmake.in index 209f0ec985..91828dc700 100644 --- a/CMakeModules/EosioTesterBuild.cmake.in +++ b/CMakeModules/EosioTesterBuild.cmake.in @@ -34,6 +34,7 @@ endif ( APPLE ) set( Boost_USE_MULTITHREADED ON ) set( Boost_USE_STATIC_LIBS ON CACHE STRING "ON or OFF" ) +set( BOOST_EXCLUDE_LIBRARIES "mysql" ) add_subdirectory( @CMAKE_SOURCE_DIR@/libraries/boost ${PROJECT_BINARY_DIR}/libraries/boost EXCLUDE_FROM_ALL) @@ -49,8 +50,8 @@ find_library(libwast WAST @CMAKE_BINARY_DIR@/libraries/wasm-jit/Source/WAST NO_D find_library(libir IR @CMAKE_BINARY_DIR@/libraries/wasm-jit/Source/IR NO_DEFAULT_PATH) find_library(liblogging Logging @CMAKE_BINARY_DIR@/libraries/wasm-jit/Source/Logging NO_DEFAULT_PATH) find_library(libsoftfloat softfloat @CMAKE_BINARY_DIR@/libraries/softfloat NO_DEFAULT_PATH) -get_filename_component(cryptodir @OPENSSL_CRYPTO_LIBRARY@ DIRECTORY) -find_library(liboscrypto crypto "${cryptodir}" NO_DEFAULT_PATH) +find_library(libbscrypto bscrypto @CMAKE_BINARY_DIR@/libraries/libfc/libraries/boringssl/boringssl NO_DEFAULT_PATH) +find_library(libdecrepit decrepit @CMAKE_BINARY_DIR@/libraries/libfc/libraries/boringssl/boringssl NO_DEFAULT_PATH) find_library(libchainbase chainbase @CMAKE_BINARY_DIR@/libraries/chainbase NO_DEFAULT_PATH) find_library(libbuiltins builtins @CMAKE_BINARY_DIR@/libraries/builtins NO_DEFAULT_PATH) @@ -64,61 +65,79 @@ if("eos-vm-oc" IN_LIST EOSIO_WASM_RUNTIMES) set(WRAP_MAIN "-Wl,-wrap=main") endif() +add_library(EosioChain INTERFACE) + +target_link_libraries(EosioChain INTERFACE + ${libchain} + ${libfc} + ${libwast} + ${libwasm} + ${libir} + ${libsoftfloat} + ${libbscrypto} + ${libdecrepit} + ${liblogging} + ${libchainbase} + ${libbuiltins} + ${libsecp256k1} + ${libbn256} + ${libbls12-381} + @GMP_LIBRARY@ + + Boost::date_time + Boost::filesystem + Boost::system + Boost::chrono + Boost::multi_index + Boost::multiprecision + Boost::interprocess + Boost::asio + Boost::signals2 + Boost::iostreams + "-lz" # Needed by Boost iostreams + + ${LLVM_LIBS} + + ${PLATFORM_SPECIFIC_LIBS} + + ${WRAP_MAIN} + Threads::Threads +) + +target_include_directories(EosioChain INTERFACE + @OPENSSL_INCLUDE_DIR@ + @CMAKE_SOURCE_DIR@/libraries/chain/include + @CMAKE_BINARY_DIR@/libraries/chain/include + @CMAKE_SOURCE_DIR@/libraries/libfc/include + @CMAKE_SOURCE_DIR@/libraries/libfc/libraries/boringssl/boringssl/src/include + @CMAKE_SOURCE_DIR@/libraries/softfloat/source/include + @CMAKE_SOURCE_DIR@/libraries/appbase/include + @CMAKE_SOURCE_DIR@/libraries/chainbase/include + @CMAKE_SOURCE_DIR@/libraries/wasm-jit/include ) + + +#adds -ltr. Ubuntu eosio.contracts build breaks without this +if(UNIX AND NOT APPLE) + target_link_libraries(EosioChain INTERFACE ${LIBRT}) +endif() + +add_library(EosioTester INTERFACE) + +target_link_libraries(EosioTester INTERFACE + ${libtester} + Boost::unit_test_framework + EosioChain +) + +target_include_directories(EosioTester INTERFACE + @CMAKE_SOURCE_DIR@/libraries/testing/include ) + macro(add_eosio_test_executable test_name) add_executable( ${test_name} ${ARGN} ) target_link_libraries( ${test_name} - ${libtester} - ${libchain} - ${libfc} - ${libwast} - ${libwasm} - ${libir} - ${libsoftfloat} - ${liboscrypto} - ${liblogging} - ${libchainbase} - ${libbuiltins} - ${libsecp256k1} - ${libbn256} - ${libbls12-381} - @GMP_LIBRARY@ - - Boost::date_time - Boost::filesystem - Boost::system - Boost::chrono - Boost::multi_index - Boost::multiprecision - Boost::interprocess - Boost::asio - Boost::signals2 - Boost::iostreams - "-lz" # Needed by Boost iostreams - Boost::unit_test_framework - - ${LLVM_LIBS} - - ${PLATFORM_SPECIFIC_LIBS} - - ${WRAP_MAIN} - Threads::Threads + EosioTester ) - #adds -ltr. Ubuntu eosio.contracts build breaks without this - if(UNIX AND NOT APPLE) - target_link_libraries(${test_name} ${LIBRT}) - endif() - - target_include_directories( ${test_name} PUBLIC - @OPENSSL_INCLUDE_DIR@ - @CMAKE_SOURCE_DIR@/libraries/chain/include - @CMAKE_BINARY_DIR@/libraries/chain/include - @CMAKE_SOURCE_DIR@/libraries/libfc/include - @CMAKE_SOURCE_DIR@/libraries/softfloat/source/include - @CMAKE_SOURCE_DIR@/libraries/appbase/include - @CMAKE_SOURCE_DIR@/libraries/chainbase/include - @CMAKE_SOURCE_DIR@/libraries/testing/include - @CMAKE_SOURCE_DIR@/libraries/wasm-jit/Include ) endmacro() macro(add_eosio_test test_name) diff --git a/README.md b/README.md index bac9bfd9d8..c5fc400c57 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,6 @@ Requirements to build: - CMake 3.16+ - LLVM 7 - 11 - for Linux only - newer versions do not work -- openssl 1.1+ - libcurl 7.40.0+ - git - GMP @@ -94,7 +93,7 @@ git submodule update --init --recursive Select build instructions below for a [pinned build](#pinned-build) (preferred) or an [unpinned build](#unpinned-build). > ℹ️ **Pinned vs. Unpinned Build** ℹ️ -We have two types of builds for Leap: "pinned" and "unpinned." The only difference is that pinned builds use specific versions for some dependencies hand-picked by the Leap engineers - they are "pinned" to those versions. In contrast, unpinned builds use the default dependency versions available on the build system at the time. We recommend performing a "pinned" build to ensure the compiler remains the same between builds of different Leap versions. Leap requires these versions to remain the same, otherwise its state might need to be recovered from a portable snapshot or the chain needs to be replayed. +We have two types of builds for Leap: "pinned" and "unpinned." A pinned build is a reproducible build with the build environment and dependency versions fixed by the development team. In contrast, unpinned builds use the dependency versions provided by the build platform. Unpinned builds tend to be quicker because the pinned build environment must be built from scratch. Pinned builds, in addition to being reproducible, ensure the compiler remains the same between builds of different Leap major versions. Leap requires the compiler version to remain the same, otherwise its state might need to be recovered from a portable snapshot or the chain needs to be replayed. > ⚠️ **A Warning On Parallel Compilation Jobs (`-j` flag)** ⚠️ When building C/C++ software, often the build is performed in parallel via a command such as `make -j "$(nproc)"` which uses all available CPU threads. However, be aware that some compilation units (`*.cpp` files) in Leap will consume nearly 4GB of memory. Failures due to memory exhaustion will typically, but not always, manifest as compiler crashes. Using all available CPU threads may also prevent you from doing other things on your computer during compilation. For these reasons, consider reducing this value. @@ -102,24 +101,15 @@ When building C/C++ software, often the build is performed in parallel via a com > 🐋 **Docker and `sudo`** 🐋 If you are in an Ubuntu docker container, omit `sudo` from all commands because you run as `root` by default. Most other docker containers also exclude `sudo`, especially Debian-family containers. If your shell prompt is a hash tag (`#`), omit `sudo`. -#### Pinned Build -Make sure you are in the root of the `leap` repo, then run the `install_depts.sh` script to install dependencies: +#### Pinned Reproducible Build +The pinned reproducible build requires Docker. Make sure you are in the root of the `leap` repo and then run ```bash -sudo scripts/install_deps.sh +DOCKER_BUILDKIT=1 docker build -f tools/reproducible.Dockerfile -o . . ``` - -Next, run the pinned build script. You have to give it three arguments in the following order: -1. A temporary folder, for all dependencies that need to be built from source. -1. A build folder, where the binaries you need to install will be built to. -1. The number of jobs or CPU cores/threads to use (note the [jobs flag](#step-3---build) warning above). - -> 🔒 You do not need to run this script with `sudo` or as root. - -For example, the following command runs the `pinned_build.sh` script, specifies a `deps` and `build` folder in the root of the Leap repo for the first two arguments, then builds the packages using all of your computer's CPU threads: +This command will take a substantial amount of time because a toolchain is built from scratch. Upon completion, the current directory will contain a built `.deb` and `.tar.gz` (you can change the `-o .` argument to place the output in a different directory). If needing to reduce the number of parallel jobs as warned above, run the command as, ```bash -scripts/pinned_build.sh deps build "$(nproc)" +DOCKER_BUILDKIT=1 docker build --build-arg LEAP_BUILD_JOBS=4 -f tools/reproducible.Dockerfile -o . . ``` -Now you can optionally [test](#step-4---test) your build, or [install](#step-5---install) the `*.deb` binary packages, which will be in the root of your build directory. #### Unpinned Build The following instructions are valid for this branch. Other release branches may have different requirements, so ensure you follow the directions in the branch or release you intend to build. If you are in an Ubuntu docker container, omit `sudo` because you run as `root` by default. @@ -133,7 +123,6 @@ sudo apt-get install -y \ git \ libcurl4-openssl-dev \ libgmp-dev \ - libssl-dev \ llvm-11-dev \ python3-numpy \ file \ diff --git a/benchmark/modexp.cpp b/benchmark/modexp.cpp index 627a719a50..14d8443331 100644 --- a/benchmark/modexp.cpp +++ b/benchmark/modexp.cpp @@ -1,4 +1,5 @@ #include +#include #include @@ -24,15 +25,14 @@ void modexp_benchmarking() { return result; }; - static constexpr unsigned int start_num_bytes = 128; // 64 - static constexpr unsigned int end_num_bytes = 256; // 512 - static constexpr unsigned int delta_num_bytes = 128; // 64 + static constexpr unsigned int start_num_bytes = 8; + static constexpr unsigned int end_num_bytes = 256; static_assert(start_num_bytes <= end_num_bytes); - static_assert(delta_num_bytes > 0); - static_assert((end_num_bytes - start_num_bytes) % delta_num_bytes == 0); + static_assert((start_num_bytes & (start_num_bytes - 1)) == 0); + static_assert((end_num_bytes & (end_num_bytes - 1)) == 0); - for (unsigned int n = start_num_bytes, slot = 0; n <= end_num_bytes; n += delta_num_bytes, ++slot) { + for (unsigned int n = start_num_bytes; n <= end_num_bytes; n *= 2) { auto base = generate_random_bytes(r, n); auto exponent = generate_random_bytes(r, n); auto modulus = generate_random_bytes(r, n); @@ -41,7 +41,21 @@ void modexp_benchmarking() { fc::modexp(base, exponent, modulus); }; - benchmarking(std::to_string(n*8) + " bit width", f); + auto even_and_odd = [&](const std::string& bm) { + //some modexp implementations have drastically different performance characteristics depending on whether the modulus is + // even or odd (this can determine whether Montgomery multiplication is used). So test both cases. + modulus.back() &= ~1; + benchmarking(std::to_string(n*8) + " bit even M, " + bm, f); + modulus.back() |= 1; + benchmarking(std::to_string(n*8) + " bit odd M, " + bm, f); + }; + + //some modexp implementations need to take a minor different path if base is greater than modulus, try both + FC_ASSERT(modulus[0] != '\xff' && modulus[0] != 0); + base.front() = 0; + even_and_odd("BM"); } // Running the above benchmark (using commented values for num_trials and *_num_bytes) with a release build on an AMD 3.4 GHz CPU diff --git a/docs/00_install/01_build-from-source/00_build-unsupported-os.md b/docs/00_install/01_build-from-source/00_build-unsupported-os.md index e0d3c19331..aada11d7b2 100644 --- a/docs/00_install/01_build-from-source/00_build-unsupported-os.md +++ b/docs/00_install/01_build-from-source/00_build-unsupported-os.md @@ -23,7 +23,6 @@ pkg update && pkg install \ curl \ boost-all \ python3 \ - openssl \ llvm11 \ pkgconf ``` diff --git a/docs/01_nodeos/03_plugins/chain_plugin/index.md b/docs/01_nodeos/03_plugins/chain_plugin/index.md index 0b932e78ac..91a68bf21e 100644 --- a/docs/01_nodeos/03_plugins/chain_plugin/index.md +++ b/docs/01_nodeos/03_plugins/chain_plugin/index.md @@ -163,10 +163,14 @@ Config Options for eosio::chain_plugin: headers signed by it will be fully validated, but transactions in those validated blocks will be trusted. - --database-map-mode arg (=mapped) Database map mode ("mapped", "heap", or - "locked"). + --database-map-mode arg (=mapped) Database map mode ("mapped", + "mapped_private", "heap", or "locked"). In "mapped" mode database is memory mapped as a file. + In "mapped_private" mode database is + memory mapped as a file using a private + mapping (no disk writeback until + program exit). In "heap" mode database is preloaded in to swappable memory and will use huge pages if available. @@ -190,10 +194,6 @@ Config Options for eosio::chain_plugin: --enable-account-queries arg (=0) enable queries to find accounts by various metadata. - --max-nonprivileged-inline-action-size arg (=4096) - maximum allowed size (in bytes) of an - inline action for a nonprivileged - account --transaction-retry-max-storage-size-gb arg Maximum size (in GiB) allowed to be allocated for the Transaction Retry diff --git a/docs/01_nodeos/03_plugins/producer_plugin/10_block-producing-explained.md b/docs/01_nodeos/03_plugins/producer_plugin/10_block-producing-explained.md index 1c3d56ef14..454a2fb613 100644 --- a/docs/01_nodeos/03_plugins/producer_plugin/10_block-producing-explained.md +++ b/docs/01_nodeos/03_plugins/producer_plugin/10_block-producing-explained.md @@ -4,87 +4,84 @@ content_title: Block Production Explained For simplicity of the explanation let's consider the following notations: -m = max_block_cpu_usage +* `r` = `producer_repetitions = 12` (hard-coded value) +* `m` = `max_block_cpu_usage` (on-chain consensus value) +* `u` = `max_block_net_usage` (on-chain consensus value) +* `t` = `block-time` +* `e` = `produce-block-offset-ms` (nodeos configuration) +* `w` = `block-time-interval = 500ms` (hard-coded value) +* `a` = `produce-block-early-amount = w - (w - (e / r)) = e / r ms` (how much to release each block of round early by) +* `l` = `produce-block-time = t - a` +* `p` = `produce block time window = w - a` (amount of wall clock time to produce a block) +* `c` = `billed_cpu_in_block = minimum(m, w - a)` +* `n` = `network tcp/ip latency` +* `h` = `block header validation time ms` + +Peer validation for similar hardware/version/config will be <= `m` + +**Let's consider the example of the following two BPs and their network topology as depicted in the below diagram** -t = block-time - -e = last-block-cpu-effort-percent - -w = block_time_interval = 500ms - -a = produce-block-early-amount = (w - w*e/100) ms - -p = produce-block-time; p = t - a - -c = billed_cpu_in_block = minimum(m, w - a) - -n = network tcp/ip latency - -peer validation for similar hardware/eosio-version/config will be <= m - -**Let's consider for exemplification the following four BPs and their network topology as depicted in below diagram** - - -```dot-svg -#p2p_local_chain_prunning.dot - local chain prunning -# -#notes: * to see image copy/paste to https://dreampuf.github.io/GraphvizOnline -# * image will be rendered by gatsby-remark-graphviz plugin in eosio docs. - -digraph { - newrank=true #allows ranks inside subgraphs (important!) - compound=true #allows edges connecting nodes with subgraphs - graph [rankdir=LR] - node [style=filled, fillcolor=lightgray, shape=square, fixedsize=true, width=.55, fontsize=10] - edge [dir=both, arrowsize=.6, weight=100] - splines=false - - subgraph cluster_chain { - label="Block Producers Peers"; labelloc="b" - graph [color=invis] - b0 [label="...", color=invis, style=""] - b1 [label="BP-A"]; b2 [label="BP-A\nPeer"]; b3 [label="BP-B\nPeer"]; b4 [label="BP-B"] - b5 [label="...", color=invis, style=""] - b0 -> b1 -> b2 -> b3 -> b4 -> b5 - } //cluster_chain - -} //digraph +``` + +------+ +------+ +------+ +------+ + -->| BP-A |---->| BP-A |------>| BP-B |---->| BP-B | + +------+ | Peer | | Peer | +------+ + +------+ +------+ ``` -`BP-A` will send block at `p` and, - -`BP-B` needs block at time `t` or otherwise will drop it. +`BP-A` will send block at `l` and, `BP-B` needs block at time `t` or otherwise will drop it. If `BP-A`is producing 12 blocks as follows `b(lock) at t(ime) 1`, `bt 1.5`, `bt 2`, `bt 2.5`, `bt 3`, `bt 3.5`, `bt 4`, `bt 4.5`, `bt 5`, `bt 5.5`, `bt 6`, `bt 6.5` then `BP-B` needs `bt 6.5` by time `6.5` so it has `.5` to produce `bt 7`. Please notice that the time of `bt 7` minus `.5` equals the time of `bt 6.5` therefore time `t` is the last block time of `BP-A` and when `BP-B` needs to start its first block. -## Example 1 -`BP-A` has 50% e, m = 200ms, c = 200ms, n = 0ms, a = 250ms: -`BP-A` sends at (t-250ms) <-> `BP-A-Peer` processes for 200ms and sends at (t - 50ms) <-> `BP-B-Peer` processes for 200ms and sends at (t + 150ms) <-> arrive at `BP-B` 150ms too late. - -## Example 2 -`BP-A` has 40% e and m = 200ms, c = 200ms, n = 0ms, a = 300ms: -(t-300ms) <-> (+200ms) <-> (+200ms) <-> arrive at `BP-B` 100ms too late. - -## Example 3 -`BP-A` has 30% e and m = 200ms, c = 150ms, n = 0ms, a = 350ms: -(t-350ms) <-> (+150ms) <-> (+150ms) <-> arrive at `BP-B` with 50ms to spare. - -## Example 4 -`BP-A` has 25% e and m = 200ms, c = 125ms, n = 0ms, a = 375ms: -(t-375ms) <-> (+125ms) <-> (+125ms) <-> arrive at `BP-B` with 125ms to spare. - -## Example 5 -`BP-A` has 10% e and m = 200ms, c = 50ms, n = 0ms, a = 450ms: -(t-450ms) <-> (+50ms) <-> (+50ms) <-> arrive at `BP-B` with 350ms to spare. - -## Example 6 -`BP-A` has 10% e and m = 200ms, c = 50ms, n = 15ms, a = 450ms: -(t-450ms) <- +15ms -> (+50ms) <- +15ms -> (+50ms) <- +15ms -> `BP-B` <-> arrive with 305ms to spare. +A block is produced and sent when either it reaches `m` or `u` or `p`. + +Starting in Leap 4.0, blocks are propagated after block header validation. This means instead of `BP-A Peer` & `BP-B Peer` taking `m` time to validate and forward a block it only takes a small number of milliseconds to verify the block header and then forward the block. + +Starting in Leap 5.0, blocks in a round are started immediately after the completion of the previous block. Before 5.0, blocks were always started on `w` intervals and a node would "sleep" between blocks if needed. In 5.0, the "sleeps" are all moved to the end of the block production round. + +## Example 1: block arrives 110ms early +* Assuming zero network latency between all nodes. +* Assuming blocks do not reach `m` and therefore take `w - a` time to produce. +* Assume block completion including signing takes zero time. +* `BP-A` has e = 120, n = 0ms, h = 5ms, a = 10ms +* `BP-A` sends b1 at `t1-10ms` => `BP-A-Peer` processes `h=5ms`, sends at `t-5ms` => `BP-B-Peer` processes `h=5ms`, sends at `t-0ms` => arrives at `BP-B` at `t`. +* `BP-A` starts b2 at `t1-10ms`, sends b2 at `t2-20ms` => `BP-A-Peer` processes `h=5ms`, sends at `t2-15ms` => `BP-B-Peer` processes `h=5ms`, sends at `t2-10ms` => arrives at `BP-B` at `t2-10ms`. +* `BP-A` starts b3 at `t2-20ms`, ... +* `BP-A` starts b12 at `t11-110ms`, sends b12 at `t12-120ms` => `BP-A-Peer` processes `h=5ms`, sends at `t12-115ms` => `BP-B-Peer` processes `h=5ms`, sends at `t12-110ms` => arrives at `BP-B` at `t12-110ms` + +## Example 2: block arrives 80ms early +* Assuming zero network latency between `BP-A` & `BP-A Peer` and between `BP-B Peer` & `BP-B`. +* Assuming 150ms network latency between `BP-A Peer` & `BP-B Peer`. +* Assuming blocks do not reach `m` and therefore take `w - a` time to produce. +* Assume block completion including signing takes zero time. +* `BP-A` has e = 240, n = 0ms/150ms, h = 5ms, a = 20ms +* `BP-A` sends b1 at `t1-20ms` => `BP-A-Peer` processes `h=5ms`, sends at `t-15ms` =(150ms)> `BP-B-Peer` processes `h=5ms`, sends at `t+140ms` => arrives at `BP-B` at `t+140ms`. +* `BP-A` starts b2 at `t1-20ms`, sends b2 at `t2-40ms` => `BP-A-Peer` processes `h=5ms`, sends at `t2-35ms` =(150ms)> `BP-B-Peer` processes `h=5ms`, sends at `t2+120ms` => arrives at `BP-B` at `t2+120ms`. +* `BP-A` starts b3 at `t2-40ms`, ... +* `BP-A` starts b12 at `t11-220ms`, sends b12 at `t12-240ms` => `BP-A-Peer` processes `h=5ms`, sends at `t12-235ms` =(150ms)> `BP-B-Peer` processes `h=5ms`, sends at `t12-80ms` => arrives at `BP-B` at `t12-80ms` + +## Example 3: block arrives 16ms late and is dropped +* Assuming zero network latency between `BP-A` & `BP-A Peer` and between `BP-B Peer` & `BP-B`. +* Assuming 200ms network latency between `BP-A Peer` & `BP-B Peer`. +* Assuming blocks do not reach `m` and therefore take `w - a` time to produce. +* Assume block completion including signing takes zero time. +* `BP-A` has e = 204, n = 0ms/200ms, h = 10ms, a = 17ms +* `BP-A` sends b1 at `t1-17ms` => `BP-A-Peer` processes `h=10ms`, sends at `t-7ms` =(200ms)> `BP-B-Peer` processes `h=10ms`, sends at `t+203ms` => arrives at `BP-B` at `t+203ms`. +* `BP-A` starts b2 at `t1-17ms`, sends b2 at `t2-34ms` => `BP-A-Peer` processes `h=10ms`, sends at `t2-24ms` =(200ms)> `BP-B-Peer` processes `h=10ms`, sends at `t2+186ms` => arrives at `BP-B` at `t2+186ms`. +* `BP-A` starts b3 at `t2-34ms`, ... +* `BP-A` starts b12 at `t11-187ms`, sends b12 at `t12-204ms` => `BP-A-Peer` processes `h=10ms`, sends at `t12-194ms` =(200ms)> `BP-B-Peer` processes `h=10ms`, sends at `t12+16ms` => arrives at `BP-B` at `t12+16ms` + +## Example 4: full blocks are produced early +* Assuming zero network latency between `BP-A` & `BP-A Peer` and between `BP-B Peer` & `BP-B`. +* Assuming 200ms network latency between `BP-A Peer` & `BP-B Peer`. +* Assume all blocks are full as there are enough queued up unapplied transactions ready to fill all blocks. +* Assume a block can be produced with 200ms worth of transactions in 225ms worth of time. There is overhead for producing the block. +* `BP-A` has e = 120, m = 200ms, n = 0ms/200ms, h = 10ms, a = 10ms +* `BP-A` sends b1 at `t1-275s` => `BP-A-Peer` processes `h=10ms`, sends at `t-265ms` =(200ms)> `BP-B-Peer` processes `h=10ms`, sends at `t-55ms` => arrives at `BP-B` at `t-55ms`. +* `BP-A` starts b2 at `t1-275ms`, sends b2 at `t2-550ms (t1-50ms)` => `BP-A-Peer` processes `h=10ms`, sends at `t2-540ms` =(200ms)> `BP-B-Peer` processes `h=10ms`, sends at `t2-330ms` => arrives at `BP-B` at `t2-330ms`. +* `BP-A` starts b3 at `t2-550ms`, ... +* `BP-A` starts b12 at `t11-3025ms`, sends b12 at `t12-3300ms` => `BP-A-Peer` processes `h=10ms`, sends at `t12-3290ms` =(200ms)> `BP-B-Peer` processes `h=10ms`, sends at `t12-3080ms` => arrives at `BP-B` at `t12-3080ms` -## Example 7 -Example world-wide network:`BP-A`has 10% e and m = 200ms, c = 50ms, n = 15ms/250ms, a = 450ms: -(t-450ms) <- +15ms -> (+50ms) <- +250ms -> (+50ms) <- +15ms -> `BP-B` <-> arrive with 70ms to spare. Running wasm-runtime=eos-vm-jit eos-vm-oc-enable on relay node will reduce the validation time. diff --git a/docs/01_nodeos/03_plugins/producer_plugin/index.md b/docs/01_nodeos/03_plugins/producer_plugin/index.md index 2008de7d6f..3d36b24f04 100644 --- a/docs/01_nodeos/03_plugins/producer_plugin/index.md +++ b/docs/01_nodeos/03_plugins/producer_plugin/index.md @@ -27,10 +27,11 @@ Config Options for eosio::producer_plugin: chain is stale. -x [ --pause-on-startup ] Start this node in a state where production is paused - --max-transaction-time arg (=30) Limits the maximum time (in - milliseconds) that is allowed a pushed - transaction's code to execute before - being considered invalid + --max-transaction-time arg (=499) Setting this value (in milliseconds) + will restrict the allowed transaction + execution time to a value potentially + lower than the on-chain consensus + max_transaction_cpu_usage value. --max-irreversible-block-age arg (=-1) Limits the maximum age (in seconds) of the DPOS Irreversible Block for a chain @@ -71,20 +72,9 @@ Config Options for eosio::producer_plugin: can extend during low usage (only enforced subjectively; use 1000 to not enforce any limit) - --produce-time-offset-us arg (=0) Offset of non last block producing time - in microseconds. Valid range 0 .. - -block_time_interval. - --last-block-time-offset-us arg (=-200000) - Offset of last block producing time in - microseconds. Valid range 0 .. - -block_time_interval. - --cpu-effort-percent arg (=80) Percentage of cpu block production time - used to produce block. Whole number - percentages, e.g. 80 for 80% - --last-block-cpu-effort-percent arg (=80) - Percentage of cpu block production time - used to produce last block. Whole - number percentages, e.g. 80 for 80% + --produce-block-offset-ms arg (=450) The minimum time to reserve at the end + of a production round for blocks to + propagate to the next block producer. --max-block-cpu-usage-threshold-us arg (=5000) Threshold of CPU block production to consider block full; when within @@ -95,13 +85,6 @@ Config Options for eosio::producer_plugin: consider block full; when within threshold of max-block-net-usage block can be produced immediately - --max-scheduled-transaction-time-per-block-ms arg (=100) - Maximum wall-clock time, in - milliseconds, spent retiring scheduled - transactions (and incoming transactions - according to incoming-defer-ratio) in - any block before returning to normal - transaction processing. --subjective-cpu-leeway-us arg (=31000) Time in microseconds allowed for a transaction that starts with @@ -114,9 +97,6 @@ Config Options for eosio::producer_plugin: --subjective-account-decay-time-minutes arg (=1440) Sets the time to return full subjective cpu for accounts - --incoming-defer-ratio arg (=1) ratio between incoming transactions and - deferred transactions when both are - queued for execution --incoming-transaction-queue-size-mb arg (=1024) Maximum size (in MiB) of the incoming transaction queue. Exceeding this value @@ -142,21 +122,6 @@ Config Options for eosio::producer_plugin: * [`chain_plugin`](../chain_plugin/index.md) -## The priority of transaction - -You can give one of the transaction types priority over another when the producer plugin has a queue of transactions pending. - -The option below sets the ratio between the incoming transaction and the deferred transaction: - -```console - --incoming-defer-ratio arg (=1) -``` - -By default value of `1`, the `producer` plugin processes one incoming transaction per deferred transaction. When `arg` sets to `10`, the `producer` plugin processes 10 incoming transactions per deferred transaction. - -If the `arg` is set to a sufficiently large number, the plugin always processes the incoming transaction first until the queue of the incoming transactions is empty. Respectively, if the `arg` is 0, the `producer` plugin processes the deferred transactions queue first. - - ### Load Dependency Examples ```console diff --git a/libraries/CMakeLists.txt b/libraries/CMakeLists.txt index 98f7a59229..a3a5df16c4 100644 --- a/libraries/CMakeLists.txt +++ b/libraries/CMakeLists.txt @@ -7,6 +7,8 @@ set(BN256_INSTALL_COMPONENT "dev") set( Boost_USE_MULTITHREADED ON ) set( Boost_USE_STATIC_LIBS ON CACHE STRING "ON or OFF" ) +# don't include boost mysql library as it does a find_package(OpenSSL) thus finding the system openssl which could conflict with the bundled boringssl +set( BOOST_EXCLUDE_LIBRARIES "mysql" ) add_subdirectory( boost EXCLUDE_FROM_ALL ) add_subdirectory( libfc ) diff --git a/libraries/chain/apply_context.cpp b/libraries/chain/apply_context.cpp index d4a067feb5..75d42dbe35 100644 --- a/libraries/chain/apply_context.cpp +++ b/libraries/chain/apply_context.cpp @@ -131,7 +131,7 @@ void apply_context::exec_one() } } } - } FC_RETHROW_EXCEPTIONS( warn, "pending console output: ${console}", ("console", _pending_console_output) ) + } FC_RETHROW_EXCEPTIONS( warn, "${receiver} <= ${account}::${action} pending console output: ${console}", ("console", _pending_console_output)("account", act->account)("action", act->name)("receiver", receiver) ) if( control.is_builtin_activated( builtin_protocol_feature_t::action_return_value ) ) { act_digest = generate_action_digest( @@ -357,12 +357,6 @@ void apply_context::execute_inline( action&& a ) { control.check_actor_list( actors ); } - if( !privileged && control.is_speculative_block() ) { - const auto& chain_config = control.get_global_properties().configuration; - EOS_ASSERT( a.data.size() < std::min(chain_config.max_inline_action_size, control.get_max_nonprivileged_inline_action_size()), - inline_action_too_big_nonprivileged, - "inline action too big for nonprivileged account ${account}", ("account", a.account)); - } // No need to check authorization if replaying irreversible blocks or contract is privileged if( !control.skip_auth_check() && !privileged && !trx_context.is_read_only() ) { try { @@ -417,13 +411,6 @@ void apply_context::execute_context_free_inline( action&& a ) { EOS_ASSERT( a.authorization.size() == 0, action_validate_exception, "context-free actions cannot have authorizations" ); - if( !privileged && control.is_speculative_block() ) { - const auto& chain_config = control.get_global_properties().configuration; - EOS_ASSERT( a.data.size() < std::min(chain_config.max_inline_action_size, control.get_max_nonprivileged_inline_action_size()), - inline_action_too_big_nonprivileged, - "inline action too big for nonprivileged account ${account}", ("account", a.account)); - } - auto inline_receiver = a.account; _cfa_inline_actions.emplace_back( schedule_action( std::move(a), inline_receiver, true ) @@ -436,6 +423,11 @@ void apply_context::execute_context_free_inline( action&& a ) { void apply_context::schedule_deferred_transaction( const uint128_t& sender_id, account_name payer, transaction&& trx, bool replace_existing ) { + // no-op after DISABLE_DEFERRED_TRXS_STAGE_1 is activated + if( control.is_builtin_activated( builtin_protocol_feature_t::disable_deferred_trxs_stage_1 ) ) { + return; + } + EOS_ASSERT( !trx_context.is_read_only(), transaction_exception, "cannot schedule a deferred transaction from within a readonly transaction" ); EOS_ASSERT( trx.context_free_actions.size() == 0, cfa_inside_generated_tx, "context free actions are not currently allowed in generated transactions" ); @@ -637,6 +629,11 @@ void apply_context::schedule_deferred_transaction( const uint128_t& sender_id, a } bool apply_context::cancel_deferred_transaction( const uint128_t& sender_id, account_name sender ) { + // no-op after DISABLE_DEFERRED_TRXS_STAGE_1 is activated + if( control.is_builtin_activated( builtin_protocol_feature_t::disable_deferred_trxs_stage_1 ) ) { + return false; + } + EOS_ASSERT( !trx_context.is_read_only(), transaction_exception, "cannot cancel a deferred transaction from within a readonly transaction" ); auto& generated_transaction_idx = db.get_mutable_index(); const auto* gto = db.find(boost::make_tuple(sender, sender_id)); diff --git a/libraries/chain/block_log.cpp b/libraries/chain/block_log.cpp index 082aeb02f6..b97008a9df 100644 --- a/libraries/chain/block_log.cpp +++ b/libraries/chain/block_log.cpp @@ -326,7 +326,7 @@ namespace eosio { namespace chain { block_log_data log_data; block_log_index log_index; - block_log_bundle(std::filesystem::path block_file, std::filesystem::path index_file) + block_log_bundle(std::filesystem::path block_file, std::filesystem::path index_file, bool validate_indx) : block_file_name(std::move(block_file)), index_file_name(std::move(index_file)) { log_data.open(block_file_name); @@ -335,6 +335,15 @@ namespace eosio { namespace chain { EOS_ASSERT(!log_data.get_preamble().is_currently_pruned(), block_log_unsupported_version, "Block log is currently in pruned format, it must be vacuumed before doing this operation"); + if (validate_indx) + validate_index(); + } + + explicit block_log_bundle(const std::filesystem::path& block_dir, bool validate_index=true) + : block_log_bundle(block_dir / "blocks.log", block_dir / "blocks.index", validate_index) {} + + // throws if not valid + void validate_index() { uint32_t log_num_blocks = log_data.num_blocks(); uint32_t index_num_blocks = log_index.num_blocks(); @@ -345,9 +354,6 @@ namespace eosio { namespace chain { ("block_file_name", block_file_name)("log_num_blocks", log_num_blocks)( "index_num_blocks", index_num_blocks)("index_file_name", index_file_name)); } - - explicit block_log_bundle(const std::filesystem::path& block_dir) - : block_log_bundle(block_dir / "blocks.log", block_dir / "blocks.index") {} }; /// Used to traverse the block position (i.e. the last 8 bytes in each block log entry) of the blocks.log file @@ -1572,12 +1578,14 @@ namespace eosio { namespace chain { // static void block_log::smoke_test(const std::filesystem::path& block_dir, uint32_t interval) { - block_log_bundle log_bundle(block_dir); + block_log_bundle log_bundle(block_dir, false); ilog("block log version= ${version}",("version", log_bundle.log_data.version())); ilog("first block= ${first}",("first", log_bundle.log_data.first_block_num())); ilog("last block= ${last}",("last", log_bundle.log_data.last_block_num())); + log_bundle.validate_index(); + ilog("blocks.log and blocks.index agree on number of blocks"); if (interval == 0) { diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index e4c6f89bb0..378b0a56fd 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -39,6 +39,7 @@ #include #include +#include namespace eosio { namespace chain { @@ -343,6 +344,7 @@ struct controller_impl { set_activation_handler(); set_activation_handler(); set_activation_handler(); + set_activation_handler(); set_activation_handler(); self.irreversible_block.connect([this](const block_state_ptr& bsp) { @@ -595,6 +597,7 @@ struct controller_impl { EOS_ASSERT( snapshot, snapshot_exception, "No snapshot reader provided" ); this->shutdown = shutdown; try { + auto snapshot_load_start_time = fc::time_point::now(); snapshot->validate(); if( auto blog_head = blog.head() ) { ilog( "Starting initialization from snapshot and block log ${b}-${e}, this may take a significant amount of time", @@ -610,8 +613,9 @@ struct controller_impl { } ilog( "Snapshot loaded, lib: ${lib}", ("lib", head->block_num) ); - init(check_shutdown); - ilog( "Finished initialization from snapshot" ); + init(std::move(check_shutdown)); + auto snapshot_load_time = (fc::time_point::now() - snapshot_load_start_time).to_seconds(); + ilog( "Finished initialization from snapshot (snapshot load time was ${t}s)", ("t", snapshot_load_time) ); } catch (boost::interprocess::bad_alloc& e) { elog( "Failed initialization from snapshot - db storage not configured to have enough storage for the provided snapshot, please increase and retry snapshot" ); shutdown(); @@ -626,7 +630,7 @@ struct controller_impl { ("genesis_chain_id", genesis_chain_id)("controller_chain_id", chain_id) ); - this->shutdown = shutdown; + this->shutdown = std::move(shutdown); if( fork_db.head() ) { if( read_mode == db_read_mode::IRREVERSIBLE && fork_db.head()->id != fork_db.root()->id ) { fork_db.rollback_head_to_root(); @@ -648,14 +652,14 @@ struct controller_impl { } else { blog.reset( genesis, head->block ); } - init(check_shutdown); + init(std::move(check_shutdown)); } void startup(std::function shutdown, std::function check_shutdown) { EOS_ASSERT( db.revision() >= 1, database_exception, "This version of controller::startup does not work with a fresh state database." ); EOS_ASSERT( fork_db.head(), fork_database_exception, "No existing fork database despite existing chain state. Replay required." ); - this->shutdown = shutdown; + this->shutdown = std::move(shutdown); uint32_t lib_num = fork_db.root()->block_num; auto first_block_num = blog.first_block_num(); if( auto blog_head = blog.head() ) { @@ -678,7 +682,7 @@ struct controller_impl { } head = fork_db.head(); - init(check_shutdown); + init(std::move(check_shutdown)); } @@ -1263,8 +1267,7 @@ struct controller_impl { || (code == contract_blacklist_exception::code_value) || (code == action_blacklist_exception::code_value) || (code == key_blacklist_exception::code_value) - || (code == sig_variable_size_limit_exception::code_value) - || (code == inline_action_too_big_nonprivileged::code_value); + || (code == sig_variable_size_limit_exception::code_value); } bool scheduled_failure_is_subjective( const fc::exception& e ) const { @@ -1308,8 +1311,11 @@ struct controller_impl { fc::datastream ds( gtrx.packed_trx.data(), gtrx.packed_trx.size() ); - EOS_ASSERT( gtrx.delay_until <= self.pending_block_time(), transaction_exception, "this transaction isn't ready", - ("gtrx.delay_until",gtrx.delay_until)("pbt",self.pending_block_time()) ); + // check delay_until only before disable_deferred_trxs_stage_1 is activated. + if( !self.is_builtin_activated( builtin_protocol_feature_t::disable_deferred_trxs_stage_1 ) ) { + EOS_ASSERT( gtrx.delay_until <= self.pending_block_time(), transaction_exception, "this transaction isn't ready", + ("gtrx.delay_until",gtrx.delay_until)("pbt",self.pending_block_time()) ); + } signed_transaction dtrx; fc::raw::unpack(ds,static_cast(dtrx) ); @@ -1318,8 +1324,11 @@ struct controller_impl { transaction_metadata::trx_type::scheduled ); trx->accepted = true; + // After disable_deferred_trxs_stage_1 is activated, a deferred transaction + // can only be retired as expired, and it can be retired as expired + // regardless of whether its delay_util or expiration times have been reached. transaction_trace_ptr trace; - if( gtrx.expiration < self.pending_block_time() ) { + if( self.is_builtin_activated( builtin_protocol_feature_t::disable_deferred_trxs_stage_1 ) || gtrx.expiration < self.pending_block_time() ) { trace = std::make_shared(); trace->id = gtrx.trx_id; trace->block_num = self.head_block_num() + 1; @@ -2771,11 +2780,6 @@ subjective_billing& controller::get_mutable_subjective_billing() { } -uint32_t controller::get_max_nonprivileged_inline_action_size()const -{ - return my->conf.max_nonprivileged_inline_action_size; -} - controller::controller( const controller::config& cfg, const chain_id_type& chain_id ) :my( new controller_impl( cfg, *this, protocol_feature_set{}, chain_id ) ) { @@ -3506,9 +3510,16 @@ void controller::validate_tapos( const transaction& trx )const { try { } FC_CAPTURE_AND_RETHROW() } void controller::validate_db_available_size() const { - const auto free = db().get_segment_manager()->get_free_memory(); + const auto free = db().get_free_memory(); const auto guard = my->conf.state_guard_size; EOS_ASSERT(free >= guard, database_guard_exception, "database free: ${f}, guard size: ${g}", ("f", free)("g",guard)); + + // give a change to chainbase to write some pages to disk if memory becomes scarce. + if (is_write_window()) { + if (auto flushed_pages = mutable_db().check_memory_and_flush_if_needed()) { + ilog("CHAINBASE: flushed ${p} pages to disk to decrease memory pressure", ("p", flushed_pages)); + } + } } bool controller::is_protocol_feature_activated( const digest_type& feature_digest )const { @@ -3873,6 +3884,15 @@ void controller_impl::on_activation( } ); } +template<> +void controller_impl::on_activation() { + const auto& idx = db.get_index(); + // remove all deferred trxs and refund their payers + for( auto itr = idx.begin(); itr != idx.end(); itr = idx.begin() ) { + remove_scheduled_transaction(*itr); + } +} + template<> void controller_impl::on_activation() { db.modify( db.get(), [&]( auto& ps ) { diff --git a/libraries/chain/include/eosio/chain/config.hpp b/libraries/chain/include/eosio/chain/config.hpp index d46df346e5..c21c62db63 100644 --- a/libraries/chain/include/eosio/chain/config.hpp +++ b/libraries/chain/include/eosio/chain/config.hpp @@ -77,10 +77,9 @@ const static uint32_t default_max_inline_action_size = 512 * 102 const static uint16_t default_max_inline_action_depth = 4; const static uint16_t default_max_auth_depth = 6; const static uint32_t default_sig_cpu_bill_pct = 50 * percent_1; // billable percentage of signature recovery -const static uint32_t default_block_cpu_effort_pct = 90 * percent_1; // percentage of block time used for producing block +const static uint32_t default_produce_block_offset_ms = 450; const static uint16_t default_controller_thread_pool_size = 2; const static uint32_t default_max_variable_signature_length = 16384u; -const static uint32_t default_max_nonprivileged_inline_action_size = 4 * 1024; // 4 KB const static uint32_t default_max_action_return_value_size = 256; const static uint32_t default_max_transaction_finality_status_success_duration_sec = 180; diff --git a/libraries/chain/include/eosio/chain/controller.hpp b/libraries/chain/include/eosio/chain/controller.hpp index b86cba8a06..3189209502 100644 --- a/libraries/chain/include/eosio/chain/controller.hpp +++ b/libraries/chain/include/eosio/chain/controller.hpp @@ -76,7 +76,6 @@ namespace eosio { namespace chain { uint64_t state_guard_size = chain::config::default_state_guard_size; uint32_t sig_cpu_bill_pct = chain::config::default_sig_cpu_bill_pct; uint16_t thread_pool_size = chain::config::default_controller_thread_pool_size; - uint32_t max_nonprivileged_inline_action_size = chain::config::default_max_nonprivileged_inline_action_size; bool read_only = false; bool force_all_checks = false; bool disable_replay_opts = false; @@ -200,7 +199,6 @@ namespace eosio { namespace chain { const protocol_feature_manager& get_protocol_feature_manager()const; const subjective_billing& get_subjective_billing()const; subjective_billing& get_mutable_subjective_billing(); - uint32_t get_max_nonprivileged_inline_action_size()const; const flat_set& get_actor_whitelist() const; const flat_set& get_actor_blacklist() const; diff --git a/libraries/chain/include/eosio/chain/exceptions.hpp b/libraries/chain/include/eosio/chain/exceptions.hpp index 151021a284..50c322ff00 100644 --- a/libraries/chain/include/eosio/chain/exceptions.hpp +++ b/libraries/chain/include/eosio/chain/exceptions.hpp @@ -323,8 +323,7 @@ namespace eosio { namespace chain { 3050010, "Action attempts to increase RAM usage of account without authorization" ) FC_DECLARE_DERIVED_EXCEPTION( restricted_error_code_exception, action_validate_exception, 3050011, "eosio_assert_code assertion failure uses restricted error code value" ) - FC_DECLARE_DERIVED_EXCEPTION( inline_action_too_big_nonprivileged, action_validate_exception, - 3050012, "Inline action exceeds maximum size limit for a non-privileged account" ) + // Removed 3050012 - inline_action_too_big_nonprivileged, no longer needed FC_DECLARE_DERIVED_EXCEPTION( action_return_value_exception, action_validate_exception, 3050014, "action return value size too big" ) diff --git a/libraries/chain/include/eosio/chain/protocol_feature_manager.hpp b/libraries/chain/include/eosio/chain/protocol_feature_manager.hpp index a998cf43ac..15d3746366 100644 --- a/libraries/chain/include/eosio/chain/protocol_feature_manager.hpp +++ b/libraries/chain/include/eosio/chain/protocol_feature_manager.hpp @@ -36,7 +36,9 @@ enum class builtin_protocol_feature_t : uint32_t { crypto_primitives = 19, get_block_num = 20, bls_primitives = 21, - instant_finality = 22, + disable_deferred_trxs_stage_1 = 22, + disable_deferred_trxs_stage_2 = 23, + instant_finality = 24, reserved_private_fork_protocol_features = 500000, }; diff --git a/libraries/chain/include/eosio/chain/wasm_eosio_binary_ops.hpp b/libraries/chain/include/eosio/chain/wasm_eosio_binary_ops.hpp index 36c6327981..968a039316 100644 --- a/libraries/chain/include/eosio/chain/wasm_eosio_binary_ops.hpp +++ b/libraries/chain/include/eosio/chain/wasm_eosio_binary_ops.hpp @@ -135,7 +135,7 @@ inline void pack( instruction_stream* stream, branchtabletype field ) { template struct field_specific_params { static constexpr int skip_ahead = sizeof(uint16_t) + sizeof(Field); - static auto unpack( char* opcode, Field& f ) { f = *reinterpret_cast(opcode); } + static auto unpack( char* opcode, Field& f ) { memcpy(&f, opcode, sizeof(f)); } static void pack(instruction_stream* stream, Field& f) { return eosio::chain::wasm_ops::pack(stream, f); } static auto to_string(Field& f) { return std::string(" ")+ eosio::chain::wasm_ops::to_string(f); } @@ -664,7 +664,8 @@ struct EOSIO_OperatorDecoderStream instr* decodeOp() { EOS_ASSERT(nextByte + sizeof(IR::Opcode) <= end, wasm_exception, ""); - IR::Opcode opcode = *(IR::Opcode*)nextByte; + IR::Opcode opcode; + memcpy(&opcode, nextByte, sizeof(opcode)); switch(opcode) { #define VISIT_OPCODE(opcode,name,nameString,Imm,...) \ diff --git a/libraries/chain/include/eosio/chain/webassembly/eos-vm-oc/eos-vm-oc.h b/libraries/chain/include/eosio/chain/webassembly/eos-vm-oc/eos-vm-oc.h index 28a8bd962e..03efd64d1e 100644 --- a/libraries/chain/include/eosio/chain/webassembly/eos-vm-oc/eos-vm-oc.h +++ b/libraries/chain/include/eosio/chain/webassembly/eos-vm-oc/eos-vm-oc.h @@ -7,7 +7,9 @@ #ifdef __cplusplus #include #include -namespace eosio { namespace chain {class apply_context;}} +namespace eosio::chain { + class apply_context; +} #endif struct eos_vm_oc_control_block { @@ -38,3 +40,9 @@ struct eos_vm_oc_control_block { int64_t max_linear_memory_pages; void* globals; }; + +#ifdef __cplusplus +namespace eosio::chain::eosvmoc { + using control_block = eos_vm_oc_control_block; +} +#endif \ No newline at end of file diff --git a/libraries/chain/include/eosio/chain/webassembly/eos-vm-oc/eos-vm-oc.hpp b/libraries/chain/include/eosio/chain/webassembly/eos-vm-oc/eos-vm-oc.hpp index 6c8d6f9fb9..95583457bd 100644 --- a/libraries/chain/include/eosio/chain/webassembly/eos-vm-oc/eos-vm-oc.hpp +++ b/libraries/chain/include/eosio/chain/webassembly/eos-vm-oc/eos-vm-oc.hpp @@ -12,13 +12,7 @@ #include #include -namespace eosio { namespace chain { - -class apply_context; - -namespace eosvmoc { - -using control_block = eos_vm_oc_control_block; +namespace eosio::chain::eosvmoc { struct no_offset{}; struct code_offset { @@ -52,7 +46,7 @@ enum eosvmoc_exitcode : int { static constexpr uint8_t current_codegen_version = 1; -}}} +} FC_REFLECT(eosio::chain::eosvmoc::no_offset, ); FC_REFLECT(eosio::chain::eosvmoc::code_offset, (offset)); diff --git a/libraries/chain/include/eosio/chain/webassembly/eos-vm-oc/memory.hpp b/libraries/chain/include/eosio/chain/webassembly/eos-vm-oc/memory.hpp index 2197878d30..6819b58d74 100644 --- a/libraries/chain/include/eosio/chain/webassembly/eos-vm-oc/memory.hpp +++ b/libraries/chain/include/eosio/chain/webassembly/eos-vm-oc/memory.hpp @@ -1,14 +1,15 @@ #pragma once +#include #include -#include +#include #include #include #include #include -namespace eosio { namespace chain { namespace eosvmoc { +namespace eosio::chain::eosvmoc { class memory { static constexpr uint64_t intrinsic_count = intrinsic_table_size(); @@ -66,7 +67,7 @@ class memory { uint8_t* fullpage_base; }; -}}} +} #define OFFSET_OF_CONTROL_BLOCK_MEMBER(M) (-(int)eosio::chain::eosvmoc::memory::cb_offset + (int)offsetof(eosio::chain::eosvmoc::control_block, M)) #define OFFSET_OF_FIRST_INTRINSIC ((int)-eosio::chain::eosvmoc::memory::first_intrinsic_offset) diff --git a/libraries/chain/protocol_feature_manager.cpp b/libraries/chain/protocol_feature_manager.cpp index 5146f736b4..bc4b4cc2e5 100644 --- a/libraries/chain/protocol_feature_manager.cpp +++ b/libraries/chain/protocol_feature_manager.cpp @@ -272,6 +272,41 @@ Adds new cryptographic host functions */ {} } ) + ( builtin_protocol_feature_t::disable_deferred_trxs_stage_1, builtin_protocol_feature_spec{ + "DISABLE_DEFERRED_TRXS_STAGE_1", + fc::variant("440c3efaaab212c387ce967c574dc813851cf8332d041beb418dfaf55facd5a9").as(), + // SHA256 hash of the raw message below within the comment delimiters (do not modify message below). +/* +Builtin protocol feature: DISABLE_DEFERRED_TRXS_STAGE_1 + +Once this first disabling deferred transactions protocol feature is activated, +the behavior of the send_deferred and cancel_deferred host functions and +canceldelay native action changes so that they become no-ops. + +In addition, any block that retires a deferred transaction with a status other +than expired is invalid. + +Also, a deferred transaction can only be retired as expired, and it can be +retired as expired regardless of whether its delay_util or expiration times +have been reached. +*/ + {} + } ) + ( builtin_protocol_feature_t::disable_deferred_trxs_stage_2, builtin_protocol_feature_spec{ + "DISABLE_DEFERRED_TRXS_STAGE_2", + fc::variant("a857eeb932774c511a40efb30346ec01bfb7796916b54c3c69fe7e5fb70d5cba").as(), + // SHA256 hash of the raw message below within the comment delimiters (do not modify message below). +/* +Builtin protocol feature: DISABLE_DEFERRED_TRXS_STAGE_2 +Depends on: DISABLE_DEFERRED_TRXS_STAGE_1 + +On activation of this second disabling deferred transactions protocol feature, +all pending deferred transactions are removed from state and the RAM paid by +the sender of each deferred transaction is refunded. Also, any block that +retires a deferred transaction is invalid. +*/ + {builtin_protocol_feature_t::disable_deferred_trxs_stage_1} + } ) ( builtin_protocol_feature_t::instant_finality, builtin_protocol_feature_spec{ "INSTANT_FINALITY", fc::variant("bc726a24928ea2d71ba294b70c5c9efc515c1542139bcf9e42f8bc174f2e72ff").as(), diff --git a/libraries/chain/transaction_context.cpp b/libraries/chain/transaction_context.cpp index 8c9e434d8f..262d7995a7 100644 --- a/libraries/chain/transaction_context.cpp +++ b/libraries/chain/transaction_context.cpp @@ -247,8 +247,11 @@ namespace eosio { namespace chain { uint64_t packed_trx_prunable_size ) { const transaction& trx = packed_trx.get_transaction(); - if ( is_transient() ) { - EOS_ASSERT( trx.delay_sec.value == 0, transaction_exception, "dry-run or read-only transaction cannot be delayed" ); + // delayed transactions are not allowed after protocol feature + // DISABLE_DEFERRED_TRXS_STAGE_1 is activated; + // read-only and dry-run transactions are not allowed to be delayed at any time + if( control.is_builtin_activated(builtin_protocol_feature_t::disable_deferred_trxs_stage_1) || is_transient() ) { + EOS_ASSERT( trx.delay_sec.value == 0, transaction_exception, "transaction cannot be delayed" ); } if( trx.transaction_extensions.size() > 0 ) { disallow_transaction_extensions( "no transaction extensions supported yet for input transactions" ); @@ -268,7 +271,6 @@ namespace eosio { namespace chain { uint64_t initial_net_usage = static_cast(cfg.base_per_transaction_net_usage) + packed_trx_unprunable_size + discounted_size_for_pruned_data; - if( trx.delay_sec.value > 0 ) { // If delayed, also charge ahead of time for the additional net usage needed to retire the delayed transaction // whether that be by successfully executing, soft failure, hard failure, or expiration. @@ -731,7 +733,6 @@ namespace eosio { namespace chain { acontext.exec(); } - void transaction_context::schedule_transaction() { // Charge ahead of time for the additional net usage needed to retire the delayed transaction // whether that be by successfully executing, soft failure, hard failure, or expiration. diff --git a/libraries/chain/webassembly/action.cpp b/libraries/chain/webassembly/action.cpp index 307ddafe6b..4ac120d499 100644 --- a/libraries/chain/webassembly/action.cpp +++ b/libraries/chain/webassembly/action.cpp @@ -5,9 +5,8 @@ namespace eosio { namespace chain { namespace webassembly { int32_t interface::read_action_data(legacy_span memory) const { auto s = context.get_action().data.size(); - if( memory.size() == 0 ) return s; - auto copy_size = std::min( static_cast(memory.size()), s ); + if( copy_size == 0 ) return s; std::memcpy( memory.data(), context.get_action().data.data(), copy_size ); return copy_size; diff --git a/libraries/chain/webassembly/runtimes/eos-vm-oc/code_cache.cpp b/libraries/chain/webassembly/runtimes/eos-vm-oc/code_cache.cpp index 37eca74914..7c48b5b079 100644 --- a/libraries/chain/webassembly/runtimes/eos-vm-oc/code_cache.cpp +++ b/libraries/chain/webassembly/runtimes/eos-vm-oc/code_cache.cpp @@ -226,13 +226,13 @@ const code_descriptor* const code_cache_sync::get_descriptor_for_code_sync(const code_cache_base::code_cache_base(const std::filesystem::path& data_dir, const eosvmoc::config& eosvmoc_config, const chainbase::database& db) : _db(db), - _cache_file_path(data_dir/"code_cache.bin") -{ + _cache_file_path(data_dir/"code_cache.bin") { static_assert(sizeof(allocator_t) <= header_offset, "header offset intersects with allocator"); std::filesystem::create_directories(data_dir); - if(!std::filesystem::exists(_cache_file_path)) { + bool created_file = false; + auto create_code_cache_file = [&] { EOS_ASSERT(eosvmoc_config.cache_size >= allocator_t::get_min_size(total_header_size), database_exception, "configured code cache size is too small"); std::ofstream ofs(_cache_file_path.generic_string(), std::ofstream::trunc); EOS_ASSERT(ofs.good(), database_exception, "unable to create EOS VM Optimized Compiler code cache"); @@ -241,19 +241,35 @@ code_cache_base::code_cache_base(const std::filesystem::path& data_dir, const eo bip::mapped_region creation_region(creation_mapping, bip::read_write); new (creation_region.get_address()) allocator_t(eosvmoc_config.cache_size, total_header_size); new ((char*)creation_region.get_address() + header_offset) code_cache_header; - } + created_file = true; + }; code_cache_header cache_header; - { + auto check_code_cache = [&] { char header_buff[total_header_size]; std::ifstream hs(_cache_file_path.generic_string(), std::ifstream::binary); hs.read(header_buff, sizeof(header_buff)); EOS_ASSERT(!hs.fail(), bad_database_version_exception, "failed to read code cache header"); memcpy((char*)&cache_header, header_buff + header_offset, sizeof(cache_header)); + + EOS_ASSERT(cache_header.id == header_id, bad_database_version_exception, "existing EOS VM OC code cache not compatible with this version"); + EOS_ASSERT(!cache_header.dirty, database_exception, "code cache is dirty"); + }; + + if (!std::filesystem::exists(_cache_file_path)) { + create_code_cache_file(); } - EOS_ASSERT(cache_header.id == header_id, bad_database_version_exception, "existing EOS VM OC code cache not compatible with this version"); - EOS_ASSERT(!cache_header.dirty, database_exception, "code cache is dirty"); + try { + check_code_cache(); + } catch (const fc::exception&) { + if (created_file) + throw; + + ilog("EOS VM optimized Compiler code cache corrupt, recreating"); + create_code_cache_file(); + check_code_cache(); + } set_on_disk_region_dirty(true); @@ -355,15 +371,14 @@ code_cache_base::~code_cache_base() { } } + uintptr_t ptr_offset = 0; if(p) { fc::datastream ds(p, sz); serialize_cache_index(ds); - uintptr_t ptr_offset = p-code_mapping; - *((uintptr_t*)(code_mapping+descriptor_ptr_from_file_start)) = ptr_offset; + ptr_offset = p-code_mapping; } - else - *((uintptr_t*)(code_mapping+descriptor_ptr_from_file_start)) = 0; + memcpy(code_mapping+descriptor_ptr_from_file_start, &ptr_offset, sizeof(ptr_offset)); msync(code_mapping, allocator->get_size(), MS_SYNC); munmap(code_mapping, allocator->get_size()); diff --git a/libraries/chain/webassembly/runtimes/eos-vm-oc/compile_monitor.cpp b/libraries/chain/webassembly/runtimes/eos-vm-oc/compile_monitor.cpp index d74fe26574..01ae7ecaba 100644 --- a/libraries/chain/webassembly/runtimes/eos-vm-oc/compile_monitor.cpp +++ b/libraries/chain/webassembly/runtimes/eos-vm-oc/compile_monitor.cpp @@ -114,7 +114,13 @@ struct compile_monitor_session { void read_message_from_compile_task(std::list>::iterator current_compile_it) { auto& [code, socket] = *current_compile_it; socket.async_wait(local::datagram_protocol::socket::wait_read, [this, current_compile_it](auto ec) { - //at this point we only expect 1 of 2 things to happen: we either get a reply (success), or we get no reply (failure) + //at this point we generally expect 1 of 2 things to happen: we either get a reply (success), or we get an error reading from the + // socket (failure). But there is also a third possibility that this compile_monitor_session is being destroyed and thus the + // socket is being destroyed by way of current_compiles being destroyed. Since this is an async_wait() and not an async_read(), + // for now just consider any error as being due to cancellation at dtor time and completely bail out (there aren't many other + // potential errors for an asnyc_wait) + if(ec) + return; auto& [code, socket] = *current_compile_it; auto [success, message, fds] = read_message_with_fds(socket); diff --git a/libraries/chain/webassembly/runtimes/eos-vm.cpp b/libraries/chain/webassembly/runtimes/eos-vm.cpp index e1692d335b..95a090dbca 100644 --- a/libraries/chain/webassembly/runtimes/eos-vm.cpp +++ b/libraries/chain/webassembly/runtimes/eos-vm.cpp @@ -287,7 +287,7 @@ std::unique_ptr eos_vm_profile_runtime::inst #endif template -thread_local eos_vm_runtime::context_t eos_vm_runtime::_exec_ctx; +thread_local typename eos_vm_runtime::context_t eos_vm_runtime::_exec_ctx; template thread_local eos_vm_backend_t eos_vm_runtime::_bkend; } diff --git a/libraries/chainbase b/libraries/chainbase index b81a6dc7aa..7615ddab28 160000 --- a/libraries/chainbase +++ b/libraries/chainbase @@ -1 +1 @@ -Subproject commit b81a6dc7aa758817fd61ea55b08bf2d0c099eafc +Subproject commit 7615ddab287e06fd31f800e66fe39b3a19320ec8 diff --git a/libraries/custom_appbase/include/eosio/chain/application.hpp b/libraries/custom_appbase/include/eosio/chain/application.hpp index b630e16ce9..6026df97dc 100644 --- a/libraries/custom_appbase/include/eosio/chain/application.hpp +++ b/libraries/custom_appbase/include/eosio/chain/application.hpp @@ -3,6 +3,7 @@ #include #include #include +#include #include /* @@ -21,29 +22,39 @@ enum class exec_window { // the main app thread is active. }; -enum class exec_queue { - read_only, // the queue storing tasks which are safe to execute - // in parallel with other read-only tasks in the read-only - // thread pool as well as on the main app thread. - // Multi-thread safe as long as nothing is executed from the read_write queue. - read_write // the queue storing tasks which can be only executed - // on the app thread while read-only tasks are - // not being executed in read-only threads. Single threaded. -}; - -class two_queue_executor { +class priority_queue_executor { public: // Trade off on returning to appbase exec() loop as the overhead of poll/run can be measurable for small running tasks. // This adds to the total time that the main thread can be busy when a high priority task is waiting. static constexpr uint16_t minimum_runtime_ms = 3; + // inform how many read_threads will be calling read_only/read_exclusive queues + // expected to only be called at program startup, not thread safe, not safe to call after startup + void init_read_threads(size_t num_read_threads) { + pri_queue_.init_read_threads(num_read_threads); + } + + // not thread safe, see init_read_threads comment + size_t get_read_threads() const { + return pri_queue_.get_read_threads(); + } + + // assume application is started on the main thread + std::thread::id get_main_thread_id() const { + return main_thread_id_; + } + template - auto post( int priority, exec_queue q, Func&& func ) { - if ( q == exec_queue::read_write ) - return boost::asio::post(io_serv_, read_write_queue_.wrap(priority, --order_, std::forward(func))); - else - return boost::asio::post( io_serv_, read_only_queue_.wrap( priority, --order_, std::forward( func))); + void post( int priority, exec_queue q, Func&& func ) { + if (q == exec_queue::read_exclusive) { + // no reason to post to io_service which then places this in the read_exclusive_handlers queue. + // read_exclusive tasks are run exclusively by read threads by pulling off the read_exclusive handlers queue. + pri_queue_.add(priority, q, --order_, std::forward(func)); + } else { + // post to io_service as the main thread may be blocked on io_service.run_one() in application::exec() + boost::asio::post(io_serv_, pri_queue_.wrap(priority, q, --order_, std::forward(func))); + } } // Legacy and deprecated. To be removed after cleaning up its uses in base appbase @@ -51,11 +62,12 @@ class two_queue_executor { auto post( int priority, Func&& func ) { // safer to use read_write queue for unknown type of operation since operations // from read_write queue are not executed in parallel with read-only operations - return boost::asio::post(io_serv_, read_write_queue_.wrap(priority, --order_, std::forward(func))); + return boost::asio::post(io_serv_, pri_queue_.wrap(priority, exec_queue::read_write, --order_, std::forward(func))); } boost::asio::io_service& get_io_service() { return io_serv_; } + // called from main thread, highest read_only and read_write bool execute_highest() { // execute for at least minimum runtime const auto end = std::chrono::high_resolution_clock::now() + std::chrono::milliseconds(minimum_runtime_ms); @@ -63,17 +75,11 @@ class two_queue_executor { bool more = false; while (true) { if ( exec_window_ == exec_window::write ) { - // During write window only main thread is accessing anything in two_queue_executor, no locking required - if( !read_write_queue_.empty() && (read_only_queue_.empty() || *read_only_queue_.top() < *read_write_queue_.top()) ) { - // read_write_queue_'s top function's priority greater than read_only_queue_'s top function's, or read_only_queue_ empty - read_write_queue_.execute_highest(); - } else if( !read_only_queue_.empty() ) { - read_only_queue_.execute_highest(); - } - more = !read_only_queue_.empty() || !read_write_queue_.empty(); + // During write window only main thread is accessing anything in priority_queue_executor, no locking required + more = pri_queue_.execute_highest(exec_queue::read_write, exec_queue::read_only); } else { - // When in read window, multiple threads including main app thread are accessing two_queue_executor, locking required - more = read_only_queue_.execute_highest_locked(false); + // When in read window, multiple threads including main app thread are accessing priority_queue_executor, locking required + more = pri_queue_.execute_highest_locked(exec_queue::read_only); } if (!more || std::chrono::high_resolution_clock::now() > end) break; @@ -81,13 +87,14 @@ class two_queue_executor { return more; } - bool execute_highest_read_only() { + bool execute_highest_read() { // execute for at least minimum runtime const auto end = std::chrono::high_resolution_clock::now() + std::chrono::milliseconds(minimum_runtime_ms); bool more = false; while (true) { - more = read_only_queue_.execute_highest_locked( true ); + get_io_service().poll(); // schedule any queued + more = pri_queue_.execute_highest_blocking_locked(exec_queue::read_only, exec_queue::read_exclusive); if (!more || std::chrono::high_resolution_clock::now() > end) break; } @@ -97,25 +104,25 @@ class two_queue_executor { template boost::asio::executor_binder wrap(int priority, exec_queue q, Function&& func ) { - if ( q == exec_queue::read_write ) - return read_write_queue_.wrap(priority, --order_, std::forward(func)); - else - return read_only_queue_.wrap( priority, --order_, std::forward( func)); + return pri_queue_.wrap(priority, q, --order_, std::forward(func)); + } + + void stop() { + pri_queue_.stop(); } void clear() { - read_only_queue_.clear(); - read_write_queue_.clear(); + pri_queue_.clear(); } - void set_to_read_window(uint32_t num_threads, std::function should_exit) { + void set_to_read_window(std::function should_exit) { exec_window_ = exec_window::read; - read_only_queue_.enable_locking(num_threads, std::move(should_exit)); + pri_queue_.enable_locking(std::move(should_exit)); } void set_to_write_window() { exec_window_ = exec_window::write; - read_only_queue_.disable_locking(); + pri_queue_.disable_locking(); } bool is_read_window() const { @@ -126,20 +133,23 @@ class two_queue_executor { return exec_window_ == exec_window::write; } - auto& read_only_queue() { return read_only_queue_; } - - auto& read_write_queue() { return read_write_queue_; } + size_t read_only_queue_size() { return pri_queue_.size(exec_queue::read_only); } + size_t read_write_queue_size() { return pri_queue_.size(exec_queue::read_write); } + size_t read_exclusive_queue_size() { return pri_queue_.size(exec_queue::read_exclusive); } + bool read_only_queue_empty() { return pri_queue_.empty(exec_queue::read_only); } + bool read_write_queue_empty() { return pri_queue_.empty(exec_queue::read_write); } + bool read_exclusive_queue_empty() { return pri_queue_.empty(exec_queue::read_exclusive); } // members are ordered taking into account that the last one is destructed first private: + std::thread::id main_thread_id_{ std::this_thread::get_id() }; boost::asio::io_service io_serv_; - appbase::exec_pri_queue read_only_queue_; - appbase::exec_pri_queue read_write_queue_; - std::atomic order_ { std::numeric_limits::max() }; // to maintain FIFO ordering in both queues within priority - exec_window exec_window_ { exec_window::write }; + appbase::exec_pri_queue pri_queue_; + std::atomic order_{ std::numeric_limits::max() }; // to maintain FIFO ordering in all queues within priority + exec_window exec_window_{ exec_window::write }; }; -using application = application_t; +using application = application_t; } #include diff --git a/libraries/custom_appbase/include/eosio/chain/exec_pri_queue.hpp b/libraries/custom_appbase/include/eosio/chain/exec_pri_queue.hpp index 984adc8d60..f6d49c45af 100644 --- a/libraries/custom_appbase/include/eosio/chain/exec_pri_queue.hpp +++ b/libraries/custom_appbase/include/eosio/chain/exec_pri_queue.hpp @@ -3,20 +3,55 @@ #include #include +#include #include namespace appbase { // adapted from: https://www.boost.org/doc/libs/1_69_0/doc/html/boost_asio/example/cpp11/invocation/prioritised_handlers.cpp +enum class exec_queue { + read_only, // the queue storing tasks which are safe to execute + // in parallel with other read-only & read_exclusive tasks in the read-only + // thread pool as well as on the main app thread. + // Multi-thread safe as long as nothing is executed from the read_write queue. + read_write, // the queue storing tasks which can be only executed + // on the app thread while read-only tasks are + // not being executed in read-only threads. Single threaded. + read_exclusive // the queue storing tasks which should only be executed + // in parallel with other read_exclusive or read_only tasks in the + // read-only thread pool. Will never be executed on the main thread. + // If no read-only thread pool is available that calls one of the execute_* with + // read_exclusive then this queue grows unbounded. exec_pri_queue asserts + // if asked to queue a read_exclusive task when init'ed with 0 read-only threads. +}; + // Locking has to be coordinated by caller, use with care. class exec_pri_queue : public boost::asio::execution_context { public: - void enable_locking(uint32_t num_threads, std::function should_exit) { - assert(num_threads > 0 && num_waiting_ == 0); + // inform how many read_threads will be calling read_only/read_exclusive queues + // expected to only be called at program startup, not thread safe, not safe to call when lock_enabled_ + void init_read_threads(size_t num_read_threads) { + assert(!lock_enabled_); + num_read_threads_ = num_read_threads; + } + + // not strictly thread safe, see init_read_threads comment + size_t get_read_threads() const { + return num_read_threads_; + } + + void stop() { + std::lock_guard g( mtx_ ); + exiting_blocking_ = true; + cond_.notify_all(); + } + + void enable_locking(std::function should_exit) { + assert(num_read_threads_ > 0 && num_waiting_ == 0); lock_enabled_ = true; - max_waiting_ = num_threads; + max_waiting_ = num_read_threads_; should_exit_ = std::move(should_exit); exiting_blocking_ = false; } @@ -28,88 +63,103 @@ class exec_pri_queue : public boost::asio::execution_context // called from appbase::application_base::exec poll_one() or run_one() template - void add(int priority, size_t order, Function function) - { + void add(int priority, exec_queue q, size_t order, Function function) { + assert( num_read_threads_ > 0 || q != exec_queue::read_exclusive); + prio_queue& que = priority_que(q); std::unique_ptr handler(new queued_handler(priority, order, std::move(function))); - if (lock_enabled_) { + if (lock_enabled_ || q == exec_queue::read_exclusive) { // called directly from any thread for read_exclusive std::lock_guard g( mtx_ ); - handlers_.push( std::move( handler ) ); + que.push( std::move( handler ) ); if (num_waiting_) cond_.notify_one(); } else { - handlers_.push( std::move( handler ) ); + que.push( std::move( handler ) ); } } // only call when no lock required - void clear() - { - handlers_ = prio_queue(); + void clear() { + read_only_handlers_ = prio_queue(); + read_write_handlers_ = prio_queue(); + read_exclusive_handlers_ = prio_queue(); } - // only call when no lock required - bool execute_highest() - { - if( !handlers_.empty() ) { - handlers_.top()->execute(); - handlers_.pop(); - } - - return !handlers_.empty(); + bool execute_highest_locked(exec_queue q) { + prio_queue& que = priority_que(q); + std::unique_lock g(mtx_); + if (que.empty()) + return false; + auto t = pop(que); + g.unlock(); + t->execute(); + return true; } -private: - // has to be defined before use, auto return type - auto pop() { - auto t = std::move(const_cast&>(handlers_.top())); - handlers_.pop(); - return t; + // only call when no lock required + bool execute_highest(exec_queue lhs, exec_queue rhs) { + prio_queue& lhs_que = priority_que(lhs); + prio_queue& rhs_que = priority_que(rhs); + size_t size = lhs_que.size() + rhs_que.size(); + if (size == 0) + return false; + exec_queue q = rhs; + if (!lhs_que.empty() && (rhs_que.empty() || *rhs_que.top() < *lhs_que.top())) + q = lhs; + prio_queue& que = priority_que(q); + assert(que.top()); + // pop, then execute since read_write queue is used to switch to read window and the pop needs to happen before that lambda starts + auto t = pop(que); + t->execute(); + --size; + return size > 0; } -public: - - bool execute_highest_locked(bool should_block) { + bool execute_highest_blocking_locked(exec_queue lhs, exec_queue rhs) { + prio_queue& lhs_que = priority_que(lhs); + prio_queue& rhs_que = priority_que(rhs); std::unique_lock g(mtx_); - if (should_block) { - ++num_waiting_; - cond_.wait(g, [this](){ - bool exit = exiting_blocking_ || should_exit_(); - bool empty = handlers_.empty(); - if (empty || exit) { - if (((empty && num_waiting_ == max_waiting_) || exit) && !exiting_blocking_) { - cond_.notify_all(); - exiting_blocking_ = true; - } - return exit || exiting_blocking_; // same as calling should_exit(), but faster + ++num_waiting_; + cond_.wait(g, [&](){ + bool exit = exiting_blocking_ || should_exit_(); + bool empty = lhs_que.empty() && rhs_que.empty(); + if (empty || exit) { + if (((empty && num_waiting_ == max_waiting_) || exit) && !exiting_blocking_) { + exiting_blocking_ = true; + cond_.notify_all(); } - return true; - }); - --num_waiting_; - if (exiting_blocking_ || should_exit_()) - return false; - } - if( handlers_.empty() ) + return exit || exiting_blocking_; // same as calling should_exit(), but faster + } + return true; + }); + --num_waiting_; + if (exiting_blocking_ || should_exit_()) + return false; + if (lhs_que.empty() && rhs_que.empty()) return false; - auto t = pop(); + exec_queue q = rhs; + if (!lhs_que.empty() && (rhs_que.empty() || *rhs_que.top() < *lhs_que.top())) + q = lhs; + auto t = pop(priority_que(q)); g.unlock(); t->execute(); - return true; + return true; // this should never return false unless all read threads should exit } // Only call when locking disabled - size_t size() const { return handlers_.size(); } + size_t size(exec_queue q) const { return priority_que(q).size(); } + size_t size() const { return read_only_handlers_.size() + read_write_handlers_.size() + read_exclusive_handlers_.size(); } // Only call when locking disabled - bool empty() const { return handlers_.empty(); } + bool empty(exec_queue q) const { return priority_que(q).empty(); } // Only call when locking disabled - const auto& top() const { return handlers_.top(); } + const auto& top(exec_queue q) const { return priority_que(q).top(); } class executor { public: - executor(exec_pri_queue& q, int p, size_t o) - : context_(q), priority_(p), order_(o) + executor(exec_pri_queue& q, int p, size_t o, exec_queue que) + : context_(q), que_(que), priority_(p), order_(o) { } @@ -121,19 +171,19 @@ class exec_pri_queue : public boost::asio::execution_context template void dispatch(Function f, const Allocator&) const { - context_.add(priority_, order_, std::move(f)); + context_.add(priority_, que_, order_, std::move(f)); } template void post(Function f, const Allocator&) const { - context_.add(priority_, order_, std::move(f)); + context_.add(priority_, que_, order_, std::move(f)); } template void defer(Function f, const Allocator&) const { - context_.add(priority_, order_, std::move(f)); + context_.add(priority_, que_, order_, std::move(f)); } void on_work_started() const noexcept {} @@ -141,7 +191,7 @@ class exec_pri_queue : public boost::asio::execution_context bool operator==(const executor& other) const noexcept { - return order_ == other.order_ && &context_ == &other.context_ && priority_ == other.priority_; + return order_ == other.order_ && priority_ == other.priority_ && que_ == other.que_ && &context_ == &other.context_; } bool operator!=(const executor& other) const noexcept @@ -151,15 +201,16 @@ class exec_pri_queue : public boost::asio::execution_context private: exec_pri_queue& context_; + exec_queue que_; int priority_; size_t order_; }; template boost::asio::executor_binder - wrap(int priority, size_t order, Function&& func) + wrap(int priority, exec_queue q, size_t order, Function&& func) { - return boost::asio::bind_executor( executor(*this, priority, order), std::forward(func) ); + return boost::asio::bind_executor( executor(*this, priority, order, q), std::forward(func) ); } private: @@ -219,15 +270,52 @@ class exec_pri_queue : public boost::asio::execution_context } }; + using prio_queue = std::priority_queue, std::deque>, deref_less>; + + prio_queue& priority_que(exec_queue q) { + switch (q) { + case exec_queue::read_only: + return read_only_handlers_; + case exec_queue::read_write: + return read_write_handlers_; + case exec_queue::read_exclusive: + return read_exclusive_handlers_; + } + assert(false); + return read_only_handlers_; + } + + const prio_queue& priority_que(exec_queue q) const { + switch (q) { + case exec_queue::read_only: + return read_only_handlers_; + case exec_queue::read_write: + return read_write_handlers_; + case exec_queue::read_exclusive: + return read_exclusive_handlers_; + } + assert(false); + return read_only_handlers_; + } + + static std::unique_ptr pop(prio_queue& que) { + // work around std::priority_queue not having a pop() that returns value + auto t = std::move(const_cast&>(que.top())); + que.pop(); + return t; + } + + size_t num_read_threads_ = 0; bool lock_enabled_ = false; - std::mutex mtx_; + mutable std::mutex mtx_; std::condition_variable cond_; uint32_t num_waiting_{0}; uint32_t max_waiting_{0}; bool exiting_blocking_{false}; std::function should_exit_; // called holding mtx_ - using prio_queue = std::priority_queue, std::deque>, deref_less>; - prio_queue handlers_; + prio_queue read_only_handlers_; + prio_queue read_write_handlers_; + prio_queue read_exclusive_handlers_; }; } // appbase diff --git a/libraries/custom_appbase/tests/CMakeLists.txt b/libraries/custom_appbase/tests/CMakeLists.txt index 95f44b66d6..7df7d2a964 100644 --- a/libraries/custom_appbase/tests/CMakeLists.txt +++ b/libraries/custom_appbase/tests/CMakeLists.txt @@ -7,7 +7,7 @@ endif() file(GLOB UNIT_TESTS "*.cpp") add_executable( custom_appbase_test ${UNIT_TESTS} ) -target_link_libraries( custom_appbase_test appbase ${CMAKE_DL_LIBS} ${PLATFORM_SPECIFIC_LIBS} ) +target_link_libraries( custom_appbase_test appbase fc ${CMAKE_DL_LIBS} ${PLATFORM_SPECIFIC_LIBS} ) target_include_directories( custom_appbase_test PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/../include" "${CMAKE_CURRENT_SOURCE_DIR}/../../appbase/include" ) add_test( custom_appbase_test custom_appbase_test ) diff --git a/libraries/custom_appbase/tests/custom_appbase_tests.cpp b/libraries/custom_appbase/tests/custom_appbase_tests.cpp index 9ee5af40cd..f62f10b0a5 100644 --- a/libraries/custom_appbase/tests/custom_appbase_tests.cpp +++ b/libraries/custom_appbase/tests/custom_appbase_tests.cpp @@ -1,54 +1,115 @@ #define BOOST_TEST_MODULE custom_appbase_tests #include -#include -#include #include +#include + +#include +#include + using namespace appbase; BOOST_AUTO_TEST_SUITE(custom_appbase_tests) -std::thread start_app_thread(appbase::scoped_app& app) { - const char* argv[] = { boost::unit_test::framework::current_test_case().p_name->c_str() }; - BOOST_CHECK(app->initialize(sizeof(argv) / sizeof(char*), const_cast(argv))); - app->startup(); - std::thread app_thread( [&]() { - app->exec(); - } ); - return app_thread; +class scoped_app_thread { +public: + explicit scoped_app_thread(bool delay_exec = false) { + app_thread_ = start_app_thread(); + if (!delay_exec) { + start_exec(); + } + } + ~scoped_app_thread() { // destroy app instance so next instance gets a clean one + application::reset_app_singleton(); + } + + scoped_app_thread(const scoped_app_thread&) = delete; + scoped_app_thread& operator=(const scoped_app_thread&) = delete; + + appbase::application* operator->() { + return app_; + } + const appbase::application* operator->() const { + return app_; + } + + void start_exec() { + start_exec_.set_value(); + } + + void join() { + app_thread_.join(); + } + +private: + std::thread start_app_thread() { + std::promise start_complete; + std::thread app_thread( [&]() { + assert(application::null_app_singleton()); + app_ = &appbase::app(); + const char* argv[] = { boost::unit_test::framework::current_test_case().p_name->c_str() }; + BOOST_CHECK(app_->initialize(sizeof(argv) / sizeof(char*), const_cast(argv))); + app_->startup(); + start_complete.set_value(); + start_exec_.get_future().get(); + app_->exec(); + } ); + start_complete.get_future().get(); + return app_thread; + } + +private: + std::thread app_thread_; + std::promise start_exec_; + appbase::application* app_; +}; + + +std::thread start_read_thread(scoped_app_thread& app) { + static int num = 0; + std::thread read_thread( [&]() { + std::string name ="read-" + std::to_string(num++); + fc::set_thread_name(name); + bool more = true; + while (more) { + more = app->executor().execute_highest_read(); // blocks until all read only threads are idle + } + }); + return read_thread; } -// verify functions from both queues are executed when execution window is not explictly set +// verify functions from both queues (read_only,read_write) are executed when execution window is not explicitly set BOOST_AUTO_TEST_CASE( default_exec_window ) { - appbase::scoped_app app; - auto app_thread = start_app_thread(app); - + scoped_app_thread app; + // post functions std::map rslts {}; int seq_num = 0; - app->executor().post( priority::medium, exec_queue::read_only, [&]() { rslts[0]=seq_num; ++seq_num; } ); - app->executor().post( priority::medium, exec_queue::read_write, [&]() { rslts[1]=seq_num; ++seq_num; } ); - app->executor().post( priority::high, exec_queue::read_write, [&]() { rslts[2]=seq_num; ++seq_num; } ); - app->executor().post( priority::high, exec_queue::read_only, [&]() { rslts[3]=seq_num; ++seq_num; } ); - app->executor().post( priority::low, exec_queue::read_only, [&]() { rslts[4]=seq_num; ++seq_num; } ); - app->executor().post( priority::low, exec_queue::read_write, [&]() { rslts[5]=seq_num; ++seq_num; } ); - app->executor().post( priority::highest,exec_queue::read_only, [&]() { rslts[6]=seq_num; ++seq_num; } ); - app->executor().post( priority::high, exec_queue::read_write, [&]() { rslts[7]=seq_num; ++seq_num; } ); + app->executor().post( priority::medium, exec_queue::read_only, [&]() { rslts[0]=seq_num; ++seq_num; } ); + app->executor().post( priority::medium, exec_queue::read_write, [&]() { rslts[1]=seq_num; ++seq_num; } ); + app->executor().post( priority::high, exec_queue::read_write, [&]() { rslts[2]=seq_num; ++seq_num; } ); + app->executor().post( priority::high, exec_queue::read_only, [&]() { rslts[3]=seq_num; ++seq_num; } ); + app->executor().post( priority::low, exec_queue::read_only, [&]() { rslts[4]=seq_num; ++seq_num; } ); + app->executor().post( priority::low, exec_queue::read_write, [&]() { rslts[5]=seq_num; ++seq_num; } ); + app->executor().post( priority::highest,exec_queue::read_only, [&]() { rslts[6]=seq_num; ++seq_num; } ); + app->executor().post( priority::high, exec_queue::read_write, [&]() { rslts[7]=seq_num; ++seq_num; } ); // Stop app. Use the lowest priority to make sure this function to execute the last app->executor().post( priority::lowest, exec_queue::read_only, [&]() { // read_only_queue should only contain the current lambda function, // and read_write_queue should have executed all its functions - BOOST_REQUIRE_EQUAL( app->executor().read_only_queue().size(), 1u); // pop()s after execute - BOOST_REQUIRE_EQUAL( app->executor().read_write_queue().size(), 0u ); + BOOST_REQUIRE_EQUAL( app->executor().read_only_queue_size(), 0u); // pop()s before execute + BOOST_REQUIRE_EQUAL( app->executor().read_exclusive_queue_size(), 0u ); + BOOST_REQUIRE_EQUAL( app->executor().read_write_queue_size(), 0u ); app->quit(); } ); - app_thread.join(); + app.join(); - // both queues are cleared after execution - BOOST_REQUIRE_EQUAL( app->executor().read_only_queue().empty(), true); - BOOST_REQUIRE_EQUAL( app->executor().read_write_queue().empty(), true); + // all queues are cleared when exiting application::exec() + BOOST_REQUIRE_EQUAL( app->executor().read_only_queue_empty(), true); + BOOST_REQUIRE_EQUAL( app->executor().read_exclusive_queue_empty(), true); + BOOST_REQUIRE_EQUAL( app->executor().read_write_queue_empty(), true); // exactly number of both queues' functions processed BOOST_REQUIRE_EQUAL( rslts.size(), 8u ); @@ -64,58 +125,60 @@ BOOST_AUTO_TEST_CASE( default_exec_window ) { BOOST_CHECK_LT( rslts[6], rslts[7] ); } -// verify functions only from read_only queue are processed during read window -BOOST_AUTO_TEST_CASE( execute_from_read_queue ) { - appbase::scoped_app app; - auto app_thread = start_app_thread(app); - +// verify functions only from read_only queue are processed during read window on the main thread +BOOST_AUTO_TEST_CASE( execute_from_read_only_queue ) { + scoped_app_thread app; + // set to run functions from read_only queue only - app->executor().set_to_read_window(1, [](){return false;}); + app->executor().init_read_threads(1); + app->executor().set_to_read_window([](){return false;}); // post functions std::map rslts {}; int seq_num = 0; - app->executor().post( priority::medium, exec_queue::read_write, [&]() { rslts[0]=seq_num; ++seq_num; } ); - app->executor().post( priority::high, exec_queue::read_only, [&]() { rslts[1]=seq_num; ++seq_num; } ); - app->executor().post( priority::high, exec_queue::read_write, [&]() { rslts[2]=seq_num; ++seq_num; } ); - app->executor().post( priority::high, exec_queue::read_only, [&]() { rslts[3]=seq_num; ++seq_num; } ); - app->executor().post( priority::low, exec_queue::read_only, [&]() { rslts[4]=seq_num; ++seq_num; } ); - app->executor().post( priority::low, exec_queue::read_write, [&]() { rslts[5]=seq_num; ++seq_num; } ); - app->executor().post( priority::highest,exec_queue::read_only, [&]() { rslts[6]=seq_num; ++seq_num; } ); - app->executor().post( priority::highest,exec_queue::read_only, [&]() { rslts[7]=seq_num; ++seq_num; } ); - app->executor().post( priority::high, exec_queue::read_only, [&]() { rslts[8]=seq_num; ++seq_num; } ); - app->executor().post( priority::high, exec_queue::read_write, [&]() { rslts[9]=seq_num; ++seq_num; } ); + app->executor().post( priority::medium, exec_queue::read_write, [&]() { rslts[0]=seq_num; ++seq_num; } ); + app->executor().post( priority::high, exec_queue::read_only, [&]() { rslts[1]=seq_num; ++seq_num; } ); + app->executor().post( priority::high, exec_queue::read_write, [&]() { rslts[2]=seq_num; ++seq_num; } ); + app->executor().post( priority::high, exec_queue::read_only, [&]() { rslts[3]=seq_num; ++seq_num; } ); + app->executor().post( priority::low, exec_queue::read_only, [&]() { rslts[4]=seq_num; ++seq_num; } ); + app->executor().post( priority::low, exec_queue::read_write, [&]() { rslts[5]=seq_num; ++seq_num; } ); + app->executor().post( priority::highest,exec_queue::read_only, [&]() { rslts[6]=seq_num; ++seq_num; } ); + app->executor().post( priority::high, exec_queue::read_exclusive, [&]() { rslts[7]=seq_num; ++seq_num; } ); + app->executor().post( priority::low, exec_queue::read_exclusive, [&]() { rslts[8]=seq_num; ++seq_num; } ); + app->executor().post( priority::high, exec_queue::read_write, [&]() { rslts[9]=seq_num; ++seq_num; } ); // stop application. Use lowest at the end to make sure this executes the last app->executor().post( priority::lowest, exec_queue::read_only, [&]() { // read_queue should be empty (read window pops before execute) and write_queue should have all its functions - BOOST_REQUIRE_EQUAL( app->executor().read_only_queue().size(), 0u); // pop()s before execute - BOOST_REQUIRE_EQUAL( app->executor().read_write_queue().size(), 4u ); + BOOST_REQUIRE_EQUAL( app->executor().read_only_queue_size(), 0u); // pop()s before execute + BOOST_REQUIRE_EQUAL( app->executor().read_exclusive_queue_size(), 2u); + BOOST_REQUIRE_EQUAL( app->executor().read_write_queue_size(), 4u ); app->quit(); } ); - app_thread.join(); + app.join(); - // both queues are cleared after execution - BOOST_REQUIRE_EQUAL( app->executor().read_only_queue().empty(), true); - BOOST_REQUIRE_EQUAL( app->executor().read_write_queue().empty(), true); + // all queues are cleared when exiting application::exec() + BOOST_REQUIRE_EQUAL( app->executor().read_only_queue_empty(), true); + BOOST_REQUIRE_EQUAL( app->executor().read_exclusive_queue_empty(), true); + BOOST_REQUIRE_EQUAL( app->executor().read_write_queue_empty(), true); // exactly number of posts processed - BOOST_REQUIRE_EQUAL( rslts.size(), 6u ); + BOOST_REQUIRE_EQUAL( rslts.size(), 4u ); - // same priority (high) of functions in read_queue executed by the post order + // same priority (high) of functions in read queues executed by the post order BOOST_CHECK_LT( rslts[1], rslts[3] ); - // higher priority posted earlier in read_queue executed earlier + // higher priority posted earlier in read queues executed earlier BOOST_CHECK_LT( rslts[3], rslts[4] ); } -// verify no functions are executed during read window if read_only queue is empty -BOOST_AUTO_TEST_CASE( execute_from_empty_read_queue ) { - appbase::scoped_app app; - auto app_thread = start_app_thread(app); - - // set to run functions from read_only queue only - app->executor().set_to_read_window(1, [](){return false;}); +// verify no functions are executed during read window if read_only & read_exclusive queue is empty +BOOST_AUTO_TEST_CASE( execute_from_empty_read_only_queue ) { + scoped_app_thread app; + + // set to run functions from read_only & read_exclusive queues only + app->executor().init_read_threads(1); + app->executor().set_to_read_window([](){return false;}); // post functions std::map rslts {}; @@ -134,24 +197,25 @@ BOOST_AUTO_TEST_CASE( execute_from_empty_read_queue ) { // Stop application. Use lowest at the end to make sure this executes the last app->executor().post( priority::lowest, exec_queue::read_only, [&]() { // read_queue should be empty (read window pops before execute) and write_queue should have all its functions - BOOST_REQUIRE_EQUAL( app->executor().read_only_queue().size(), 0u); // pop()s before execute - BOOST_REQUIRE_EQUAL( app->executor().read_write_queue().size(), 10u ); + BOOST_REQUIRE_EQUAL( app->executor().read_only_queue_size(), 0u); // pop()s before execute + BOOST_REQUIRE_EQUAL( app->executor().read_exclusive_queue_size(), 0u); + BOOST_REQUIRE_EQUAL( app->executor().read_write_queue_size(), 10u ); app->quit(); } ); - app_thread.join(); + app.join(); - // both queues are cleared after execution - BOOST_REQUIRE_EQUAL( app->executor().read_only_queue().empty(), true); - BOOST_REQUIRE_EQUAL( app->executor().read_write_queue().empty(), true); + // all queues are cleared when exiting application::exec() + BOOST_REQUIRE_EQUAL( app->executor().read_only_queue_empty(), true); + BOOST_REQUIRE_EQUAL( app->executor().read_only_queue_empty(), true); + BOOST_REQUIRE_EQUAL( app->executor().read_write_queue_empty(), true); // no results BOOST_REQUIRE_EQUAL( rslts.size(), 0u ); } -// verify functions from both queues are processed in write window -BOOST_AUTO_TEST_CASE( execute_from_both_queues ) { - appbase::scoped_app app; - auto app_thread = start_app_thread(app); +// verify functions from both queues (read_only, read_write) are processed in write window, but not read_exclusive +BOOST_AUTO_TEST_CASE( execute_from_read_only_and_read_write_queues ) { + scoped_app_thread app; // set to run functions from both queues app->executor().is_write_window(); @@ -159,32 +223,34 @@ BOOST_AUTO_TEST_CASE( execute_from_both_queues ) { // post functions std::map rslts {}; int seq_num = 0; - app->executor().post( priority::medium, exec_queue::read_only, [&]() { rslts[0]=seq_num; ++seq_num; } ); - app->executor().post( priority::medium, exec_queue::read_write, [&]() { rslts[1]=seq_num; ++seq_num; } ); - app->executor().post( priority::high, exec_queue::read_write, [&]() { rslts[2]=seq_num; ++seq_num; } ); - app->executor().post( priority::lowest, exec_queue::read_only, [&]() { rslts[3]=seq_num; ++seq_num; } ); - app->executor().post( priority::low, exec_queue::read_only, [&]() { rslts[4]=seq_num; ++seq_num; } ); - app->executor().post( priority::low, exec_queue::read_write, [&]() { rslts[5]=seq_num; ++seq_num; } ); - app->executor().post( priority::highest,exec_queue::read_only, [&]() { rslts[6]=seq_num; ++seq_num; } ); - app->executor().post( priority::low, exec_queue::read_write, [&]() { rslts[7]=seq_num; ++seq_num; } ); - app->executor().post( priority::lowest, exec_queue::read_only, [&]() { rslts[8]=seq_num; ++seq_num; } ); - app->executor().post( priority::lowest, exec_queue::read_only, [&]() { rslts[9]=seq_num; ++seq_num; } ); - app->executor().post( priority::low, exec_queue::read_write, [&]() { rslts[10]=seq_num; ++seq_num; } ); - app->executor().post( priority::medium, exec_queue::read_write, [&]() { rslts[11]=seq_num; ++seq_num; } ); + app->executor().post( priority::medium, exec_queue::read_only, [&]() { rslts[0]=seq_num; ++seq_num; } ); + app->executor().post( priority::medium, exec_queue::read_write, [&]() { rslts[1]=seq_num; ++seq_num; } ); + app->executor().post( priority::high, exec_queue::read_write, [&]() { rslts[2]=seq_num; ++seq_num; } ); + app->executor().post( priority::lowest, exec_queue::read_only, [&]() { rslts[3]=seq_num; ++seq_num; } ); + app->executor().post( priority::low, exec_queue::read_only, [&]() { rslts[4]=seq_num; ++seq_num; } ); + app->executor().post( priority::low, exec_queue::read_write, [&]() { rslts[5]=seq_num; ++seq_num; } ); + app->executor().post( priority::highest,exec_queue::read_only, [&]() { rslts[6]=seq_num; ++seq_num; } ); + app->executor().post( priority::low, exec_queue::read_write, [&]() { rslts[7]=seq_num; ++seq_num; } ); + app->executor().post( priority::lowest, exec_queue::read_only, [&]() { rslts[8]=seq_num; ++seq_num; } ); + app->executor().post( priority::lowest, exec_queue::read_only, [&]() { rslts[9]=seq_num; ++seq_num; } ); + app->executor().post( priority::low, exec_queue::read_write, [&]() { rslts[10]=seq_num; ++seq_num; } ); + app->executor().post( priority::medium, exec_queue::read_write, [&]() { rslts[11]=seq_num; ++seq_num; } ); // stop application. Use lowest at the end to make sure this executes the last app->executor().post( priority::lowest, exec_queue::read_only, [&]() { // read_queue should have current function and write_queue's functions are all executed - BOOST_REQUIRE_EQUAL( app->executor().read_only_queue().size(), 1u); // pop()s after execute - BOOST_REQUIRE_EQUAL( app->executor().read_write_queue().size(), 0u ); + BOOST_REQUIRE_EQUAL( app->executor().read_only_queue_size(), 0u); // pop()s before execute + BOOST_REQUIRE_EQUAL( app->executor().read_exclusive_queue_size(), 0u); + BOOST_REQUIRE_EQUAL( app->executor().read_write_queue_size(), 0u ); app->quit(); } ); - app_thread.join(); + app.join(); - // queues are emptied after quit - BOOST_REQUIRE_EQUAL( app->executor().read_only_queue().empty(), true); - BOOST_REQUIRE_EQUAL( app->executor().read_write_queue().empty(), true); + // queues are emptied after exec + BOOST_REQUIRE_EQUAL( app->executor().read_only_queue_empty(), true); + BOOST_REQUIRE_EQUAL( app->executor().read_exclusive_queue_empty(), true); + BOOST_REQUIRE_EQUAL( app->executor().read_write_queue_empty(), true); // exactly number of posts processed BOOST_REQUIRE_EQUAL( rslts.size(), 12u ); @@ -212,4 +278,175 @@ BOOST_AUTO_TEST_CASE( execute_from_both_queues ) { BOOST_CHECK_LT( rslts[6], rslts[11] ); } +// verify tasks from both queues (read_only, read_exclusive) are processed in read window +BOOST_AUTO_TEST_CASE( execute_from_read_only_and_read_exclusive_queues ) { + scoped_app_thread app(true); + + app->executor().init_read_threads(3); + // set to run functions from read_only & read_exclusive queues only + app->executor().set_to_read_window([](){return false;}); + + // post functions + std::vector> rslts(16); + std::atomic seq_num = 0; + app->executor().post( priority::medium, exec_queue::read_only, [&]() { rslts.at(0)=1; ++seq_num; } ); + app->executor().post( priority::medium, exec_queue::read_exclusive, [&]() { rslts.at(1)=2; ++seq_num; } ); + app->executor().post( priority::high, exec_queue::read_exclusive, [&]() { rslts.at(2)=3; ++seq_num; } ); + app->executor().post( priority::lowest, exec_queue::read_only, [&]() { rslts.at(3)=4; ++seq_num; } ); + app->executor().post( priority::low, exec_queue::read_only, [&]() { rslts.at(4)=5; ++seq_num; } ); + app->executor().post( priority::low, exec_queue::read_write, [&]() { rslts.at(5)=6; ++seq_num; } ); + app->executor().post( priority::highest,exec_queue::read_only, [&]() { rslts.at(6)=7; ++seq_num; } ); + app->executor().post( priority::medium, exec_queue::read_write, [&]() { rslts.at(7)=8; ++seq_num; } ); + app->executor().post( priority::lowest, exec_queue::read_only, [&]() { rslts.at(8)=9; ++seq_num; } ); + app->executor().post( priority::lowest, exec_queue::read_exclusive, [&]() { rslts.at(9)=10; ++seq_num; } ); + app->executor().post( priority::low, exec_queue::read_write, [&]() { rslts.at(10)=11; ++seq_num; } ); + app->executor().post( priority::medium, exec_queue::read_exclusive, [&]() { rslts.at(11)=12; ++seq_num; } ); + app->executor().post( priority::highest,exec_queue::read_exclusive, [&]() { rslts.at(12)=13; ++seq_num; } ); + app->executor().post( priority::lowest, exec_queue::read_exclusive, [&]() { rslts.at(13)=14; ++seq_num; } ); + app->executor().post( priority::medium, exec_queue::read_exclusive, [&]() { rslts.at(14)=15; ++seq_num; } ); + app->executor().post( priority::low, exec_queue::read_only, [&]() { rslts.at(15)=16; ++seq_num; } ); + + // Use lowest at the end to make sure this executes the last + app->executor().post( priority::lowest, exec_queue::read_exclusive, [&]() { + BOOST_REQUIRE_EQUAL( app->executor().read_only_queue_size(), 0u); // pop()s before execute + BOOST_REQUIRE_EQUAL( app->executor().read_exclusive_queue_size(), 0u); + BOOST_REQUIRE_EQUAL( app->executor().read_write_queue_size(), 3u ); + } ); + + + std::optional work; + work.emplace(app->get_io_service()); + while( true ) { + app->get_io_service().poll(); + size_t s = app->executor().read_only_queue_size() + app->executor().read_exclusive_queue_size() + app->executor().read_write_queue_size(); + if (s == 17) + break; + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } + + app.start_exec(); + constexpr int num_expected = 13; // 16 - 3 read_write + + auto read_thread1 = start_read_thread(app); + auto read_thread2 = start_read_thread(app); + auto read_thread3 = start_read_thread(app); + read_thread1.join(); + read_thread2.join(); + read_thread3.join(); + + size_t num_sleeps = 0; + while (seq_num < num_expected) { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + if (++num_sleeps > 10000) + break; + }; + work.reset(); + app->quit(); + app.join(); + + // queues are emptied after exec + BOOST_REQUIRE_EQUAL( app->executor().read_only_queue_empty(), true); + BOOST_REQUIRE_EQUAL( app->executor().read_exclusive_queue_empty(), true); + BOOST_REQUIRE_EQUAL( app->executor().read_write_queue_empty(), true); + + // exactly number of posts processed + BOOST_REQUIRE_EQUAL( std::count_if(rslts.cbegin(), rslts.cend(), [](const auto& v){return v > 0; }), num_expected ); + + // all low must be processed the in order of posting + BOOST_CHECK_LT( rslts[4], rslts[15] ); + + // all medium must be processed the in order of posting + BOOST_CHECK_LT( rslts[0], rslts[1] ); + BOOST_CHECK_LT( rslts[1], rslts[11] ); + BOOST_CHECK_LT( rslts[11], rslts[14] ); + + // all functions posted after high before highest must be processed after high + BOOST_CHECK_LT( rslts[2], rslts[3] ); + BOOST_CHECK_LT( rslts[2], rslts[4] ); + BOOST_CHECK_LT( rslts[2], rslts[9] ); + + // all functions posted after highest must be processed after it + BOOST_CHECK_LT( rslts[6], rslts[8] ); + BOOST_CHECK_LT( rslts[6], rslts[9] ); + BOOST_CHECK_LT( rslts[6], rslts[11] ); + BOOST_CHECK_LT( rslts[6], rslts[12] ); + BOOST_CHECK_LT( rslts[6], rslts[14] ); +} + +// verify tasks from both queues (read_only, read_exclusive) are processed in read window +BOOST_AUTO_TEST_CASE( execute_many_from_read_only_and_read_exclusive_queues ) { + scoped_app_thread app; + + // set to run functions from read_only & read_exclusive queues only + app->executor().init_read_threads(3); + app->executor().set_to_read_window([](){return false;}); + + // post functions + constexpr int num_expected = 600; + std::vector> rslts(num_expected); + std::atomic seq_num = 0; + for (size_t i = 0; i < 200; i+=5) { + app->executor().post( priority::high, exec_queue::read_exclusive, [&,i]() { rslts.at(i) = std::this_thread::get_id(); ++seq_num; std::this_thread::sleep_for(std::chrono::microseconds(10)); } ); + app->executor().post( priority::low, exec_queue::read_only, [&,i]() { rslts.at(i+1) = std::this_thread::get_id(); ++seq_num; } ); + app->executor().post( priority::low, exec_queue::read_exclusive, [&,i]() { rslts.at(i+2) = std::this_thread::get_id(); ++seq_num; } ); + app->executor().post( priority::high, exec_queue::read_only, [&,i]() { rslts.at(i+3) = std::this_thread::get_id(); ++seq_num; } ); + app->executor().post( priority::medium, exec_queue::read_only, [&,i]() { rslts.at(i+4) = std::this_thread::get_id(); ++seq_num; std::this_thread::sleep_for(std::chrono::microseconds(i+1)); } ); + } + auto read_thread1 = start_read_thread(app); + std::thread::id read_thread1_id = read_thread1.get_id(); + for (size_t i = 200; i < 400; i+=5) { + app->executor().post( priority::high, exec_queue::read_exclusive, [&,i]() { rslts.at(i) = std::this_thread::get_id(); ++seq_num; std::this_thread::sleep_for(std::chrono::microseconds(i)); } ); + app->executor().post( priority::low, exec_queue::read_only, [&,i]() { rslts.at(i+1) = std::this_thread::get_id(); ++seq_num; std::this_thread::sleep_for(std::chrono::microseconds(i)); } ); + app->executor().post( priority::low, exec_queue::read_exclusive, [&,i]() { rslts.at(i+2) = std::this_thread::get_id(); ++seq_num; std::this_thread::sleep_for(std::chrono::microseconds(i)); } ); + app->executor().post( priority::high, exec_queue::read_only, [&,i]() { rslts.at(i+3) = std::this_thread::get_id(); ++seq_num; std::this_thread::sleep_for(std::chrono::microseconds(i)); } ); + app->executor().post( priority::medium, exec_queue::read_exclusive, [&,i]() { rslts.at(i+4) = std::this_thread::get_id(); ++seq_num; std::this_thread::sleep_for(std::chrono::microseconds(i)); } ); + } + auto read_thread2 = start_read_thread(app); + std::thread::id read_thread2_id = read_thread2.get_id(); + for (size_t i = 400; i < num_expected; i+=5) { + app->executor().post( priority::high, exec_queue::read_only, [&,i]() { rslts.at(i) = std::this_thread::get_id(); ++seq_num; std::this_thread::sleep_for(std::chrono::microseconds(10)); } ); + app->executor().post( priority::low, exec_queue::read_only, [&,i]() { rslts.at(i+1) = std::this_thread::get_id(); ++seq_num; std::this_thread::sleep_for(std::chrono::microseconds(10)); } ); + app->executor().post( priority::low, exec_queue::read_only, [&,i]() { rslts.at(i+2) = std::this_thread::get_id(); ++seq_num; } ); + app->executor().post( priority::high, exec_queue::read_only, [&,i]() { rslts.at(i+3) = std::this_thread::get_id(); ++seq_num; } ); + app->executor().post( priority::medium, exec_queue::read_exclusive, [&,i]() { rslts.at(i+4) = std::this_thread::get_id(); ++seq_num; } ); + } + auto read_thread3 = start_read_thread(app); + std::thread::id read_thread3_id = read_thread3.get_id(); + + // Use lowest at the end to make sure this executes the last + app->executor().post( priority::lowest, exec_queue::read_exclusive, [&]() { + BOOST_REQUIRE_EQUAL( app->executor().read_only_queue_size(), 0u); // pop()s before execute + BOOST_REQUIRE_EQUAL( app->executor().read_exclusive_queue_size(), 0u); + BOOST_REQUIRE_EQUAL( app->executor().read_write_queue_size(), 0u ); + } ); + + read_thread1.join(); + read_thread2.join(); + read_thread3.join(); + + size_t num_sleeps = 0; + while (seq_num < num_expected) { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + if (++num_sleeps > 10000) + break; + }; + + app->quit(); + app.join(); + + // exactly number of posts processed + BOOST_REQUIRE_EQUAL( std::count_if(rslts.cbegin(), rslts.cend(), [](const auto& v){ return v != std::thread::id(); }), num_expected ); + + const auto run_on_1 = std::count_if(rslts.cbegin(), rslts.cend(), [&](const auto& v){ return v == read_thread1_id; }); + const auto run_on_2 = std::count_if(rslts.cbegin(), rslts.cend(), [&](const auto& v){ return v == read_thread2_id; }); + const auto run_on_3 = std::count_if(rslts.cbegin(), rslts.cend(), [&](const auto& v){ return v == read_thread3_id; }); + const auto run_on_main = std::count_if(rslts.cbegin(), rslts.cend(), [&](const auto& v){ return v == app->executor().get_main_thread_id(); }); + + BOOST_REQUIRE_EQUAL(run_on_1+run_on_2+run_on_3+run_on_main, num_expected); + BOOST_CHECK(run_on_1 > 0); + BOOST_CHECK(run_on_2 > 0); + BOOST_CHECK(run_on_3 > 0); + BOOST_CHECK(run_on_main > 0); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/libraries/eos-vm b/libraries/eos-vm index b06ac3d4c1..33e91ebf90 160000 --- a/libraries/eos-vm +++ b/libraries/eos-vm @@ -1 +1 @@ -Subproject commit b06ac3d4c171cfd0a0f8fd74752e4eab35f60cb0 +Subproject commit 33e91ebf90088152477b7e7795cf5c871e70cb5c diff --git a/libraries/libfc/CMakeLists.txt b/libraries/libfc/CMakeLists.txt index 13e13eb477..f1914b6ec9 100644 --- a/libraries/libfc/CMakeLists.txt +++ b/libraries/libfc/CMakeLists.txt @@ -1,12 +1,12 @@ add_subdirectory( secp256k1 ) add_subdirectory( libraries/bn256/src ) add_subdirectory( libraries/bls12-381 ) +add_subdirectory( libraries/boringssl ) set(CMAKE_THREAD_PREFER_PTHREAD TRUE) set(THREADS_PREFER_PTHREAD_FLAG TRUE) find_package(Threads) -find_package(OpenSSL REQUIRED) set( fc_sources src/uint128.cpp @@ -70,19 +70,6 @@ file( GLOB_RECURSE fc_headers ${CMAKE_CURRENT_SOURCE_DIR} *.hpp *.h ) add_library(fc ${fc_sources} ${fc_headers}) -# Yuck: newer CMake files from boost iostreams will effectively target_link_libraries(Boost::iostreams z;bz2;lzma;zstd) -# without first "finding" those libraries. This resolves to simple -lz -lbz2 etc: it'll look for those libraries in the linker's -# library search path. This is most problematic on macOS where something like libzstd isn't in the standard search path. Historically -# fc would just "-L/usr/local/lib" as a heavy handed way to make sure something like -lzstd can be found in brew's library path. But -# that isn't sufficient for something like ARM homebrew. Let's just "null" these libraries out since we're already linking to zlib -# explicitly anyways via a proper find_package(ZLIB) below. -if(APPLE) - add_library(z INTERFACE) - add_library(bz2 INTERFACE) - add_library(lzma INTERFACE) - add_library(zstd INTERFACE) -endif() - find_path(GMP_INCLUDE_DIR NAMES gmp.h) find_library(GMP_LIBRARY gmp) if(NOT GMP_LIBRARY MATCHES ${CMAKE_SHARED_LIBRARY_SUFFIX}) @@ -118,11 +105,7 @@ if(APPLE) endif() target_link_libraries( fc PUBLIC Boost::date_time Boost::chrono Boost::iostreams Boost::interprocess Boost::multi_index Boost::dll Boost::multiprecision Boost::beast Boost::asio Boost::thread Boost::unit_test_framework Threads::Threads - OpenSSL::Crypto ZLIB::ZLIB ${PLATFORM_SPECIFIC_LIBS} ${CMAKE_DL_LIBS} secp256k1 bls12-381 ${security_framework} ${corefoundation_framework}) - -# Critically, this ensures that OpenSSL 1.1 & 3.0 both have a variant of BN_zero() with void return value. But it also allows access -# to some obsoleted AES functions in 3.0 too, since 3.0's API_COMPAT is effectively 3.0 by default -target_compile_definitions(fc PUBLIC "OPENSSL_API_COMPAT=0x10100000L" "OPENSSL_NO_DEPRECATED") + boringssl ZLIB::ZLIB ${PLATFORM_SPECIFIC_LIBS} ${CMAKE_DL_LIBS} secp256k1 bls12-381 ${security_framework} ${corefoundation_framework}) add_subdirectory( test ) diff --git a/libraries/libfc/libraries/boringssl/CMakeLists.txt b/libraries/libfc/libraries/boringssl/CMakeLists.txt new file mode 100644 index 0000000000..b67bc6c1f6 --- /dev/null +++ b/libraries/libfc/libraries/boringssl/CMakeLists.txt @@ -0,0 +1,28 @@ +add_subdirectory(boringssl EXCLUDE_FROM_ALL) +target_compile_options(fipsmodule PRIVATE -Wno-error) +target_compile_options(crypto PRIVATE -Wno-error) +target_compile_options(decrepit PRIVATE -Wno-error) + +#paranoia for when a dependent library depends on openssl (such as libcurl) +set_target_properties(fipsmodule PROPERTIES C_VISIBILITY_PRESET hidden) +set_target_properties(crypto PROPERTIES C_VISIBILITY_PRESET hidden) +set_target_properties(decrepit PROPERTIES C_VISIBILITY_PRESET hidden) + +add_library(boringssl INTERFACE) +target_link_libraries(boringssl INTERFACE crypto decrepit) +target_include_directories(boringssl INTERFACE boringssl/src/include) + +# avoid conflict with system lib +set_target_properties(crypto PROPERTIES PREFIX libbs) + +install( TARGETS crypto + LIBRARY DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR} COMPONENT dev EXCLUDE_FROM_ALL + ARCHIVE DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR} COMPONENT dev EXCLUDE_FROM_ALL +) + +install( TARGETS decrepit + LIBRARY DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR} COMPONENT dev EXCLUDE_FROM_ALL + ARCHIVE DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR} COMPONENT dev EXCLUDE_FROM_ALL +) + +install( DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/boringssl/src/include/" DESTINATION "${CMAKE_INSTALL_FULL_INCLUDEDIR}/leapboringssl" COMPONENT dev EXCLUDE_FROM_ALL ) diff --git a/libraries/libfc/libraries/boringssl/boringssl b/libraries/libfc/libraries/boringssl/boringssl new file mode 160000 index 0000000000..83b08306ba --- /dev/null +++ b/libraries/libfc/libraries/boringssl/boringssl @@ -0,0 +1 @@ +Subproject commit 83b08306ba471bdd18d97a54c2a87db5989b55d6 diff --git a/libraries/libfc/secp256k1/CMakeLists.txt b/libraries/libfc/secp256k1/CMakeLists.txt index 1469032e03..0218592a5a 100644 --- a/libraries/libfc/secp256k1/CMakeLists.txt +++ b/libraries/libfc/secp256k1/CMakeLists.txt @@ -2,13 +2,15 @@ # for compiling the library (where PRIVATE would have been fine), but also for the unit tests. add_library(secp256k1-internal INTERFACE) -target_include_directories(secp256k1-internal - INTERFACE - secp256k1/src - config -) - -target_compile_definitions(secp256k1-internal INTERFACE HAVE_CONFIG_H) +target_include_directories(secp256k1-internal INTERFACE secp256k1/src) + +target_compile_definitions(secp256k1-internal INTERFACE ENABLE_MODULE_RECOVERY=1 + ECMULT_GEN_PREC_BITS=4 + ECMULT_WINDOW_SIZE=15 + SECP256K1_STATIC=1) +if(CMAKE_SYSTEM_PROCESSOR STREQUAL x86_64 OR CMAKE_SYSTEM_PROCESSOR STREQUAL amd64) + target_compile_definitions(secp256k1-internal INTERFACE USE_ASM_X86_64=1) +endif() # secp256k1 produces over 190 "unused-function" warnings like # warning: ‘secp256k1_fe_normalize_weak’ declared ‘static’ but never defined [-Wunused-f unction] diff --git a/libraries/libfc/secp256k1/config/libsecp256k1-config.h b/libraries/libfc/secp256k1/config/libsecp256k1-config.h deleted file mode 100644 index b4e4550177..0000000000 --- a/libraries/libfc/secp256k1/config/libsecp256k1-config.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#define ENABLE_MODULE_RECOVERY 1 - -#define ECMULT_GEN_PREC_BITS 4 -#define ECMULT_WINDOW_SIZE 15 - -//enable asm -#ifdef __x86_64__ - #define USE_ASM_X86_64 1 -#endif diff --git a/libraries/libfc/secp256k1/secp256k1 b/libraries/libfc/secp256k1/secp256k1 index 485f608fa9..199d27cea3 160000 --- a/libraries/libfc/secp256k1/secp256k1 +++ b/libraries/libfc/secp256k1/secp256k1 @@ -1 +1 @@ -Subproject commit 485f608fa9e28f132f127df97136617645effe81 +Subproject commit 199d27cea32203b224b208627533c2e813cd3b21 diff --git a/libraries/libfc/src/crypto/_elliptic_impl_priv.hpp b/libraries/libfc/src/crypto/_elliptic_impl_priv.hpp index 45d0ef8791..f9f44440a3 100644 --- a/libraries/libfc/src/crypto/_elliptic_impl_priv.hpp +++ b/libraries/libfc/src/crypto/_elliptic_impl_priv.hpp @@ -9,7 +9,6 @@ namespace fc { namespace ecc { namespace detail { const secp256k1_context* _get_context(); -void _init_lib(); class private_key_impl { diff --git a/libraries/libfc/src/crypto/_elliptic_impl_pub.hpp b/libraries/libfc/src/crypto/_elliptic_impl_pub.hpp index b982ba125d..4a9701ec7f 100644 --- a/libraries/libfc/src/crypto/_elliptic_impl_pub.hpp +++ b/libraries/libfc/src/crypto/_elliptic_impl_pub.hpp @@ -8,8 +8,6 @@ namespace fc { namespace ecc { namespace detail { -void _init_lib(); - class public_key_impl { public: diff --git a/libraries/libfc/src/crypto/elliptic_common.cpp b/libraries/libfc/src/crypto/elliptic_common.cpp index 4fa0925b93..7b46dfe004 100644 --- a/libraries/libfc/src/crypto/elliptic_common.cpp +++ b/libraries/libfc/src/crypto/elliptic_common.cpp @@ -75,8 +75,8 @@ namespace fc { namespace ecc { ssl_bignum order; FC_ASSERT( EC_GROUP_get_order( group, order, ctx ) ); private_key_secret bin; - FC_ASSERT( BN_num_bytes( order ) == static_cast(bin.data_size()) ); - FC_ASSERT( BN_bn2bin( order, (unsigned char*) bin.data() ) == static_cast(bin.data_size()) ); + FC_ASSERT( BN_num_bytes( order ) == bin.data_size() ); + FC_ASSERT( BN_bn2bin( order, (unsigned char*) bin.data() ) == bin.data_size() ); return bin; } @@ -94,8 +94,8 @@ namespace fc { namespace ecc { FC_ASSERT( EC_GROUP_get_order( group, order, ctx ) ); BN_rshift1( order, order ); private_key_secret bin; - FC_ASSERT( BN_num_bytes( order ) == static_cast(bin.data_size()) ); - FC_ASSERT( BN_bn2bin( order, (unsigned char*) bin.data() ) == static_cast(bin.data_size()) ); + FC_ASSERT( BN_num_bytes( order ) == bin.data_size() ); + FC_ASSERT( BN_bn2bin( order, (unsigned char*) bin.data() ) == bin.data_size() ); return bin; } @@ -196,21 +196,6 @@ namespace fc { namespace ecc { BN_bn2bin(bn, &((unsigned char*)&sec)[32-nbytes] ); return sec; } - - private_key private_key::generate() - { - EC_KEY* k = EC_KEY_new_by_curve_name( NID_secp256k1 ); - if( !k ) FC_THROW_EXCEPTION( exception, "Unable to generate EC key" ); - if( !EC_KEY_generate_key( k ) ) - { - FC_THROW_EXCEPTION( exception, "ecc key generation error" ); - - } - - return private_key( k ); - } - - } void to_variant( const ecc::private_key& var, variant& vo ) diff --git a/libraries/libfc/src/crypto/elliptic_impl_priv.cpp b/libraries/libfc/src/crypto/elliptic_impl_priv.cpp index 1134c0b4b0..cbbc64e31f 100644 --- a/libraries/libfc/src/crypto/elliptic_impl_priv.cpp +++ b/libraries/libfc/src/crypto/elliptic_impl_priv.cpp @@ -10,14 +10,10 @@ namespace fc { namespace ecc { namespace detail { - private_key_impl::private_key_impl() BOOST_NOEXCEPT - { - _init_lib(); - } + private_key_impl::private_key_impl() BOOST_NOEXCEPT {} private_key_impl::private_key_impl( const private_key_impl& cpy ) BOOST_NOEXCEPT { - _init_lib(); this->_key = cpy._key; } diff --git a/libraries/libfc/src/crypto/elliptic_secp256k1.cpp b/libraries/libfc/src/crypto/elliptic_secp256k1.cpp index 459a8d7c86..9ac404443e 100644 --- a/libraries/libfc/src/crypto/elliptic_secp256k1.cpp +++ b/libraries/libfc/src/crypto/elliptic_secp256k1.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -12,6 +13,8 @@ #include #include +#include + #if _WIN32 # include #elif defined(__FreeBSD__) @@ -25,29 +28,27 @@ namespace fc { namespace ecc { namespace detail { + struct context_creator { + context_creator() { + ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); + char seed[32]; + rand_bytes(seed, sizeof(seed)); + FC_ASSERT(secp256k1_context_randomize(ctx, (const unsigned char*)seed)); + } + secp256k1_context* ctx = nullptr; + }; const secp256k1_context* _get_context() { - static secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_SIGN); - return ctx; - } - - void _init_lib() { - static const secp256k1_context* ctx = _get_context(); - (void)ctx; + static context_creator cc; + return cc.ctx; } class public_key_impl { public: - public_key_impl() BOOST_NOEXCEPT - { - _init_lib(); - } + public_key_impl() BOOST_NOEXCEPT {} public_key_impl( const public_key_impl& cpy ) BOOST_NOEXCEPT - : _key( cpy._key ) - { - _init_lib(); - } + : _key( cpy._key ) {} public_key_data _key; }; @@ -79,6 +80,14 @@ namespace fc { namespace ecc { return fc::sha512::hash( serialized_result.begin() + 1, serialized_result.size() - 1 ); } + private_key private_key::generate() + { + private_key ret; + do { + rand_bytes(ret.my->_key.data(), ret.my->_key.data_size()); + } while(!secp256k1_ec_seckey_verify(detail::_get_context(), (const uint8_t*)ret.my->_key.data())); + return ret; + } public_key::public_key() {} diff --git a/libraries/libfc/src/crypto/k1_recover.cpp b/libraries/libfc/src/crypto/k1_recover.cpp index cc755da60e..67af0a5853 100644 --- a/libraries/libfc/src/crypto/k1_recover.cpp +++ b/libraries/libfc/src/crypto/k1_recover.cpp @@ -6,7 +6,7 @@ namespace fc { const secp256k1_context* k1_recover_context() { - static secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); + static secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); return ctx; } diff --git a/libraries/state_history/include/eosio/state_history/log.hpp b/libraries/state_history/include/eosio/state_history/log.hpp index 567294c2a2..0c574476e9 100644 --- a/libraries/state_history/include/eosio/state_history/log.hpp +++ b/libraries/state_history/include/eosio/state_history/log.hpp @@ -73,9 +73,10 @@ struct state_history_log_header { chain::block_id_type block_id = {}; uint64_t payload_size = 0; }; -static const int state_history_log_header_serial_size = sizeof(state_history_log_header::magic) + - sizeof(state_history_log_header::block_id) + - sizeof(state_history_log_header::payload_size); +static constexpr int state_history_log_header_serial_size = sizeof(state_history_log_header::magic) + + sizeof(state_history_log_header::block_id) + + sizeof(state_history_log_header::payload_size); +static_assert(sizeof(state_history_log_header) == state_history_log_header_serial_size); namespace state_history { struct prune_config { @@ -323,7 +324,7 @@ class state_history_log { catalog.open(log_dir, conf.retained_dir, conf.archive_dir, name); catalog.max_retained_files = conf.max_retained_files; if (_end_block == 0) { - _begin_block = _end_block = catalog.last_block_num() +1; + _index_begin_block = _begin_block = _end_block = catalog.last_block_num() +1; } } }, _config); @@ -539,6 +540,7 @@ class state_history_log { "wrote payload with incorrect size to ${name}.log", ("name", name)); fc::raw::pack(log, pos); + index.seek_end(0); fc::raw::pack(index, pos); if (_begin_block == _end_block) _index_begin_block = _begin_block = block_num; @@ -576,10 +578,14 @@ class state_history_log { if (block_num >= _begin_block && block_num < _end_block) { state_history_log_header header; get_entry(block_num, header); + EOS_ASSERT(chain::block_header::num_from_id(header.block_id) == block_num, chain::plugin_exception, + "header id does not match requested ${a} != ${b}", ("a", chain::block_header::num_from_id(header.block_id))("b", block_num)); return header.block_id; } return {}; } + EOS_ASSERT(chain::block_header::num_from_id(*result) == block_num, chain::plugin_exception, + "catalog id does not match requested ${a} != ${b}", ("a", chain::block_header::num_from_id(*result))("b", block_num)); return result; } @@ -894,47 +900,16 @@ class state_history_log { } void split_log() { - - std::filesystem::path log_file_path = log.get_file_path(); - std::filesystem::path index_file_path = index.get_file_path(); - - fc::datastream new_log_file; - fc::datastream new_index_file; - - std::filesystem::path tmp_log_file_path = log_file_path; - tmp_log_file_path.replace_extension("log.tmp"); - std::filesystem::path tmp_index_file_path = index_file_path; - tmp_index_file_path.replace_extension("index.tmp"); - - new_log_file.set_file_path(tmp_log_file_path); - new_index_file.set_file_path(tmp_index_file_path); - - try { - new_log_file.open(fc::cfile::truncate_rw_mode); - new_index_file.open(fc::cfile::truncate_rw_mode); - - } catch (...) { - wlog("Unable to open new state history log or index file for writing during log spliting, " - "continue writing to existing block log file\n"); - return; - } - index.close(); log.close(); catalog.add(_begin_block, _end_block - 1, log.get_file_path().parent_path(), name); - _begin_block = _end_block; + _index_begin_block = _begin_block = _end_block; - using std::swap; - swap(new_log_file, log); - swap(new_index_file, index); - - std::filesystem::rename(tmp_log_file_path, log_file_path); - std::filesystem::rename(tmp_index_file_path, index_file_path); - - log.set_file_path(log_file_path); - index.set_file_path(index_file_path); + log.open(fc::cfile::truncate_rw_mode); + log.seek_end(0); + index.open(fc::cfile::truncate_rw_mode); } }; // state_history_log diff --git a/libraries/testing/include/eosio/testing/tester.hpp b/libraries/testing/include/eosio/testing/tester.hpp index 0037bc3127..5389dc076c 100644 --- a/libraries/testing/include/eosio/testing/tester.hpp +++ b/libraries/testing/include/eosio/testing/tester.hpp @@ -64,6 +64,7 @@ namespace eosio { namespace testing { preactivate_feature_only, preactivate_feature_and_new_bios, old_wasm_parser, + full_except_do_not_disable_deferred_trx, full }; @@ -156,7 +157,7 @@ namespace eosio { namespace testing { virtual ~base_tester() {}; - void init(const setup_policy policy = setup_policy::full, db_read_mode read_mode = db_read_mode::HEAD, std::optional genesis_max_inline_action_size = std::optional{}, std::optional config_max_nonprivileged_inline_action_size = std::optional{}); + void init(const setup_policy policy = setup_policy::full, db_read_mode read_mode = db_read_mode::HEAD, std::optional genesis_max_inline_action_size = std::optional{}); void init(controller::config config, const snapshot_reader_ptr& snapshot); void init(controller::config config, const genesis_state& genesis); void init(controller::config config); @@ -386,6 +387,7 @@ namespace eosio { namespace testing { void preactivate_protocol_features(const vector feature_digests); void preactivate_builtin_protocol_features(const std::vector& features); void preactivate_all_builtin_protocol_features(); + void preactivate_all_but_disable_deferred_trx(); static genesis_state default_genesis() { genesis_state genesis; @@ -395,7 +397,7 @@ namespace eosio { namespace testing { return genesis; } - static std::pair default_config(const fc::temp_directory& tempdir, std::optional genesis_max_inline_action_size = std::optional{}, std::optional config_max_nonprivileged_inline_action_size = std::optional{}) { + static std::pair default_config(const fc::temp_directory& tempdir, std::optional genesis_max_inline_action_size = std::optional{}) { controller::config cfg; cfg.blocks_dir = tempdir.path() / config::default_blocks_dir_name; cfg.state_dir = tempdir.path() / config::default_state_dir_name; @@ -419,9 +421,6 @@ namespace eosio { namespace testing { if (genesis_max_inline_action_size) { gen.initial_configuration.max_inline_action_size = *genesis_max_inline_action_size; } - if (config_max_nonprivileged_inline_action_size) { - cfg.max_nonprivileged_inline_action_size = *config_max_nonprivileged_inline_action_size; - } return {cfg, gen}; } @@ -448,12 +447,15 @@ namespace eosio { namespace testing { public: vector protocol_features_to_be_activated_wo_preactivation; + + private: + std::vector get_all_builtin_protocol_features(); }; class tester : public base_tester { public: - tester(setup_policy policy = setup_policy::full, db_read_mode read_mode = db_read_mode::HEAD, std::optional genesis_max_inline_action_size = std::optional{}, std::optional config_max_nonprivileged_inline_action_size = std::optional{}) { - init(policy, read_mode, genesis_max_inline_action_size, config_max_nonprivileged_inline_action_size); + tester(setup_policy policy = setup_policy::full, db_read_mode read_mode = db_read_mode::HEAD, std::optional genesis_max_inline_action_size = std::optional{}) { + init(policy, read_mode, genesis_max_inline_action_size); } tester(controller::config config, const genesis_state& genesis) { @@ -515,6 +517,12 @@ namespace eosio { namespace testing { bool validate() { return true; } }; + class tester_no_disable_deferred_trx : public tester { + public: + tester_no_disable_deferred_trx(): tester(setup_policy::full_except_do_not_disable_deferred_trx) { + } + }; + class validating_tester : public base_tester { public: virtual ~validating_tester() { @@ -660,6 +668,12 @@ namespace eosio { namespace testing { bool skip_validate = false; }; + class validating_tester_no_disable_deferred_trx : public validating_tester { + public: + validating_tester_no_disable_deferred_trx(): validating_tester({}, nullptr, setup_policy::full_except_do_not_disable_deferred_trx) { + } + }; + /** * Utility predicate to check whether an fc::exception message is equivalent to a given string */ diff --git a/libraries/testing/tester.cpp b/libraries/testing/tester.cpp index 6bcc9d1b8d..8a9b7a0ad6 100644 --- a/libraries/testing/tester.cpp +++ b/libraries/testing/tester.cpp @@ -179,8 +179,8 @@ namespace eosio { namespace testing { return control->head_block_id() == other.control->head_block_id(); } - void base_tester::init(const setup_policy policy, db_read_mode read_mode, std::optional genesis_max_inline_action_size, std::optional config_max_nonprivileged_inline_action_size) { - auto def_conf = default_config(tempdir, genesis_max_inline_action_size, config_max_nonprivileged_inline_action_size); + void base_tester::init(const setup_policy policy, db_read_mode read_mode, std::optional genesis_max_inline_action_size) { + auto def_conf = default_config(tempdir, genesis_max_inline_action_size); def_conf.first.read_mode = read_mode; cfg = def_conf.first; @@ -265,11 +265,16 @@ namespace eosio { namespace testing { set_bios_contract(); break; } - case setup_policy::full: { + case setup_policy::full: + case setup_policy::full_except_do_not_disable_deferred_trx: { schedule_preactivate_protocol_feature(); produce_block(); set_before_producer_authority_bios_contract(); - preactivate_all_builtin_protocol_features(); + if( policy == setup_policy::full ) { + preactivate_all_builtin_protocol_features(); + } else { + preactivate_all_but_disable_deferred_trx(); + } produce_block(); set_bios_contract(); break; @@ -1184,20 +1189,7 @@ namespace eosio { namespace testing { } } - void base_tester::preactivate_builtin_protocol_features(const std::vector& builtin_features) { - const auto& pfs = control->get_protocol_feature_manager().get_protocol_feature_set(); - - // This behavior is disabled by configurable_wasm_limits - std::vector features; - for(builtin_protocol_feature_t feature : builtin_features ) { - if( auto digest = pfs.get_builtin_digest( feature ) ) { - features.push_back( *digest ); - } - } - preactivate_protocol_features(features); - } - - void base_tester::preactivate_all_builtin_protocol_features() { + void base_tester::preactivate_builtin_protocol_features(const std::vector& builtins) { const auto& pfm = control->get_protocol_feature_manager(); const auto& pfs = pfm.get_protocol_feature_set(); const auto current_block_num = control->head_block_num() + (control->is_building_block() ? 1 : 0); @@ -1225,12 +1217,7 @@ namespace eosio { namespace testing { preactivations.emplace_back( feature_digest ); }; - std::vector ordered_builtins; - for( const auto& f : builtin_protocol_feature_codenames ) { - ordered_builtins.push_back( f.first ); - } - std::sort( ordered_builtins.begin(), ordered_builtins.end() ); - for( const auto& f : ordered_builtins ) { + for( const auto& f : builtins ) { auto digest = pfs.get_builtin_digest( f); if( !digest ) continue; add_digests( *digest ); @@ -1239,6 +1226,42 @@ namespace eosio { namespace testing { preactivate_protocol_features( preactivations ); } + std::vector base_tester::get_all_builtin_protocol_features() { + std::vector builtins; + for( const auto& f : builtin_protocol_feature_codenames ) { + builtins.push_back( f.first ); + } + + // Sorting is here to ensure a consistent order across platforms given that it is + // pulling the items from an std::unordered_map. This order is important because + // it impacts the block IDs generated and written out to logs for some tests such + // as the deep-mind tests. + std::sort( builtins.begin(), builtins.end() ); + + return builtins; + } + + void base_tester::preactivate_all_builtin_protocol_features() { + preactivate_builtin_protocol_features( get_all_builtin_protocol_features() ); + } + + void base_tester::preactivate_all_but_disable_deferred_trx() { + std::vector builtins; + for( const auto& f : get_all_builtin_protocol_features() ) { + // Before deferred trxs feature is fully disabled, existing tests involving + // deferred trxs need to be exercised to make sure existing behaviors are + // maintained. Excluding DISABLE_DEFERRED_TRXS_STAGE_1 and DISABLE_DEFERRED_TRXS_STAGE_2 + // from full protocol feature list such that existing tests can run. + if( f == builtin_protocol_feature_t::disable_deferred_trxs_stage_1 || f == builtin_protocol_feature_t::disable_deferred_trxs_stage_2 ) { + continue; + } + + builtins.push_back( f ); + } + + preactivate_builtin_protocol_features( builtins ); + } + tester::tester(const std::function& control_setup, setup_policy policy, db_read_mode read_mode) { auto def_conf = default_config(tempdir); def_conf.first.read_mode = read_mode; diff --git a/libraries/wasm-jit/Include/IR/Operators.h b/libraries/wasm-jit/Include/IR/Operators.h index 6a82e5d7ae..397b6fc28a 100644 --- a/libraries/wasm-jit/Include/IR/Operators.h +++ b/libraries/wasm-jit/Include/IR/Operators.h @@ -297,6 +297,7 @@ namespace IR }); // Specialize for the empty immediate structs so they don't take an extra byte of space. + PACKED_STRUCT( template<> struct OpcodeAndImm { @@ -305,7 +306,8 @@ namespace IR Opcode opcode; NoImm imm; }; - }; + }); + PACKED_STRUCT( template<> struct OpcodeAndImm { @@ -314,7 +316,7 @@ namespace IR Opcode opcode; MemoryImm imm; }; - }; + }); // Decodes an operator from an input stream and dispatches by opcode. struct OperatorDecoderStream @@ -328,7 +330,8 @@ namespace IR typename Visitor::Result decodeOp(Visitor& visitor) { WAVM_ASSERT_THROW(nextByte + sizeof(Opcode) <= end); - Opcode opcode = *(Opcode*)nextByte; + Opcode opcode; + memcpy(&opcode, nextByte, sizeof(opcode)); switch(opcode) { #define VISIT_OPCODE(opcode,name,nameString,Imm,...) \ diff --git a/libraries/wasm-jit/Include/Inline/Serialization.h b/libraries/wasm-jit/Include/Inline/Serialization.h index 7b0933339c..87eec16d72 100644 --- a/libraries/wasm-jit/Include/Inline/Serialization.h +++ b/libraries/wasm-jit/Include/Inline/Serialization.h @@ -35,7 +35,7 @@ namespace Serialization // Advances the stream cursor by numBytes, and returns a pointer to the previous stream cursor. inline U8* advance(Uptr numBytes) { - if(next + numBytes > end) { extendBuffer(numBytes); } + if(next == nullptr || next + numBytes > end) { extendBuffer(numBytes); } WAVM_ASSERT_THROW(next + numBytes <= end); U8* data = next; diff --git a/package.cmake b/package.cmake index dd1c1b8e57..c4847f6aef 100644 --- a/package.cmake +++ b/package.cmake @@ -1,4 +1,4 @@ -set(CPACK_GENERATOR "TGZ") +set(CPACK_GENERATOR "TZST") find_program(DPKG_FOUND "dpkg") find_program(RPMBUILD_FOUND "rpmbuild") if(DPKG_FOUND) @@ -65,7 +65,7 @@ set(CPACK_DEBIAN_BASE_FILE_NAME "${CPACK_DEBIAN_FILE_NAME}.deb") string(REGEX REPLACE "^(${CMAKE_PROJECT_NAME})" "\\1-dev" CPACK_DEBIAN_DEV_FILE_NAME "${CPACK_DEBIAN_BASE_FILE_NAME}") #deb package tooling will be unable to detect deps for the dev package. llvm is tricky since we don't know what package could have been used; try to figure it out -set(CPACK_DEBIAN_DEV_PACKAGE_DEPENDS "libssl-dev, libgmp-dev, python3-distutils, python3-numpy, zlib1g-dev") +set(CPACK_DEBIAN_DEV_PACKAGE_DEPENDS "libgmp-dev, python3-distutils, python3-numpy, zlib1g-dev") find_program(DPKG_QUERY "dpkg-query") if(DPKG_QUERY AND OS_RELEASE MATCHES "\n?ID=\"?ubuntu" AND LLVM_CMAKE_DIR) execute_process(COMMAND "${DPKG_QUERY}" -S "${LLVM_CMAKE_DIR}" COMMAND cut -d: -f1 RESULT_VARIABLE LLVM_PKG_FIND_RESULT OUTPUT_VARIABLE LLVM_PKG_FIND_OUTPUT) diff --git a/plugins/chain_api_plugin/chain_api_plugin.cpp b/plugins/chain_api_plugin/chain_api_plugin.cpp index 0ecf89afb7..1fc626d9e8 100644 --- a/plugins/chain_api_plugin/chain_api_plugin.cpp +++ b/plugins/chain_api_plugin/chain_api_plugin.cpp @@ -150,7 +150,6 @@ void chain_api_plugin::plugin_startup() { CHAIN_RO_CALL(get_required_keys, 200, http_params_types::params_required), CHAIN_RO_CALL(get_transaction_id, 200, http_params_types::params_required), // transaction related APIs will be posted to read_write queue after keys are recovered, they are safe to run in parallel until they post to the read_write queue - CHAIN_RO_CALL_ASYNC(send_read_only_transaction, chain_apis::read_only::send_read_only_transaction_results, 200, http_params_types::params_required), CHAIN_RO_CALL_ASYNC(compute_transaction, chain_apis::read_only::compute_transaction_results, 200, http_params_types::params_required), CHAIN_RW_CALL_ASYNC(push_transaction, chain_apis::read_write::push_transaction_results, 202, http_params_types::params_required), CHAIN_RW_CALL_ASYNC(push_transactions, chain_apis::read_write::push_transactions_results, 202, http_params_types::params_required), @@ -170,6 +169,8 @@ void chain_api_plugin::plugin_startup() { } _http_plugin.add_async_api({ + // chain_plugin send_read_only_transaction will post to read_exclusive queue + CHAIN_RO_CALL_ASYNC(send_read_only_transaction, chain_apis::read_only::send_read_only_transaction_results, 200, http_params_types::params_required), CHAIN_RO_CALL_WITH_400(get_raw_block, 200, http_params_types::params_required), CHAIN_RO_CALL_WITH_400(get_block_header, 200, http_params_types::params_required) }); diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index 8a07e7af3e..52666f789c 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -349,8 +349,9 @@ void chain_plugin::set_program_options(options_description& cli, options_descrip "Subjectively limit the maximum length of variable components in a variable legnth signature to this size in bytes") ("trusted-producer", bpo::value>()->composing(), "Indicate a producer whose blocks headers signed by it will be fully validated, but transactions in those validated blocks will be trusted.") ("database-map-mode", bpo::value()->default_value(chainbase::pinnable_mapped_file::map_mode::mapped), - "Database map mode (\"mapped\", \"heap\", or \"locked\").\n" + "Database map mode (\"mapped\", \"mapped_private\", \"heap\", or \"locked\").\n" "In \"mapped\" mode database is memory mapped as a file.\n" + "In \"mapped_private\" mode database is memory mapped as a file using a private mapping (no disk writeback until program exit).\n" #ifndef _WIN32 "In \"heap\" mode database is preloaded in to swappable memory and will use huge pages if available.\n" "In \"locked\" mode database is preloaded, locked in to memory, and will use huge pages if available.\n" @@ -372,7 +373,6 @@ void chain_plugin::set_program_options(options_description& cli, options_descrip "'none' - EOS VM OC tier-up is completely disabled.\n") #endif ("enable-account-queries", bpo::value()->default_value(false), "enable queries to find accounts by various metadata.") - ("max-nonprivileged-inline-action-size", bpo::value()->default_value(config::default_max_nonprivileged_inline_action_size), "maximum allowed size (in bytes) of an inline action for a nonprivileged account") ("transaction-retry-max-storage-size-gb", bpo::value(), "Maximum size (in GiB) allowed to be allocated for the Transaction Retry feature. Setting above 0 enables this feature.") ("transaction-retry-interval-sec", bpo::value()->default_value(20), @@ -463,14 +463,6 @@ void clear_directory_contents( const std::filesystem::path& p ) { } } -void clear_chainbase_files( const std::filesystem::path& p ) { - if( !std::filesystem::is_directory( p ) ) - return; - - std::filesystem::remove( p / "shared_memory.bin" ); - std::filesystem::remove( p / "shared_memory.meta" ); -} - namespace { // This can be removed when versions of eosio that support reversible chainbase state file no longer supported. void upgrade_from_reversible_to_fork_db(chain_plugin_impl* my) { @@ -637,9 +629,6 @@ void chain_plugin_impl::plugin_initialize(const variables_map& options) { if( options.count( "chain-state-db-guard-size-mb" )) chain_config->state_guard_size = options.at( "chain-state-db-guard-size-mb" ).as() * 1024 * 1024; - if( options.count( "max-nonprivileged-inline-action-size" )) - chain_config->max_nonprivileged_inline_action_size = options.at( "max-nonprivileged-inline-action-size" ).as(); - if( options.count( "transaction-finality-status-max-storage-size-gb" )) { const uint64_t max_storage_size = options.at( "transaction-finality-status-max-storage-size-gb" ).as() * 1024 * 1024 * 1024; if (max_storage_size > 0) { @@ -765,7 +754,7 @@ void chain_plugin_impl::plugin_initialize(const variables_map& options) { ilog( "Replay requested: deleting state database" ); if( options.at( "truncate-at-block" ).as() > 0 ) wlog( "The --truncate-at-block option does not work for a regular replay of the blockchain." ); - clear_chainbase_files( chain_config->state_dir ); + clear_directory_contents( chain_config->state_dir ); } else if( options.at( "truncate-at-block" ).as() > 0 ) { wlog( "The --truncate-at-block option can only be used with --hard-replay-blockchain." ); } @@ -2220,6 +2209,7 @@ void read_write::push_transactions(const read_write::push_transactions_params& p } CATCH_AND_CALL(next); } +// called from read-exclusive thread for read-only template void api_base::send_transaction_gen(API &api, send_transaction_params_t params, next_function next) { try { @@ -2590,12 +2580,19 @@ void read_only::compute_transaction(compute_transaction_params params, next_func } void read_only::send_read_only_transaction(send_read_only_transaction_params params, next_function next) { + static bool read_only_enabled = app().executor().get_read_threads() > 0; + EOS_ASSERT( read_only_enabled, unsupported_feature, + "read-only transactions execution not enabled on API node. Set read-only-threads > 0" ); + send_transaction_params_t gen_params { .return_failure_trace = false, .retry_trx = false, .retry_trx_num_blocks = std::nullopt, .trx_type = transaction_metadata::trx_type::read_only, .transaction = std::move(params.transaction) }; - return send_transaction_gen(*this, std::move(gen_params), std::move(next)); + // run read-only trx exclusively on read-only threads + app().executor().post(priority::low, exec_queue::read_exclusive, [this, gen_params{std::move(gen_params)}, next{std::move(next)}]() mutable { + send_transaction_gen(*this, std::move(gen_params), std::move(next)); + }); } read_only::get_transaction_id_result read_only::get_transaction_id( const read_only::get_transaction_id_params& params, const fc::time_point& ) const { @@ -2654,7 +2651,9 @@ read_only::get_consensus_parameters(const get_consensus_parameters_params&, cons get_consensus_parameters_results results; results.chain_config = db.get_global_properties().configuration; - results.wasm_config = db.get_global_properties().wasm_configuration; + if (db.is_builtin_activated(builtin_protocol_feature_t::configurable_wasm_limits)) { + results.wasm_config = db.get_global_properties().wasm_configuration; + } return results; } diff --git a/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp b/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp index 7ab17137a7..44b9f282c1 100644 --- a/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp +++ b/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp @@ -829,8 +829,8 @@ class read_only : public api_base { using get_consensus_parameters_params = empty; struct get_consensus_parameters_results { - chain::chain_config chain_config; - chain::wasm_config wasm_config; + chain::chain_config chain_config; + std::optional wasm_config; }; get_consensus_parameters_results get_consensus_parameters(const get_consensus_parameters_params&, const fc::time_point& deadline) const; diff --git a/plugins/http_plugin/include/eosio/http_plugin/beast_http_session.hpp b/plugins/http_plugin/include/eosio/http_plugin/beast_http_session.hpp index 2ac3ebb5a4..4ad2d928f0 100644 --- a/plugins/http_plugin/include/eosio/http_plugin/beast_http_session.hpp +++ b/plugins/http_plugin/include/eosio/http_plugin/beast_http_session.hpp @@ -295,9 +295,10 @@ class beast_http_session : public detail::abstract_conn, void on_read_header(beast::error_code ec, std::size_t /* bytes_transferred */) { if(ec) { - if(ec == http::error::end_of_stream) // other side closed the connection + // See on_read comment below + if(ec == http::error::end_of_stream || ec == asio::error::connection_reset) return do_eof(); - + return fail(ec, "read_header", plugin_state_.get_logger(), "closing connection"); } @@ -502,7 +503,8 @@ class beast_http_session : public detail::abstract_conn, try { // Send a shutdown signal beast::error_code ec; - socket_.shutdown(Socket::shutdown_send, ec); + socket_.shutdown(Socket::shutdown_both, ec); + socket_.close(ec); // At this point the connection is closed gracefully } catch(...) { handle_exception(); diff --git a/plugins/http_plugin/include/eosio/http_plugin/common.hpp b/plugins/http_plugin/include/eosio/http_plugin/common.hpp index 5f12134086..100bee41f8 100644 --- a/plugins/http_plugin/include/eosio/http_plugin/common.hpp +++ b/plugins/http_plugin/include/eosio/http_plugin/common.hpp @@ -154,18 +154,18 @@ struct http_plugin_state { */ inline auto make_http_response_handler(http_plugin_state& plugin_state, detail::abstract_conn_ptr session_ptr, http_content_type content_type) { return [&plugin_state, - session_ptr{std::move(session_ptr)}, content_type](int code, std::optional response) { + session_ptr{std::move(session_ptr)}, content_type](int code, std::optional response) mutable { auto payload_size = detail::in_flight_sizeof(response); - if(auto error_str = session_ptr->verify_max_bytes_in_flight(payload_size); !error_str.empty()) { - session_ptr->send_busy_response(std::move(error_str)); - return; - } - plugin_state.bytes_in_flight += payload_size; // post back to an HTTP thread to allow the response handler to be called from any thread - boost::asio::post(plugin_state.thread_pool.get_executor(), - [&plugin_state, session_ptr, code, payload_size, response = std::move(response), content_type]() { + boost::asio::dispatch(plugin_state.thread_pool.get_executor(), + [&plugin_state, session_ptr{std::move(session_ptr)}, code, payload_size, response = std::move(response), content_type]() { + if(auto error_str = session_ptr->verify_max_bytes_in_flight(0); !error_str.empty()) { + session_ptr->send_busy_response(std::move(error_str)); + return; + } + try { plugin_state.bytes_in_flight -= payload_size; if (response.has_value()) { diff --git a/plugins/net_plugin/include/eosio/net_plugin/auto_bp_peering.hpp b/plugins/net_plugin/include/eosio/net_plugin/auto_bp_peering.hpp index b5122f80aa..d88c47729e 100644 --- a/plugins/net_plugin/include/eosio/net_plugin/auto_bp_peering.hpp +++ b/plugins/net_plugin/include/eosio/net_plugin/auto_bp_peering.hpp @@ -145,7 +145,7 @@ class bp_connection_manager { // Only called from connection strand std::size_t num_established_clients() const { uint32_t num_clients = 0; - self()->connections.for_each_connection([&num_clients](auto&& conn) { + self()->connections.for_each_connection([&num_clients](const std::shared_ptr& conn) { if (established_client_connection(conn)) { ++num_clients; } @@ -157,7 +157,7 @@ class bp_connection_manager { // Only called from connection strand // This should only be called after the first handshake message is received to check if an incoming connection // has exceeded the pre-configured max_client_count limit. - bool exceeding_connection_limit(Connection* new_connection) const { + bool exceeding_connection_limit(std::shared_ptr new_connection) const { return auto_bp_peering_enabled() && self()->connections.get_max_client_count() != 0 && established_client_connection(new_connection) && num_established_clients() > self()->connections.get_max_client_count(); } @@ -182,7 +182,7 @@ class bp_connection_manager { fc_dlog(self()->get_logger(), "pending_downstream_neighbors: ${pending_downstream_neighbors}", ("pending_downstream_neighbors", to_string(pending_downstream_neighbors))); - for (auto neighbor : pending_downstream_neighbors) { self()->connections.connect(config.bp_peer_addresses[neighbor], *self()->p2p_addresses.begin() ); } + for (auto neighbor : pending_downstream_neighbors) { self()->connections.resolve_and_connect(config.bp_peer_addresses[neighbor], self()->get_first_p2p_address() ); } pending_neighbors = std::move(pending_downstream_neighbors); finder.add_upstream_neighbors(pending_neighbors); diff --git a/plugins/net_plugin/include/eosio/net_plugin/net_plugin.hpp b/plugins/net_plugin/include/eosio/net_plugin/net_plugin.hpp index c18fb4e12c..a2a0cf4357 100644 --- a/plugins/net_plugin/include/eosio/net_plugin/net_plugin.hpp +++ b/plugins/net_plugin/include/eosio/net_plugin/net_plugin.hpp @@ -55,8 +55,12 @@ namespace eosio { std::chrono::nanoseconds last_bytes_received{0}; size_t bytes_sent{0}; std::chrono::nanoseconds last_bytes_sent{0}; + size_t block_sync_bytes_received{0}; + size_t block_sync_bytes_sent{0}; + bool block_sync_throttling{false}; std::chrono::nanoseconds connection_start_time{0}; - std::string log_p2p_address; + std::string p2p_address; + std::string unique_conn_node_id; }; explicit p2p_per_connection_metrics(size_t count) { peers.reserve(count); diff --git a/plugins/net_plugin/include/eosio/net_plugin/protocol.hpp b/plugins/net_plugin/include/eosio/net_plugin/protocol.hpp index 811885768a..aa8d31be82 100644 --- a/plugins/net_plugin/include/eosio/net_plugin/protocol.hpp +++ b/plugins/net_plugin/include/eosio/net_plugin/protocol.hpp @@ -17,9 +17,11 @@ namespace eosio { // Longest domain name is 253 characters according to wikipedia. // Addresses include ":port" where max port is 65535, which adds 6 chars. + // Addresses may also include ":bitrate" with suffix and separators, which adds 30 chars, + // for the maximum comma-separated value that fits in a size_t expressed in decimal plus a suffix. // We also add our own extentions of "[:trx|:blk] - xxxxxxx", which adds 14 chars, total= 273. // Allow for future extentions as well, hence 384. - constexpr size_t max_p2p_address_length = 253 + 6; + constexpr size_t max_p2p_address_length = 253 + 6 + 30; constexpr size_t max_handshake_str_length = 384; struct handshake_message { diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index b54ad066b0..ed27ad8ab1 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -24,11 +24,13 @@ #include #include #include +#include #include #include #include #include +#include // should be defined for c++17, but clang++16 still has not implemented it #ifdef __cpp_lib_hardware_interference_size @@ -68,6 +70,7 @@ namespace eosio { using boost::asio::ip::address_v4; using boost::asio::ip::host_name; using boost::multi_index_container; + using namespace boost::multi_index; using fc::time_point; using fc::time_point_sec; @@ -343,14 +346,39 @@ namespace eosio { constexpr uint32_t packed_transaction_which = fc::get_index(); // see protocol net_message class connections_manager { + public: + struct connection_detail { + std::string host; + connection_ptr c; + tcp::endpoint active_ip; + tcp::resolver::results_type ips; + }; + + using connection_details_index = multi_index_container< + connection_detail, + indexed_by< + ordered_non_unique< + tag, + key<&connection_detail::host> + >, + ordered_unique< + tag, + key<&connection_detail::c> + > + > + >; + enum class timer_type { check, stats }; + private: alignas(hardware_destructive_interference_size) mutable std::shared_mutex connections_mtx; - chain::flat_set connections; + connection_details_index connections; chain::flat_set supplied_peers; alignas(hardware_destructive_interference_size) fc::mutex connector_check_timer_mtx; unique_ptr connector_check_timer GUARDED_BY(connector_check_timer_mtx); + fc::mutex connection_stats_timer_mtx; + unique_ptr connection_stats_timer GUARDED_BY(connection_stats_timer_mtx); /// thread safe, only modified on startup std::chrono::milliseconds heartbeat_timeout{def_keepalive_interval*2}; @@ -361,10 +389,9 @@ namespace eosio { private: // must call with held mutex connection_ptr find_connection_i(const string& host) const; - void add_i(connection_ptr&& c); - void connect_i(const string& peer, const string& p2p_address); void connection_monitor(const std::weak_ptr& from_connection); + void connection_statistics_monitor(const std::weak_ptr& from_connection); public: size_t number_connections() const; @@ -384,18 +411,26 @@ namespace eosio { void connect_supplied_peers(const string& p2p_address); - void start_conn_timer(); - void start_conn_timer(boost::asio::steady_timer::duration du, std::weak_ptr from_connection); - void stop_conn_timer(); + void start_conn_timers(); + void start_conn_timer(boost::asio::steady_timer::duration du, + std::weak_ptr from_connection, + timer_type which); + void stop_conn_timers(); void add(connection_ptr c); string connect(const string& host, const string& p2p_address); + string resolve_and_connect(const string& host, const string& p2p_address); + void update_connection_endpoint(connection_ptr c, const tcp::endpoint& endpoint); + void connect(const connection_ptr& c); string disconnect(const string& host); void close_all(); std::optional status(const string& host) const; vector connection_statuses() const; + template + bool any_of_supplied_peers(Function&& f) const; + template void for_each_connection(Function&& f) const; @@ -407,7 +442,7 @@ namespace eosio { template bool any_of_block_connections(UnaryPredicate&& p) const; - }; + }; // connections_manager class net_plugin_impl : public std::enable_shared_from_this, public auto_bp_peering::bp_connection_manager { @@ -424,6 +459,7 @@ namespace eosio { */ vector p2p_addresses; vector p2p_server_addresses; + const string& get_first_p2p_address() const; vector allowed_peers; ///< peer keys allowed to connect std::map increment_dropped_trxs; private: + inline static const std::map prefix_multipliers{ + {"",1},{"K",pow(10,3)},{"M",pow(10,6)},{"G",pow(10, 9)},{"T",pow(10, 12)}, + {"Ki",pow(2,10)},{"Mi",pow(2,20)},{"Gi",pow(2,30)},{"Ti",pow(2,40)} + }; alignas(hardware_destructive_interference_size) mutable fc::mutex chain_info_mtx; // protects chain_info_t chain_info_t chain_info GUARDED_BY(chain_info_mtx); @@ -543,14 +583,18 @@ namespace eosio { constexpr static uint16_t to_protocol_version(uint16_t v); + std::tuple parse_listen_address(const std::string& peer) const; + size_t parse_connection_rate_limit(const string& limit_str) const; void plugin_initialize(const variables_map& options); void plugin_startup(); void plugin_shutdown(); bool in_sync() const; fc::logger& get_logger() { return logger; } - void create_session(tcp::socket&& socket, const string listen_address); - }; + void create_session(tcp::socket&& socket, const string listen_address, size_t limit); + + std::string empty{}; + }; //net_plugin_impl // peer_[x]log must be called from thread in connection strand #define peer_dlog( PEER, FORMAT, ... ) \ @@ -776,7 +820,8 @@ namespace eosio { /// assignment not allowed block_status_monitor& operator=( const block_status_monitor& ) = delete; block_status_monitor& operator=( block_status_monitor&& ) = delete; - }; + }; // block_status_monitor + class connection : public std::enable_shared_from_this { public: @@ -786,7 +831,7 @@ namespace eosio { /// @brief ctor /// @param socket created by boost::asio in fc::listener /// @param address identifier of listen socket which accepted this new connection - explicit connection( tcp::socket&& socket, const string& listen_address ); + explicit connection( tcp::socket&& socket, const string& listen_address, size_t block_sync_rate_limit ); ~connection() = default; connection( const connection& ) = delete; @@ -815,6 +860,9 @@ namespace eosio { std::chrono::nanoseconds get_last_bytes_received() const { return last_bytes_received.load(); } size_t get_bytes_sent() const { return bytes_sent.load(); } std::chrono::nanoseconds get_last_bytes_sent() const { return last_bytes_sent.load(); } + size_t get_block_sync_bytes_received() const { return block_sync_bytes_received.load(); } + size_t get_block_sync_bytes_sent() const { return block_sync_total_bytes_sent.load(); } + bool get_block_sync_throttling() const { return block_sync_throttling.load(); } boost::asio::ip::port_type get_remote_endpoint_port() const { return remote_endpoint_port.load(); } void set_heartbeat_timeout(std::chrono::milliseconds msec) { hb_timeout = msec; @@ -834,7 +882,6 @@ namespace eosio { std::atomic conn_state{connection_state::connecting}; - string listen_address; // address sent to peer in handshake const string peer_addr; enum connection_types : char { both, @@ -842,6 +889,8 @@ namespace eosio { blocks_only }; + size_t block_sync_rate_limit{0}; // bytes/second, default unlimited + std::atomic connection_type{both}; std::atomic peer_start_block_num{0}; std::atomic peer_head_block_num{0}; @@ -850,6 +899,11 @@ namespace eosio { std::atomic bytes_received{0}; std::atomic last_bytes_received{0ns}; std::atomic bytes_sent{0}; + std::atomic block_sync_bytes_received{0}; + std::atomic block_sync_total_bytes_sent{0}; + std::chrono::nanoseconds block_sync_send_start{0ns}; // start of enqueue blocks + size_t block_sync_frame_bytes_sent{0}; // bytes sent in this set of enqueue blocks + std::atomic block_sync_throttling{false}; std::atomic last_bytes_sent{0ns}; std::atomic remote_endpoint_port{0}; @@ -864,6 +918,7 @@ namespace eosio { fc::sha256 conn_node_id; string short_conn_node_id; + string listen_address; // address sent to peer in handshake string log_p2p_address; string log_remote_endpoint_ip; string log_remote_endpoint_port; @@ -907,7 +962,9 @@ namespace eosio { block_id_type fork_head GUARDED_BY(conn_mtx); uint32_t fork_head_num GUARDED_BY(conn_mtx) {0}; fc::time_point last_close GUARDED_BY(conn_mtx); - string remote_endpoint_ip GUARDED_BY(conn_mtx); + std::string p2p_address GUARDED_BY(conn_mtx); + std::string unique_conn_node_id GUARDED_BY(conn_mtx); + std::string remote_endpoint_ip GUARDED_BY(conn_mtx); boost::asio::ip::address_v6::bytes_type remote_endpoint_ip_array GUARDED_BY(conn_mtx); std::chrono::nanoseconds connection_start_time{0}; @@ -942,13 +999,13 @@ namespace eosio { bool process_next_block_message(uint32_t message_length); bool process_next_trx_message(uint32_t message_length); - void update_endpoints(); + void update_endpoints(const tcp::endpoint& endpoint = tcp::endpoint()); public: bool populate_handshake( handshake_message& hello ) const; - bool resolve_and_connect(); - void connect( const std::shared_ptr& resolver, const tcp::resolver::results_type& endpoints ); + bool reconnect(); + void connect( const tcp::resolver::results_type& endpoints ); void start_read_message(); /** \brief Process the next message from the pending message buffer @@ -977,10 +1034,11 @@ namespace eosio { void send_time(const time_message& msg); /** \brief Read system time and convert to a 64 bit integer. * - * There are five calls to this routine in the program. One + * There are six calls to this routine in the program. One * when a packet arrives from the network, one when a packet - * is placed on the send queue, one during start session, and - * one each when data is counted as received or sent. + * is placed on the send queue, one during start session, one + * when a sync block is queued and one each when data is + * counted as received or sent. * Calls the kernel time of day routine and converts to * a (at least) 64 bit integer. */ @@ -995,7 +1053,7 @@ namespace eosio { void stop_send(); void enqueue( const net_message &msg ); - void enqueue_block( const signed_block_ptr& sb, bool to_sync_queue = false); + size_t enqueue_block( const signed_block_ptr& sb, bool to_sync_queue = false); void enqueue_buffer( const std::shared_ptr>& send_buffer, go_away_reason close_after_send, bool to_sync_queue = false); @@ -1153,18 +1211,28 @@ namespace eosio { } + template + bool connections_manager::any_of_supplied_peers( Function&& f ) const { + std::shared_lock g( connections_mtx ); + return std::any_of(supplied_peers.begin(), supplied_peers.end(), std::forward(f)); + } + template void connections_manager::for_each_connection( Function&& f ) const { std::shared_lock g( connections_mtx ); - std::for_each(connections.begin(), connections.end(), std::forward(f)); + auto& index = connections.get(); + for( const connection_detail& cd : index ) { + f(cd.c); + } } template void connections_manager::for_each_block_connection( Function&& f ) const { std::shared_lock g( connections_mtx ); - for( auto& c : connections ) { - if (c->is_blocks_connection()) { - f(c); + auto& index = connections.get(); + for( const connection_detail& cd : index ) { + if (cd.c->is_blocks_connection()) { + f(cd.c); } } } @@ -1172,15 +1240,21 @@ namespace eosio { template bool connections_manager::any_of_connections(UnaryPredicate&& p) const { std::shared_lock g(connections_mtx); - return std::any_of(connections.cbegin(), connections.cend(), std::forward(p)); + auto& index = connections.get(); + for( const connection_detail& cd : index ) { + if (p(cd.c)) + return true; + } + return false; } template bool connections_manager::any_of_block_connections(UnaryPredicate&& p) const { std::shared_lock g( connections_mtx ); - for( auto& c : connections ) { - if( c->is_blocks_connection() ) { - if (p(c)) + auto& index = connections.get(); + for( const connection_detail& cd : index ) { + if( cd.c->is_blocks_connection() ) { + if (p(cd.c)) return true; } } @@ -1191,26 +1265,28 @@ namespace eosio { //--------------------------------------------------------------------------- connection::connection( const string& endpoint, const string& listen_address ) - : listen_address( listen_address ), - peer_addr( endpoint ), + : peer_addr( endpoint ), strand( my_impl->thread_pool.get_executor() ), socket( new tcp::socket( my_impl->thread_pool.get_executor() ) ), + listen_address( listen_address ), log_p2p_address( endpoint ), connection_id( ++my_impl->current_connection_id ), response_expected_timer( my_impl->thread_pool.get_executor() ), last_handshake_recv(), - last_handshake_sent() + last_handshake_sent(), + p2p_address( endpoint ) { my_impl->mark_bp_connection(this); update_endpoints(); fc_ilog( logger, "created connection ${c} to ${n}", ("c", connection_id)("n", endpoint) ); } - connection::connection(tcp::socket&& s, const string& listen_address) - : listen_address( listen_address ), - peer_addr(), + connection::connection(tcp::socket&& s, const string& listen_address, size_t block_sync_rate_limit) + : peer_addr(), + block_sync_rate_limit(block_sync_rate_limit), strand( my_impl->thread_pool.get_executor() ), socket( new tcp::socket( std::move(s) ) ), + listen_address( listen_address ), connection_id( ++my_impl->current_connection_id ), response_expected_timer( my_impl->thread_pool.get_executor() ), last_handshake_recv(), @@ -1220,11 +1296,10 @@ namespace eosio { fc_dlog( logger, "new connection object created for peer ${address}:${port} from listener ${addr}", ("address", log_remote_endpoint_ip)("port", log_remote_endpoint_port)("addr", listen_address) ); } - // called from connection strand - void connection::update_endpoints() { + void connection::update_endpoints(const tcp::endpoint& endpoint) { boost::system::error_code ec; boost::system::error_code ec2; - auto rep = socket->remote_endpoint(ec); + auto rep = endpoint == tcp::endpoint() ? socket->remote_endpoint(ec) : endpoint; auto lep = socket->local_endpoint(ec2); remote_endpoint_port = ec ? 0 : rep.port(); log_remote_endpoint_ip = ec ? unknown : rep.address().to_string(); @@ -1311,7 +1386,7 @@ namespace eosio { boost::system::error_code ec; socket->set_option( nodelay, ec ); if( ec ) { - peer_elog( this, "connection failed (set_option): ${e1}", ( "e1", ec.message() ) ); + peer_wlog( this, "connection failed (set_option): ${e1}", ( "e1", ec.message() ) ); close(); return false; } else { @@ -1402,9 +1477,14 @@ namespace eosio { latest_msg_time = std::chrono::system_clock::time_point::min(); latest_blk_time = std::chrono::system_clock::time_point::min(); set_state(connection_state::closed); + block_sync_send_start = 0ns; + block_sync_frame_bytes_sent = 0; + block_sync_throttling = false; if( reconnect && !shutdown ) { - my_impl->connections.start_conn_timer( std::chrono::milliseconds( 100 ), connection_wptr() ); + my_impl->connections.start_conn_timer( std::chrono::milliseconds( 100 ), + connection_wptr(), + connections_manager::timer_type::check ); } } @@ -1487,6 +1567,7 @@ namespace eosio { peer_ilog( this, "fetch block by id returned null, id ${id}", ("id", blkid) ); } } catch( const assert_exception& ex ) { + // possible corrupted block log peer_elog( this, "caught assert on fetch_block_by_id, ${ex}, id ${id}", ("ex", ex.to_string())("id", blkid) ); } catch( ... ) { peer_elog( this, "caught other exception fetching block id ${id}", ("id", blkid) ); @@ -1614,7 +1695,7 @@ namespace eosio { if( ec ) { if( ec.value() != boost::asio::error::eof ) { - peer_elog( c, "Error sending to peer: ${i}", ( "i", ec.message() ) ); + peer_wlog( c, "Error sending to peer: ${i}", ( "i", ec.message() ) ); } else { peer_wlog( c, "connection closure detected on write" ); } @@ -1670,11 +1751,7 @@ namespace eosio { } else { peer_dlog( this, "enqueue sync block ${num}", ("num", peer_requested->last + 1) ); } - uint32_t num = ++peer_requested->last; - if(num == peer_requested->end_block) { - peer_requested.reset(); - peer_dlog( this, "completing enqueue_sync_block ${num}", ("num", num) ); - } + uint32_t num = peer_requested->last + 1; controller& cc = my_impl->chain_plug->chain(); signed_block_ptr sb; @@ -1682,14 +1759,42 @@ namespace eosio { sb = cc.fetch_block_by_number( num ); // thread-safe } FC_LOG_AND_DROP(); if( sb ) { - enqueue_block( sb, true ); + // Skip transmitting block this loop if threshold exceeded + if (block_sync_send_start == 0ns) { // start of enqueue blocks + block_sync_send_start = get_time(); + block_sync_frame_bytes_sent = 0; + } + if( block_sync_rate_limit > 0 && block_sync_frame_bytes_sent > 0 && peer_syncing_from_us ) { + auto now = get_time(); + auto elapsed_us = std::chrono::duration_cast(now - block_sync_send_start); + double current_rate_sec = (double(block_sync_frame_bytes_sent) / elapsed_us.count()) * 100000; // convert from bytes/us => bytes/sec + peer_dlog(this, "start enqueue block time ${st}, now ${t}, elapsed ${e}, rate ${r}, limit ${l}", + ("st", block_sync_send_start.count())("t", now.count())("e", elapsed_us.count())("r", current_rate_sec)("l", block_sync_rate_limit)); + if( current_rate_sec >= block_sync_rate_limit ) { + block_sync_throttling = true; + peer_dlog( this, "throttling block sync to peer ${host}:${port}", ("host", log_remote_endpoint_ip)("port", log_remote_endpoint_port)); + return false; + } + } + block_sync_throttling = false; + auto sent = enqueue_block( sb, true ); + block_sync_total_bytes_sent += sent; + block_sync_frame_bytes_sent += sent; + ++peer_requested->last; + if(num == peer_requested->end_block) { + peer_requested.reset(); + block_sync_send_start = 0ns; + block_sync_frame_bytes_sent = 0; + peer_dlog( this, "completing enqueue_sync_block ${num}", ("num", num) ); + } } else { peer_ilog( this, "enqueue sync, unable to fetch block ${num}, sending benign_other go away", ("num", num) ); peer_requested.reset(); // unable to provide requested blocks + block_sync_send_start = 0ns; + block_sync_frame_bytes_sent = 0; no_retry = benign_other; enqueue( go_away_message( benign_other ) ); } - return true; } @@ -1800,7 +1905,7 @@ namespace eosio { } // called from connection strand - void connection::enqueue_block( const signed_block_ptr& b, bool to_sync_queue) { + size_t connection::enqueue_block( const signed_block_ptr& b, bool to_sync_queue) { peer_dlog( this, "enqueue block ${num}", ("num", b->block_num()) ); verify_strand_in_this_thread( strand, __func__, __LINE__ ); @@ -1808,6 +1913,7 @@ namespace eosio { const auto& sb = buff_factory.get_send_buffer( b ); latest_blk_time = std::chrono::system_clock::now(); enqueue_buffer( sb, no_reason, to_sync_queue); + return sb->size(); } // called from connection strand @@ -2055,7 +2161,7 @@ namespace eosio { // verify there is an available source if( !new_sync_source ) { - fc_elog( logger, "Unable to continue syncing at this time"); + fc_wlog( logger, "Unable to continue syncing at this time"); sync_source.reset(); sync_known_lib_num = chain_info.lib_num; sync_last_requested_num = 0; @@ -2088,7 +2194,7 @@ namespace eosio { // static, thread safe void sync_manager::send_handshakes() { - my_impl->connections.for_each_connection( []( auto& ci ) { + my_impl->connections.for_each_connection( []( const connection_ptr& ci ) { if( ci->current() ) { ci->send_handshake(); } @@ -2302,7 +2408,7 @@ namespace eosio { "sync_recv_notice only called on catch_up" ); if (msg.known_blocks.mode == catch_up) { if (msg.known_blocks.ids.empty()) { - peer_elog( c, "got a catch up with ids size = 0" ); + peer_wlog( c, "got a catch up with ids size = 0" ); } else { const block_id_type& id = msg.known_blocks.ids.back(); peer_ilog( c, "notice_message, pending ${p}, blk_num ${n}, id ${id}...", @@ -2576,7 +2682,7 @@ namespace eosio { void dispatch_manager::bcast_transaction(const packed_transaction_ptr& trx) { trx_buffer_factory buff_factory; const fc::time_point_sec now{fc::time_point::now()}; - my_impl->connections.for_each_connection( [this, &trx, &now, &buff_factory]( auto& cp ) { + my_impl->connections.for_each_connection( [this, &trx, &now, &buff_factory]( const connection_ptr& cp ) { if( !cp->is_transactions_connection() || !cp->current() ) { return; } @@ -2602,7 +2708,7 @@ namespace eosio { void dispatch_manager::recv_notice(const connection_ptr& c, const notice_message& msg, bool generated) { if (msg.known_trx.mode == normal) { } else if (msg.known_trx.mode != none) { - peer_elog( c, "passed a notice_message with something other than a normal on none known_trx" ); + peer_wlog( c, "passed a notice_message with something other than a normal on none known_trx" ); return; } if (msg.known_blocks.mode == normal) { @@ -2613,7 +2719,7 @@ namespace eosio { } } } else if (msg.known_blocks.mode != none) { - peer_elog( c, "passed a notice_message with something other than a normal on none known_blocks" ); + peer_wlog( c, "passed a notice_message with something other than a normal on none known_blocks" ); return; } } @@ -2674,8 +2780,7 @@ namespace eosio { //------------------------------------------------------------------------ - // called from any thread - bool connection::resolve_and_connect() { + bool connection::reconnect() { switch ( no_retry ) { case no_reason: case wrong_version: @@ -2686,15 +2791,6 @@ namespace eosio { fc_dlog( logger, "Skipping connect due to go_away reason ${r}",("r", reason_str( no_retry ))); return false; } - - string::size_type colon = peer_address().find(':'); - if (colon == std::string::npos || colon == 0) { - fc_elog( logger, "Invalid peer address. must be \"host:port[:|]\": ${p}", ("p", peer_address()) ); - return false; - } - - connection_ptr c = shared_from_this(); - if( consecutive_immediate_connection_close > def_max_consecutive_immediate_connection_close || no_retry == benign_other ) { fc::microseconds connector_period = my_impl->connections.get_connector_period(); fc::lock_guard g( conn_mtx ); @@ -2702,46 +2798,30 @@ namespace eosio { return true; // true so doesn't remove from valid connections } } - + connection_ptr c = shared_from_this(); strand.post([c]() { - auto [host, port, type] = split_host_port_type(c->peer_address()); - c->set_connection_type( c->peer_address() ); - - auto resolver = std::make_shared( my_impl->thread_pool.get_executor() ); - connection_wptr weak_conn = c; - resolver->async_resolve(host, port, boost::asio::bind_executor( c->strand, - [resolver, weak_conn, host = host, port = port]( const boost::system::error_code& err, const tcp::resolver::results_type& endpoints ) { - auto c = weak_conn.lock(); - if( !c ) return; - if( !err ) { - c->connect( resolver, endpoints ); - } else { - fc_elog( logger, "Unable to resolve ${host}:${port} ${error}", - ("host", host)("port", port)( "error", err.message() ) ); - c->set_state(connection_state::closed); - ++c->consecutive_immediate_connection_close; - } - } ) ); - } ); + my_impl->connections.connect(c); + }); return true; } // called from connection strand - void connection::connect( const std::shared_ptr& resolver, const tcp::resolver::results_type& endpoints ) { + void connection::connect( const tcp::resolver::results_type& endpoints ) { set_state(connection_state::connecting); pending_message_buffer.reset(); buffer_queue.clear_out_queue(); boost::asio::async_connect( *socket, endpoints, boost::asio::bind_executor( strand, - [resolver, c = shared_from_this(), socket=socket]( const boost::system::error_code& err, const tcp::endpoint& endpoint ) { + [c = shared_from_this(), socket=socket]( const boost::system::error_code& err, const tcp::endpoint& endpoint ) { if( !err && socket->is_open() && socket == c->socket ) { - c->update_endpoints(); + my_impl->connections.update_connection_endpoint(c, endpoint); + c->update_endpoints(endpoint); if( c->start_session() ) { c->send_handshake(); c->send_time(); } } else { - fc_elog( logger, "connection failed to ${a}, ${error}", ("a", c->peer_address())( "error", err.message())); + fc_ilog( logger, "connection failed to ${a}, ${error}", ("a", c->peer_address())( "error", err.message())); c->close( false ); if (my_impl->increment_failed_p2p_connections) { my_impl->increment_failed_p2p_connections(); @@ -2751,17 +2831,21 @@ namespace eosio { } - void net_plugin_impl::create_session(tcp::socket&& socket, const string listen_address) { + const string& net_plugin_impl::get_first_p2p_address() const { + return p2p_addresses.size() > 0 ? *p2p_addresses.begin() : empty; + } + + void net_plugin_impl::create_session(tcp::socket&& socket, const string listen_address, size_t limit) { uint32_t visitors = 0; uint32_t from_addr = 0; boost::system::error_code rec; const auto& paddr_add = socket.remote_endpoint(rec).address(); string paddr_str; if (rec) { - fc_elog(logger, "Error getting remote endpoint: ${m}", ("m", rec.message())); + fc_ilog(logger, "Unable to get remote endpoint: ${m}", ("m", rec.message())); } else { paddr_str = paddr_add.to_string(); - connections.for_each_connection([&visitors, &from_addr, &paddr_str](auto& conn) { + connections.for_each_connection([&visitors, &from_addr, &paddr_str](const connection_ptr& conn) { if (conn->socket_is_open()) { if (conn->peer_address().empty()) { ++visitors; @@ -2777,7 +2861,19 @@ namespace eosio { visitors < connections.get_max_client_count())) { fc_ilog(logger, "Accepted new connection: " + paddr_str); - connection_ptr new_connection = std::make_shared(std::move(socket), listen_address); + connections.any_of_supplied_peers([&listen_address, &paddr_str, &limit](const string& peer_addr) { + auto [host, port, type] = split_host_port_type(peer_addr); + if (host == paddr_str) { + if (limit > 0) { + fc_dlog(logger, "Connection inbound to ${la} from ${a} is a configured p2p-peer-address and will not be throttled", ("la", listen_address)("a", paddr_str)); + } + limit = 0; + return true; + } + return false; + }); + + connection_ptr new_connection = std::make_shared(std::move(socket), listen_address, limit); new_connection->strand.post([new_connection, this]() { if (new_connection->start_session()) { connections.add(new_connection); @@ -2963,7 +3059,7 @@ namespace eosio { } } catch( const fc::exception& e ) { - peer_elog( this, "Exception in handling message: ${s}", ("s", e.to_detail_string()) ); + peer_wlog( this, "Exception in handling message: ${s}", ("s", e.to_detail_string()) ); close(); return false; } @@ -2977,7 +3073,6 @@ namespace eosio { fc::raw::unpack( peek_ds, which ); // throw away block_header bh; fc::raw::unpack( peek_ds, bh ); - const block_id_type blk_id = bh.calculate_id(); const uint32_t blk_num = last_received_block_num = block_header::num_from_id(blk_id); // don't add_peer_block because we have not validated this block header yet @@ -3011,6 +3106,7 @@ namespace eosio { return true; } } else { + block_sync_bytes_received += message_length; my_impl->sync_master->sync_recv_block(shared_from_this(), blk_id, blk_num, false); } @@ -3049,7 +3145,8 @@ namespace eosio { return true; } if (my_impl->sync_master->syncing_from_peer()) { - peer_wlog(this, "syncing, dropping trx"); + peer_dlog(this, "syncing, dropping trx"); + pending_message_buffer.advance_read_ptr( message_length ); return true; } @@ -3088,7 +3185,7 @@ namespace eosio { void net_plugin_impl::plugin_shutdown() { in_shutdown = true; - connections.stop_conn_timer(); + connections.stop_conn_timers(); { fc::lock_guard g( expire_timer_mtx ); if( expire_timer ) @@ -3179,7 +3276,7 @@ namespace eosio { // called from connection strand void connection::handle_message( const handshake_message& msg ) { if( !is_valid( msg ) ) { - peer_elog( this, "bad handshake message"); + peer_wlog( this, "bad handshake message"); no_retry = go_away_reason::fatal_other; enqueue( go_away_message( fatal_other ) ); return; @@ -3197,16 +3294,20 @@ namespace eosio { set_state(connection_state::connected); if (msg.generation == 1) { if( msg.node_id == my_impl->node_id) { - peer_elog( this, "Self connection detected node_id ${id}. Closing connection", ("id", msg.node_id) ); + peer_ilog( this, "Self connection detected node_id ${id}. Closing connection", ("id", msg.node_id) ); no_retry = go_away_reason::self; enqueue( go_away_message( go_away_reason::self ) ); return; } log_p2p_address = msg.p2p_address; + fc::unique_lock g_conn( conn_mtx ); + p2p_address = msg.p2p_address; + unique_conn_node_id = msg.node_id.str().substr( 0, 7 ); + g_conn.unlock(); my_impl->mark_bp_connection(this); - if (my_impl->exceeding_connection_limit(this)) { + if (my_impl->exceeding_connection_limit(shared_from_this())) { // When auto bp peering is enabled, create_session() check doesn't have enough information to determine // if a client is a BP peer. In create_session(), it only has the peer address which a node is connecting // from, but it would be different from the address it is listening. The only way to make sure is when the @@ -3223,7 +3324,7 @@ namespace eosio { set_connection_type( msg.p2p_address ); peer_dlog( this, "checking for duplicate" ); - auto is_duplicate = [&](const auto& check) { + auto is_duplicate = [&](const connection_ptr& check) { if(check.get() == this) return false; fc::unique_lock g_check_conn( check->conn_mtx ); @@ -3272,7 +3373,7 @@ namespace eosio { } if( msg.chain_id != my_impl->chain_id ) { - peer_elog( this, "Peer on a different chain. Closing connection" ); + peer_ilog( this, "Peer on a different chain. Closing connection" ); no_retry = go_away_reason::wrong_chain; enqueue( go_away_message(go_away_reason::wrong_chain) ); return; @@ -3289,7 +3390,7 @@ namespace eosio { short_conn_node_id = conn_node_id.str().substr( 0, 7 ); if( !my_impl->authenticate_peer( msg ) ) { - peer_elog( this, "Peer not authenticated. Closing connection." ); + peer_wlog( this, "Peer not authenticated. Closing connection." ); no_retry = go_away_reason::authentication; enqueue( go_away_message( go_away_reason::authentication ) ); return; @@ -3314,9 +3415,9 @@ namespace eosio { on_fork = true; } if( on_fork ) { - peer_elog( this, "Peer chain is forked, sending: forked go away" ); - no_retry = go_away_reason::forked; - enqueue( go_away_message( go_away_reason::forked ) ); + peer_wlog( this, "Peer chain is forked, sending: forked go away" ); + no_retry = go_away_reason::forked; + enqueue( go_away_message( go_away_reason::forked ) ); } } @@ -3451,7 +3552,7 @@ namespace eosio { // set_state(connection_state::connected); if( msg.known_blocks.ids.size() > 2 ) { - peer_elog( this, "Invalid notice_message, known_blocks.ids.size ${s}, closing connection", + peer_wlog( this, "Invalid notice_message, known_blocks.ids.size ${s}, closing connection", ("s", msg.known_blocks.ids.size()) ); close( false ); return; @@ -3503,7 +3604,7 @@ namespace eosio { break; } default: { - peer_elog( this, "bad notice_message : invalid known_blocks.mode ${m}", + peer_wlog( this, "bad notice_message : invalid known_blocks.mode ${m}", ("m", static_cast(msg.known_blocks.mode)) ); } } @@ -3511,7 +3612,7 @@ namespace eosio { void connection::handle_message( const request_message& msg ) { if( msg.req_blocks.ids.size() > 1 ) { - peer_elog( this, "Invalid request_message, req_blocks.ids.size ${s}, closing", + peer_wlog( this, "Invalid request_message, req_blocks.ids.size ${s}, closing", ("s", msg.req_blocks.ids.size()) ); close(); return; @@ -3542,7 +3643,7 @@ namespace eosio { // no break case normal : if( !msg.req_trx.ids.empty() ) { - peer_elog( this, "Invalid request_message, req_trx.ids.size ${s}", ("s", msg.req_trx.ids.size()) ); + peer_wlog( this, "Invalid request_message, req_trx.ids.size ${s}", ("s", msg.req_trx.ids.size()) ); close(); return; } @@ -3597,7 +3698,7 @@ namespace eosio { if( !trace->except ) { fc_dlog( logger, "chain accepted transaction, bcast ${id}", ("id", trace->id) ); } else { - fc_elog( logger, "bad packed_transaction : ${m}", ("m", trace->except->what())); + fc_ilog( logger, "bad packed_transaction : ${m}", ("m", trace->except->what())); } } connection_ptr conn = weak.lock(); @@ -3629,11 +3730,11 @@ namespace eosio { bsp = cc.create_block_state( id, ptr ); } catch( const fc::exception& ex ) { exception = true; - fc_elog( logger, "bad block exception connection ${cid}: #${n} ${id}...: ${m}", + fc_ilog( logger, "bad block exception connection ${cid}: #${n} ${id}...: ${m}", ("cid", cid)("n", ptr->block_num())("id", id.str().substr(8,16))("m",ex.to_string())); } catch( ... ) { exception = true; - fc_elog( logger, "bad block connection ${cid}: #${n} ${id}...: unknown exception", + fc_wlog( logger, "bad block connection ${cid}: #${n} ${id}...: unknown exception", ("cid", cid)("n", ptr->block_num())("id", id.str().substr(8,16))); } if( exception ) { @@ -3681,8 +3782,11 @@ namespace eosio { }); return; } - } catch(...) { - fc_elog( logger, "Caught an unknown exception trying to fetch block ${id}", ("id", blk_id) ); + } catch( const assert_exception& ex ) { + // possible corrupted block log + fc_elog( logger, "caught assert on fetch_block_by_id, ${ex}, id ${id}, conn ${c}", ("ex", ex.to_string())("id", blk_id)("c", connection_id) ); + } catch( ... ) { + fc_elog( logger, "caught an unknown exception trying to fetch block ${id}, conn ${c}", ("id", blk_id)("c", connection_id) ); } fc::microseconds age( fc::time_point::now() - block->timestamp); @@ -3695,23 +3799,23 @@ namespace eosio { accepted = my_impl->chain_plug->accept_block(block, blk_id, bsp); my_impl->update_chain_info(); } catch( const unlinkable_block_exception &ex) { - fc_elog(logger, "unlinkable_block_exception connection ${cid}: #${n} ${id}...: ${m}", + fc_ilog(logger, "unlinkable_block_exception connection ${cid}: #${n} ${id}...: ${m}", ("cid", c->connection_id)("n", blk_num)("id", blk_id.str().substr(8,16))("m",ex.to_string())); reason = unlinkable; } catch( const block_validate_exception &ex ) { - fc_elog(logger, "block_validate_exception connection ${cid}: #${n} ${id}...: ${m}", + fc_ilog(logger, "block_validate_exception connection ${cid}: #${n} ${id}...: ${m}", ("cid", c->connection_id)("n", blk_num)("id", blk_id.str().substr(8,16))("m",ex.to_string())); reason = validation; } catch( const assert_exception &ex ) { - fc_elog(logger, "block assert_exception connection ${cid}: #${n} ${id}...: ${m}", + fc_wlog(logger, "block assert_exception connection ${cid}: #${n} ${id}...: ${m}", ("cid", c->connection_id)("n", blk_num)("id", blk_id.str().substr(8,16))("m",ex.to_string())); reason = fatal_other; } catch( const fc::exception &ex ) { - fc_elog(logger, "bad block exception connection ${cid}: #${n} ${id}...: ${m}", + fc_ilog(logger, "bad block exception connection ${cid}: #${n} ${id}...: ${m}", ("cid", c->connection_id)("n", blk_num)("id", blk_id.str().substr(8,16))("m",ex.to_string())); reason = fatal_other; } catch( ... ) { - fc_elog(logger, "bad block connection ${cid}: #${n} ${id}...: unknown exception", + fc_wlog(logger, "bad block connection ${cid}: #${n} ${id}...: unknown exception", ("cid", c->connection_id)("n", blk_num)("id", blk_id.str().substr(8,16))); reason = fatal_other; } @@ -3782,7 +3886,7 @@ namespace eosio { } auto current_time = std::chrono::system_clock::now(); - my->connections.for_each_connection( [current_time]( auto& c ) { + my->connections.for_each_connection( [current_time]( const connection_ptr& c ) { if( c->socket_is_open() ) { c->strand.post([c, current_time]() { c->check_heartbeat(current_time); @@ -3797,7 +3901,7 @@ namespace eosio { fc::lock_guard g( expire_timer_mtx ); expire_timer = std::make_unique( my_impl->thread_pool.get_executor() ); } - connections.start_conn_timer(); + connections.start_conn_timers(); start_expire_timer(); } @@ -3875,7 +3979,7 @@ namespace eosio { if(producer_plug != nullptr) found_producer_key = producer_plug->is_producer_key(msg.key); if( allowed_it == allowed_peers.end() && private_it == private_keys.end() && !found_producer_key) { - fc_elog( logger, "Peer ${peer} sent a handshake with an unauthorized key: ${key}.", + fc_wlog( logger, "Peer ${peer} sent a handshake with an unauthorized key: ${key}.", ("peer", msg.p2p_address)("key", msg.key) ); return false; } @@ -3884,7 +3988,7 @@ namespace eosio { if(msg.sig != chain::signature_type() && msg.token != sha256()) { sha256 hash = fc::sha256::hash(msg.time); if(hash != msg.token) { - fc_elog( logger, "Peer ${peer} sent a handshake with an invalid token.", ("peer", msg.p2p_address) ); + fc_wlog( logger, "Peer ${peer} sent a handshake with an invalid token.", ("peer", msg.p2p_address) ); return false; } chain::public_key_type peer_key; @@ -3892,11 +3996,11 @@ namespace eosio { peer_key = crypto::public_key(msg.sig, msg.token, true); } catch (const std::exception& /*e*/) { - fc_elog( logger, "Peer ${peer} sent a handshake with an unrecoverable key.", ("peer", msg.p2p_address) ); + fc_wlog( logger, "Peer ${peer} sent a handshake with an unrecoverable key.", ("peer", msg.p2p_address) ); return false; } if((allowed_connections & (Producers | Specified)) && peer_key != msg.key) { - fc_elog( logger, "Peer ${peer} sent a handshake with an unauthenticated key.", ("peer", msg.p2p_address) ); + fc_wlog( logger, "Peer ${peer} sent a handshake with an unauthenticated key.", ("peer", msg.p2p_address) ); return false; } } @@ -3978,7 +4082,17 @@ namespace eosio { void net_plugin::set_program_options( options_description& /*cli*/, options_description& cfg ) { cfg.add_options() - ( "p2p-listen-endpoint", bpo::value< vector >()->default_value( vector(1, string("0.0.0.0:9876")) ), "The actual host:port used to listen for incoming p2p connections. May be used multiple times.") + ( "p2p-listen-endpoint", bpo::value< vector >()->default_value( vector(1, string("0.0.0.0:9876:0")) ), "The actual host:port[:] used to listen for incoming p2p connections. May be used multiple times. " + " The optional rate cap will limit per connection block sync bandwidth to the specified rate. Total " + " allowed bandwidth is the rate-cap multiplied by the connection count limit. A number alone will be " + " interpreted as bytes per second. The number may be suffixed with units. Supported units are: " + " 'B/s', 'KB/s', 'MB/s, 'GB/s', 'TB/s', 'KiB/s', 'MiB/s', 'GiB/s', 'TiB/s'." + " Transactions and blocks outside of sync mode are not throttled." + " Examples:\n" + " 192.168.0.100:9876:1MiB/s\n" + " node.eos.io:9876:1512KB/s\n" + " node.eos.io:9876:0.5GB/s\n" + " [2001:db8:85a3:8d3:1319:8a2e:370:7348]:9876:250KB/s") ( "p2p-server-address", bpo::value< vector >(), "An externally accessible host:port for identifying this node. Defaults to p2p-listen-endpoint. May be used as many times as p2p-listen-endpoint. If provided, the first address will be used in handshakes with other nodes. Otherwise the default is used.") ( "p2p-peer-address", bpo::value< vector >()->composing(), "The public endpoint of a peer node to connect to. Use multiple p2p-peer-address options as needed to compose a network.\n" @@ -4034,6 +4148,52 @@ namespace eosio { return fc::json::from_string(s).as(); } + std::tuple net_plugin_impl::parse_listen_address( const std::string& address ) const { + auto listen_addr = address; + auto limit = string("0"); + auto last_colon_location = address.rfind(':'); + if( auto right_bracket_location = address.find(']'); right_bracket_location != address.npos ) { + if( std::count(address.begin()+right_bracket_location, address.end(), ':') > 1 ) { + listen_addr = std::string(address, 0, last_colon_location); + limit = std::string(address, last_colon_location+1); + } + } else { + if( auto colon_count = std::count(address.begin(), address.end(), ':'); colon_count > 1 ) { + EOS_ASSERT( colon_count <= 2, plugin_config_exception, "Invalid address specification ${addr}; IPv6 addresses must be enclosed in square brackets.", ("addr", address)); + listen_addr = std::string(address, 0, last_colon_location); + limit = std::string(address, last_colon_location+1); + } + } + auto block_sync_rate_limit = parse_connection_rate_limit(limit); + + return {listen_addr, block_sync_rate_limit}; + } + + size_t net_plugin_impl::parse_connection_rate_limit( const std::string& limit_str) const { + std::istringstream in(limit_str); + double limit{0}; + in >> limit; + EOS_ASSERT(limit >= 0.0, plugin_config_exception, "block sync rate limit must not be negative: ${limit}", ("limit", limit_str)); + size_t block_sync_rate_limit = 0; + if( limit > 0.0 ) { + std::string units; + in >> units; + std::regex units_regex{"([KMGT]?[i]?)B/s"}; + std::smatch units_match; + std::regex_match(units, units_match, units_regex); + if( units.length() > 0 ) { + EOS_ASSERT(units_match.size() == 2, plugin_config_exception, "invalid block sync rate limit specification: ${limit}", ("limit", units)); + try { + block_sync_rate_limit = boost::numeric_cast(limit * prefix_multipliers.at(units_match[1].str())); + fc_ilog( logger, "setting block_sync_rate_limit to ${limit} megabytes per second", ("limit", double(block_sync_rate_limit)/1000000)); + } catch (boost::numeric::bad_numeric_cast&) { + EOS_THROW(plugin_config_exception, "block sync rate limit specification overflowed: ${limit}", ("limit", limit_str)); + } + } + } + return block_sync_rate_limit; + } + void net_plugin_impl::plugin_initialize( const variables_map& options ) { try { fc_ilog( logger, "Initialize net plugin" ); @@ -4190,7 +4350,6 @@ namespace eosio { set_producer_accounts(producer_plug->producer_accounts()); thread_pool.start( thread_pool_size, []( const fc::exception& e ) { - fc_elog( logger, "Exception in net plugin thread pool, exiting: ${e}", ("e", e.to_detail_string()) ); app().quit(); } ); @@ -4259,10 +4418,16 @@ namespace eosio { std::string extra_listening_log_info = ", max clients is " + std::to_string(my->connections.get_max_client_count()); - + + auto [listen_addr, block_sync_rate_limit] = my->parse_listen_address(address); + fc::create_listener( - my->thread_pool.get_executor(), logger, accept_timeout, address, extra_listening_log_info, - [my = my, addr = p2p_addr](tcp::socket&& socket) { my->create_session(std::move(socket), addr); }); + my->thread_pool.get_executor(), logger, accept_timeout, listen_addr, extra_listening_log_info, + [my = my, addr = p2p_addr, block_sync_rate_limit = block_sync_rate_limit](tcp::socket&& socket) { fc_dlog( logger, "start listening on ${addr} with peer sync throttle ${limit}", ("addr", addr)("limit", block_sync_rate_limit)); my->create_session(std::move(socket), addr, block_sync_rate_limit); }); + } catch (const plugin_config_exception& e) { + fc_elog( logger, "${msg}", ("msg", e.top_message())); + app().quit(); + return; } catch (const std::exception& e) { fc_elog( logger, "net_plugin::plugin_startup failed to listen on ${addr}, ${what}", ("addr", address)("what", e.what()) ); @@ -4275,7 +4440,7 @@ namespace eosio { my->ticker(); my->start_monitors(); my->update_chain_info(); - my->connections.connect_supplied_peers(*my->p2p_addresses.begin()); // attribute every outbound connection to the first listen port + my->connections.connect_supplied_peers(my->get_first_p2p_address()); // attribute every outbound connection to the first listen port when one exists }); } @@ -4312,7 +4477,7 @@ namespace eosio { /// RPC API string net_plugin::connect( const string& host ) { - return my->connections.connect( host, *my->p2p_addresses.begin() ); + return my->connections.connect( host, my->get_first_p2p_address() ); } /// RPC API @@ -4387,35 +4552,99 @@ namespace eosio { } void connections_manager::connect_supplied_peers(const string& p2p_address) { - std::lock_guard g(connections_mtx); - for (const auto& peer : supplied_peers) { - connect_i(peer, p2p_address); + std::unique_lock g(connections_mtx); + chain::flat_set peers = supplied_peers; + g.unlock(); + for (const auto& peer : peers) { + resolve_and_connect(peer, p2p_address); } } void connections_manager::add( connection_ptr c ) { std::lock_guard g( connections_mtx ); - add_i( std::move(c) ); + boost::system::error_code ec; + auto endpoint = c->socket->remote_endpoint(ec); + connections.insert( connection_detail{ + .host = c->peer_address(), + .c = std::move(c), + .active_ip = endpoint} ); } // called by API string connections_manager::connect( const string& host, const string& p2p_address ) { + std::unique_lock g( connections_mtx ); + supplied_peers.insert(host); + g.unlock(); + return resolve_and_connect( host, p2p_address ); + } + + string connections_manager::resolve_and_connect( const string& peer_address, const string& listen_address ) { + string::size_type colon = peer_address.find(':'); + if (colon == std::string::npos || colon == 0) { + fc_elog( logger, "Invalid peer address. must be \"host:port[:|]\": ${p}", ("p", peer_address) ); + return "invalid peer address"; + } + std::lock_guard g( connections_mtx ); - if( find_connection_i( host ) ) + if( find_connection_i( peer_address ) ) return "already connected"; - connect_i( host, p2p_address ); - supplied_peers.insert(host); + auto [host, port, type] = split_host_port_type(peer_address); + + auto resolver = std::make_shared( my_impl->thread_pool.get_executor() ); + + resolver->async_resolve(host, port, + [resolver, host = host, port = port, peer_address = peer_address, listen_address = listen_address, this]( const boost::system::error_code& err, const tcp::resolver::results_type& results ) { + connection_ptr c = std::make_shared( peer_address, listen_address ); + c->set_heartbeat_timeout( heartbeat_timeout ); + std::lock_guard g( connections_mtx ); + auto [it, inserted] = connections.emplace( connection_detail{ + .host = peer_address, + .c = std::move(c), + .ips = results + }); + if( !err ) { + it->c->connect( results ); + } else { + fc_wlog( logger, "Unable to resolve ${host}:${port} ${error}", + ("host", host)("port", port)( "error", err.message() ) ); + it->c->set_state(connection::connection_state::closed); + ++(it->c->consecutive_immediate_connection_close); + } + } ); + return "added connection"; } + void connections_manager::update_connection_endpoint(connection_ptr c, + const tcp::endpoint& endpoint) { + std::unique_lock g( connections_mtx ); + auto& index = connections.get(); + const auto& it = index.find(c); + if( it != index.end() ) { + index.modify(it, [endpoint](connection_detail& cd) { + cd.active_ip = endpoint; + }); + } + } + + void connections_manager::connect(const connection_ptr& c) { + std::lock_guard g( connections_mtx ); + const auto& index = connections.get(); + const auto& it = index.find(c); + if( it != index.end() ) { + it->c->connect( it->ips ); + } + } + // called by API string connections_manager::disconnect( const string& host ) { std::lock_guard g( connections_mtx ); - if( auto c = find_connection_i( host ) ) { - fc_ilog( logger, "disconnecting: ${cid}", ("cid", c->connection_id) ); - c->close(); - connections.erase(c); + auto& index = connections.get(); + if( auto i = index.find( host ); i != index.end() ) { + fc_ilog( logger, "disconnecting: ${cid}", ("cid", i->c->connection_id) ); + i->c->close(); + connections.erase(i); supplied_peers.erase(host); return "connection removed"; } @@ -4423,11 +4652,12 @@ namespace eosio { } void connections_manager::close_all() { - fc_ilog( logger, "close all ${s} connections", ("s", connections.size()) ); std::lock_guard g( connections_mtx ); - for( auto& con : connections ) { - fc_dlog( logger, "close: ${cid}", ("cid", con->connection_id) ); - con->close( false, true ); + auto& index = connections.get(); + fc_ilog( logger, "close all ${s} connections", ("s", index.size()) ); + for( const connection_detail& cd : index ) { + fc_dlog( logger, "close: ${cid}", ("cid", cd.c->connection_id) ); + cd.c->close( false, true ); } connections.clear(); } @@ -4444,143 +4674,180 @@ namespace eosio { vector connections_manager::connection_statuses()const { vector result; std::shared_lock g( connections_mtx ); - result.reserve( connections.size() ); - for( const auto& c : connections ) { - result.push_back( c->get_status() ); + auto& index = connections.get(); + result.reserve( index.size() ); + for( const connection_detail& cd : index ) { + result.emplace_back( cd.c->get_status() ); } return result; } // call with connections_mtx connection_ptr connections_manager::find_connection_i( const string& host )const { - for( const auto& c : connections ) { - if (c->peer_address() == host) - return c; - } + auto& index = connections.get(); + auto iter = index.find(host); + if(iter != index.end()) + return iter->c; return {}; } - // call with connections_mtx - void connections_manager::connect_i( const string& host, const string& p2p_address ) { - connection_ptr c = std::make_shared( host, p2p_address ); - fc_dlog( logger, "calling active connector: ${h}", ("h", host) ); - if( c->resolve_and_connect() ) { - fc_dlog( logger, "adding new connection to the list: ${host} ${cid}", ("host", host)("cid", c->connection_id) ); - add_i( std::move(c) ); - } - } - - // call with connections_mtx - void connections_manager::add_i(connection_ptr&& c) { - c->set_heartbeat_timeout( heartbeat_timeout ); - connections.insert( std::move(c) ); - } - // called from any thread - void connections_manager::start_conn_timer() { - start_conn_timer(connector_period, {}); // this locks mutex + void connections_manager::start_conn_timers() { + start_conn_timer(connector_period, {}, timer_type::check); // this locks mutex + start_conn_timer(connector_period, {}, timer_type::stats); // this locks mutex + if (update_p2p_connection_metrics) { + start_conn_timer(connector_period + connector_period / 2, {}, timer_type::stats); // this locks mutex + } } // called from any thread - void connections_manager::start_conn_timer(boost::asio::steady_timer::duration du, std::weak_ptr from_connection) { - fc::lock_guard g( connector_check_timer_mtx ); - if (!connector_check_timer) { - connector_check_timer = std::make_unique( my_impl->thread_pool.get_executor() ); - } - connector_check_timer->expires_from_now( du ); - connector_check_timer->async_wait( [this, from_connection{std::move(from_connection)}](boost::system::error_code ec) mutable { + void connections_manager::start_conn_timer(boost::asio::steady_timer::duration du, + std::weak_ptr from_connection, + timer_type which) { + auto& mtx = which == timer_type::check ? connector_check_timer_mtx : connection_stats_timer_mtx; + auto& timer = which == timer_type::check ? connector_check_timer : connection_stats_timer; + const auto& func = which == timer_type::check ? &connections_manager::connection_monitor : &connections_manager::connection_statistics_monitor; + fc::lock_guard g( mtx ); + if (!timer) { + timer = std::make_unique( my_impl->thread_pool.get_executor() ); + } + timer->expires_from_now( du ); + timer->async_wait( [this, from_connection{std::move(from_connection)}, f = func](boost::system::error_code ec) mutable { if( !ec ) { - connection_monitor(from_connection); + (this->*f)(from_connection); } }); } - void connections_manager::stop_conn_timer() { - fc::lock_guard g( connector_check_timer_mtx ); - if (connector_check_timer) { - connector_check_timer->cancel(); + void connections_manager::stop_conn_timers() { + { + fc::lock_guard g( connector_check_timer_mtx ); + if (connector_check_timer) { + connector_check_timer->cancel(); + } + } + { + fc::lock_guard g( connection_stats_timer_mtx ); + if (connection_stats_timer) { + connection_stats_timer->cancel(); + } } } // called from any thread void connections_manager::connection_monitor(const std::weak_ptr& from_connection) { + size_t num_rm = 0, num_clients = 0, num_peers = 0, num_bp_peers = 0; + auto cleanup = [&num_peers, &num_rm, this](vector&& reconnecting, + vector&& removing) { + for( auto& c : reconnecting ) { + if (!c->reconnect()) { + --num_peers; + ++num_rm; + removing.push_back(c); + } + } + std::scoped_lock g( connections_mtx ); + auto& index = connections.get(); + for( auto& c : removing ) { + index.erase(c); + } + }; auto max_time = fc::time_point::now().safe_add(max_cleanup_time); + std::vector reconnecting, removing; auto from = from_connection.lock(); std::unique_lock g( connections_mtx ); - auto it = (from ? connections.find(from) : connections.begin()); - if (it == connections.end()) it = connections.begin(); - size_t num_rm = 0, num_clients = 0, num_peers = 0, num_bp_peers = 0; - net_plugin::p2p_per_connection_metrics per_connection(connections.size()); - while (it != connections.end()) { + auto& index = connections.get(); + auto it = (from ? index.find(from) : index.begin()); + if (it == index.end()) it = index.begin(); + while (it != index.end()) { if (fc::time_point::now() >= max_time) { - connection_wptr wit = *it; + connection_wptr wit = (*it).c; g.unlock(); + cleanup(std::move(reconnecting), std::move(removing)); fc_dlog( logger, "Exiting connection monitor early, ran out of time: ${t}", ("t", max_time - fc::time_point::now()) ); fc_ilog( logger, "p2p client connections: ${num}/${max}, peer connections: ${pnum}/${pmax}", ("num", num_clients)("max", max_client_count)("pnum", num_peers)("pmax", supplied_peers.size()) ); - start_conn_timer( std::chrono::milliseconds( 1 ), wit ); // avoid exhausting + start_conn_timer( std::chrono::milliseconds( 1 ), wit, timer_type::check ); // avoid exhausting return; } - if ((*it)->is_bp_connection) { + const connection_ptr& c = it->c; + if (c->is_bp_connection) { ++num_bp_peers; - } else if ((*it)->incoming()) { + } else if (c->incoming()) { ++num_clients; } else { ++num_peers; } - if (update_p2p_connection_metrics) { - fc::unique_lock g_conn((*it)->conn_mtx); - boost::asio::ip::address_v6::bytes_type addr = (*it)->remote_endpoint_ip_array; - g_conn.unlock(); - net_plugin::p2p_per_connection_metrics::connection_metric metrics{ - .connection_id = (*it)->connection_id - , .address = addr - , .port = (*it)->get_remote_endpoint_port() - , .accepting_blocks = (*it)->is_blocks_connection() - , .last_received_block = (*it)->get_last_received_block_num() - , .first_available_block = (*it)->get_peer_start_block_num() - , .last_available_block = (*it)->get_peer_head_block_num() - , .unique_first_block_count = (*it)->get_unique_blocks_rcvd_count() - , .latency = (*it)->get_peer_ping_time_ns() - , .bytes_received = (*it)->get_bytes_received() - , .last_bytes_received = (*it)->get_last_bytes_received() - , .bytes_sent = (*it)->get_bytes_sent() - , .last_bytes_sent = (*it)->get_last_bytes_sent() - , .connection_start_time = (*it)->connection_start_time - , .log_p2p_address = (*it)->log_p2p_address - }; - per_connection.peers.push_back(metrics); - } - if (!(*it)->socket_is_open() && (*it)->state() != connection::connection_state::connecting) { - if (!(*it)->incoming()) { - if (!(*it)->resolve_and_connect()) { - it = connections.erase(it); - --num_peers; - ++num_rm; - continue; - } + if (!c->socket_is_open() && c->state() != connection::connection_state::connecting) { + if (!c->incoming()) { + reconnecting.push_back(c); } else { --num_clients; ++num_rm; - it = connections.erase(it); - continue; + removing.push_back(c); } } ++it; } g.unlock(); - - if (update_p2p_connection_metrics) { - update_p2p_connection_metrics({num_peers, num_clients, std::move(per_connection)}); - } + cleanup(std::move(reconnecting), std::move(removing)); if( num_clients > 0 || num_peers > 0 ) { fc_ilog(logger, "p2p client connections: ${num}/${max}, peer connections: ${pnum}/${pmax}, block producer peers: ${num_bp_peers}", ("num", num_clients)("max", max_client_count)("pnum", num_peers)("pmax", supplied_peers.size())("num_bp_peers", num_bp_peers)); } fc_dlog( logger, "connection monitor, removed ${n} connections", ("n", num_rm) ); - start_conn_timer( connector_period, {}); + start_conn_timer( connector_period, {}, timer_type::check ); } -} // namespace eosio + // called from any thread + void connections_manager::connection_statistics_monitor(const std::weak_ptr& from_connection) { + assert(update_p2p_connection_metrics); + auto from = from_connection.lock(); + std::shared_lock g(connections_mtx); + auto& index = connections.get(); + size_t num_clients = 0, num_peers = 0, num_bp_peers = 0; + net_plugin::p2p_per_connection_metrics per_connection(index.size()); + for (auto it = index.begin(); it != index.end(); ++it) { + const connection_ptr& c = it->c; + if(c->is_bp_connection) { + ++num_bp_peers; + } else if(c->incoming()) { + ++num_clients; + } else { + ++num_peers; + } + fc::unique_lock g_conn(c->conn_mtx); + boost::asio::ip::address_v6::bytes_type addr = c->remote_endpoint_ip_array; + std::string p2p_addr = c->p2p_address; + std::string conn_node_id = c->unique_conn_node_id; + g_conn.unlock(); + per_connection.peers.emplace_back( + net_plugin::p2p_per_connection_metrics::connection_metric{ + .connection_id = c->connection_id + , .address = addr + , .port = c->get_remote_endpoint_port() + , .accepting_blocks = c->is_blocks_connection() + , .last_received_block = c->get_last_received_block_num() + , .first_available_block = c->get_peer_start_block_num() + , .last_available_block = c->get_peer_head_block_num() + , .unique_first_block_count = c->get_unique_blocks_rcvd_count() + , .latency = c->get_peer_ping_time_ns() + , .bytes_received = c->get_bytes_received() + , .last_bytes_received = c->get_last_bytes_received() + , .bytes_sent = c->get_bytes_sent() + , .last_bytes_sent = c->get_last_bytes_sent() + , .block_sync_bytes_received = c->get_block_sync_bytes_received() + , .block_sync_bytes_sent = c->get_block_sync_bytes_sent() + , .block_sync_throttling = c->get_block_sync_throttling() + , .connection_start_time = c->connection_start_time + , .p2p_address = p2p_addr + , .unique_conn_node_id = conn_node_id + }); + } + g.unlock(); + update_p2p_connection_metrics({num_peers+num_bp_peers, num_clients, std::move(per_connection)}); + start_conn_timer( connector_period, {}, timer_type::stats ); + } +} // namespace eosio \ No newline at end of file diff --git a/plugins/net_plugin/tests/CMakeLists.txt b/plugins/net_plugin/tests/CMakeLists.txt index bcabe6428f..210a748e07 100644 --- a/plugins/net_plugin/tests/CMakeLists.txt +++ b/plugins/net_plugin/tests/CMakeLists.txt @@ -5,4 +5,12 @@ target_link_libraries(auto_bp_peering_unittest eosio_chain) target_include_directories(auto_bp_peering_unittest PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/../include" ) -add_test(auto_bp_peering_unittest auto_bp_peering_unittest) \ No newline at end of file +add_test(auto_bp_peering_unittest auto_bp_peering_unittest) + +add_executable(rate_limit_parse_unittest rate_limit_parse_unittest.cpp) + +target_link_libraries(rate_limit_parse_unittest net_plugin) + +target_include_directories(rate_limit_parse_unittest PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/../include") + +add_test(rate_limit_parse_unittest rate_limit_parse_unittest) diff --git a/plugins/net_plugin/tests/auto_bp_peering_unittest.cpp b/plugins/net_plugin/tests/auto_bp_peering_unittest.cpp index ddfeba7b1c..57c7a8f6a1 100644 --- a/plugins/net_plugin/tests/auto_bp_peering_unittest.cpp +++ b/plugins/net_plugin/tests/auto_bp_peering_unittest.cpp @@ -6,6 +6,11 @@ struct mock_connection { bool is_bp_connection = false; bool is_open = false; bool handshake_received = false; + mock_connection(bool bp_connection, bool open, bool received) + : is_bp_connection(bp_connection) + , is_open(open) + , handshake_received(received) + {} bool socket_is_open() const { return is_open; } bool incoming_and_handshake_received() const { return handshake_received; } @@ -16,9 +21,9 @@ using namespace std::literals::string_literals; struct mock_connections_manager { uint32_t max_client_count = 0; - std::vector connections; + std::vector> connections; - std::function connect; + std::function resolve_and_connect; std::function disconnect; uint32_t get_max_client_count() const { return max_client_count; } @@ -26,7 +31,7 @@ struct mock_connections_manager { template void for_each_connection(Function&& func) const { for (auto c : connections) { - if (!func(&c)) + if (!func(c)) return; } } @@ -37,6 +42,7 @@ struct mock_net_plugin : eosio::auto_bp_peering::bp_connection_manager p2p_addresses{"0.0.0.0:9876"}; + const std::string& get_first_p2p_address() const { return *p2p_addresses.begin(); } bool in_sync() { return is_in_sync; } @@ -166,7 +172,7 @@ BOOST_AUTO_TEST_CASE(test_on_pending_schedule) { std::vector connected_hosts; - plugin.connections.connect = [&connected_hosts](std::string host, std::string p2p_address) { connected_hosts.push_back(host); }; + plugin.connections.resolve_and_connect = [&connected_hosts](std::string host, std::string p2p_address) { connected_hosts.push_back(host); }; // make sure nothing happens when it is not in_sync plugin.is_in_sync = false; @@ -210,7 +216,7 @@ BOOST_AUTO_TEST_CASE(test_on_active_schedule1) { plugin.config.my_bp_accounts = { "prodd"_n, "produ"_n }; plugin.active_neighbors = { "proda"_n, "prodh"_n, "prodn"_n }; - plugin.connections.connect = [](std::string host, std::string p2p_address) {}; + plugin.connections.resolve_and_connect = [](std::string host, std::string p2p_address) {}; std::vector disconnected_hosts; plugin.connections.disconnect = [&disconnected_hosts](std::string host) { disconnected_hosts.push_back(host); }; @@ -246,7 +252,7 @@ BOOST_AUTO_TEST_CASE(test_on_active_schedule2) { plugin.config.my_bp_accounts = { "prodd"_n, "produ"_n }; plugin.active_neighbors = { "proda"_n, "prodh"_n, "prodn"_n }; - plugin.connections.connect = [](std::string host, std::string p2p_address) {}; + plugin.connections.resolve_and_connect = [](std::string host, std::string p2p_address) {}; std::vector disconnected_hosts; plugin.connections.disconnect = [&disconnected_hosts](std::string host) { disconnected_hosts.push_back(host); }; @@ -272,24 +278,24 @@ BOOST_AUTO_TEST_CASE(test_exceeding_connection_limit) { plugin.config.my_bp_accounts = { "prodd"_n, "produ"_n }; plugin.connections.max_client_count = 1; plugin.connections.connections = { - { .is_bp_connection = true, .is_open = true, .handshake_received = true }, // 0 - { .is_bp_connection = true, .is_open = true, .handshake_received = false }, // 1 - { .is_bp_connection = true, .is_open = false, .handshake_received = true }, // 2 - { .is_bp_connection = true, .is_open = false, .handshake_received = false }, // 3 - { .is_bp_connection = false, .is_open = true, .handshake_received = true }, // 4 - { .is_bp_connection = false, .is_open = true, .handshake_received = false }, // 5 - { .is_bp_connection = false, .is_open = true, .handshake_received = true }, // 6 - { .is_bp_connection = false, .is_open = false, .handshake_received = false } // 7 + std::make_shared( true, true, true ), // 0 + std::make_shared( true, true, false ), // 1 + std::make_shared( true, false, true ), // 2 + std::make_shared( true, false, false ), // 3 + std::make_shared( false, true, true ), // 4 + std::make_shared( false, true, false ), // 5 + std::make_shared( false, true, true ), // 6 + std::make_shared( false, false, false ) // 7 }; BOOST_CHECK_EQUAL(plugin.num_established_clients(), 2u); - BOOST_CHECK(!plugin.exceeding_connection_limit(&plugin.connections.connections[0])); - BOOST_CHECK(!plugin.exceeding_connection_limit(&plugin.connections.connections[1])); - BOOST_CHECK(!plugin.exceeding_connection_limit(&plugin.connections.connections[2])); - BOOST_CHECK(!plugin.exceeding_connection_limit(&plugin.connections.connections[3])); - BOOST_CHECK(plugin.exceeding_connection_limit(&plugin.connections.connections[4])); - BOOST_CHECK(!plugin.exceeding_connection_limit(&plugin.connections.connections[5])); - BOOST_CHECK(plugin.exceeding_connection_limit(&plugin.connections.connections[6])); - BOOST_CHECK(!plugin.exceeding_connection_limit(&plugin.connections.connections[7])); + BOOST_CHECK(!plugin.exceeding_connection_limit(plugin.connections.connections[0])); + BOOST_CHECK(!plugin.exceeding_connection_limit(plugin.connections.connections[1])); + BOOST_CHECK(!plugin.exceeding_connection_limit(plugin.connections.connections[2])); + BOOST_CHECK(!plugin.exceeding_connection_limit(plugin.connections.connections[3])); + BOOST_CHECK(plugin.exceeding_connection_limit(plugin.connections.connections[4])); + BOOST_CHECK(!plugin.exceeding_connection_limit(plugin.connections.connections[5])); + BOOST_CHECK(plugin.exceeding_connection_limit(plugin.connections.connections[6])); + BOOST_CHECK(!plugin.exceeding_connection_limit(plugin.connections.connections[7])); } diff --git a/plugins/net_plugin/tests/rate_limit_parse_unittest.cpp b/plugins/net_plugin/tests/rate_limit_parse_unittest.cpp new file mode 100644 index 0000000000..efd0cc36b7 --- /dev/null +++ b/plugins/net_plugin/tests/rate_limit_parse_unittest.cpp @@ -0,0 +1,54 @@ +#define BOOST_TEST_MODULE rate_limit_parsing +#include +#include "../net_plugin.cpp" + +BOOST_AUTO_TEST_CASE(test_parse_rate_limit) { + eosio::net_plugin_impl plugin_impl; + std::vector p2p_addresses = { + "0.0.0.0:9876" + , "0.0.0.0:9776:0" + , "0.0.0.0:9877:640KB/s" + , "192.168.0.1:9878:20MiB/s" + , "localhost:9879:0.5KB/s" + , "[2001:db8:85a3:8d3:1319:8a2e:370:7348]:9876:250KB/s" + , "[::1]:9876:250KB/s" + , "2001:db8:85a3:8d3:1319:8a2e:370:7348:9876:250KB/s" + , "[::1]:9876:-250KB/s" + , "0.0.0.0:9877:640Kb/s" + , "0.0.0.0:9877:999999999999999999999999999TiB/s" + }; + size_t which = 0; + auto [listen_addr, block_sync_rate_limit] = plugin_impl.parse_listen_address(p2p_addresses[which++]); + BOOST_CHECK_EQUAL(listen_addr, "0.0.0.0:9876"); + BOOST_CHECK_EQUAL(block_sync_rate_limit, 0u); + std::tie(listen_addr, block_sync_rate_limit) = plugin_impl.parse_listen_address(p2p_addresses[which++]); + BOOST_CHECK_EQUAL(listen_addr, "0.0.0.0:9776"); + BOOST_CHECK_EQUAL(block_sync_rate_limit, 0u); + std::tie(listen_addr, block_sync_rate_limit) = plugin_impl.parse_listen_address(p2p_addresses[which++]); + BOOST_CHECK_EQUAL(listen_addr, "0.0.0.0:9877"); + BOOST_CHECK_EQUAL(block_sync_rate_limit, 640000u); + std::tie(listen_addr, block_sync_rate_limit) = plugin_impl.parse_listen_address(p2p_addresses[which++]); + BOOST_CHECK_EQUAL(listen_addr, "192.168.0.1:9878"); + BOOST_CHECK_EQUAL(block_sync_rate_limit, 20971520u); + std::tie(listen_addr, block_sync_rate_limit) = plugin_impl.parse_listen_address(p2p_addresses[which++]); + BOOST_CHECK_EQUAL(listen_addr, "localhost:9879"); + BOOST_CHECK_EQUAL(block_sync_rate_limit, 500u); + std::tie(listen_addr, block_sync_rate_limit) = plugin_impl.parse_listen_address(p2p_addresses[which++]); + BOOST_CHECK_EQUAL(listen_addr, "[2001:db8:85a3:8d3:1319:8a2e:370:7348]:9876"); + BOOST_CHECK_EQUAL(block_sync_rate_limit, 250000u); + std::tie(listen_addr, block_sync_rate_limit) = plugin_impl.parse_listen_address(p2p_addresses[which++]); + BOOST_CHECK_EQUAL(listen_addr, "[::1]:9876"); + BOOST_CHECK_EQUAL(block_sync_rate_limit, 250000u); + BOOST_CHECK_EXCEPTION(plugin_impl.parse_listen_address(p2p_addresses[which++]), eosio::chain::plugin_config_exception, + [](const eosio::chain::plugin_config_exception& e) + {return std::strstr(e.top_message().c_str(), "IPv6 addresses must be enclosed in square brackets");}); + BOOST_CHECK_EXCEPTION(plugin_impl.parse_listen_address(p2p_addresses[which++]), eosio::chain::plugin_config_exception, + [](const eosio::chain::plugin_config_exception& e) + {return std::strstr(e.top_message().c_str(), "block sync rate limit must not be negative");}); + BOOST_CHECK_EXCEPTION(plugin_impl.parse_listen_address(p2p_addresses[which++]), eosio::chain::plugin_config_exception, + [](const eosio::chain::plugin_config_exception& e) + {return std::strstr(e.top_message().c_str(), "invalid block sync rate limit specification");}); + BOOST_CHECK_EXCEPTION(plugin_impl.parse_listen_address(p2p_addresses[which++]), eosio::chain::plugin_config_exception, + [](const eosio::chain::plugin_config_exception& e) + {return std::strstr(e.top_message().c_str(), "block sync rate limit specification overflowed");}); +} diff --git a/plugins/producer_plugin/include/eosio/producer_plugin/block_timing_util.hpp b/plugins/producer_plugin/include/eosio/producer_plugin/block_timing_util.hpp index b4e3741874..27ba83ff6c 100644 --- a/plugins/producer_plugin/include/eosio/producer_plugin/block_timing_util.hpp +++ b/plugins/producer_plugin/include/eosio/producer_plugin/block_timing_util.hpp @@ -42,28 +42,28 @@ namespace block_timing_util { // In the past, a producer would always start a block `config::block_interval_us` ahead of its block time. However, // it causes the last block in a block production round being released too late for the next producer to have // received it and start producing on schedule. To mitigate the problem, we leave no time gap in block producing. For - // example, given block_interval=500 ms and cpu effort=400 ms, assuming the our round start at time point 0; in the + // example, given block_interval=500 ms and cpu effort=400 ms, assuming our round starts at time point 0; in the // past, the block start time points would be at time point -500, 0, 500, 1000, 1500, 2000 .... With this new // approach, the block time points would become -500, -100, 300, 700, 1100 ... - inline fc::time_point production_round_block_start_time(uint32_t cpu_effort_us, chain::block_timestamp_type block_time) { + inline fc::time_point production_round_block_start_time(fc::microseconds cpu_effort, chain::block_timestamp_type block_time) { uint32_t block_slot = block_time.slot; uint32_t production_round_start_block_slot = (block_slot / chain::config::producer_repetitions) * chain::config::producer_repetitions; uint32_t production_round_index = block_slot % chain::config::producer_repetitions; return chain::block_timestamp_type(production_round_start_block_slot - 1).to_time_point() + - fc::microseconds(cpu_effort_us * production_round_index); + fc::microseconds(cpu_effort.count() * production_round_index); } - inline fc::time_point calculate_producing_block_deadline(uint32_t cpu_effort_us, chain::block_timestamp_type block_time) { - auto estimated_deadline = production_round_block_start_time(cpu_effort_us, block_time) + fc::microseconds(cpu_effort_us); + inline fc::time_point calculate_producing_block_deadline(fc::microseconds cpu_effort, chain::block_timestamp_type block_time) { + auto estimated_deadline = production_round_block_start_time(cpu_effort, block_time) + cpu_effort; auto now = fc::time_point::now(); if (estimated_deadline > now) { return estimated_deadline; } else { // This could only happen when the producer stop producing and then comes back alive in the middle of its own // production round. In this case, we just use the hard deadline. - const auto hard_deadline = block_time.to_time_point() - fc::microseconds(chain::config::block_interval_us - cpu_effort_us); - return std::min(hard_deadline, now + fc::microseconds(cpu_effort_us)); + const auto hard_deadline = block_time.to_time_point() - fc::microseconds(chain::config::block_interval_us - cpu_effort.count()); + return std::min(hard_deadline, now + cpu_effort); } } @@ -118,7 +118,7 @@ namespace block_timing_util { // Return the *next* block start time according to its block time slot. // Returns empty optional if no producers are in the active_schedule. // block_num is only used for watermark minimum offset. - inline std::optional calculate_producer_wake_up_time(uint32_t cpu_effort_us, uint32_t block_num, + inline std::optional calculate_producer_wake_up_time(fc::microseconds cpu_effort, uint32_t block_num, const chain::block_timestamp_type& ref_block_time, const std::set& producers, const std::vector& active_schedule, @@ -141,7 +141,7 @@ namespace block_timing_util { return {}; } - return production_round_block_start_time(cpu_effort_us, chain::block_timestamp_type(wake_up_slot)); + return production_round_block_start_time(cpu_effort, chain::block_timestamp_type(wake_up_slot)); } } // namespace block_timing_util diff --git a/plugins/producer_plugin/include/eosio/producer_plugin/producer_plugin.hpp b/plugins/producer_plugin/include/eosio/producer_plugin/producer_plugin.hpp index f102dfcf0b..495d1b91a6 100644 --- a/plugins/producer_plugin/include/eosio/producer_plugin/producer_plugin.hpp +++ b/plugins/producer_plugin/include/eosio/producer_plugin/producer_plugin.hpp @@ -17,10 +17,9 @@ class producer_plugin : public appbase::plugin { struct runtime_options { std::optional max_transaction_time; std::optional max_irreversible_block_age; - std::optional cpu_effort_us; - std::optional max_scheduled_transaction_time_per_block_ms; + // minimum time to reserve at the end of a production round for blocks to propagate to the next block producer. + std::optional produce_block_offset_ms; std::optional subjective_cpu_leeway_us; - std::optional incoming_defer_ratio; std::optional greylist_limit; }; @@ -162,7 +161,6 @@ class producer_plugin : public appbase::plugin { struct produced_block_metrics : public speculative_block_metrics { std::size_t unapplied_transactions_total = 0; - std::size_t blacklisted_transactions_total = 0; std::size_t subjective_bill_account_size_total = 0; std::size_t scheduled_trxs_total = 0; std::size_t trxs_produced_total = 0; @@ -199,7 +197,7 @@ class producer_plugin : public appbase::plugin { } //eosio -FC_REFLECT(eosio::producer_plugin::runtime_options, (max_transaction_time)(max_irreversible_block_age)(cpu_effort_us)(max_scheduled_transaction_time_per_block_ms)(subjective_cpu_leeway_us)(incoming_defer_ratio)(greylist_limit)); +FC_REFLECT(eosio::producer_plugin::runtime_options, (max_transaction_time)(max_irreversible_block_age)(produce_block_offset_ms)(subjective_cpu_leeway_us)(greylist_limit)); FC_REFLECT(eosio::producer_plugin::greylist_params, (accounts)); FC_REFLECT(eosio::producer_plugin::whitelist_blacklist, (actor_whitelist)(actor_blacklist)(contract_whitelist)(contract_blacklist)(action_blacklist)(key_blacklist) ) FC_REFLECT(eosio::producer_plugin::integrity_hash_information, (head_block_id)(integrity_hash)) diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index 757b930303..c64d9493e3 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -17,10 +17,6 @@ #include #include -#include -#include -#include -#include #include #include @@ -28,15 +24,6 @@ #include #include -namespace bmi = boost::multi_index; -using bmi::hashed_unique; -using bmi::indexed_by; -using bmi::member; -using bmi::ordered_non_unique; -using bmi::tag; - -using boost::multi_index_container; - using boost::signals2::scoped_connection; using std::string; using std::vector; @@ -108,19 +95,6 @@ bool exception_is_exhausted(const fc::exception& e) { } } // namespace -struct transaction_id_with_expiry { - transaction_id_type trx_id; - fc::time_point expiry; -}; - -struct by_id; -struct by_expiry; - -using transaction_id_with_expiry_index = multi_index_container< - transaction_id_with_expiry, - indexed_by, BOOST_MULTI_INDEX_MEMBER(transaction_id_with_expiry, transaction_id_type, trx_id)>, - ordered_non_unique, BOOST_MULTI_INDEX_MEMBER(transaction_id_with_expiry, fc::time_point, expiry)>>>; - namespace { // track multiple failures on unapplied transactions @@ -397,9 +371,8 @@ class producer_plugin_impl : public std::enable_shared_from_thischain().get_subjective_cpu_leeway() ? chain_plug->chain().get_subjective_cpu_leeway()->count() : std::optional(), - _incoming_defer_ratio, chain_plug->chain().get_greylist_limit()}; } @@ -530,15 +501,14 @@ class producer_plugin_impl : public std::enable_shared_from_this _max_transaction_time_ms; // modified by app thread, read by net_plugin thread pool std::atomic _received_block{0}; // modified by net_plugin thread pool fc::microseconds _max_irreversible_block_age_us; - int32_t _cpu_effort_us = 0; + // produce-block-offset is in terms of the complete round, internally use calculated value for each block of round + fc::microseconds _produce_block_cpu_effort; fc::time_point _pending_block_deadline; uint32_t _max_block_cpu_usage_threshold_us = 0; uint32_t _max_block_net_usage_threshold_bytes = 0; - int32_t _max_scheduled_transaction_time_per_block_ms = 0; bool _disable_subjective_p2p_billing = true; bool _disable_subjective_api_billing = true; fc::time_point _irreversible_block_time; - fc::time_point _idle_trx_time{fc::time_point::now()}; std::vector _protocol_features_to_activate; bool _protocol_features_signaled = false; // to mark whether it has been signaled in start_block @@ -550,7 +520,6 @@ class producer_plugin_impl : public std::enable_shared_from_this next); + void set_produce_block_offset(uint32_t produce_block_offset_ms) { + EOS_ASSERT(produce_block_offset_ms < (config::producer_repetitions * config::block_interval_ms), plugin_config_exception, + "produce-block-offset-ms ${p} must be [0 - ${max})", ("p", produce_block_offset_ms)("max", config::producer_repetitions * config::block_interval_ms)); + _produce_block_cpu_effort = fc::microseconds(config::block_interval_us - (produce_block_offset_ms*1000 / config::producer_repetitions) ); + } + + fc::microseconds get_produce_block_offset() const { + return fc::milliseconds( (config::block_interval_ms * config::producer_repetitions) - + ((_produce_block_cpu_effort.count() / 1000) * config::producer_repetitions) ); + } + void on_block(const block_state_ptr& bsp) { auto& chain = chain_plug->chain(); auto before = _unapplied_transactions.size(); @@ -807,12 +784,17 @@ class producer_plugin_impl : public std::enable_shared_from_this next) { + + const transaction& t = trx->get_transaction(); + EOS_ASSERT( t.delay_sec.value == 0, transaction_exception, "transaction cannot be delayed" ); + if (trx_type == transaction_metadata::trx_type::read_only) { - // Post all read only trxs to read_only queue for execution. + assert(_ro_thread_pool_size > 0); // enforced by chain_plugin + assert(app().executor().get_main_thread_id() != std::this_thread::get_id()); // should only be called from read only threads + + // Post all read only trxs to read_exclusive queue for execution. auto trx_metadata = transaction_metadata::create_no_recover_keys(trx, transaction_metadata::trx_type::read_only); - app().executor().post(priority::low, exec_queue::read_only, [this, trx{std::move(trx_metadata)}, next{std::move(next)}]() mutable { - push_read_only_transaction(std::move(trx), std::move(next)); - }); + push_read_only_transaction(std::move(trx_metadata), std::move(next)); return; } @@ -1049,8 +1031,8 @@ void producer_plugin::set_program_options( ("enable-stale-production,e", boost::program_options::bool_switch()->notifier([this](bool e){my->_production_enabled = e;}), "Enable block production, even if the chain is stale.") ("pause-on-startup,x", boost::program_options::bool_switch()->notifier([this](bool p){my->_pause_production = p;}), "Start this node in a state where production is paused") - ("max-transaction-time", bpo::value()->default_value(30), - "Limits the maximum time (in milliseconds) that is allowed a pushed transaction's code to execute before being considered invalid") + ("max-transaction-time", bpo::value()->default_value(config::block_interval_ms-1), + "Setting this value (in milliseconds) will restrict the allowed transaction execution time to a value potentially lower than the on-chain consensus max_transaction_cpu_usage value.") ("max-irreversible-block-age", bpo::value()->default_value( -1 ), "Limits the maximum age (in seconds) of the DPOS Irreversible Block for a chain this node will produce blocks on (use negative value to indicate unlimited)") ("producer-name,p", boost::program_options::value>()->composing()->multitoken(), @@ -1063,14 +1045,12 @@ void producer_plugin::set_program_options( "account that can not access to extended CPU/NET virtual resources") ("greylist-limit", boost::program_options::value()->default_value(1000), "Limit (between 1 and 1000) on the multiple that CPU/NET virtual resources can extend during low usage (only enforced subjectively; use 1000 to not enforce any limit)") - ("cpu-effort-percent", bpo::value()->default_value(config::default_block_cpu_effort_pct / config::percent_1), - "Percentage of cpu block production time used to produce block. Whole number percentages, e.g. 80 for 80%") + ("produce-block-offset-ms", bpo::value()->default_value(config::default_produce_block_offset_ms), + "The minimum time to reserve at the end of a production round for blocks to propagate to the next block producer.") ("max-block-cpu-usage-threshold-us", bpo::value()->default_value( 5000 ), "Threshold of CPU block production to consider block full; when within threshold of max-block-cpu-usage block can be produced immediately") ("max-block-net-usage-threshold-bytes", bpo::value()->default_value( 1024 ), "Threshold of NET block production to consider block full; when within threshold of max-block-net-usage block can be produced immediately") - ("max-scheduled-transaction-time-per-block-ms", boost::program_options::value()->default_value(100), - "Maximum wall-clock time, in milliseconds, spent retiring scheduled transactions (and incoming transactions according to incoming-defer-ratio) in any block before returning to normal transaction processing.") ("subjective-cpu-leeway-us", boost::program_options::value()->default_value( config::default_subjective_cpu_leeway_us ), "Time in microseconds allowed for a transaction that starts with insufficient CPU quota to complete and cover its CPU usage.") ("subjective-account-max-failures", boost::program_options::value()->default_value(3), @@ -1079,8 +1059,6 @@ void producer_plugin::set_program_options( "Sets the window size in number of blocks for subjective-account-max-failures.") ("subjective-account-decay-time-minutes", bpo::value()->default_value( config::account_cpu_usage_average_window_ms / 1000 / 60 ), "Sets the time to return full subjective cpu for accounts") - ("incoming-defer-ratio", bpo::value()->default_value(1.0), - "ratio between incoming transactions and deferred transactions when both are queued for execution") ("incoming-transaction-queue-size-mb", bpo::value()->default_value( 1024 ), "Maximum size (in MiB) of the incoming transaction queue. Exceeding this value will subjectively drop transaction with resource exhaustion.") ("disable-subjective-account-billing", boost::program_options::value>()->composing()->multitoken(), @@ -1168,12 +1146,7 @@ void producer_plugin_impl::plugin_initialize(const boost::program_options::varia _account_fails.set_max_failures_per_account(options.at("subjective-account-max-failures").as(), subjective_account_max_failures_window_size); - uint32_t cpu_effort_pct = options.at("cpu-effort-percent").as(); - EOS_ASSERT(cpu_effort_pct >= 0 && cpu_effort_pct <= 100, plugin_config_exception, - "cpu-effort-percent ${pct} must be 0 - 100", ("pct", cpu_effort_pct)); - cpu_effort_pct *= config::percent_1; - - _cpu_effort_us = EOS_PERCENT(config::block_interval_us, cpu_effort_pct); + set_produce_block_offset(options.at("produce-block-offset-ms").as()); _max_block_cpu_usage_threshold_us = options.at("max-block-cpu-usage-threshold-us").as(); EOS_ASSERT(_max_block_cpu_usage_threshold_us < config::block_interval_us, @@ -1183,8 +1156,6 @@ void producer_plugin_impl::plugin_initialize(const boost::program_options::varia _max_block_net_usage_threshold_bytes = options.at("max-block-net-usage-threshold-bytes").as(); - _max_scheduled_transaction_time_per_block_ms = options.at("max-scheduled-transaction-time-per-block-ms").as(); - if (options.at("subjective-cpu-leeway-us").as() != config::default_subjective_cpu_leeway_us) { chain.set_subjective_cpu_leeway(fc::microseconds(options.at("subjective-cpu-leeway-us").as())); } @@ -1207,8 +1178,6 @@ void producer_plugin_impl::plugin_initialize(const boost::program_options::varia _unapplied_transactions.set_max_transaction_queue_size(max_incoming_transaction_queue_size); - _incoming_defer_ratio = options.at("incoming-defer-ratio").as(); - _disable_subjective_p2p_billing = options.at("disable-subjective-p2p-billing").as(); _disable_subjective_api_billing = options.at("disable-subjective-api-billing").as(); dlog("disable-subjective-p2p-billing: ${p2p}, disable-subjective-api-billing: ${api}", @@ -1280,28 +1249,26 @@ void producer_plugin_impl::plugin_initialize(const boost::program_options::varia ("read", _ro_read_window_time_us)("min", _ro_read_window_minimum_time_us)); _ro_read_window_effective_time_us = _ro_read_window_time_us - _ro_read_window_minimum_time_us; - // Make sure a read-only transaction can finish within the read - // window if scheduled at the very beginning of the window. - // Add _ro_read_window_minimum_time_us for safety margin. - if (_max_transaction_time_ms.load() > 0) { - EOS_ASSERT( - _ro_read_window_time_us > (fc::milliseconds(_max_transaction_time_ms.load()) + _ro_read_window_minimum_time_us), - plugin_config_exception, - "read-only-read-window-time-us (${read} us) must be greater than max-transaction-time (${trx_time} us) " - "plus ${min} us, required: ${read} us > (${trx_time} us + ${min} us).", - ("read", _ro_read_window_time_us)("trx_time", _max_transaction_time_ms.load() * 1000)("min", _ro_read_window_minimum_time_us)); - } ilog("read-only-write-window-time-us: ${ww} us, read-only-read-window-time-us: ${rw} us, effective read window time to be used: ${w} us", ("ww", _ro_write_window_time_us)("rw", _ro_read_window_time_us)("w", _ro_read_window_effective_time_us)); } + app().executor().init_read_threads(_ro_thread_pool_size); - // Make sure _ro_max_trx_time_us is alwasys set. + // Make sure _ro_max_trx_time_us is always set. + // Make sure a read-only transaction can finish within the read + // window if scheduled at the very beginning of the window. + // Add _ro_read_window_minimum_time_us for safety margin. if (_max_transaction_time_ms.load() > 0) { _ro_max_trx_time_us = fc::milliseconds(_max_transaction_time_ms.load()); } else { // max-transaction-time can be set to negative for unlimited time _ro_max_trx_time_us = fc::microseconds::maximum(); } + if (_ro_max_trx_time_us > _ro_read_window_effective_time_us) { + _ro_max_trx_time_us = _ro_read_window_effective_time_us; + } + ilog("Read-only max transaction time ${rot}us set to fit in the effective read-only window ${row}us.", + ("rot", _ro_max_trx_time_us)("row", _ro_read_window_effective_time_us)); ilog("read-only-threads ${s}, max read-only trx time to be enforced: ${t} us", ("s", _ro_thread_pool_size)("t", _ro_max_trx_time_us)); _incoming_block_sync_provider = app().get_method().register_provider( @@ -1440,6 +1407,9 @@ void producer_plugin::plugin_startup() { void producer_plugin_impl::plugin_shutdown() { boost::system::error_code ec; _timer.cancel(ec); + _ro_timer.cancel(ec); + app().executor().stop(); + _ro_thread_pool.stop(); _thread_pool.stop(); _unapplied_transactions.clear(); @@ -1489,16 +1459,8 @@ void producer_plugin_impl::update_runtime_options(const producer_plugin::runtime check_speculating = true; } - if (options.cpu_effort_us) { - _cpu_effort_us = *options.cpu_effort_us; - } - - if (options.max_scheduled_transaction_time_per_block_ms) { - _max_scheduled_transaction_time_per_block_ms = *options.max_scheduled_transaction_time_per_block_ms; - } - - if (options.incoming_defer_ratio) { - _incoming_defer_ratio = *options.incoming_defer_ratio; + if (options.produce_block_offset_ms) { + set_produce_block_offset(*options.produce_block_offset_ms); } if (check_speculating && in_speculating_mode()) { @@ -1881,7 +1843,7 @@ producer_plugin_impl::start_block_result producer_plugin_impl::start_block() { } // create speculative blocks at regular intervals, so we create blocks with "current" block time - _pending_block_deadline = now + fc::microseconds(config::block_interval_us); + _pending_block_deadline = block_timing_util::calculate_producing_block_deadline(_produce_block_cpu_effort, block_time); if (in_producing_mode()) { uint32_t production_round_index = block_timestamp_type(block_time).slot % chain::config::producer_repetitions; if (production_round_index == 0) { @@ -1893,15 +1855,6 @@ producer_plugin_impl::start_block_result producer_plugin_impl::start_block() { return start_block_result::waiting_for_production; } } - - _pending_block_deadline = block_timing_util::calculate_producing_block_deadline(_cpu_effort_us, block_time); - } else if (!_producers.empty()) { - // cpu effort percent doesn't matter for the first block of the round, use max (block_interval_us) for cpu effort - auto wake_time = block_timing_util::calculate_producer_wake_up_time(config::block_interval_us, chain.head_block_num(), chain.head_block_time(), - _producers, chain.head_block_state()->active_schedule.producers, - _producer_watermarks); - if (wake_time) - _pending_block_deadline = std::min(*wake_time, _pending_block_deadline); } const auto& preprocess_deadline = _pending_block_deadline; @@ -1993,8 +1946,6 @@ producer_plugin_impl::start_block_result producer_plugin_impl::start_block() { if (!remove_expired_trxs(preprocess_deadline)) return start_block_result::exhausted; - if (!remove_expired_blacklisted_trxs(preprocess_deadline)) - return start_block_result::exhausted; if (!subjective_bill.remove_expired(_log, chain.pending_block_time(), fc::time_point::now(), [&]() { return should_interrupt_start_block(preprocess_deadline, pending_block_num); })) { @@ -2008,14 +1959,15 @@ producer_plugin_impl::start_block_result producer_plugin_impl::start_block() { if (!process_unapplied_trxs(preprocess_deadline)) return start_block_result::exhausted; - - auto scheduled_trx_deadline = preprocess_deadline; - if (_max_scheduled_transaction_time_per_block_ms >= 0) { - scheduled_trx_deadline = std::min( - scheduled_trx_deadline, fc::time_point::now() + fc::milliseconds(_max_scheduled_transaction_time_per_block_ms)); + // after DISABLE_DEFERRED_TRXS_STAGE_2 is activated, + // no deferred trxs are allowed to be retired + if (!chain.is_builtin_activated( builtin_protocol_feature_t::disable_deferred_trxs_stage_2) ) { + // Hard-code the deadline to retire expired deferred trxs to 10ms + auto deferred_trxs_deadline = std::min(preprocess_deadline, fc::time_point::now() + fc::milliseconds(10)); + if (!retire_deferred_trxs(deferred_trxs_deadline)) { + return start_block_result::failed; + } } - // may exhaust scheduled_trx_deadline but not preprocess_deadline, exhausted preprocess_deadline checked below - process_scheduled_and_incoming_trxs(scheduled_trx_deadline, incoming_itr); } repost_exhausted_transactions(preprocess_deadline); @@ -2061,8 +2013,8 @@ bool producer_plugin_impl::remove_expired_trxs(const fc::time_point& deadline) { }); if (exhausted && in_producing_mode()) { - fc_wlog(_log, "Unable to process all expired transactions of the ${n} transactions in the unapplied queue before deadline, " - "Expired ${expired}", ("n", orig_count)("expired", num_expired)); + fc_wlog(_log, "Unable to process all expired transactions of the ${n} transactions in the unapplied queue before deadline ${d}, " + "Expired ${expired}", ("n", orig_count)("d", deadline)("expired", num_expired)); } else { fc_dlog(_log, "Processed ${ex} expired transactions of the ${n} transactions in the unapplied queue.", ("n", orig_count)("ex", num_expired)); } @@ -2070,31 +2022,6 @@ bool producer_plugin_impl::remove_expired_trxs(const fc::time_point& deadline) { return !exhausted; } -bool producer_plugin_impl::remove_expired_blacklisted_trxs(const fc::time_point& deadline) { - bool exhausted = false; - auto& blacklist_by_expiry = _blacklisted_transactions.get(); - if (!blacklist_by_expiry.empty()) { - const chain::controller& chain = chain_plug->chain(); - const auto lib_time = chain.last_irreversible_block_time(); - const auto pending_block_num = chain.pending_block_num(); - - int num_expired = 0; - int orig_count = _blacklisted_transactions.size(); - - while (!blacklist_by_expiry.empty() && blacklist_by_expiry.begin()->expiry <= lib_time) { - if (should_interrupt_start_block(deadline, pending_block_num)) { - exhausted = true; - break; - } - blacklist_by_expiry.erase(blacklist_by_expiry.begin()); - num_expired++; - } - - fc_dlog(_log, "Processed ${n} blacklisted transactions, Expired ${expired}", ("n", orig_count)("expired", num_expired)); - } - return !exhausted; -} - // Returns contract name, action name, and exception text of an exception that occurred in a contract inline std::string get_detailed_contract_except_info(const packed_transaction_ptr& trx, const transaction_trace_ptr& trace, @@ -2383,78 +2310,37 @@ bool producer_plugin_impl::process_unapplied_trxs(const fc::time_point& deadline return !exhausted; } -void producer_plugin_impl::process_scheduled_and_incoming_trxs(const fc::time_point& deadline, unapplied_transaction_queue::iterator& itr) { - // scheduled transactions - int num_applied = 0; - int num_failed = 0; - int num_processed = 0; - bool exhausted = false; - double incoming_trx_weight = 0.0; +bool producer_plugin_impl::retire_deferred_trxs(const fc::time_point& deadline) { + int num_applied = 0; + int num_failed = 0; + int num_processed = 0; + bool exhausted = false; - auto& blacklist_by_id = _blacklisted_transactions.get(); chain::controller& chain = chain_plug->chain(); time_point pending_block_time = chain.pending_block_time(); - auto end = _unapplied_transactions.incoming_end(); - const auto& sch_idx = chain.db().get_index(); - const auto scheduled_trxs_size = sch_idx.size(); - auto sch_itr = sch_idx.begin(); - while (sch_itr != sch_idx.end()) { - if (sch_itr->delay_until > pending_block_time) - break; // not scheduled yet - if (exhausted || deadline <= fc::time_point::now()) { - exhausted = true; + const auto& expired_idx = chain.db().get_index(); + const auto expired_size = expired_idx.size(); + auto expired_itr = expired_idx.begin(); + bool stage_1_activated = chain.is_builtin_activated( builtin_protocol_feature_t::disable_deferred_trxs_stage_1); + + while (expired_itr != expired_idx.end()) { + // * Before disable_deferred_trxs_stage_1 is activated, retire only expired deferred trxs. + // * After disable_deferred_trxs_stage_1, retire any deferred trxs in any order + if (!stage_1_activated && expired_itr->expiration >= pending_block_time) { // before stage_1 and not expired yet break; } - if (sch_itr->published >= pending_block_time) { - ++sch_itr; - continue; // do not allow schedule and execute in same block - } - - if (blacklist_by_id.find(sch_itr->trx_id) != blacklist_by_id.end()) { - ++sch_itr; - continue; - } - - const transaction_id_type trx_id = sch_itr->trx_id; // make copy since reference could be invalidated - const auto sch_expiration = sch_itr->expiration; - auto sch_itr_next = sch_itr; // save off next since sch_itr may be invalidated by loop - ++sch_itr_next; - const auto next_delay_until = sch_itr_next != sch_idx.end() ? sch_itr_next->delay_until : sch_itr->delay_until; - const auto next_id = sch_itr_next != sch_idx.end() ? sch_itr_next->id : sch_itr->id; - - num_processed++; - - // configurable ratio of incoming txns vs deferred txns - while (incoming_trx_weight >= 1.0 && itr != end) { - if (deadline <= fc::time_point::now()) { - exhausted = true; - break; - } - - incoming_trx_weight -= 1.0; - - auto trx_meta = itr->trx_meta; - bool api_trx = itr->trx_type == trx_enum_type::incoming_api; - - auto trx_tracker = _time_tracker.start_trx(trx_meta->is_transient()); - push_result pr = push_transaction(deadline, trx_meta, api_trx, itr->return_failure_trace, trx_tracker, itr->next); - - exhausted = pr.block_exhausted; - if (pr.trx_exhausted) { - ++itr; // leave in incoming - } else { - itr = _unapplied_transactions.erase(itr); - } - - if (exhausted) - break; - } if (exhausted || deadline <= fc::time_point::now()) { exhausted = true; break; } + const transaction_id_type trx_id = expired_itr->trx_id; // make copy since reference could be invalidated + auto expired_itr_next = expired_itr; // save off next since expired_itr may be invalidated by loop + ++expired_itr_next; + + num_processed++; + auto get_first_authorizer = [&](const transaction_trace_ptr& trace) { for (const auto& a : trace->action_traces) { for (const auto& u : a.act.authorization) @@ -2466,9 +2352,7 @@ void producer_plugin_impl::process_scheduled_and_incoming_trxs(const fc::time_po try { auto start = fc::time_point::now(); auto trx_tracker = _time_tracker.start_trx(false, start); // delayed transaction cannot be transient - fc::microseconds max_trx_time = fc::milliseconds(_max_transaction_time_ms.load()); - if (max_trx_time.count() < 0) - max_trx_time = fc::microseconds::maximum(); + fc::microseconds max_trx_time = fc::microseconds::maximum(); // hard-coded as it is not used in push_scheduled_transaction when trx expired. auto trace = chain.push_scheduled_transaction(trx_id, deadline, max_trx_time, 0, false); auto end = fc::time_point::now(); @@ -2487,8 +2371,6 @@ void producer_plugin_impl::process_scheduled_and_incoming_trxs(const fc::time_po "[TRX_TRACE] Block ${block_num} for producer ${prod} is REJECTING scheduled tx: ${entire_trace}", ("block_num", chain.head_block_num() + 1)("prod", get_pending_block_producer()) ("entire_trace", chain_plug->get_log_trx_trace(trace))); - // this failed our configured maximum transaction time, we don't want to replay it add it to a blacklist - _blacklisted_transactions.insert(transaction_id_with_expiry{trx_id, sch_expiration}); num_failed++; } } else { @@ -2506,17 +2388,20 @@ void producer_plugin_impl::process_scheduled_and_incoming_trxs(const fc::time_po } LOG_AND_DROP(); - incoming_trx_weight += _incoming_defer_ratio; - - if (sch_itr_next == sch_idx.end()) + if (expired_itr_next == expired_idx.end()) break; - sch_itr = sch_idx.lower_bound(boost::make_tuple(next_delay_until, next_id)); + expired_itr = expired_itr_next; } - if (scheduled_trxs_size > 0) { + if (expired_size > 0) { fc_dlog(_log, "Processed ${m} of ${n} scheduled transactions, Applied ${applied}, Failed/Dropped ${failed}", - ("m", num_processed)("n", scheduled_trxs_size)("applied", num_applied)("failed", num_failed)); + ("m", num_processed)("n", expired_size)("applied", num_applied)("failed", num_failed)); } + + if (stage_1_activated && num_failed > 0) { + return false; + } + return true; } bool producer_plugin_impl::process_incoming_trxs(const fc::time_point& deadline, unapplied_transaction_queue::iterator& itr) { @@ -2597,7 +2482,7 @@ void producer_plugin_impl::schedule_production_loop() { if (!_producers.empty() && !production_disabled_by_policy()) { chain::controller& chain = chain_plug->chain(); fc_dlog(_log, "Waiting till another block is received and scheduling Speculative/Production Change"); - auto wake_time = block_timing_util::calculate_producer_wake_up_time(_cpu_effort_us, chain.head_block_num(), calculate_pending_block_time(), + auto wake_time = block_timing_util::calculate_producer_wake_up_time(_produce_block_cpu_effort, chain.head_block_num(), calculate_pending_block_time(), _producers, chain.head_block_state()->active_schedule.producers, _producer_watermarks); schedule_delayed_production_loop(weak_from_this(), wake_time); @@ -2616,7 +2501,7 @@ void producer_plugin_impl::schedule_production_loop() { chain::controller& chain = chain_plug->chain(); fc_dlog(_log, "Speculative Block Created; Scheduling Speculative/Production Change"); EOS_ASSERT(chain.is_building_block(), missing_pending_block_state, "speculating without pending_block_state"); - auto wake_time = block_timing_util::calculate_producer_wake_up_time(_cpu_effort_us, chain.pending_block_num(), chain.pending_block_timestamp(), + auto wake_time = block_timing_util::calculate_producer_wake_up_time(_produce_block_cpu_effort, chain.pending_block_num(), chain.pending_block_timestamp(), _producers, chain.head_block_state()->active_schedule.producers, _producer_watermarks); schedule_delayed_production_loop(weak_from_this(), wake_time); @@ -2633,7 +2518,7 @@ void producer_plugin_impl::schedule_maybe_produce_block(bool exhausted) { assert(in_producing_mode()); // we succeeded but block may be exhausted static const boost::posix_time::ptime epoch(boost::gregorian::date(1970, 1, 1)); - auto deadline = block_timing_util::calculate_producing_block_deadline(_cpu_effort_us, chain.pending_block_time()); + auto deadline = block_timing_util::calculate_producing_block_deadline(_produce_block_cpu_effort, chain.pending_block_time()); if (!exhausted && deadline > fc::time_point::now()) { // ship this block off no later than its deadline @@ -2774,7 +2659,6 @@ void producer_plugin_impl::produce_block() { if (_update_produced_block_metrics) { metrics.unapplied_transactions_total = _unapplied_transactions.size(); - metrics.blacklisted_transactions_total = _blacklisted_transactions.size(); metrics.subjective_bill_account_size_total = chain.get_subjective_billing().get_account_cache_size(); metrics.scheduled_trxs_total = chain.db().get_index().size(); metrics.trxs_produced_total = new_bs->block->transactions.size(); @@ -2804,11 +2688,8 @@ void producer_plugin::log_failed_transaction(const transaction_id_type& trx_i // Called from only one read_only thread void producer_plugin_impl::switch_to_write_window() { - if (_log.is_enabled(fc::log_level::debug)) { - auto now = fc::time_point::now(); - fc_dlog(_log, "Read-only threads ${n}, read window ${r}us, total all threads ${t}us", - ("n", _ro_thread_pool_size)("r", now - _ro_read_window_start_time)("t", _ro_all_threads_exec_time_us.load())); - } + fc_dlog(_log, "Read-only threads ${n}, read window ${r}us, total all threads ${t}us", + ("n", _ro_thread_pool_size)("r", fc::time_point::now() - _ro_read_window_start_time)("t", _ro_all_threads_exec_time_us.load())); chain::controller& chain = chain_plug->chain(); @@ -2858,16 +2739,18 @@ void producer_plugin_impl::switch_to_read_window() { _time_tracker.pause(); // we are in write window, so no read-only trx threads are processing transactions. - if (app().executor().read_only_queue().empty()) { // no read-only tasks to process. stay in write window + app().get_io_service().poll(); // make sure we schedule any ready + if (app().executor().read_only_queue_empty() && app().executor().read_exclusive_queue_empty()) { // no read-only tasks to process. stay in write window start_write_window(); // restart write window timer for next round return; } + fc_dlog(_log, "Read only queue size ${s1}, read exclusive size ${s2}", + ("s1", app().executor().read_only_queue_size())("s2", app().executor().read_exclusive_queue_size())); uint32_t pending_block_num = chain.head_block_num() + 1; _ro_read_window_start_time = fc::time_point::now(); _ro_window_deadline = _ro_read_window_start_time + _ro_read_window_effective_time_us; - app().executor().set_to_read_window( - _ro_thread_pool_size, [received_block = &_received_block, pending_block_num, ro_window_deadline = _ro_window_deadline]() { + app().executor().set_to_read_window([received_block = &_received_block, pending_block_num, ro_window_deadline = _ro_window_deadline]() { return fc::time_point::now() >= ro_window_deadline || (received_block->load() >= pending_block_num); // should_exit() }); chain.set_to_read_window(); @@ -2909,7 +2792,7 @@ bool producer_plugin_impl::read_only_execution_task(uint32_t pending_block_num) // 2. net_plugin receives a block // 3. no read-only tasks to execute while (fc::time_point::now() < _ro_window_deadline && _received_block < pending_block_num) { - bool more = app().executor().execute_highest_read_only(); // blocks until all read only threads are idle + bool more = app().executor().execute_highest_read(); // blocks until all read only threads are idle if (!more) { break; } @@ -2923,10 +2806,10 @@ bool producer_plugin_impl::read_only_execution_task(uint32_t pending_block_num) // will be executed from the main app thread because all read-only threads are idle now self->switch_to_write_window(); }); - // last thread post any exhausted back into read_only queue with slightly higher priority (low+1) so they are executed first + // last thread post any exhausted back into read_exclusive queue with slightly higher priority (low+1) so they are executed first ro_trx_t t; while (_ro_exhausted_trx_queue.pop_front(t)) { - app().executor().post(priority::low + 1, exec_queue::read_only, [this, trx{std::move(t.trx)}, next{std::move(t.next)}]() mutable { + app().executor().post(priority::low + 1, exec_queue::read_exclusive, [this, trx{std::move(t.trx)}, next{std::move(t.next)}]() mutable { push_read_only_transaction(std::move(trx), std::move(next)); }); } @@ -2941,10 +2824,10 @@ void producer_plugin_impl::repost_exhausted_transactions(const fc::time_point& d if (!_ro_exhausted_trx_queue.empty()) { chain::controller& chain = chain_plug->chain(); uint32_t pending_block_num = chain.pending_block_num(); - // post any exhausted back into read_only queue with slightly higher priority (low+1) so they are executed first + // post any exhausted back into read_exclusive queue with slightly higher priority (low+1) so they are executed first ro_trx_t t; while (!should_interrupt_start_block(deadline, pending_block_num) && _ro_exhausted_trx_queue.pop_front(t)) { - app().executor().post(priority::low + 1, exec_queue::read_only, [this, trx{std::move(t.trx)}, next{std::move(t.next)}]() mutable { + app().executor().post(priority::low + 1, exec_queue::read_exclusive, [this, trx{std::move(t.trx)}, next{std::move(t.next)}]() mutable { push_read_only_transaction(std::move(trx), std::move(next)); }); } @@ -2964,21 +2847,10 @@ bool producer_plugin_impl::push_read_only_transaction(transaction_metadata_ptr t return true; } - // When executing a read-only trx on the main thread while in the write window, - // need to switch db mode to read only. - auto db_read_only_mode_guard = fc::make_scoped_exit([&] { - if (chain.is_write_window()) - chain.unset_db_read_only_mode(); - }); + assert(!chain.is_write_window()); - std::optional trx_tracker; - if ( chain.is_write_window() ) { - chain.set_db_read_only_mode(); - trx_tracker.emplace(_time_tracker.start_trx(true, start)); - } - - // use read-window/write-window deadline if there are read/write windows, otherwise use block_deadline if only the app thead - auto window_deadline = (_ro_thread_pool_size != 0) ? _ro_window_deadline : _pending_block_deadline; + // use read-window/write-window deadline + auto window_deadline = _ro_window_deadline; // Ensure the trx to finish by the end of read-window or write-window or block_deadline depending on auto trace = chain.push_transaction(trx, window_deadline, _ro_max_trx_time_us, 0, false, 0); @@ -2996,9 +2868,6 @@ bool producer_plugin_impl::push_read_only_transaction(transaction_metadata_ptr t _ro_exhausted_trx_queue.push_front({std::move(trx), std::move(next)}); } - if ( chain.is_write_window() && !pr.failed ) { - trx_tracker->trx_success(); - } } catch (const guard_exception& e) { chain_plugin::handle_guard_exception(e); } catch (boost::interprocess::bad_alloc&) { diff --git a/plugins/producer_plugin/test/CMakeLists.txt b/plugins/producer_plugin/test/CMakeLists.txt index 42c42596f8..877ffd9f11 100644 --- a/plugins/producer_plugin/test/CMakeLists.txt +++ b/plugins/producer_plugin/test/CMakeLists.txt @@ -2,7 +2,8 @@ add_executable( test_producer_plugin test_trx_full.cpp test_options.cpp test_block_timing_util.cpp + test_disallow_delayed_trx.cpp main.cpp ) target_link_libraries( test_producer_plugin producer_plugin eosio_testing eosio_chain_wrap ) -add_test(NAME test_producer_plugin COMMAND plugins/producer_plugin/test/test_producer_plugin WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) \ No newline at end of file +add_test(NAME test_producer_plugin COMMAND plugins/producer_plugin/test/test_producer_plugin WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) diff --git a/plugins/producer_plugin/test/test_block_timing_util.cpp b/plugins/producer_plugin/test/test_block_timing_util.cpp index efb045b477..a3a43452e8 100644 --- a/plugins/producer_plugin/test/test_block_timing_util.cpp +++ b/plugins/producer_plugin/test/test_block_timing_util.cpp @@ -25,7 +25,7 @@ BOOST_AUTO_TEST_CASE(test_production_round_block_start_time) { for (int i = 0; i < eosio::chain::config::producer_repetitions; ++i, expected_start_time = expected_start_time + cpu_effort) { auto block_time = eosio::chain::block_timestamp_type(production_round_1st_block_slot + i); - BOOST_CHECK_EQUAL(eosio::block_timing_util::production_round_block_start_time(cpu_effort_us, block_time), expected_start_time); + BOOST_CHECK_EQUAL(eosio::block_timing_util::production_round_block_start_time(cpu_effort, block_time), expected_start_time); } } @@ -43,7 +43,7 @@ BOOST_AUTO_TEST_CASE(test_calculate_block_deadline) { for (int i = 0; i < eosio::chain::config::producer_repetitions; ++i) { auto block_time = eosio::chain::block_timestamp_type(production_round_1st_block_slot + i); auto expected_deadline = block_time.to_time_point() - fc::milliseconds((i + 1) * 100); - BOOST_CHECK_EQUAL(calculate_producing_block_deadline(cpu_effort_us, block_time), + BOOST_CHECK_EQUAL(calculate_producing_block_deadline(cpu_effort, block_time), expected_deadline); fc::mock_time_traits::set_now(expected_deadline); } @@ -56,18 +56,18 @@ BOOST_AUTO_TEST_CASE(test_calculate_block_deadline) { auto second_block_time = eosio::chain::block_timestamp_type(production_round_1st_block_slot + 1); fc::mock_time_traits::set_now(second_block_time.to_time_point() - fc::milliseconds(200)); auto second_block_hard_deadline = second_block_time.to_time_point() - fc::milliseconds(100); - BOOST_CHECK_EQUAL(calculate_producing_block_deadline(cpu_effort_us, second_block_time), + BOOST_CHECK_EQUAL(calculate_producing_block_deadline(cpu_effort, second_block_time), second_block_hard_deadline); // use previous deadline as now fc::mock_time_traits::set_now(second_block_hard_deadline); auto third_block_time = eosio::chain::block_timestamp_type(production_round_1st_block_slot + 2); - BOOST_CHECK_EQUAL(calculate_producing_block_deadline(cpu_effort_us, third_block_time), + BOOST_CHECK_EQUAL(calculate_producing_block_deadline(cpu_effort, third_block_time), third_block_time.to_time_point() - fc::milliseconds(300)); // use previous deadline as now fc::mock_time_traits::set_now(third_block_time.to_time_point() - fc::milliseconds(300)); auto forth_block_time = eosio::chain::block_timestamp_type(production_round_1st_block_slot + 3); - BOOST_CHECK_EQUAL(calculate_producing_block_deadline(cpu_effort_us, forth_block_time), + BOOST_CHECK_EQUAL(calculate_producing_block_deadline(cpu_effort, forth_block_time), forth_block_time.to_time_point() - fc::milliseconds(400)); /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -75,21 +75,21 @@ BOOST_AUTO_TEST_CASE(test_calculate_block_deadline) { auto seventh_block_time = eosio::chain::block_timestamp_type(production_round_1st_block_slot + 6); fc::mock_time_traits::set_now(seventh_block_time.to_time_point() - fc::milliseconds(500)); - BOOST_CHECK_EQUAL(calculate_producing_block_deadline(cpu_effort_us, seventh_block_time), + BOOST_CHECK_EQUAL(calculate_producing_block_deadline(cpu_effort, seventh_block_time), seventh_block_time.to_time_point() - fc::milliseconds(100)); // use previous deadline as now fc::mock_time_traits::set_now(seventh_block_time.to_time_point() - fc::milliseconds(100)); auto eighth_block_time = eosio::chain::block_timestamp_type(production_round_1st_block_slot + 7); - BOOST_CHECK_EQUAL(calculate_producing_block_deadline(cpu_effort_us, eighth_block_time), + BOOST_CHECK_EQUAL(calculate_producing_block_deadline(cpu_effort, eighth_block_time), eighth_block_time.to_time_point() - fc::milliseconds(200)); // use previous deadline as now fc::mock_time_traits::set_now(eighth_block_time.to_time_point() - fc::milliseconds(200)); auto ninth_block_time = eosio::chain::block_timestamp_type(production_round_1st_block_slot + 8); - BOOST_CHECK_EQUAL(calculate_producing_block_deadline(cpu_effort_us, ninth_block_time), + BOOST_CHECK_EQUAL(calculate_producing_block_deadline(cpu_effort, ninth_block_time), ninth_block_time.to_time_point() - fc::milliseconds(300)); } } @@ -102,7 +102,7 @@ BOOST_AUTO_TEST_CASE(test_calculate_producer_wake_up_time) { producer_watermarks empty_watermarks; // use full cpu effort for most of these tests since calculate_producing_block_deadline is tested above - constexpr uint32_t full_cpu_effort = eosio::chain::config::block_interval_us; + constexpr fc::microseconds full_cpu_effort = fc::microseconds{eosio::chain::config::block_interval_us}; { // no producers BOOST_CHECK_EQUAL(calculate_producer_wake_up_time(full_cpu_effort, 2, chain::block_timestamp_type{}, {}, {}, empty_watermarks), std::optional{}); @@ -206,7 +206,7 @@ BOOST_AUTO_TEST_CASE(test_calculate_producer_wake_up_time) { BOOST_CHECK_EQUAL(calculate_producer_wake_up_time(full_cpu_effort, 2, block_timestamp, producers, active_schedule, empty_watermarks), expected_block_time); // cpu_effort at 50%, initc - constexpr uint32_t half_cpu_effort = eosio::chain::config::block_interval_us / 2u; + constexpr fc::microseconds half_cpu_effort = fc::microseconds{eosio::chain::config::block_interval_us / 2u}; producers = std::set{ "initc"_n }; block_timestamp = block_timestamp_type(prod_round_1st_block_slot); expected_block_time = block_timestamp_type(prod_round_1st_block_slot + 2*config::producer_repetitions).to_time_point(); @@ -221,7 +221,7 @@ BOOST_AUTO_TEST_CASE(test_calculate_producer_wake_up_time) { block_timestamp = block_timestamp_type(prod_round_1st_block_slot + 2*config::producer_repetitions + 2); // second in round is 50% sooner expected_block_time = block_timestamp.to_time_point(); - expected_block_time -= fc::microseconds(2*half_cpu_effort); + expected_block_time -= fc::microseconds(2*half_cpu_effort.count()); BOOST_CHECK_EQUAL(calculate_producer_wake_up_time(half_cpu_effort, 2, block_timestamp, producers, active_schedule, empty_watermarks), expected_block_time); } { // test watermark diff --git a/plugins/producer_plugin/test/test_disallow_delayed_trx.cpp b/plugins/producer_plugin/test/test_disallow_delayed_trx.cpp new file mode 100644 index 0000000000..3723970ffc --- /dev/null +++ b/plugins/producer_plugin/test/test_disallow_delayed_trx.cpp @@ -0,0 +1,101 @@ +#include +#include +#include + +namespace eosio::test::detail { +using namespace eosio::chain::literals; +struct testit { + uint64_t id; + + testit( uint64_t id = 0 ) :id(id){} + + static account_name get_account() { + return chain::config::system_account_name; + } + + static action_name get_name() { + return "testit"_n; + } +}; +} +FC_REFLECT( eosio::test::detail::testit, (id) ) + +namespace { + +using namespace eosio; +using namespace eosio::chain; +using namespace eosio::test::detail; + +auto make_delayed_trx( const chain_id_type& chain_id ) { + account_name creator = config::system_account_name; + + signed_transaction trx; + trx.actions.emplace_back( vector{{creator, config::active_name}}, testit{0} ); + trx.delay_sec = 10; + auto priv_key = private_key_type::regenerate(fc::sha256::hash(std::string("nathan"))); + trx.sign( priv_key, chain_id ); + + return std::make_shared( std::move(trx) ); +} +} + +BOOST_AUTO_TEST_SUITE(disallow_delayed_trx_test) + +// Verifies that incoming delayed transactions are blocked. +BOOST_AUTO_TEST_CASE(delayed_trx) { + using namespace std::chrono_literals; + fc::temp_directory temp; + appbase::scoped_app app; + auto temp_dir_str = temp.path().string(); + + std::promise> plugin_promise; + std::future> plugin_fut = plugin_promise.get_future(); + std::thread app_thread( [&]() { + try { + fc::logger::get(DEFAULT_LOGGER).set_log_level(fc::log_level::debug); + std::vector argv = + {"test", "--data-dir", temp_dir_str.c_str(), "--config-dir", temp_dir_str.c_str(), + "-p", "eosio", "-e", "--disable-subjective-p2p-billing=true" }; + app->initialize( argv.size(), (char**) &argv[0] ); + app->startup(); + plugin_promise.set_value( + {app->find_plugin(), app->find_plugin()} ); + app->exec(); + return; + } FC_LOG_AND_DROP() + BOOST_CHECK(!"app threw exception see logged error"); + } ); + + auto[prod_plug, chain_plug] = plugin_fut.get(); + auto chain_id = chain_plug->get_chain_id(); + + // create a delayed trx + auto ptrx = make_delayed_trx( chain_id ); + + // send it as incoming trx + app->post( priority::low, [ptrx, &app]() { + bool return_failure_traces = true; + + // the delayed trx is blocked + BOOST_REQUIRE_EXCEPTION( + app->get_method()(ptrx, + false, + transaction_metadata::trx_type::input, + return_failure_traces, + [ptrx] (const next_function_variant& result) { + elog( "trace with except ${e}", ("e", fc::json::to_pretty_string( *std::get( result ) )) ); + } + ), + fc::exception, + eosio::testing::fc_exception_message_starts_with("transaction cannot be delayed") + ); + }); + + // leave time for transaction to be executed + std::this_thread::sleep_for( 2000ms ); + + app->quit(); + app_thread.join(); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/plugins/prometheus_plugin/include/eosio/prometheus_plugin/prometheus_plugin.hpp b/plugins/prometheus_plugin/include/eosio/prometheus_plugin/prometheus_plugin.hpp index 0413bd57c1..1ca104cf67 100644 --- a/plugins/prometheus_plugin/include/eosio/prometheus_plugin/prometheus_plugin.hpp +++ b/plugins/prometheus_plugin/include/eosio/prometheus_plugin/prometheus_plugin.hpp @@ -3,6 +3,8 @@ #include #include #include +#include +#include namespace eosio { @@ -13,7 +15,7 @@ namespace eosio { prometheus_plugin(); ~prometheus_plugin() override; - APPBASE_PLUGIN_REQUIRES((http_plugin)(chain_plugin)) + APPBASE_PLUGIN_REQUIRES((http_plugin)(chain_plugin)(producer_plugin)(net_plugin)) void set_program_options(options_description&, options_description& cfg) override; diff --git a/plugins/prometheus_plugin/metrics.hpp b/plugins/prometheus_plugin/metrics.hpp index 873f65f3f4..656d27a408 100644 --- a/plugins/prometheus_plugin/metrics.hpp +++ b/plugins/prometheus_plugin/metrics.hpp @@ -33,18 +33,37 @@ struct catalog_type { // http plugin prometheus::Family& http_request_counts; - // net plugin p2p-connections - prometheus::Family& p2p_connections; - - Gauge& num_peers; - Gauge& num_clients; - // net plugin failed p2p connection Counter& failed_p2p_connections; // net plugin dropped_trxs Counter& dropped_trxs_total; + struct p2p_connection_metrics { + Gauge& num_peers; + Gauge& num_clients; + + prometheus::Family& addr; // Empty gauge; ipv6 address can't be transmitted as a double + prometheus::Family& port; + prometheus::Family& connection_number; + prometheus::Family& accepting_blocks; + prometheus::Family& last_received_block; + prometheus::Family& first_available_block; + prometheus::Family& last_available_block; + prometheus::Family& unique_first_block_count; + prometheus::Family& latency; + prometheus::Family& bytes_received; + prometheus::Family& last_bytes_received; + prometheus::Family& bytes_sent; + prometheus::Family& last_bytes_sent; + prometheus::Family& block_sync_bytes_received; + prometheus::Family& block_sync_bytes_sent; + prometheus::Family& block_sync_throttling; + prometheus::Family& connection_start_time; + prometheus::Family& peer_addr; // Empty gauge; we only want the label + }; + p2p_connection_metrics p2p_metrics; + // producer plugin prometheus::Family& cpu_usage_us; prometheus::Family& net_usage_us; @@ -68,7 +87,6 @@ struct catalog_type { // produced blocks Counter& unapplied_transactions_total; - Counter& blacklisted_transactions_total; Counter& subjective_bill_account_size_total; Counter& scheduled_trxs_total; Counter& trxs_produced_total; @@ -98,20 +116,36 @@ struct catalog_type { catalog_type() : info(family("nodeos", "static information about the server")) , http_request_counts(family("nodeos_http_requests_total", "number of HTTP requests")) - , p2p_connections(family("nodeos_p2p_connections", "current number of connected p2p connections")) - , num_peers(p2p_connections.Add({{"direction", "out"}})) - , num_clients(p2p_connections.Add({{"direction", "in"}})) - , failed_p2p_connections( - build("nodeos_failed_p2p_connections", "total number of failed out-going p2p connections")) - , dropped_trxs_total(build("nodeos_dropped_trxs_total", "total number of dropped transactions by net plugin")) + , failed_p2p_connections(build("nodeos_p2p_failed_connections", "total number of failed out-going p2p connections")) + , dropped_trxs_total(build("nodeos_p2p_dropped_trxs_total", "total number of dropped transactions by net plugin")) + , p2p_metrics{ + .num_peers{build("nodeos_p2p_peers", "current number of connected outgoing peers")} + , .num_clients{build("nodeos_p2p_clients", "current number of connected incoming clients")} + , .addr{family("nodeos_p2p_addr", "ipv6 address")} + , .port{family("nodeos_p2p_port", "port")} + , .connection_number{family("nodeos_p2p_connection_number", "monatomic increasing connection number")} + , .accepting_blocks{family("nodeos_p2p_accepting_blocks", "accepting blocks on connection")} + , .last_received_block{family("nodeos_p2p_last_received_block", "last received block on connection")} + , .first_available_block{family("nodeos_p2p_first_available_block", "first block available from connection")} + , .last_available_block{family("nodeos_p2p_last_available_block", "last block available from connection")} + , .unique_first_block_count{family("nodeos_p2p_unique_first_block_count", "number of blocks first received from any connection on this connection")} + , .latency{family("nodeos_p2p_latency", "last calculated latency with connection")} + , .bytes_received{family("nodeos_p2p_bytes_received", "total bytes received on connection")} + , .last_bytes_received{family("nodeos_p2p_last_bytes_received", "last time anything received from peer")} + , .bytes_sent{family("nodeos_p2p_bytes_sent", "total bytes sent to peer")} + , .last_bytes_sent{family("nodeos_p2p_last_bytes_sent", "last time anything sent to peer")} + , .block_sync_bytes_received{family("nodeos_p2p_block_sync_bytes_received", "bytes of blocks received during syncing")} + , .block_sync_bytes_sent{family("nodeos_p2p_block_sync_bytes_sent", "bytes of blocks sent during syncing")} + , .block_sync_throttling{family("nodeos_p2p_block_sync_throttling", "is block sync throttling currently active")} + , .connection_start_time{family("nodeos_p2p_connection_start_time", "time of last connection to peer")} + , .peer_addr{family("nodeos_p2p_peer_addr", "peer address")} + } , cpu_usage_us(family("nodeos_cpu_usage_us_total", "total cpu usage in microseconds for blocks")) , net_usage_us(family("nodeos_net_usage_us_total", "total net usage in microseconds for blocks")) , last_irreversible(build("nodeos_last_irreversible", "last irreversible block number")) , head_block_num(build("nodeos_head_block_num", "head block number")) , unapplied_transactions_total(build("nodeos_unapplied_transactions_total", "total number of unapplied transactions from produced blocks")) - , blacklisted_transactions_total(build("nodeos_blacklisted_transactions_total", - "total number of blacklisted transactions from produced blocks")) , subjective_bill_account_size_total(build( "nodeos_subjective_bill_account_size_total", "total number of subjective bill account size from produced blocks")) , scheduled_trxs_total( @@ -167,31 +201,36 @@ struct catalog_type { } void update(const net_plugin::p2p_connections_metrics& metrics) { - num_peers.Set(metrics.num_peers); - num_clients.Set(metrics.num_clients); + p2p_metrics.num_peers.Set(metrics.num_peers); + p2p_metrics.num_clients.Set(metrics.num_clients); for(size_t i = 0; i < metrics.stats.peers.size(); ++i) { - std::string label{"connid_" + to_string(metrics.stats.peers[i].connection_id)}; - auto add_and_set_gauge = [&](const std::string& label_value, - const auto& value) { - auto& gauge = p2p_connections.Add({{label, label_value}}); + const auto& peer = metrics.stats.peers[i]; + const auto& conn_id = peer.unique_conn_node_id; + + const auto addr = boost::asio::ip::make_address_v6(peer.address).to_string(); + p2p_metrics.addr.Add({{"connid", conn_id},{"ipv6", addr},{"address", peer.p2p_address}}); + + auto add_and_set_gauge = [&](auto& fam, const auto& value) { + auto& gauge = fam.Add({{"connid", conn_id}}); gauge.Set(value); }; - auto& peer = metrics.stats.peers[i]; - auto addr = std::string("addr_") + boost::asio::ip::make_address_v6(peer.address).to_string(); - add_and_set_gauge(addr, 0); // Empty gauge; ipv6 address can't be transmitted as a double - add_and_set_gauge("port", peer.port); - add_and_set_gauge("accepting_blocks", peer.accepting_blocks); - add_and_set_gauge("last_received_block", peer.last_received_block); - add_and_set_gauge("first_available_block", peer.first_available_block); - add_and_set_gauge("last_available_block", peer.last_available_block); - add_and_set_gauge("unique_first_block_count", peer.unique_first_block_count); - add_and_set_gauge("latency", peer.latency); - add_and_set_gauge("bytes_received", peer.bytes_received); - add_and_set_gauge("last_bytes_received", peer.last_bytes_received.count()); - add_and_set_gauge("bytes_sent", peer.bytes_sent); - add_and_set_gauge("last_bytes_sent", peer.last_bytes_sent.count()); - add_and_set_gauge("connection_start_time", peer.connection_start_time.count()); - add_and_set_gauge(peer.log_p2p_address, 0); // Empty gauge; we only want the label + + add_and_set_gauge(p2p_metrics.connection_number, peer.connection_id); + add_and_set_gauge(p2p_metrics.port, peer.port); + add_and_set_gauge(p2p_metrics.accepting_blocks, peer.accepting_blocks); + add_and_set_gauge(p2p_metrics.last_received_block, peer.last_received_block); + add_and_set_gauge(p2p_metrics.first_available_block, peer.first_available_block); + add_and_set_gauge(p2p_metrics.last_available_block, peer.last_available_block); + add_and_set_gauge(p2p_metrics.unique_first_block_count, peer.unique_first_block_count); + add_and_set_gauge(p2p_metrics.latency, peer.latency); + add_and_set_gauge(p2p_metrics.bytes_received, peer.bytes_received); + add_and_set_gauge(p2p_metrics.last_bytes_received, peer.last_bytes_received.count()); + add_and_set_gauge(p2p_metrics.bytes_sent, peer.bytes_sent); + add_and_set_gauge(p2p_metrics.last_bytes_sent, peer.last_bytes_sent.count()); + add_and_set_gauge(p2p_metrics.block_sync_bytes_received, peer.block_sync_bytes_received); + add_and_set_gauge(p2p_metrics.block_sync_bytes_sent, peer.block_sync_bytes_sent); + add_and_set_gauge(p2p_metrics.block_sync_throttling, peer.block_sync_throttling); + add_and_set_gauge(p2p_metrics.connection_start_time, peer.connection_start_time.count()); } } @@ -211,7 +250,6 @@ struct catalog_type { void update(const producer_plugin::produced_block_metrics& metrics) { unapplied_transactions_total.Increment(metrics.unapplied_transactions_total); - blacklisted_transactions_total.Increment(metrics.blacklisted_transactions_total); subjective_bill_account_size_total.Increment(metrics.subjective_bill_account_size_total); scheduled_trxs_total.Increment(metrics.scheduled_trxs_total); trxs_produced_total.Increment(metrics.trxs_produced_total); @@ -288,4 +326,4 @@ struct catalog_type { } }; -} // namespace eosio::metrics \ No newline at end of file +} // namespace eosio::metrics diff --git a/plugins/prometheus_plugin/prometheus_plugin.cpp b/plugins/prometheus_plugin/prometheus_plugin.cpp index 2f14e5eba3..ff929d282f 100644 --- a/plugins/prometheus_plugin/prometheus_plugin.cpp +++ b/plugins/prometheus_plugin/prometheus_plugin.cpp @@ -3,9 +3,7 @@ #include #include #include -#include #include -#include #include @@ -36,9 +34,6 @@ namespace eosio { prometheus_plugin::~prometheus_plugin() = default; void prometheus_plugin::set_program_options(options_description&, options_description& cfg) { - cfg.add_options() - ("prometheus-exporter-address", bpo::value()->default_value("127.0.0.1:9101"), - "The local IP and port to listen for incoming prometheus metrics http request."); } struct prometheus_api_handle { diff --git a/plugins/resource_monitor_plugin/include/eosio/resource_monitor_plugin/file_space_handler.hpp b/plugins/resource_monitor_plugin/include/eosio/resource_monitor_plugin/file_space_handler.hpp index 230edf62fb..a4c04b02d1 100644 --- a/plugins/resource_monitor_plugin/include/eosio/resource_monitor_plugin/file_space_handler.hpp +++ b/plugins/resource_monitor_plugin/include/eosio/resource_monitor_plugin/file_space_handler.hpp @@ -4,18 +4,47 @@ #include #include - +#include namespace eosio::resource_monitor { template class file_space_handler { public: - file_space_handler(SpaceProvider&& space_provider, boost::asio::io_context& ctx) - :space_provider(std::move(space_provider)), - timer{ctx} + file_space_handler(SpaceProvider&& space_provider) + :space_provider(std::move(space_provider)) { } + void start(const std::vector& directories) { + for ( auto& dir: directories ) { + add_file_system( dir ); + + // A directory like "data" contains subdirectories like + // "block". Those subdirectories can mount on different + // file systems. Make sure they are taken care of. + for (std::filesystem::directory_iterator itr(dir); itr != std::filesystem::directory_iterator(); ++itr) { + if (std::filesystem::is_directory(itr->path())) { + add_file_system( itr->path() ); + } + } + } + + thread_pool.start(thread_pool_size, + []( const fc::exception& e ) { + elog("Exception in resource monitor plugin thread pool, exiting: ${e}", ("e", e.to_detail_string()) ); + appbase::app().quit(); }, + [&]() { space_monitor_loop(); } + ); + } + + // called on main thread from plugin shutdown() + void stop() { + // After thread pool stops, timer is not accessible within it. + // In addition, timer's destructor will call cancel. + // Therefore, no need to call cancel explicitly. + thread_pool.stop(); + } + void set_sleep_time(uint32_t sleep_time) { sleep_time_in_secs = sleep_time; } @@ -128,6 +157,7 @@ namespace eosio::resource_monitor { ("path_name", path_name.string())("shutdown_available", to_gib(shutdown_available)) ("capacity", to_gib(info.capacity))("threshold_desc", threshold_desc()) ); } + // on resmon thread void space_monitor_loop() { if ( is_threshold_exceeded() && shutdown_on_exceeded ) { elog("Gracefully shutting down, exceeded file system configured threshold."); @@ -137,9 +167,12 @@ namespace eosio::resource_monitor { update_warning_interval_counter(); timer.expires_from_now( boost::posix_time::seconds( sleep_time_in_secs )); - timer.async_wait([this](const auto& ec) { if ( ec ) { + // No need to check if ec is operation_aborted (cancelled), + // as cancel callback will never be make it here after thread_pool + // is stopped, even though cancel is called in the timer's + // destructor. wlog("Exit due to error: ${ec}, message: ${message}", ("ec", ec.value()) ("message", ec.message())); @@ -154,7 +187,10 @@ namespace eosio::resource_monitor { private: SpaceProvider space_provider; - boost::asio::deadline_timer timer; + static constexpr size_t thread_pool_size = 1; + eosio::chain::named_thread_pool thread_pool; + + boost::asio::deadline_timer timer {thread_pool.get_executor()}; uint32_t sleep_time_in_secs {2}; uint32_t shutdown_threshold {90}; diff --git a/plugins/resource_monitor_plugin/resource_monitor_plugin.cpp b/plugins/resource_monitor_plugin/resource_monitor_plugin.cpp index 15cf0dcbdc..f0088987d2 100644 --- a/plugins/resource_monitor_plugin/resource_monitor_plugin.cpp +++ b/plugins/resource_monitor_plugin/resource_monitor_plugin.cpp @@ -37,7 +37,7 @@ namespace eosio { class resource_monitor_plugin_impl { public: resource_monitor_plugin_impl() - :space_handler(system_file_space_provider(), ctx) + :space_handler(system_file_space_provider()) { } @@ -109,42 +109,14 @@ class resource_monitor_plugin_impl { // Start main thread void plugin_startup() { - ilog("Creating and starting monitor thread"); - - // By now all plugins are initialized. - // Find out filesystems containing the directories requested - // so far. - for ( auto& dir: directories_registered ) { - space_handler.add_file_system( dir ); - - // A directory like "data" contains subdirectories like - // "block". Those subdirectories can mount on different - // file systems. Make sure they are taken care of. - for (std::filesystem::directory_iterator itr(dir); itr != std::filesystem::directory_iterator(); ++itr) { - if (std::filesystem::is_directory(itr->path())) { - space_handler.add_file_system( itr->path() ); - } - } - } - - monitor_thread = std::thread( [this] { - fc::set_thread_name( "resmon" ); // console_appender uses 9 chars for thread name reporting. - space_handler.space_monitor_loop(); - - ctx.run(); - } ); + space_handler.start(directories_registered); } // System is shutting down. void plugin_shutdown() { - ilog("shutdown..."); - - ctx.stop(); - - // Wait for the thread to end - monitor_thread.join(); - - ilog("exit shutdown"); + ilog("entered shutdown..."); + space_handler.stop(); + ilog("exiting shutdown"); } void monitor_directory(const std::filesystem::path& path) { @@ -169,8 +141,6 @@ class resource_monitor_plugin_impl { static constexpr uint32_t warning_interval_min = 1; static constexpr uint32_t warning_interval_max = 450; // e.g. if the monitor interval is 2 sec, the warning interval is at most 15 minutes - boost::asio::io_context ctx; - using file_space_handler_t = file_space_handler; file_space_handler_t space_handler; }; diff --git a/plugins/resource_monitor_plugin/test/CMakeLists.txt b/plugins/resource_monitor_plugin/test/CMakeLists.txt index a564c515dc..e9f0bf03ba 100644 --- a/plugins/resource_monitor_plugin/test/CMakeLists.txt +++ b/plugins/resource_monitor_plugin/test/CMakeLists.txt @@ -1,4 +1,4 @@ -add_executable( test_resmon_plugin test_resmon_plugin.cpp test_add_file_system.cpp test_monitor_loop.cpp test_threshold.cpp ) +add_executable( test_resmon_plugin test_resmon_plugin.cpp test_add_file_system.cpp test_threshold.cpp ) target_link_libraries( test_resmon_plugin resource_monitor_plugin ) target_include_directories( test_resmon_plugin PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" ) add_test(NAME test_resmon_plugin COMMAND plugins/resource_monitor_plugin/test/test_resmon_plugin WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) diff --git a/plugins/resource_monitor_plugin/test/test_add_file_system.cpp b/plugins/resource_monitor_plugin/test/test_add_file_system.cpp index 201fa96555..baae648c12 100644 --- a/plugins/resource_monitor_plugin/test/test_add_file_system.cpp +++ b/plugins/resource_monitor_plugin/test/test_add_file_system.cpp @@ -23,11 +23,9 @@ struct add_file_system_fixture { add_file_system_fixture& fixture; }; - boost::asio::io_context ctx; - using file_space_handler_t = file_space_handler; add_file_system_fixture() - : space_handler(mock_space_provider(*this), ctx) + : space_handler(mock_space_provider(*this)) { } diff --git a/plugins/resource_monitor_plugin/test/test_monitor_loop.cpp b/plugins/resource_monitor_plugin/test/test_monitor_loop.cpp deleted file mode 100644 index c48488f8fb..0000000000 --- a/plugins/resource_monitor_plugin/test/test_monitor_loop.cpp +++ /dev/null @@ -1,151 +0,0 @@ -#include - -#include - -using namespace eosio; -using namespace eosio::resource_monitor; -using namespace boost::system; - -struct space_handler_fixture { - struct mock_space_provider { - explicit mock_space_provider(space_handler_fixture& fixture) - :fixture(fixture) - {} - - int get_stat(const char *path, struct stat *buf) const { - return fixture.mock_get_stat(path, buf); - } - - std::filesystem::space_info get_space(const std::filesystem::path& p, std::error_code& ec) const { - return fixture.mock_get_space(p, ec); - } - - space_handler_fixture& fixture; - }; - - boost::asio::io_context ctx; - - using file_space_handler_t = file_space_handler; - space_handler_fixture() - : space_handler(mock_space_provider( *this ), ctx) - { - } - - void add_file_system(const std::filesystem::path& path_name) { - space_handler.add_file_system( path_name ); - } - - void set_threshold(uint32_t threshold, uint32_t warning_threshold) { - space_handler.set_threshold( threshold, warning_threshold ); - } - - void set_sleep_time(uint32_t sleep_time) { - space_handler.set_sleep_time( sleep_time ); - } - - void set_shutdown_on_exceeded(bool shutdown_on_exceeded) { - space_handler.set_shutdown_on_exceeded(shutdown_on_exceeded); - } - - bool is_threshold_exceeded() { - return space_handler.is_threshold_exceeded(); - } - - void space_monitor_loop() { - return space_handler.space_monitor_loop(); - } - - bool test_loop_common(int num_loops, int interval) - { - mock_get_space = [ i = 0, num_loops ]( const std::filesystem::path& p, std::error_code& ec) mutable -> std::filesystem::space_info { - ec = boost::system::errc::make_error_code(errc::success); - - std::filesystem::space_info rc{}; - rc.capacity = 1000000; - - if ( i < num_loops + 1 ) { // "+ 1" for the get_space in add_file_system - rc.available = 300000; - } else { - rc.available = 100000; - } - - i++; - - return rc; - }; - - mock_get_stat = []( const char *path, struct stat *buf ) -> int { - buf->st_dev = 0; - return 0; - }; - - set_threshold(80, 75); - set_shutdown_on_exceeded(true); - set_sleep_time(interval); - add_file_system("/test"); - - auto start = std::chrono::system_clock::now(); - - auto monitor_thread = std::thread( [this] { - space_monitor_loop(); - ctx.run(); - }); - - monitor_thread.join(); - - auto end = std::chrono::system_clock::now(); - std::chrono::duration test_duration = end - start; - - // For tests to be repeatable on any platforms under any loads, - // particularly for longer runs, - // we just make sure the test duration is longer than a margin - // of theroretical duration. - bool finished_in_time = (test_duration >= std::chrono::duration((num_loops - 1) * interval)); - - return finished_in_time; - } - - // fixture data and methods - std::function mock_get_space; - std::function mock_get_stat; - - file_space_handler_t space_handler; -}; - -BOOST_AUTO_TEST_SUITE(monitor_loop_tests) - BOOST_FIXTURE_TEST_CASE(zero_loop, space_handler_fixture) - { - BOOST_TEST( test_loop_common(0, 1) ); - } - - BOOST_FIXTURE_TEST_CASE(one_loop_1_secs_interval, space_handler_fixture) - { - BOOST_TEST( test_loop_common(1, 1) ); - } - - BOOST_FIXTURE_TEST_CASE(two_loops_1_sec_interval, space_handler_fixture) - { - BOOST_TEST( test_loop_common(2, 1) ); - } - - BOOST_FIXTURE_TEST_CASE(ten_loops_1_sec_interval, space_handler_fixture) - { - BOOST_TEST( test_loop_common(10, 1) ); - } - - BOOST_FIXTURE_TEST_CASE(one_loop_5_secs_interval, space_handler_fixture) - { - BOOST_TEST( test_loop_common(1, 5) ); - } - - BOOST_FIXTURE_TEST_CASE(two_loops_5_sec_interval, space_handler_fixture) - { - BOOST_TEST( test_loop_common(2, 5) ); - } - - BOOST_FIXTURE_TEST_CASE(five_loops_5_sec_interval, space_handler_fixture) - { - BOOST_TEST( test_loop_common(5, 5) ); - } - -BOOST_AUTO_TEST_SUITE_END() diff --git a/plugins/resource_monitor_plugin/test/test_resmon_plugin.cpp b/plugins/resource_monitor_plugin/test/test_resmon_plugin.cpp index 9e2aafbe27..2d865d0b25 100644 --- a/plugins/resource_monitor_plugin/test/test_resmon_plugin.cpp +++ b/plugins/resource_monitor_plugin/test/test_resmon_plugin.cpp @@ -144,29 +144,31 @@ BOOST_AUTO_TEST_SUITE(resmon_plugin_tests) BOOST_FIXTURE_TEST_CASE(startupNormal, resmon_fixture) { - BOOST_REQUIRE_NO_THROW( plugin_startup({"/tmp"})); + // do not use native "/tmp", as subdirectories in /tmp on test machine + // can be removed during a test run, causing file_space_handler::add_file_system + // to assert when doing get_stat on a removed directory + fc::temp_directory temp_dir; + BOOST_REQUIRE_NO_THROW(plugin_startup({temp_dir.path()})); } BOOST_FIXTURE_TEST_CASE(startupDuplicateDirs, resmon_fixture) { - BOOST_REQUIRE_NO_THROW( plugin_startup({"/tmp", "/tmp"})); + fc::temp_directory temp_dir; + BOOST_REQUIRE_NO_THROW(plugin_startup({temp_dir.path(), temp_dir.path()})); } BOOST_FIXTURE_TEST_CASE(startupMultDirs, resmon_fixture) { - // Under "/" are multiple file systems - BOOST_REQUIRE_NO_THROW( plugin_startup({"/", "/tmp"})); + fc::temp_directory temp_dir_1; + fc::temp_directory temp_dir_2; + BOOST_REQUIRE_NO_THROW(plugin_startup({temp_dir_1.path(), temp_dir_2.path()})); } BOOST_FIXTURE_TEST_CASE(startupNoExistingDirs, resmon_fixture) { - // "hsdfgd983" a random file and not existing - BOOST_REQUIRE_THROW( plugin_startup({"/tmp", "hsdfgd983"}), chain::plugin_config_exception); - } - - BOOST_FIXTURE_TEST_CASE(startupLongRun, resmon_fixture) - { - BOOST_REQUIRE_NO_THROW( plugin_startup({"/tmp"}, 5)); + fc::temp_directory temp_dir; + // temp_dir/hsdfgd983 does not exist in a just created temp directory + BOOST_REQUIRE_THROW(plugin_startup({temp_dir.path(), temp_dir.path() / "hsdfgd983"}), chain::plugin_config_exception); } BOOST_FIXTURE_TEST_CASE(warningIntervalTooBig, resmon_fixture) diff --git a/plugins/resource_monitor_plugin/test/test_threshold.cpp b/plugins/resource_monitor_plugin/test/test_threshold.cpp index b84261c50b..1a420d9976 100644 --- a/plugins/resource_monitor_plugin/test/test_threshold.cpp +++ b/plugins/resource_monitor_plugin/test/test_threshold.cpp @@ -23,11 +23,9 @@ struct threshold_fixture { threshold_fixture& fixture; }; - boost::asio::io_context ctx; - using file_space_handler_t = file_space_handler; threshold_fixture() - : space_handler(std::make_unique(mock_space_provider(*this), ctx)) + : space_handler(std::make_unique(mock_space_provider(*this))) { } @@ -49,7 +47,7 @@ struct threshold_fixture { bool test_threshold_common(std::map& available, std::map& dev, uint32_t warning_threshold=75) { bool first = test_threshold_common_(available, dev, warning_threshold); - space_handler = std::make_unique(mock_space_provider(*this), ctx); + space_handler = std::make_unique(mock_space_provider(*this)); test_absolute = true; bool second = test_threshold_common_(available, dev, warning_threshold); diff --git a/plugins/state_history_plugin/include/eosio/state_history_plugin/session.hpp b/plugins/state_history_plugin/include/eosio/state_history_plugin/session.hpp index 3d3c920af1..26af991d58 100644 --- a/plugins/state_history_plugin/include/eosio/state_history_plugin/session.hpp +++ b/plugins/state_history_plugin/include/eosio/state_history_plugin/session.hpp @@ -57,11 +57,15 @@ class session_manager { private: using entry_ptr = std::unique_ptr; + boost::asio::io_context& ship_io_context; std::set> session_set; bool sending = false; std::deque, entry_ptr>> send_queue; public: + explicit session_manager(boost::asio::io_context& ship_io_context) + : ship_io_context(ship_io_context) {} + void insert(std::shared_ptr s) { session_set.insert(std::move(s)); } @@ -103,8 +107,12 @@ class session_manager { void pop_entry(bool call_send = true) { send_queue.erase(send_queue.begin()); sending = false; - if (call_send || !send_queue.empty()) - send(); + if (call_send || !send_queue.empty()) { + // avoid blowing the stack + boost::asio::post(ship_io_context, [this]() { + send(); + }); + } } void send_updates() { diff --git a/plugins/state_history_plugin/state_history_plugin.cpp b/plugins/state_history_plugin/state_history_plugin.cpp index f117996f14..a779a50be0 100644 --- a/plugins/state_history_plugin/state_history_plugin.cpp +++ b/plugins/state_history_plugin/state_history_plugin.cpp @@ -62,7 +62,6 @@ struct state_history_plugin_impl : std::enable_shared_from_this thread_pool; + session_manager session_mgr{thread_pool.get_executor()}; + bool plugin_started = false; public: diff --git a/plugins/state_history_plugin/tests/session_test.cpp b/plugins/state_history_plugin/tests/session_test.cpp index c7b7be1ecc..e1bc439ef2 100644 --- a/plugins/state_history_plugin/tests/session_test.cpp +++ b/plugins/state_history_plugin/tests/session_test.cpp @@ -101,20 +101,22 @@ struct mock_state_history_plugin { eosio::state_history::block_position block_head; fc::temp_directory log_dir; - std::optional log; + std::optional trace_log; + std::optional state_log; std::atomic stopping = false; - eosio::session_manager session_mgr; + eosio::session_manager session_mgr{ship_ioc}; constexpr static uint32_t default_frame_size = 1024; - std::optional& get_trace_log() { return log; } - std::optional& get_chain_state_log() { return log; } + std::optional& get_trace_log() { return trace_log; } + std::optional& get_chain_state_log() { return state_log; } fc::sha256 get_chain_id() const { return {}; } boost::asio::io_context& get_ship_executor() { return ship_ioc; } void setup_state_history_log(eosio::state_history_log_config conf = {}) { - log.emplace("ship", log_dir.path(), conf); + trace_log.emplace("ship_trace", log_dir.path(), conf); + state_log.emplace("ship_state", log_dir.path(), conf); } fc::logger logger = fc::logger::get(DEFAULT_LOGGER); @@ -130,7 +132,20 @@ struct mock_state_history_plugin { return fc::time_point{}; } - std::optional get_block_id(uint32_t block_num) { return block_id_for(block_num); } + std::optional get_block_id(uint32_t block_num) { + std::optional id; + if( trace_log ) { + id = trace_log->get_block_id( block_num ); + if( id ) + return id; + } + if( state_log ) { + id = state_log->get_block_id( block_num ); + if( id ) + return id; + } + return block_id_for(block_num); + } eosio::state_history::block_position get_block_head() { return block_head; } eosio::state_history::block_position get_last_irreversible() { return block_head; } @@ -284,13 +299,24 @@ struct state_history_test_fixture { header.payload_size += sizeof(uint64_t); } - server.log->write_entry(header, block_id_for(index - 1), [&](auto& f) { + std::unique_lock gt(server.trace_log->_mx); + server.trace_log->write_entry(header, block_id_for(index - 1), [&](auto& f) { f.write((const char*)&type, sizeof(type)); if (type == 1) { f.write((const char*)&decompressed_byte_count, sizeof(decompressed_byte_count)); } f.write(compressed.data(), compressed.size()); }); + gt.unlock(); + std::unique_lock gs(server.state_log->_mx); + server.state_log->write_entry(header, block_id_for(index - 1), [&](auto& f) { + f.write((const char*)&type, sizeof(type)); + if (type == 1) { + f.write((const char*)&decompressed_byte_count, sizeof(decompressed_byte_count)); + } + f.write(compressed.data(), compressed.size()); + }); + gs.unlock(); if (written_data.size() < index) written_data.resize(index); @@ -428,6 +454,62 @@ BOOST_FIXTURE_TEST_CASE(test_session_no_prune, state_history_test_fixture) { FC_LOG_AND_RETHROW() } +BOOST_FIXTURE_TEST_CASE(test_split_log, state_history_test_fixture) { + try { + // setup block head for the server + constexpr uint32_t head = 1023; + eosio::state_history::partition_config conf; + conf.stride = 25; + server.setup_state_history_log(conf); + uint32_t head_block_num = head; + server.block_head = {head_block_num, block_id_for(head_block_num)}; + + // generate the log data used for traces and deltas + uint32_t n = mock_state_history_plugin::default_frame_size; + add_to_log(1, n * sizeof(uint32_t), generate_data(n)); // original data format + add_to_log(2, 0, generate_data(n)); // format to accommodate the compressed size greater than 4GB + add_to_log(3, 1, generate_data(n)); // format to encode decompressed size to avoid decompress entire data upfront. + for (size_t i = 4; i <= head; ++i) { + add_to_log(i, 1, generate_data(n)); + } + + send_request(eosio::state_history::get_blocks_request_v0{.start_block_num = 1, + .end_block_num = UINT32_MAX, + .max_messages_in_flight = UINT32_MAX, + .have_positions = {}, + .irreversible_only = false, + .fetch_block = true, + .fetch_traces = true, + .fetch_deltas = true}); + + eosio::state_history::state_result result; + // we should get 1023 consecutive block result + eosio::chain::block_id_type prev_id; + for (uint32_t i = 0; i < head; ++i) { + receive_result(result); + BOOST_REQUIRE(std::holds_alternative(result)); + auto r = std::get(result); + BOOST_REQUIRE_EQUAL(r.head.block_num, server.block_head.block_num); + if (i > 0) { + BOOST_TEST(prev_id.str() == r.prev_block->block_id.str()); + } + prev_id = r.this_block->block_id; + BOOST_REQUIRE(r.traces.has_value()); + BOOST_REQUIRE(r.deltas.has_value()); + auto traces = r.traces.value(); + auto deltas = r.deltas.value(); + auto& data = written_data[i]; + auto data_size = data.size() * sizeof(int32_t); + BOOST_REQUIRE_EQUAL(traces.size(), data_size); + BOOST_REQUIRE_EQUAL(deltas.size(), data_size); + + BOOST_REQUIRE(std::equal(traces.begin(), traces.end(), (const char*)data.data())); + BOOST_REQUIRE(std::equal(deltas.begin(), deltas.end(), (const char*)data.data())); + } + } + FC_LOG_AND_RETHROW() +} + BOOST_FIXTURE_TEST_CASE(test_session_with_prune, state_history_test_fixture) { try { // setup block head for the server diff --git a/plugins/wallet_plugin/se_wallet.cpp b/plugins/wallet_plugin/se_wallet.cpp index 8f461401ac..18f745ddb7 100644 --- a/plugins/wallet_plugin/se_wallet.cpp +++ b/plugins/wallet_plugin/se_wallet.cpp @@ -371,7 +371,7 @@ bool se_wallet::import_key(string wif_key) { string se_wallet::create_key(string key_type) { EOS_ASSERT(key_type.empty() || key_type == "R1", chain::unsupported_key_type_exception, "Secure Enclave wallet only supports R1 keys"); - return my->create().to_string(); + return my->create().to_string({}); } bool se_wallet::remove_key(string key) { diff --git a/programs/cleos/help_text.cpp.in b/programs/cleos/help_text.cpp.in index 3802b34a37..20ba17a9bb 100644 --- a/programs/cleos/help_text.cpp.in +++ b/programs/cleos/help_text.cpp.in @@ -208,11 +208,18 @@ const char* error_advice_missing_auth_exception = R"=====(Ensure that you have If you are currently using '@CLI_CLIENT_EXECUTABLE_NAME@ push action' command, try to add the relevant authority using -p option.)====="; const char* error_advice_irrelevant_auth_exception = "Please remove the unnecessary authority from your action!"; -const char* error_advice_missing_chain_api_plugin_exception = "Ensure that you have \033[2meosio::chain_api_plugin\033[0m\033[32m added to your node's configuration!"; -const char* error_advice_missing_wallet_api_plugin_exception = "Ensure that you have \033[2meosio::wallet_api_plugin\033[0m\033[32m added to your node's configuration!\n"\ - "Otherwise specify your wallet location with \033[2m--wallet-url\033[0m\033[32m argument!"; -const char* error_advice_missing_history_api_plugin_exception = "Ensure that you have \033[2meosio::history_api_plugin\033[0m\033[32m added to your node's configuration!"; -const char* error_advice_missing_net_api_plugin_exception = "Ensure that you have \033[2meosio::net_api_plugin\033[0m\033[32m added to your node's configuration!"; +const char* error_advice_missing_chain_api_plugin_exception = "Ensure that you have \033[2meosio::chain_api_plugin\033[0m\033[32m added to your node's configuration and enabled on the specified endpoint.\n" + "For example:\n" + "http-server-address = http-category-address\n" + "http-category-address = chain_ro,127.0.0.1:8081\n" + "http-category-address = chain_rw,[::]:8083"; +const char* error_advice_missing_wallet_api_plugin_exception = "Ensure that you have keosd enabled on the \033[2m--wallet-url\033[0m\033[32m specified endpoint."; +const char* error_advice_missing_history_api_plugin_exception = "The \033[2meosio::history_api_plugin\033[0m\033[32m has been removed. Verify endpoint simulates removed history_api_plugin or use a different option."; +const char* error_advice_missing_net_api_plugin_exception = "Ensure that you have \033[2meosio::net_api_plugin\033[0m\033[32m added to your node's configuration and enabled on the specified endpoint.\n" + "For example:\n" + "http-server-address = http-category-address\n" + "http-category-address = net_ro,127.0.0.1:8081\n" + "http-category-address = net_rw,[::]:8083"; const char* error_advice_wallet_exist_exception = "Try to use different wallet name."; const char* error_advice_wallet_nonexistent_exception = "Are you sure you typed the wallet name correctly?"; diff --git a/programs/cleos/httpc.cpp b/programs/cleos/httpc.cpp index dd61c27681..7a542c6010 100644 --- a/programs/cleos/httpc.cpp +++ b/programs/cleos/httpc.cpp @@ -63,13 +63,13 @@ fc::variant do_http_call(const config_t& config, const std::string& base_uri, co } else if( status_code == 404 ) { // Unknown endpoint if (path.compare(0, chain_func_base.size(), chain_func_base) == 0) { - throw chain::missing_chain_api_plugin_exception(FC_LOG_MESSAGE(error, "Chain API plugin is not enabled")); + throw chain::missing_chain_api_plugin_exception(FC_LOG_MESSAGE(error, "Chain API plugin is not enabled on specified endpoint")); } else if (path.compare(0, wallet_func_base.size(), wallet_func_base) == 0) { - throw chain::missing_wallet_api_plugin_exception(FC_LOG_MESSAGE(error, "Wallet is not available")); + throw chain::missing_wallet_api_plugin_exception(FC_LOG_MESSAGE(error, "Wallet is not available on specified endpoint")); } else if (path.compare(0, history_func_base.size(), history_func_base) == 0) { - throw chain::missing_history_api_plugin_exception(FC_LOG_MESSAGE(error, "History API plugin is not enabled")); + throw chain::missing_history_api_plugin_exception(FC_LOG_MESSAGE(error, "History API support is not enabled on specified endpoint")); } else if (path.compare(0, net_func_base.size(), net_func_base) == 0) { - throw chain::missing_net_api_plugin_exception(FC_LOG_MESSAGE(error, "Net API plugin is not enabled")); + throw chain::missing_net_api_plugin_exception(FC_LOG_MESSAGE(error, "Net API plugin is not enabled on specified endpoint")); } } else { auto &&error_info = response_result.as().error; diff --git a/programs/leap-util/actions/snapshot.cpp b/programs/leap-util/actions/snapshot.cpp index 7e98040f7a..419158da51 100644 --- a/programs/leap-util/actions/snapshot.cpp +++ b/programs/leap-util/actions/snapshot.cpp @@ -103,7 +103,7 @@ int snapshot_actions::run_subcommand() { snap_out.flush(); snap_out.close(); } catch(const database_guard_exception& e) { - std::cerr << "Database is not configured to have enough storage to handle provided snapshot, please increase storage and try aagain" << std::endl; + std::cerr << "Database is not configured to have enough storage to handle provided snapshot, please increase storage and try again" << std::endl; control.reset(); throw; } diff --git a/programs/nodeos/CMakeLists.txt b/programs/nodeos/CMakeLists.txt index 493c9e3a43..49b43670b4 100644 --- a/programs/nodeos/CMakeLists.txt +++ b/programs/nodeos/CMakeLists.txt @@ -5,7 +5,6 @@ if( UNIX AND NOT APPLE ) endif() configure_file(config.hpp.in config.hpp ESCAPE_QUOTES) -configure_file(logging.json ${CMAKE_BINARY_DIR}/tests/TestHarness/logging-template.json) target_include_directories(${NODE_EXECUTABLE_NAME} PUBLIC ${CMAKE_CURRENT_BINARY_DIR}) diff --git a/scripts/install_deps.sh b/scripts/install_deps.sh deleted file mode 100755 index 5dfaff555f..0000000000 --- a/scripts/install_deps.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/bash -apt-get update -apt-get update --fix-missing -export DEBIAN_FRONTEND='noninteractive' -export TZ='Etc/UTC' -apt-get install -y \ - build-essential \ - bzip2 \ - cmake \ - curl \ - file \ - git \ - libbz2-dev \ - libcurl4-openssl-dev \ - libgmp-dev \ - libncurses5 \ - libssl-dev \ - libtinfo-dev \ - libzstd-dev \ - python3 \ - python3-numpy \ - time \ - tzdata \ - unzip \ - wget \ - zip \ - zlib1g-dev diff --git a/scripts/pinned_build.sh b/scripts/pinned_build.sh deleted file mode 100755 index ebf37d29d7..0000000000 --- a/scripts/pinned_build.sh +++ /dev/null @@ -1,166 +0,0 @@ -#!/bin/bash -set -eo pipefail - -echo "Leap Pinned Build" - -if [[ "$(uname)" == "Linux" ]]; then - if [[ -e /etc/os-release ]]; then - # obtain NAME and other information - . /etc/os-release - if [[ "${NAME}" != "Ubuntu" ]]; then - echo "Currently only supporting Ubuntu based builds. Proceed at your own risk." - fi - else - echo "Currently only supporting Ubuntu based builds. /etc/os-release not found. Your Linux distribution is not supported. Proceed at your own risk." - fi -else - echo "Currently only supporting Ubuntu based builds. Your architecture is not supported. Proceed at your own risk." -fi - -if [ $# -eq 0 ] || [ -z "$1" ]; then - echo "Please supply a directory for the build dependencies to be placed and a directory for leap build and a value for the number of jobs to use for building." - echo "The binary packages will be created and placed into the leap build directory." - echo "./pinned_build.sh <1-100>" - exit 255 -fi - -export CORE_SYM='EOS' -# CMAKE_C_COMPILER requires absolute path -DEP_DIR="$(realpath "$1")" -LEAP_DIR="$2" -JOBS="$3" -CLANG_VER=11.0.1 -LLVM_VER=11.0.1 -SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]:-$0}"; )" &> /dev/null && pwd 2> /dev/null; )"; -START_DIR="$(pwd)" - - -pushdir() { - DIR="$1" - mkdir -p "${DIR}" - pushd "${DIR}" &> /dev/null -} - -popdir() { - EXPECTED="$1" - D="$(popd)" - popd &> /dev/null - echo "${D}" - D="$(eval echo "$D" | head -n1 | cut -d " " -f1)" - - # -ef compares absolute paths - if ! [[ "${D}" -ef "${EXPECTED}" ]]; then - echo "Directory is not where expected EXPECTED=${EXPECTED} at ${D}" - exit 1 - fi -} - -try(){ - "$@" - res=$? - if [[ ${res} -ne 0 ]]; then - exit 255 - fi -} - -install_clang() { - CLANG_DIR="$1" - if [ ! -d "${CLANG_DIR}" ]; then - echo "Installing Clang ${CLANG_VER} @ ${CLANG_DIR}" - mkdir -p "${CLANG_DIR}" - CLANG_FN="clang+llvm-${CLANG_VER}-x86_64-linux-gnu-ubuntu-16.04.tar.xz" - try wget -O "${CLANG_FN}" "https://github.com/llvm/llvm-project/releases/download/llvmorg-${CLANG_VER}/${CLANG_FN}" - try tar -xvf "${CLANG_FN}" -C "${CLANG_DIR}" - pushdir "${CLANG_DIR}" - mv clang+*/* . - popdir "${DEP_DIR}" - rm "${CLANG_FN}" - fi - export PATH="${CLANG_DIR}/bin:$PATH" - export CLANG_DIR="${CLANG_DIR}" -} - -install_llvm() { - LLVM_DIR="$1" - if [ ! -d "${LLVM_DIR}" ]; then - echo "Installing LLVM ${LLVM_VER} @ ${LLVM_DIR}" - mkdir -p "${LLVM_DIR}" - try wget -O "llvm-${LLVM_VER}.src.tar.xz" "https://github.com/llvm/llvm-project/releases/download/llvmorg-${LLVM_VER}/llvm-${LLVM_VER}.src.tar.xz" - try tar -xvf "llvm-${LLVM_VER}.src.tar.xz" - pushdir "${LLVM_DIR}.src" - pushdir build - try cmake -DCMAKE_TOOLCHAIN_FILE="${SCRIPT_DIR}/pinned_toolchain.cmake" -DCMAKE_INSTALL_PREFIX="${LLVM_DIR}" -DCMAKE_BUILD_TYPE=Release -DLLVM_TARGETS_TO_BUILD=host -DLLVM_BUILD_TOOLS=Off -DLLVM_ENABLE_RTTI=On -DLLVM_ENABLE_TERMINFO=Off -DCMAKE_EXE_LINKER_FLAGS=-pthread -DCMAKE_SHARED_LINKER_FLAGS=-pthread -DLLVM_ENABLE_PIC=NO .. - try make -j "${JOBS}" - try make -j "${JOBS}" install - popdir "${LLVM_DIR}.src" - popdir "${DEP_DIR}" - rm -rf "${LLVM_DIR}.src" - rm "llvm-${LLVM_VER}.src.tar.xz" - fi - export LLVM_DIR="${LLVM_DIR}" -} - -pushdir "${DEP_DIR}" - -install_clang "${DEP_DIR}/clang-${CLANG_VER}" -install_llvm "${DEP_DIR}/llvm-${LLVM_VER}" - -# go back to the directory where the script starts -popdir "${START_DIR}" - -pushdir "${LEAP_DIR}" - -# build Leap -echo "Building Leap ${SCRIPT_DIR}" -try cmake -DCMAKE_TOOLCHAIN_FILE="${SCRIPT_DIR}/pinned_toolchain.cmake" -DCMAKE_INSTALL_PREFIX=${LEAP_PINNED_INSTALL_PREFIX:-/usr/local} -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="${LLVM_DIR}/lib/cmake" "${SCRIPT_DIR}/.." - -try make -j "${JOBS}" -try cpack - -# art generated with DALL-E (https://openai.com/blog/dall-e), then fed through ASCIIart.club (https://asciiart.club) with permission -cat <<'TXT' # BASH interpolation must remain disabled for the ASCII art to print correctly - - ,▄▄A` - _╓▄██` - ╓▄▓▓▀▀` - ╓▓█▀╓▄▓ - ▓▌▓▓▓▀ - ,▄▓███▓H - _╨╫▀╚▀╠▌`╙¥, - ╓« _╟▄▄ `½, ╓▄▄╦▄≥_ - ╙▓╫╬▒R▀▀╙▀▀▓φ_ «_╙Y╥▄mmMM#╦▄,_ ,╓╦mM╩╨╙╙╙\`║═ - `` `▀▄__╫▓▓╨` _```"""*ⁿⁿ^`````Ω, `╟∩ - ╙▌▓▓"` ,«ñ` ╔╬▓▌⌂ ╔▌ - ╙█▌,,╔╗M╨,░ ` "╫▓m_ ╟H _ - _,,,,__,╠█▓▒` .╣▌µ _ _.╓╔▄▄▓█▓▓N_ ╙▀╩KKM╙╟▓N - ,▄▓█▓████▀▀▀╙▀╓╔φ»█▓▓Ñ╦«, :»»µ╦▓▓█▀└╙▀███▓╥__ _,╓▄▓▓▓M▓`, - __╓Φ▓█╫▓▓▓▓▓▓▓▓▓▓▓▓▓▀K▀▀███▓▓▓▓▓▓▀▀╙ `▀▀▀▓▄▄K╨╙└ `▀▌╙█▄*. - ,╓Φ▓▓▀▄▓▀` ╙▀╙ ╙▓╙╙▓▄* - .▄▓╫▀╦▄▀` ╙▓╙µ╙▀ - ▄▓▀╨▓▓╨_ `▀▄▄M - _█▌▄▌╙` `╙ - ╙└` - - - Ñ▓▓▓▓ ¢▄▄▄▄▄▄▄▄▄▄ , ,,,,,,,,,,,_ - _╫▓▓█▌ ╟▓████████▀ ╓╣▓▌_ ╠╫▓█▓▓▓▓█▓▓▓▓▄ - _▓▓▓█▌ ╟╫██▄,,,,_ æ▄███▓▄ ▐║████▀╨╨▀▓███▌ - :╫▓▓█▌ ╟╢████████▓ ,╬███████▓, ▐║████▓▄▄▓▓███▀ - :╫▓▓█▌_ _╟║███▀▀▀▀▀▀ ╓╫███╣╫╬███▓N_ j▐██▀▀▀▀▀▀▀▀▀` - ___________]╫▓▓█▓φ╓╓╓╓╓╓,__╟╣█▌▌,,,,,_ _╬▓████████████▓▄_ ▐M█▌ - _ _________]╫▌▓█████████▓▓▄╟╣████████▓▄╣██▓▀^ _ ╙▓██▓▓╗__M█▓ - ___ _ _ ▀╣▀╣╩╩╩╩╩╩╩▀▀▀▀╙▀▀▀▀▀▀▀▀▀▀▀▀▀▀` ╙▀▀▀▀╩═╩▀▀ - _ __ __ _____ ___ ____ _ __ _ ____ ___ - ____ ____ __ _ _ _ _ _ _ __ _ __ __ - __ _ ________ ___ ________ ___ _ _ _ _ - _ __ __ _ __ ____ _ _ ____ _ _ _ _ - _ _ _ ____ ____ _ _ _ __ _ _ _ __ - ---- -Leap has successfully built and constructed its packages. You should be able to -find the packages at: -TXT -echo "${LEAP_DIR}" -echo -echo 'Thank you, fam!!' -echo diff --git a/scripts/pinned_toolchain.cmake b/scripts/pinned_toolchain.cmake deleted file mode 100644 index ba791016ac..0000000000 --- a/scripts/pinned_toolchain.cmake +++ /dev/null @@ -1,19 +0,0 @@ -set(CLANG_DIR $ENV{CLANG_DIR}) -set(CMAKE_C_COMPILER_WORKS 1) -set(CMAKE_CXX_COMPILER_WORKS 1) -set(CMAKE_C_COMPILER ${CLANG_DIR}/bin/clang) -set(CMAKE_CXX_COMPILER ${CLANG_DIR}/bin/clang++) - -set(CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES ${CLANG_DIR}/include/c++/v1 /usr/local/include /usr/include) - -set(CMAKE_C_FLAGS_INIT "-D_FORTIFY_SOURCE=2 -fstack-protector-strong -fpie") -set(CMAKE_CXX_FLAGS_INIT "-nostdinc++ -D_FORTIFY_SOURCE=2 -fstack-protector-strong -fpie") - -set(CMAKE_EXE_LINKER_FLAGS_INIT "-stdlib=libc++ -nostdlib++ -pie") -if(NOT APPLE) - string(APPEND CMAKE_EXE_LINKER_FLAGS_INIT " -Wl,-z,relro,-z,now") -endif() - -set(CMAKE_SHARED_LINKER_FLAGS_INIT "-stdlib=libc++ -nostdlib++") -set(CMAKE_MODULE_LINKER_FLAGS_INIT "-stdlib=libc++ -nostdlib++") -set(CMAKE_CXX_STANDARD_LIBRARIES "${CLANG_DIR}/lib/libc++.a ${CLANG_DIR}/lib/libc++abi.a") diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index ff05447fb5..4ab75a1abf 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -52,6 +52,8 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/http_plugin_test.py ${CMAKE_CURRENT_B configure_file(${CMAKE_CURRENT_SOURCE_DIR}/p2p_high_latency_test.py ${CMAKE_CURRENT_BINARY_DIR}/p2p_high_latency_test.py COPYONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/p2p_multiple_listen_test.py ${CMAKE_CURRENT_BINARY_DIR}/p2p_multiple_listen_test.py COPYONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/p2p_no_listen_test.py ${CMAKE_CURRENT_BINARY_DIR}/p2p_no_listen_test.py COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/p2p_sync_throttle_test.py ${CMAKE_CURRENT_BINARY_DIR}/p2p_sync_throttle_test.py COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/p2p_sync_throttle_test_shape.json ${CMAKE_CURRENT_BINARY_DIR}/p2p_sync_throttle_test_shape.json COPYONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/compute_transaction_test.py ${CMAKE_CURRENT_BINARY_DIR}/compute_transaction_test.py COPYONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/subjective_billing_test.py ${CMAKE_CURRENT_BINARY_DIR}/subjective_billing_test.py COPYONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/get_account_test.py ${CMAKE_CURRENT_BINARY_DIR}/get_account_test.py COPYONLY) @@ -132,13 +134,13 @@ add_test(NAME nodeos_protocol_feature_test COMMAND tests/nodeos_protocol_feature set_property(TEST nodeos_protocol_feature_test PROPERTY LABELS nonparallelizable_tests) add_test(NAME compute_transaction_test COMMAND tests/compute_transaction_test.py -v -p 2 -n 3 ${UNSHARE} WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) set_property(TEST compute_transaction_test PROPERTY LABELS nonparallelizable_tests) -add_test(NAME read-only-trx-basic-test COMMAND tests/read_only_trx_test.py -v -p 2 -n 3 --read-only-threads 0 ${UNSHARE} WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) +add_test(NAME read-only-trx-basic-test COMMAND tests/read_only_trx_test.py -p 2 -n 3 --read-only-threads 1 ${UNSHARE} WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) set_property(TEST read-only-trx-basic-test PROPERTY LABELS nonparallelizable_tests) -add_test(NAME read-only-trx-parallel-test COMMAND tests/read_only_trx_test.py -v -p 2 -n 3 --read-only-threads 128 --num-test-runs 3 ${UNSHARE} WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) +add_test(NAME read-only-trx-parallel-test COMMAND tests/read_only_trx_test.py -p 2 -n 3 --read-only-threads 16 --num-test-runs 3 ${UNSHARE} WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) set_property(TEST read-only-trx-parallel-test PROPERTY LABELS nonparallelizable_tests) -add_test(NAME read-only-trx-parallel-eos-vm-oc-test COMMAND tests/read_only_trx_test.py -v -p 2 -n 3 --eos-vm-oc-enable all --read-only-threads 128 --num-test-runs 3 ${UNSHARE} WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) +add_test(NAME read-only-trx-parallel-eos-vm-oc-test COMMAND tests/read_only_trx_test.py -p 2 -n 3 --eos-vm-oc-enable all --read-only-threads 16 --num-test-runs 3 ${UNSHARE} WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) set_property(TEST read-only-trx-parallel-eos-vm-oc-test PROPERTY LABELS nonparallelizable_tests) -add_test(NAME read-only-trx-parallel-no-oc-test COMMAND tests/read_only_trx_test.py -v -p 2 -n 3 --eos-vm-oc-enable none --read-only-threads 6 --num-test-runs 2 ${UNSHARE} WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) +add_test(NAME read-only-trx-parallel-no-oc-test COMMAND tests/read_only_trx_test.py -p 2 -n 3 --eos-vm-oc-enable none --read-only-threads 6 --num-test-runs 2 ${UNSHARE} WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) set_property(TEST read-only-trx-parallel-no-oc-test PROPERTY LABELS nonparallelizable_tests) add_test(NAME subjective_billing_test COMMAND tests/subjective_billing_test.py -v -p 2 -n 4 ${UNSHARE} WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) set_property(TEST subjective_billing_test PROPERTY LABELS nonparallelizable_tests) @@ -188,6 +190,8 @@ add_test(NAME p2p_multiple_listen_test COMMAND tests/p2p_multiple_listen_test.py set_property(TEST p2p_multiple_listen_test PROPERTY LABELS nonparallelizable_tests) add_test(NAME p2p_no_listen_test COMMAND tests/p2p_no_listen_test.py -v ${UNSHARE} WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) set_property(TEST p2p_no_listen_test PROPERTY LABELS nonparallelizable_tests) +add_test(NAME p2p_sync_throttle_test COMMAND tests/p2p_sync_throttle_test.py -v -d 2 ${UNSHARE} WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) +set_property(TEST p2p_sync_throttle_test PROPERTY LABELS nonparallelizable_tests) # needs iproute-tc or iproute2 depending on platform #add_test(NAME p2p_high_latency_test COMMAND tests/p2p_high_latency_test.py -v WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) @@ -223,7 +227,7 @@ set_property(TEST nodeos_startup_catchup_lr_test PROPERTY LABELS long_running_te add_test(NAME nodeos_short_fork_take_over_test COMMAND tests/nodeos_short_fork_take_over_test.py -v --wallet-port 9905 ${UNSHARE} WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) set_property(TEST nodeos_short_fork_take_over_test PROPERTY LABELS nonparallelizable_tests) -add_test(NAME nodeos_extra_packed_data_test COMMAND tests/nodeos_extra_packed_data_test.py -v -p 8 ${UNSHARE} WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) +add_test(NAME nodeos_extra_packed_data_test COMMAND tests/nodeos_extra_packed_data_test.py -v -p 2 ${UNSHARE} WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) set_property(TEST nodeos_extra_packed_data_test PROPERTY LABELS nonparallelizable_tests) add_test(NAME nodeos_producer_watermark_lr_test COMMAND tests/nodeos_producer_watermark_test.py -v ${UNSHARE} WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) @@ -277,7 +281,7 @@ set_property(TEST gelf_test PROPERTY LABELS nonparallelizable_tests) add_test(NAME performance_test_bp COMMAND tests/PerformanceHarnessScenarioRunner.py findMax testBpOpMode --max-tps-to-test 50 --test-iteration-min-step 10 --test-iteration-duration-sec 10 --final-iterations-duration-sec 10 --calc-chain-threads lmax overrideBasicTestConfig -v --tps-limit-per-generator 25 --chain-state-db-size-mb 200 ${UNSHARE} WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) add_test(NAME performance_test_api COMMAND tests/PerformanceHarnessScenarioRunner.py findMax testApiOpMode --max-tps-to-test 50 --test-iteration-min-step 10 --test-iteration-duration-sec 10 --final-iterations-duration-sec 10 --calc-chain-threads lmax overrideBasicTestConfig -v --tps-limit-per-generator 25 --chain-state-db-size-mb 200 ${UNSHARE} WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) -add_test(NAME performance_test_read_only_trxs COMMAND tests/PerformanceHarnessScenarioRunner.py findMax testApiOpMode --max-tps-to-test 50 --test-iteration-min-step 10 --test-iteration-duration-sec 10 --final-iterations-duration-sec 10 overrideBasicTestConfig -v --tps-limit-per-generator 25 --api-nodes-read-only-threads 2 --account-name "payloadless" --abi-file payloadless.abi --wasm-file payloadless.wasm --contract-dir unittests/test-contracts/payloadless --user-trx-data-file tests/PerformanceHarness/readOnlyTrxData.json --chain-state-db-size-mb 200 ${UNSHARE} WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) +add_test(NAME performance_test_read_only_trxs COMMAND tests/PerformanceHarnessScenarioRunner.py findMax testApiOpMode --max-tps-to-test 50 --test-iteration-min-step 10 --test-iteration-duration-sec 10 --final-iterations-duration-sec 10 overrideBasicTestConfig -v --tps-limit-per-generator 25 --api-nodes-read-only-threads 2 --read-only-write-window-time-us 1000 --read-only-read-window-time-us 165000 --account-name "payloadless" --abi-file payloadless.abi --wasm-file payloadless.wasm --contract-dir unittests/test-contracts/payloadless --user-trx-data-file tests/PerformanceHarness/readOnlySlowTrxData.json --chain-state-db-size-mb 200 ${UNSHARE} WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) add_test(NAME performance_test_cpu_trx_spec COMMAND tests/PerformanceHarnessScenarioRunner.py findMax testBpOpMode --max-tps-to-test 50 --test-iteration-min-step 10 --test-iteration-duration-sec 10 --final-iterations-duration-sec 10 overrideBasicTestConfig -v --tps-limit-per-generator 25 --chain-state-db-size-mb 200 --account-name "c" --abi-file eosmechanics.abi --wasm-file eosmechanics.wasm --contract-dir unittests/contracts/eosio.mechanics --user-trx-data-file tests/PerformanceHarness/cpuTrxData.json ${UNSHARE} WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) add_test(NAME performance_test_basic_p2p COMMAND tests/PerformanceHarnessScenarioRunner.py singleTest -v --producer-nodes 1 --validation-nodes 1 --target-tps 20 --tps-limit-per-generator 10 --test-duration-sec 5 --chain-state-db-size-mb 200 ${UNSHARE} WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) add_test(NAME performance_test_basic_http COMMAND tests/PerformanceHarnessScenarioRunner.py singleTest -v --endpoint-mode http --producer-nodes 1 --validation-nodes 1 --api-nodes 1 --target-tps 10 --tps-limit-per-generator 10 --test-duration-sec 5 --chain-state-db-size-mb 200 ${UNSHARE} WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) @@ -285,7 +289,7 @@ add_test(NAME performance_test_basic_transfer_trx_spec COMMAND tests/Performance add_test(NAME performance_test_basic_new_acct_trx_spec COMMAND tests/PerformanceHarnessScenarioRunner.py singleTest -v --producer-nodes 1 --validation-nodes 1 --target-tps 20 --tps-limit-per-generator 10 --test-duration-sec 5 --chain-state-db-size-mb 200 --user-trx-data-file tests/PerformanceHarness/userTrxDataNewAccount.json ${UNSHARE} WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) add_test(NAME performance_test_basic_cpu_trx_spec COMMAND tests/PerformanceHarnessScenarioRunner.py singleTest -v --producer-nodes 1 --validation-nodes 1 --target-tps 20 --tps-limit-per-generator 10 --test-duration-sec 5 --chain-state-db-size-mb 200 --account-name "c" --abi-file eosmechanics.abi --wasm-file eosmechanics.wasm --contract-dir unittests/contracts/eosio.mechanics --user-trx-data-file tests/PerformanceHarness/cpuTrxData.json ${UNSHARE} WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) add_test(NAME performance_test_basic_ram_trx_spec COMMAND tests/PerformanceHarnessScenarioRunner.py singleTest -v --producer-nodes 1 --validation-nodes 1 --target-tps 20 --tps-limit-per-generator 10 --test-duration-sec 5 --chain-state-db-size-mb 200 --account-name "r" --abi-file eosmechanics.abi --wasm-file eosmechanics.wasm --contract-dir unittests/contracts/eosio.mechanics --user-trx-data-file tests/PerformanceHarness/ramTrxData.json ${UNSHARE} WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) -add_test(NAME performance_test_basic_read_only_trxs COMMAND tests/PerformanceHarnessScenarioRunner.py singleTest -v --endpoint-mode http --producer-nodes 1 --validation-nodes 1 --api-nodes 1 --api-nodes-read-only-threads 2 --target-tps 20 --tps-limit-per-generator 10 --test-duration-sec 5 --chain-state-db-size-mb 200 --account-name "payloadless" --abi-file payloadless.abi --wasm-file payloadless.wasm --contract-dir unittests/test-contracts/payloadless --user-trx-data-file tests/PerformanceHarness/readOnlyTrxData.json ${UNSHARE} WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) +add_test(NAME performance_test_basic_read_only_trxs COMMAND tests/PerformanceHarnessScenarioRunner.py singleTest -v --endpoint-mode http --producer-nodes 1 --validation-nodes 1 --api-nodes 1 --api-nodes-read-only-threads 2 --read-only-write-window-time-us 1000 --read-only-read-window-time-us 165000 --target-tps 20 --tps-limit-per-generator 10 --test-duration-sec 5 --chain-state-db-size-mb 200 --account-name "payloadless" --abi-file payloadless.abi --wasm-file payloadless.wasm --contract-dir unittests/test-contracts/payloadless --user-trx-data-file tests/PerformanceHarness/readOnlySlowTrxData.json ${UNSHARE} WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) set_property(TEST performance_test_bp PROPERTY LABELS long_running_tests) set_property(TEST performance_test_api PROPERTY LABELS long_running_tests) set_property(TEST performance_test_read_only_trxs PROPERTY LABELS long_running_tests) diff --git a/tests/PerformanceHarness/CMakeLists.txt b/tests/PerformanceHarness/CMakeLists.txt index f5a7711e3f..cba9f6282e 100644 --- a/tests/PerformanceHarness/CMakeLists.txt +++ b/tests/PerformanceHarness/CMakeLists.txt @@ -5,6 +5,7 @@ configure_file(genesis.json . COPYONLY) configure_file(cpuTrxData.json . COPYONLY) configure_file(ramTrxData.json . COPYONLY) configure_file(readOnlyTrxData.json . COPYONLY) +configure_file(readOnlySlowTrxData.json . COPYONLY) configure_file(userTrxDataTransfer.json . COPYONLY) configure_file(userTrxDataNewAccount.json . COPYONLY) diff --git a/tests/PerformanceHarness/README.md b/tests/PerformanceHarness/README.md index 3178aa9e51..42ff944ef0 100644 --- a/tests/PerformanceHarness/README.md +++ b/tests/PerformanceHarness/README.md @@ -32,19 +32,19 @@ Please refer to [Leap: Build and Install from Source](https://github.com/Antelop 3. Collect Results - By default the Performance Harness will capture and save logs. To delete logs, use `--del-perf-logs`. Additionally, final reports will be collected by default. To omit final reports, use `--del-report` and/or `--del-test-report`. 1. Navigate to performance test logs directory ```bash - cd ./build/PerformanceHarnessScenarioRunnerLogs/ + cd ./build/PHSRLogs/ ``` 2. Log Directory Structure is hierarchical with each run of the `PerformanceHarnessScenarioRunner` reporting into a timestamped directory where it includes the full performance report as well as a directory containing output from each test type run (here, `PerformanceTestBasic`) and each individual test run outputs into a timestamped directory within `testRunLogs` that may contain block data logs and transaction generator logs as well as the test's basic report. An example directory structure follows:
Expand Example Directory Structure ``` bash - PerformanceHarnessScenarioRunnerLogs/ + PHSRLogs/ └── 2023-04-05_14-35-59 ├── pluginThreadOptRunLogs │   ├── chainThreadResults.txt │   ├── netThreadResults.txt - │   ├── PerformanceHarnessScenarioRunnerLogs + │   ├── PHSRLogs │   │   ├── 2023-04-05_14-35-59-50000 │   │   │   ├── blockDataLogs │   │   │   │   ├── blockData.txt @@ -163,7 +163,7 @@ Please refer to [Leap: Build and Install from Source](https://github.com/Antelop │   └── producerThreadResults.txt ├── report.json └── testRunLogs - └── PerformanceHarnessScenarioRunnerLogs + └── PHSRLogs ├── 2023-04-05_16-14-31-50000 │   ├── blockDataLogs │   │   ├── blockData.txt @@ -504,12 +504,14 @@ usage: PerformanceHarnessScenarioRunner.py findMax testBpOpMode overrideBasicTes [--cluster-log-lvl {all,debug,info,warn,error,off}] [--net-threads NET_THREADS] [--disable-subjective-billing DISABLE_SUBJECTIVE_BILLING] - [--cpu-effort-percent CPU_EFFORT_PERCENT] + [--produce-block-offset-ms PRODUCE_BLOCK_OFFSET_MS] [--producer-threads PRODUCER_THREADS] + [--read-only-write-window-time-us READ_ONLY_WRITE_WINDOW_TIME_US] + [--read-only-read-window-time-us READ_ONLY_READ_WINDOW_TIME_US] [--http-max-in-flight-requests HTTP_MAX_IN_FLIGHT_REQUESTS] [--http-max-response-time-ms HTTP_MAX_RESPONSE_TIME_MS] [--http-max-bytes-in-flight-mb HTTP_MAX_BYTES_IN_FLIGHT_MB] - [--del-perf-logs] [--del-report] [--quiet] [--prods-enable-trace-api] + [--del-perf-logs] [--del-report] [--save-state] [--quiet] [--prods-enable-trace-api] [--print-missing-transactions] [--account-name ACCOUNT_NAME] [--contract-dir CONTRACT_DIR] [--wasm-file WASM_FILE] [--abi-file ABI_FILE] [--user-trx-data-file USER_TRX_DATA_FILE] @@ -577,10 +579,15 @@ Performance Test Basic Base: Number of worker threads in net_plugin thread pool --disable-subjective-billing DISABLE_SUBJECTIVE_BILLING Disable subjective CPU billing for API/P2P transactions - --cpu-effort-percent CPU_EFFORT_PERCENT - Percentage of cpu block production time used to produce block. Whole number percentages, e.g. 80 for 80% + --produce-block-offset-ms PRODUCE_BLOCK_OFFSET_MS + The number of milliseconds early the last block of a production round should + be produced. --producer-threads PRODUCER_THREADS Number of worker threads in producer thread pool + --read-only-write-window-time-us READ_ONLY_WRITE_WINDOW_TIME_US + Time in microseconds the write window lasts. + --read-only-read-window-time-us READ_ONLY_READ_WINDOW_TIME_US + Time in microseconds the read window lasts. --http-max-in-flight-requests HTTP_MAX_IN_FLIGHT_REQUESTS Maximum number of requests http_plugin should use for processing http requests. 429 error response when exceeded. -1 for unlimited --http-max-response-time-ms HTTP_MAX_RESPONSE_TIME_MS @@ -589,6 +596,7 @@ Performance Test Basic Base: Maximum size in megabytes http_plugin should use for processing http requests. -1 for unlimited. 429 error response when exceeded. --del-perf-logs Whether to delete performance test specific logs. --del-report Whether to delete overarching performance run report. + --save-state Whether to save node state. (Warning: large disk usage) --quiet Whether to quiet printing intermediate results and reports to stdout --prods-enable-trace-api Determines whether producer nodes should have eosio::trace_api_plugin enabled @@ -656,12 +664,12 @@ The following classes and scripts are typically used by the Performance Harness [--cluster-log-lvl {all,debug,info,warn,error,off}] [--net-threads NET_THREADS] [--disable-subjective-billing DISABLE_SUBJECTIVE_BILLING] - [--cpu-effort-percent CPU_EFFORT_PERCENT] + [--produce-block-offset-ms PRODUCE_BLOCK_OFFSET_MS] [--producer-threads PRODUCER_THREADS] [--http-max-in-flight-requests HTTP_MAX_IN_FLIGHT_REQUESTS] [--http-max-response-time-ms HTTP_MAX_RESPONSE_TIME_MS] [--http-max-bytes-in-flight-mb HTTP_MAX_BYTES_IN_FLIGHT_MB] - [--del-perf-logs] [--del-report] [--quiet] + [--del-perf-logs] [--del-report] [--save-state] [--quiet] [--prods-enable-trace-api] [--print-missing-transactions] [--account-name ACCOUNT_NAME] @@ -735,8 +743,9 @@ Performance Test Basic Base: Number of worker threads in net_plugin thread pool (default: 4) --disable-subjective-billing DISABLE_SUBJECTIVE_BILLING Disable subjective CPU billing for API/P2P transactions (default: True) - --cpu-effort-percent CPU_EFFORT_PERCENT - Percentage of cpu block production time used to produce block. Whole number percentages, e.g. 80 for 80% (default: 100) + --produce-block-offset-ms PRODUCE_BLOCK_OFFSET_MS + The number of milliseconds early the last block of a production round should + be produced. --producer-threads PRODUCER_THREADS Number of worker threads in producer thread pool (default: 2) --http-max-in-flight-requests HTTP_MAX_IN_FLIGHT_REQUESTS @@ -747,6 +756,7 @@ Performance Test Basic Base: Maximum size in megabytes http_plugin should use for processing http requests. -1 for unlimited. 429 error response when exceeded. (default: -1) --del-perf-logs Whether to delete performance test specific logs. (default: False) --del-report Whether to delete overarching performance run report. (default: False) + --save-state Whether to save node state. (Warning: large disk usage) --quiet Whether to quiet printing intermediate results and reports to stdout (default: False) --prods-enable-trace-api Determines whether producer nodes should have eosio::trace_api_plugin enabled (default: False) @@ -923,7 +933,7 @@ Next, a summary of the search scenario conducted and respective results is inclu "expectedTxns": 140010, "resultTxns": 140010, "testAnalysisBlockCnt": 17, - "logsDir": "PerformanceHarnessScenarioRunnerLogs/2023-08-18_16-16-57/testRunLogs/PerformanceHarnessScenarioRunnerLogs/2023-08-18_17-49-42-14001" + "logsDir": "PHSRLogs/2023-08-18_16-16-57/testRunLogs/PHSRunLogs/2023-08-18_17-49-42-14001" } } ``` @@ -1001,7 +1011,7 @@ Finally, the full detail test report for each of the determined max TPS throughp "expectedTxns": 500000, "resultTxns": 295339, "testAnalysisBlockCnt": 41, - "logsDir": "PerformanceHarnessScenarioRunnerLogs/2023-08-18_16-16-57/testRunLogs/PerformanceHarnessScenarioRunnerLogs/2023-08-18_17-39-08-50000" + "logsDir": "PHSRLogs/2023-08-18_16-16-57/testRunLogs/PHSRunLogs/2023-08-18_17-39-08-50000" } }, "1": { @@ -1023,7 +1033,7 @@ Finally, the full detail test report for each of the determined max TPS throughp "expectedTxns": 250010, "resultTxns": 249933, "testAnalysisBlockCnt": 34, - "logsDir": "PerformanceHarnessScenarioRunnerLogs/2023-08-18_16-16-57/testRunLogs/PerformanceHarnessScenarioRunnerLogs/2023-08-18_17-40-45-25001" + "logsDir": "PHSRLogs/2023-08-18_16-16-57/testRunLogs/PHSRunLogs/2023-08-18_17-40-45-25001" } }, "2": { @@ -1045,7 +1055,7 @@ Finally, the full detail test report for each of the determined max TPS throughp "expectedTxns": 125010, "resultTxns": 125010, "testAnalysisBlockCnt": 17, - "logsDir": "PerformanceHarnessScenarioRunnerLogs/2023-08-18_16-16-57/testRunLogs/PerformanceHarnessScenarioRunnerLogs/2023-08-18_17-42-10-12501" + "logsDir": "PHSRLogs/2023-08-18_16-16-57/testRunLogs/PHSRunLogs/2023-08-18_17-42-10-12501" } }, "3": { @@ -1067,7 +1077,7 @@ Finally, the full detail test report for each of the determined max TPS throughp "expectedTxns": 190010, "resultTxns": 190010, "testAnalysisBlockCnt": 23, - "logsDir": "PerformanceHarnessScenarioRunnerLogs/2023-08-18_16-16-57/testRunLogs/PerformanceHarnessScenarioRunnerLogs/2023-08-18_17-43-23-19001" + "logsDir": "PHSRLogs/2023-08-18_16-16-57/testRunLogs/PHSRunLogs/2023-08-18_17-43-23-19001" } }, "4": { @@ -1089,7 +1099,7 @@ Finally, the full detail test report for each of the determined max TPS throughp "expectedTxns": 160010, "resultTxns": 160010, "testAnalysisBlockCnt": 19, - "logsDir": "PerformanceHarnessScenarioRunnerLogs/2023-08-18_16-16-57/testRunLogs/PerformanceHarnessScenarioRunnerLogs/2023-08-18_17-44-44-16001" + "logsDir": "PHSRLogs/2023-08-18_16-16-57/testRunLogs/PHSRunLogs/2023-08-18_17-44-44-16001" } }, "5": { @@ -1111,7 +1121,7 @@ Finally, the full detail test report for each of the determined max TPS throughp "expectedTxns": 145010, "resultTxns": 144898, "testAnalysisBlockCnt": 17, - "logsDir": "PerformanceHarnessScenarioRunnerLogs/2023-08-18_16-16-57/testRunLogs/PerformanceHarnessScenarioRunnerLogs/2023-08-18_17-46-01-14501" + "logsDir": "PHSRLogs/2023-08-18_16-16-57/testRunLogs/PHSRunLogs/2023-08-18_17-46-01-14501" } }, "6": { @@ -1133,7 +1143,7 @@ Finally, the full detail test report for each of the determined max TPS throughp "expectedTxns": 135010, "resultTxns": 135010, "testAnalysisBlockCnt": 17, - "logsDir": "PerformanceHarnessScenarioRunnerLogs/2023-08-18_16-16-57/testRunLogs/PerformanceHarnessScenarioRunnerLogs/2023-08-18_17-47-15-13501" + "logsDir": "PHSRLogs/2023-08-18_16-16-57/testRunLogs/PHSRunLogs/2023-08-18_17-47-15-13501" } }, "7": { @@ -1155,7 +1165,7 @@ Finally, the full detail test report for each of the determined max TPS throughp "expectedTxns": 140010, "resultTxns": 140010, "testAnalysisBlockCnt": 17, - "logsDir": "PerformanceHarnessScenarioRunnerLogs/2023-08-18_16-16-57/testRunLogs/PerformanceHarnessScenarioRunnerLogs/2023-08-18_17-48-29-14001" + "logsDir": "PHSRLogs/2023-08-18_16-16-57/testRunLogs/PHSRunLogs/2023-08-18_17-48-29-14001" } } }, @@ -1195,7 +1205,7 @@ Finally, the full detail test report for each of the determined max TPS throughp "expectedTxns": 140010, "resultTxns": 140010, "testAnalysisBlockCnt": 17, - "logsDir": "PerformanceHarnessScenarioRunnerLogs/2023-08-18_16-16-57/testRunLogs/PerformanceHarnessScenarioRunnerLogs/2023-08-18_17-49-42-14001" + "logsDir": "PHSRLogs/2023-08-18_16-16-57/testRunLogs/PHSRunLogs/2023-08-18_17-49-42-14001" } } }, @@ -1365,8 +1375,6 @@ Finally, the full detail test report for each of the determined max TPS throughp "_enableAccountQueriesNodeosDefault": 0, "_enableAccountQueriesNodeosArg": "--enable-account-queries", "maxNonprivilegedInlineActionSize": null, - "_maxNonprivilegedInlineActionSizeNodeosDefault": 4096, - "_maxNonprivilegedInlineActionSizeNodeosArg": "--max-nonprivileged-inline-action-size", "transactionRetryMaxStorageSizeGb": null, "_transactionRetryMaxStorageSizeGbNodeosDefault": null, "_transactionRetryMaxStorageSizeGbNodeosArg": "--transaction-retry-max-storage-size-gb", @@ -1580,18 +1588,15 @@ Finally, the full detail test report for each of the determined max TPS throughp "greylistLimit": null, "_greylistLimitNodeosDefault": 1000, "_greylistLimitNodeosArg": "--greylist-limit", - "cpuEffortPercent": 100, - "_cpuEffortPercentNodeosDefault": 90, - "_cpuEffortPercentNodeosArg": "--cpu-effort-percent", + "produceBlockOffsetMs": 0, + "_produceBlockOffsetMsDefault": 450, + "_produceBlockOffsetMsArg": "--produce-block-offset-ms", "maxBlockCpuUsageThresholdUs": null, "_maxBlockCpuUsageThresholdUsNodeosDefault": 5000, "_maxBlockCpuUsageThresholdUsNodeosArg": "--max-block-cpu-usage-threshold-us", "maxBlockNetUsageThresholdBytes": null, "_maxBlockNetUsageThresholdBytesNodeosDefault": 1024, "_maxBlockNetUsageThresholdBytesNodeosArg": "--max-block-net-usage-threshold-bytes", - "maxScheduledTransactionTimePerBlockMs": null, - "_maxScheduledTransactionTimePerBlockMsNodeosDefault": 100, - "_maxScheduledTransactionTimePerBlockMsNodeosArg": "--max-scheduled-transaction-time-per-block-ms", "subjectiveCpuLeewayUs": null, "_subjectiveCpuLeewayUsNodeosDefault": 31000, "_subjectiveCpuLeewayUsNodeosArg": "--subjective-cpu-leeway-us", @@ -1604,9 +1609,6 @@ Finally, the full detail test report for each of the determined max TPS throughp "subjectiveAccountDecayTimeMinutes": null, "_subjectiveAccountDecayTimeMinutesNodeosDefault": 1440, "_subjectiveAccountDecayTimeMinutesNodeosArg": "--subjective-account-decay-time-minutes", - "incomingDeferRatio": null, - "_incomingDeferRatioNodeosDefault": 1, - "_incomingDeferRatioNodeosArg": "--incoming-defer-ratio", "incomingTransactionQueueSizeMb": null, "_incomingTransactionQueueSizeMbNodeosDefault": 1024, "_incomingTransactionQueueSizeMbNodeosArg": "--incoming-transaction-queue-size-mb", @@ -1775,11 +1777,11 @@ Finally, the full detail test report for each of the determined max TPS throughp "userTrxDataFile": null, "endpointMode": "p2p", "opModeCmd": "testBpOpMode", - "logDirBase": "PerformanceHarnessScenarioRunnerLogs", + "logDirBase": "PHSRLogs", "logDirTimestamp": "2023-08-18_16-16-57", - "logDirPath": "PerformanceHarnessScenarioRunnerLogs/2023-08-18_16-16-57", - "ptbLogsDirPath": "PerformanceHarnessScenarioRunnerLogs/2023-08-18_16-16-57/testRunLogs", - "pluginThreadOptLogsDirPath": "PerformanceHarnessScenarioRunnerLogs/2023-08-18_16-16-57/pluginThreadOptRunLogs" + "logDirPath": "PHSRLogs/2023-08-18_16-16-57", + "ptbLogsDirPath": "PHSRLogs/2023-08-18_16-16-57/testRunLogs", + "pluginThreadOptLogsDirPath": "PHSRLogs/2023-08-18_16-16-57/pluginThreadOptRunLogs" }, "env": { "system": "Linux", @@ -1795,7 +1797,7 @@ Finally, the full detail test report for each of the determined max TPS throughp ## Performance Test Basic Report -The Performance Test Basic generates, by default, a report that details results of the test, statistics around metrics of interest, as well as diagnostic information about the test run. If `PerformanceHarnessScenarioRunner.py findMax` is run with `--del-test-report`, or `PerformanceHarnessScenarioRunner.py singleTest` is run with `--del-report`, the report described below will not be written. Otherwise the report will be written to the timestamped directory within the `PerformanceHarnessScenarioRunnerLogs` log directory for the test run with the file name `data.json`. +The Performance Test Basic generates, by default, a report that details results of the test, statistics around metrics of interest, as well as diagnostic information about the test run. If `PerformanceHarnessScenarioRunner.py findMax` is run with `--del-test-report`, or `PerformanceHarnessScenarioRunner.py singleTest` is run with `--del-report`, the report described below will not be written. Otherwise the report will be written to the timestamped directory within the `PHSRLogs` log directory for the test run with the file name `data.json`.
Expand for full sample report @@ -1818,7 +1820,7 @@ The Performance Test Basic generates, by default, a report that details results "expectedTxns": 140010, "resultTxns": 140010, "testAnalysisBlockCnt": 17, - "logsDir": "PerformanceHarnessScenarioRunnerLogs/2023-08-18_16-16-57/testRunLogs/PerformanceHarnessScenarioRunnerLogs/2023-08-18_17-49-42-14001" + "logsDir": "PHSRLogs/2023-08-18_16-16-57/testRunLogs/PHSRunLogs/2023-08-18_17-49-42-14001" }, "Analysis": { "BlockSize": { @@ -2033,8 +2035,6 @@ The Performance Test Basic generates, by default, a report that details results "_enableAccountQueriesNodeosDefault": 0, "_enableAccountQueriesNodeosArg": "--enable-account-queries", "maxNonprivilegedInlineActionSize": null, - "_maxNonprivilegedInlineActionSizeNodeosDefault": 4096, - "_maxNonprivilegedInlineActionSizeNodeosArg": "--max-nonprivileged-inline-action-size", "transactionRetryMaxStorageSizeGb": null, "_transactionRetryMaxStorageSizeGbNodeosDefault": null, "_transactionRetryMaxStorageSizeGbNodeosArg": "--transaction-retry-max-storage-size-gb", @@ -2248,18 +2248,15 @@ The Performance Test Basic generates, by default, a report that details results "greylistLimit": null, "_greylistLimitNodeosDefault": 1000, "_greylistLimitNodeosArg": "--greylist-limit", - "cpuEffortPercent": 100, - "_cpuEffortPercentNodeosDefault": 90, - "_cpuEffortPercentNodeosArg": "--cpu-effort-percent", + "produceBlockOffsetMs": 0, + "_produceBlockOffsetMsDefault": 450, + "_produceBlockOffsetMsArg": "--produce-block-offset-ms", "maxBlockCpuUsageThresholdUs": null, "_maxBlockCpuUsageThresholdUsNodeosDefault": 5000, "_maxBlockCpuUsageThresholdUsNodeosArg": "--max-block-cpu-usage-threshold-us", "maxBlockNetUsageThresholdBytes": null, "_maxBlockNetUsageThresholdBytesNodeosDefault": 1024, "_maxBlockNetUsageThresholdBytesNodeosArg": "--max-block-net-usage-threshold-bytes", - "maxScheduledTransactionTimePerBlockMs": null, - "_maxScheduledTransactionTimePerBlockMsNodeosDefault": 100, - "_maxScheduledTransactionTimePerBlockMsNodeosArg": "--max-scheduled-transaction-time-per-block-ms", "subjectiveCpuLeewayUs": null, "_subjectiveCpuLeewayUsNodeosDefault": 31000, "_subjectiveCpuLeewayUsNodeosArg": "--subjective-cpu-leeway-us", @@ -2272,9 +2269,6 @@ The Performance Test Basic generates, by default, a report that details results "subjectiveAccountDecayTimeMinutes": null, "_subjectiveAccountDecayTimeMinutesNodeosDefault": 1440, "_subjectiveAccountDecayTimeMinutesNodeosArg": "--subjective-account-decay-time-minutes", - "incomingDeferRatio": null, - "_incomingDeferRatioNodeosDefault": 1, - "_incomingDeferRatioNodeosArg": "--incoming-defer-ratio", "incomingTransactionQueueSizeMb": null, "_incomingTransactionQueueSizeMbNodeosDefault": 1024, "_incomingTransactionQueueSizeMbNodeosArg": "--incoming-transaction-queue-size-mb", @@ -2428,7 +2422,7 @@ The Performance Test Basic generates, by default, a report that details results "testTrxGenDurationSec": 10, "tpsLimitPerGenerator": 4000, "numAddlBlocksToPrune": 2, - "logDirRoot": "PerformanceHarnessScenarioRunnerLogs/2023-08-18_16-16-57/testRunLogs", + "logDirRoot": "PHSRLogs/2023-08-18_16-16-57/testRunLogs", "delReport": false, "quiet": false, "delPerfLogs": false, @@ -2437,10 +2431,10 @@ The Performance Test Basic generates, by default, a report that details results "userTrxDataFile": null, "endpointMode": "p2p", "apiEndpoint": null, - "logDirBase": "PerformanceHarnessScenarioRunnerLogs/2023-08-18_16-16-57/testRunLogs/PerformanceHarnessScenarioRunnerLogs", + "logDirBase": "PHSRLogs/2023-08-18_16-16-57/testRunLogs/PHSRunLogs", "logDirTimestamp": "2023-08-18_17-49-42", "logDirTimestampedOptSuffix": "-14001", - "logDirPath": "PerformanceHarnessScenarioRunnerLogs/2023-08-18_16-16-57/testRunLogs/PerformanceHarnessScenarioRunnerLogs/2023-08-18_17-49-42-14001", + "logDirPath": "PHSRLogs/2023-08-18_16-16-57/testRunLogs/PHSRunLogs/2023-08-18_17-49-42-14001", "userTrxData": "NOT CONFIGURED" }, "env": { diff --git a/tests/PerformanceHarness/log_reader.py b/tests/PerformanceHarness/log_reader.py index 70bb605fc1..ef68d4b4d5 100644 --- a/tests/PerformanceHarness/log_reader.py +++ b/tests/PerformanceHarness/log_reader.py @@ -269,11 +269,13 @@ def scrapeTrxGenTrxSentDataLogs(trxSent: dict, trxGenLogDirPath, quiet): if not quiet: print(f"Transaction Log Files Scraped: {filesScraped}") -def populateTrxSentAndAcked(trxSent: dict, trxDict: dict, notFound): +def populateTrxSentAndAcked(trxSent: dict, data: chainData, notFound): + trxDict = data.trxDict for sentTrxId in trxSent.keys(): if (isinstance(trxSent[sentTrxId], sentTrxExtTrace)): trxDict[sentTrxId] = trxData(blockNum=trxSent[sentTrxId].blockNum, cpuUsageUs=trxSent[sentTrxId].cpuUsageUs, netUsageUs=trxSent[sentTrxId].netUsageWords, blockTime=trxSent[sentTrxId].blockTime, acknowledged=trxSent[sentTrxId].acked, ackRespTimeUs=trxSent[sentTrxId].ackResponseTimeUs) trxDict[sentTrxId].sentTimestamp = trxSent[sentTrxId].sentTime + data.blockDict[str(trxSent[sentTrxId].blockNum)].transactions +=1 elif sentTrxId in trxDict.keys(): trxDict[sentTrxId].sentTimestamp = trxSent[sentTrxId].sentTime trxDict[sentTrxId].acknowledged = trxSent[sentTrxId].acked @@ -493,7 +495,7 @@ def analyzeLogResults(data: chainData, tpsTestConfig: TpsTestConfig, artifacts: trxAckStatsApplicable="NOT APPLICABLE" if list(trxSent.values())[0].acked == "NA" else "APPLICABLE" notFound = [] - populateTrxSentAndAcked(trxSent, data.trxDict, notFound) + populateTrxSentAndAcked(trxSent, data, notFound) prodDict = {} getProductionWindows(prodDict, data) diff --git a/tests/PerformanceHarness/performance_test.py b/tests/PerformanceHarness/performance_test.py index 4332450304..489521164e 100755 --- a/tests/PerformanceHarness/performance_test.py +++ b/tests/PerformanceHarness/performance_test.py @@ -50,6 +50,7 @@ class PtConfig: endpointMode: str="p2p" opModeCmd: str="" trxGenerator: Path=Path(".") + saveState: bool=False def __post_init__(self): @@ -96,10 +97,10 @@ def __init__(self, testHelperConfig: PerformanceTestBasic.TestHelperConfig=Perfo self.testsStart = datetime.utcnow() - self.loggingConfig = PerformanceTest.LoggingConfig(logDirBase=Path(self.ptConfig.logDirRoot)/f"{os.path.basename(sys.argv[0]).rsplit('.',maxsplit=1)[0]}Logs", + self.loggingConfig = PerformanceTest.LoggingConfig(logDirBase=Path(self.ptConfig.logDirRoot)/f"PHSRLogs", logDirTimestamp=f"{self.testsStart.strftime('%Y-%m-%d_%H-%M-%S')}") - def performPtbBinarySearch(self, clusterConfig: PerformanceTestBasic.ClusterConfig, logDirRoot: Path, delReport: bool, quiet: bool, delPerfLogs: bool) -> TpsTestResult.PerfTestSearchResults: + def performPtbBinarySearch(self, clusterConfig: PerformanceTestBasic.ClusterConfig, logDirRoot: Path, delReport: bool, quiet: bool, delPerfLogs: bool, saveState: bool) -> TpsTestResult.PerfTestSearchResults: floor = self.ptConfig.minTpsToTest ceiling = self.ptConfig.maxTpsToTest binSearchTarget = self.ptConfig.maxTpsToTest @@ -114,10 +115,10 @@ def performPtbBinarySearch(self, clusterConfig: PerformanceTestBasic.ClusterConf scenarioResult = PerformanceTest.PerfTestSearchIndivResult(success=False, searchTarget=binSearchTarget, searchFloor=floor, searchCeiling=ceiling) ptbConfig = PerformanceTestBasic.PtbConfig(targetTps=binSearchTarget, testTrxGenDurationSec=self.ptConfig.testDurationSec, tpsLimitPerGenerator=self.ptConfig.tpsLimitPerGenerator, numAddlBlocksToPrune=self.ptConfig.numAddlBlocksToPrune, logDirRoot=logDirRoot, delReport=delReport, - quiet=quiet, userTrxDataFile=self.ptConfig.userTrxDataFile, endpointMode=self.ptConfig.endpointMode, - trxGenerator=self.ptConfig.trxGenerator) + quiet=quiet, delPerfLogs=delPerfLogs, userTrxDataFile=self.ptConfig.userTrxDataFile, endpointMode=self.ptConfig.endpointMode, + trxGenerator=self.ptConfig.trxGenerator, saveState=saveState) - myTest = PerformanceTestBasic(testHelperConfig=self.testHelperConfig, clusterConfig=clusterConfig, ptbConfig=ptbConfig, testNamePath=os.path.basename(sys.argv[0]).rsplit('.',maxsplit=1)[0]) + myTest = PerformanceTestBasic(testHelperConfig=self.testHelperConfig, clusterConfig=clusterConfig, ptbConfig=ptbConfig, testNamePath="PHSRun") myTest.runTest() if myTest.testResult.testPassed: maxTpsAchieved = binSearchTarget @@ -158,9 +159,9 @@ def performPtbReverseLinearSearch(self, tpsInitial: int) -> TpsTestResult.PerfTe ptbConfig = PerformanceTestBasic.PtbConfig(targetTps=searchTarget, testTrxGenDurationSec=self.ptConfig.testDurationSec, tpsLimitPerGenerator=self.ptConfig.tpsLimitPerGenerator, numAddlBlocksToPrune=self.ptConfig.numAddlBlocksToPrune, logDirRoot=self.loggingConfig.ptbLogsDirPath, delReport=self.ptConfig.delReport, quiet=self.ptConfig.quiet, delPerfLogs=self.ptConfig.delPerfLogs, userTrxDataFile=self.ptConfig.userTrxDataFile, endpointMode=self.ptConfig.endpointMode, - trxGenerator=self.ptConfig.trxGenerator) + trxGenerator=self.ptConfig.trxGenerator, saveState=self.ptConfig.saveState) - myTest = PerformanceTestBasic(testHelperConfig=self.testHelperConfig, clusterConfig=self.clusterConfig, ptbConfig=ptbConfig, testNamePath=os.path.basename(sys.argv[0]).rsplit('.',maxsplit=1)[0]) + myTest = PerformanceTestBasic(testHelperConfig=self.testHelperConfig, clusterConfig=self.clusterConfig, ptbConfig=ptbConfig, testNamePath="PHSRun") myTest.runTest() if myTest.testResult.testPassed: maxTpsAchieved = searchTarget @@ -216,7 +217,7 @@ def optimizePluginThreadCount(self, optPlugin: PluginThreadOpt, optType: Plugin setattr(getattr(clusterConfig.extraNodeosArgs, optPlugin.value + 'PluginArgs'), f"{optPlugin.value}Threads", threadCount) binSearchResults = self.performPtbBinarySearch(clusterConfig=clusterConfig, logDirRoot=self.loggingConfig.pluginThreadOptLogsDirPath, - delReport=True, quiet=False, delPerfLogs=True) + delReport=True, quiet=False, delPerfLogs=True, saveState=False) threadToMaxTpsDict[threadCount] = binSearchResults.maxTpsAchieved if not self.ptConfig.quiet: @@ -335,7 +336,8 @@ def performTpsTest(self) -> TpsTestResult: perfRunSuccessful = False binSearchResults = self.performPtbBinarySearch(clusterConfig=self.clusterConfig, logDirRoot=self.loggingConfig.ptbLogsDirPath, - delReport=self.ptConfig.delReport, quiet=self.ptConfig.quiet, delPerfLogs=self.ptConfig.delPerfLogs) + delReport=self.ptConfig.delReport, quiet=self.ptConfig.quiet, delPerfLogs=self.ptConfig.delPerfLogs, + saveState=self.ptConfig.saveState) print(f"Successful rate of: {binSearchResults.maxTpsAchieved}") diff --git a/tests/PerformanceHarness/performance_test_basic.py b/tests/PerformanceHarness/performance_test_basic.py index d2d3b72fa0..0d56329985 100755 --- a/tests/PerformanceHarness/performance_test_basic.py +++ b/tests/PerformanceHarness/performance_test_basic.py @@ -124,6 +124,7 @@ def __post_init__(self): def configureValidationNodes(): validationNodeSpecificNodeosStr = "" + validationNodeSpecificNodeosStr += '--p2p-accept-transactions false ' if "v2" in self.nodeosVers: validationNodeSpecificNodeosStr += '--plugin eosio::history_api_plugin --filter-on "*" ' else: @@ -137,6 +138,7 @@ def configureValidationNodes(): def configureApiNodes(): apiNodeSpecificNodeosStr = "" + apiNodeSpecificNodeosStr += "--p2p-accept-transactions false " apiNodeSpecificNodeosStr += "--plugin eosio::chain_api_plugin " apiNodeSpecificNodeosStr += "--plugin eosio::net_api_plugin " if "v4" in self.nodeosVers: @@ -174,6 +176,7 @@ class PtbConfig: endpointMode: str="p2p" apiEndpoint: str=None trxGenerator: Path=Path(".") + saveState: bool=False def __post_init__(self): self.expectedTransactionsSent = self.testTrxGenDurationSec * self.targetTps @@ -226,7 +229,7 @@ def __init__(self, testHelperConfig: TestHelperConfig=TestHelperConfig(), cluste self.producerNodeId = self.clusterConfig._producerNodeIds[0] self.validationNodeId = self.clusterConfig._validationNodeIds[0] pid = os.getpid() - self.nodeosLogDir = Path(self.loggingConfig.logDirPath)/"var"/f"{self.testNamePath}{pid}" + self.nodeosLogDir = Path(self.loggingConfig.logDirPath)/"var"/f"{Utils.DataRoot}{Utils.PID}" self.nodeosLogPath = self.nodeosLogDir/f"node_{str(self.validationNodeId).zfill(2)}"/"stderr.txt" # Setup cluster and its wallet manager @@ -258,6 +261,24 @@ def removeAllArtifactsExceptFinalReport(): except OSError as error: print(error) + def testDirsCleanupState(self): + try: + def removeArtifacts(path): + print(f"Checking if test artifacts dir exists: {path}") + if Path(path).is_dir(): + print(f"Cleaning up test artifacts dir and all contents of: {path}") + shutil.rmtree(f"{path}") + nodeDirPaths = list(Path(self.varLogsDirPath).rglob("node_*")) + print(f"nodeDirPaths: {nodeDirPaths}") + for nodeDirPath in nodeDirPaths: + stateDirs = list(Path(nodeDirPath).rglob("state")) + print(f"stateDirs: {stateDirs}") + for stateDirPath in stateDirs: + removeArtifacts(stateDirPath) + + except OSError as error: + print(error) + def testDirsSetup(self): try: def createArtifactsDir(path): @@ -622,6 +643,10 @@ def runTest(self) -> bool: print(f"Cleaning up logs directory: {self.loggingConfig.logDirPath}") self.testDirsCleanup(self.ptbConfig.delReport) + if not self.ptbConfig.saveState: + print(f"Cleaning up state directories: {self.varLogsDirPath}") + self.testDirsCleanupState() + return self.testResult.testRunSuccessful def setupTestHelperConfig(args) -> TestHelperConfig: @@ -638,8 +663,10 @@ def setupClusterConfig(args) -> ClusterConfig: producerPluginArgs = ProducerPluginArgs(disableSubjectiveApiBilling=args.disable_subjective_billing, disableSubjectiveP2pBilling=args.disable_subjective_billing, - cpuEffortPercent=args.cpu_effort_percent, - producerThreads=args.producer_threads, maxTransactionTime=-1) + produceBlockOffsetMs=args.produce_block_offset_ms, + producerThreads=args.producer_threads, maxTransactionTime=-1, + readOnlyWriteWindowTimeUs=args.read_only_write_window_time_us, + readOnlyReadWindowTimeUs=args.read_only_read_window_time_us) httpPluginArgs = HttpPluginArgs(httpMaxBytesInFlightMb=args.http_max_bytes_in_flight_mb, httpMaxInFlightRequests=args.http_max_in_flight_requests, httpMaxResponseTimeMs=args.http_max_response_time_ms, httpThreads=args.http_threads) netPluginArgs = NetPluginArgs(netThreads=args.net_threads, maxClients=0) @@ -693,14 +720,17 @@ def _createBaseArgumentParser(defEndpointApiDef: str, defProdNodeCnt: int, defVa choices=["all", "debug", "info", "warn", "error", "off"], default="info") ptbBaseParserGroup.add_argument("--net-threads", type=int, help=argparse.SUPPRESS if suppressHelp else "Number of worker threads in net_plugin thread pool", default=4) ptbBaseParserGroup.add_argument("--disable-subjective-billing", type=bool, help=argparse.SUPPRESS if suppressHelp else "Disable subjective CPU billing for API/P2P transactions", default=True) - ptbBaseParserGroup.add_argument("--cpu-effort-percent", type=int, help=argparse.SUPPRESS if suppressHelp else "Percentage of cpu block production time used to produce block. Whole number percentages, e.g. 80 for 80%%", default=100) + ptbBaseParserGroup.add_argument("--produce-block-offset-ms", type=int, help=argparse.SUPPRESS if suppressHelp else "The minimum time to reserve at the end of a production round for blocks to propagate to the next block producer.", default=0) ptbBaseParserGroup.add_argument("--producer-threads", type=int, help=argparse.SUPPRESS if suppressHelp else "Number of worker threads in producer thread pool", default=2) + ptbBaseParserGroup.add_argument("--read-only-write-window-time-us", type=int, help=argparse.SUPPRESS if suppressHelp else "Time in microseconds the write window lasts.", default=200000) + ptbBaseParserGroup.add_argument("--read-only-read-window-time-us", type=int, help=argparse.SUPPRESS if suppressHelp else "Time in microseconds the read window lasts.", default=60000) ptbBaseParserGroup.add_argument("--http-max-in-flight-requests", type=int, help=argparse.SUPPRESS if suppressHelp else "Maximum number of requests http_plugin should use for processing http requests. 429 error response when exceeded. -1 for unlimited", default=-1) ptbBaseParserGroup.add_argument("--http-max-response-time-ms", type=int, help=argparse.SUPPRESS if suppressHelp else "Maximum time for processing a request, -1 for unlimited", default=-1) ptbBaseParserGroup.add_argument("--http-max-bytes-in-flight-mb", type=int, help=argparse.SUPPRESS if suppressHelp else "Maximum size in megabytes http_plugin should use for processing http requests. -1 for unlimited. 429\ error response when exceeded.", default=-1) ptbBaseParserGroup.add_argument("--del-perf-logs", help=argparse.SUPPRESS if suppressHelp else "Whether to delete performance test specific logs.", action='store_true') ptbBaseParserGroup.add_argument("--del-report", help=argparse.SUPPRESS if suppressHelp else "Whether to delete overarching performance run report.", action='store_true') + ptbBaseParserGroup.add_argument("--save-state", help=argparse.SUPPRESS if suppressHelp else "Whether to save node state. (Warning: large disk usage)", action='store_true') ptbBaseParserGroup.add_argument("--quiet", help=argparse.SUPPRESS if suppressHelp else "Whether to quiet printing intermediate results and reports to stdout", action='store_true') ptbBaseParserGroup.add_argument("--prods-enable-trace-api", help=argparse.SUPPRESS if suppressHelp else "Determines whether producer nodes should have eosio::trace_api_plugin enabled", action='store_true') ptbBaseParserGroup.add_argument("--print-missing-transactions", help=argparse.SUPPRESS if suppressHelp else "Toggles if missing transactions are be printed upon test completion.", action='store_true') diff --git a/tests/PerformanceHarness/readOnlySlowTrxData.json b/tests/PerformanceHarness/readOnlySlowTrxData.json new file mode 100644 index 0000000000..ec6a61fd96 --- /dev/null +++ b/tests/PerformanceHarness/readOnlySlowTrxData.json @@ -0,0 +1,14 @@ +{ + "initAccounts": ["payloadless"], + "abiFile": "unittests/test-contracts/payloadless/payloadless.abi", + "apiEndpoint": "/v1/chain/send_read_only_transaction", + "actions": [ + { + "actionName": "doitslow", + "actionData": { + }, + "actionAuthAcct": "payloadless", + "authorization": {} + } + ] +} diff --git a/tests/PerformanceHarnessScenarioRunner.py b/tests/PerformanceHarnessScenarioRunner.py index 564ca0cf19..a172c5e3a3 100755 --- a/tests/PerformanceHarnessScenarioRunner.py +++ b/tests/PerformanceHarnessScenarioRunner.py @@ -64,7 +64,8 @@ def main(): printMissingTransactions=args.print_missing_transactions, userTrxDataFile=Path(args.user_trx_data_file) if args.user_trx_data_file is not None else None, endpointMode=args.endpoint_mode, - trxGenerator=args.trx_generator) + trxGenerator=args.trx_generator, + saveState=args.save_state) Utils.Print(f"testNamePath: {PurePath(PurePath(__file__).name).stem}") myTest = performance_test_basic.PerformanceTestBasic(testHelperConfig=testHelperConfig, clusterConfig=testClusterConfig, ptbConfig=ptbConfig, testNamePath=f"{PurePath(PurePath(__file__).name).stem}") elif args.scenario_type_sub_cmd == "findMax": @@ -87,7 +88,8 @@ def main(): userTrxDataFile=Path(args.user_trx_data_file) if args.user_trx_data_file is not None else None, endpointMode=args.endpoint_mode, opModeCmd=args.op_mode_sub_cmd, - trxGenerator=args.trx_generator) + trxGenerator=args.trx_generator, + saveState=args.save_state) myTest = performance_test.PerformanceTest(testHelperConfig=testHelperConfig, clusterConfig=testClusterConfig, ptConfig=ptConfig) else: diff --git a/tests/TestHarness/CMakeLists.txt b/tests/TestHarness/CMakeLists.txt index 1e00fbf567..82da444a6e 100644 --- a/tests/TestHarness/CMakeLists.txt +++ b/tests/TestHarness/CMakeLists.txt @@ -14,3 +14,4 @@ configure_file(logging.py . COPYONLY) configure_file(depresolver.py . COPYONLY) configure_file(launcher.py . COPYONLY) configure_file(accounts.py . COPYONLY) +configure_file(logging-template.json . COPYONLY) diff --git a/tests/TestHarness/Node.py b/tests/TestHarness/Node.py index 888048d6dd..b529990b6f 100644 --- a/tests/TestHarness/Node.py +++ b/tests/TestHarness/Node.py @@ -146,10 +146,10 @@ def validateAccounts(self, accounts): Utils.Print("account validation failed. account: %s" % (account.name)) raise - def waitForTransactionInBlock(self, transId, timeout=None): + def waitForTransactionInBlock(self, transId, timeout=None, exitOnError=True): """Wait for trans id to appear in a block.""" assert(isinstance(transId, str)) - lam = lambda: self.isTransInAnyBlock(transId) + lam = lambda: self.isTransInAnyBlock(transId, exitOnError=exitOnError) ret=Utils.waitForBool(lam, timeout) return ret @@ -226,7 +226,7 @@ def waitForTransBlockIfNeeded(self, trans, waitForTransBlock, exitOnError=False) if not waitForTransBlock: return trans transId=NodeosQueries.getTransId(trans) - if not self.waitForTransactionInBlock(transId): + if not self.waitForTransactionInBlock(transId, exitOnError=exitOnError): if exitOnError: Utils.cmdError("transaction with id %s never made it into a block" % (transId)) Utils.errorExit("Failed to find transaction with id %s in a block before timeout" % (transId)) diff --git a/tests/TestHarness/logging-template.json b/tests/TestHarness/logging-template.json new file mode 100644 index 0000000000..fff1143346 --- /dev/null +++ b/tests/TestHarness/logging-template.json @@ -0,0 +1,150 @@ +{ + "includes": [], + "appenders": [{ + "name": "stderr", + "type": "console", + "args": { + "format": " : ] ", + "stream": "std_error", + "level_colors": [{ + "level": "debug", + "color": "green" + },{ + "level": "warn", + "color": "brown" + },{ + "level": "error", + "color": "red" + } + ], + "flush": true + }, + "enabled": true + },{ + "name": "stdout", + "type": "console", + "args": { + "stream": "std_out", + "level_colors": [{ + "level": "debug", + "color": "green" + },{ + "level": "warn", + "color": "brown" + },{ + "level": "error", + "color": "red" + } + ], + "flush": true + }, + "enabled": true + } + ], + "loggers": [{ + "name": "default", + "level": "debug", + "enabled": true, + "additivity": false, + "appenders": [ + "stderr" + ] + },{ + "name": "net_plugin_impl", + "level": "info", + "enabled": true, + "additivity": false, + "appenders": [ + "stderr" + ] + },{ + "name": "http_plugin", + "level": "debug", + "enabled": true, + "additivity": false, + "appenders": [ + "stderr" + ] + },{ + "name": "producer_plugin", + "level": "debug", + "enabled": true, + "additivity": false, + "appenders": [ + "stderr" + ] + },{ + "name": "transaction_success_tracing", + "level": "debug", + "enabled": true, + "additivity": false, + "appenders": [ + "stderr" + ] + },{ + "name": "transaction_failure_tracing", + "level": "debug", + "enabled": true, + "additivity": false, + "appenders": [ + "stderr" + ] + },{ + "name": "trace_api", + "level": "debug", + "enabled": true, + "additivity": false, + "appenders": [ + "stderr" + ] + },{ + "name": "transaction_trace_success", + "level": "info", + "enabled": true, + "additivity": false, + "appenders": [ + "stderr" + ] + },{ + "name": "transaction_trace_failure", + "level": "info", + "enabled": true, + "additivity": false, + "appenders": [ + "stderr" + ] + },{ + "name": "transient_trx_success_tracing", + "level": "debug", + "enabled": true, + "additivity": false, + "appenders": [ + "stderr" + ] + },{ + "name": "transient_trx_failure_tracing", + "level": "debug", + "enabled": true, + "additivity": false, + "appenders": [ + "stderr" + ] + },{ + "name": "state_history", + "level": "info", + "enabled": true, + "additivity": false, + "appenders": [ + "stderr" + ] + },{ + "name": "transaction", + "level": "info", + "enabled": true, + "additivity": false, + "appenders": [ + "stderr" + ] + } + ] +} diff --git a/tests/TestHarness/queries.py b/tests/TestHarness/queries.py index aa28521476..d7b3695fd2 100644 --- a/tests/TestHarness/queries.py +++ b/tests/TestHarness/queries.py @@ -319,11 +319,11 @@ def getBlockNumByTransId(self, transId, exitOnError=True, delayedRetry=True, blo return None - def isTransInAnyBlock(self, transId: str): + def isTransInAnyBlock(self, transId: str, exitOnError=True): """Check if transaction (transId) is in a block.""" assert(transId) assert(isinstance(transId, str)) - blockId=self.getBlockNumByTransId(transId) + blockId=self.getBlockNumByTransId(transId, exitOnError=exitOnError) return True if blockId else False def isTransFinalized(self, transId): diff --git a/tests/TestHarness/testUtils.py b/tests/TestHarness/testUtils.py index c386953c4c..3894d00268 100644 --- a/tests/TestHarness/testUtils.py +++ b/tests/TestHarness/testUtils.py @@ -256,6 +256,9 @@ def waitForObj(lam, timeout=None, sleepTime=1, reporter=None): if reporter is not None: reporter() time.sleep(sleepTime) + else: + if timeout == 60: + raise RuntimeError('waitForObj reached 60 second timeout') finally: if needsNewLine: Utils.Print() @@ -612,4 +615,4 @@ def readSocketDataStr(sock : socket.socket, maxMsgSize : int, enc : str) -> str: @staticmethod def getNodeosVersion(): - return os.popen(f"{Utils.EosServerPath} --version").read().replace("\n", "") + return os.popen(f"{Utils.EosServerPath} --full-version").read().replace("\n", "") diff --git a/tests/TestHarness/transactions.py b/tests/TestHarness/transactions.py index c00c7ad4ea..e755a10e98 100644 --- a/tests/TestHarness/transactions.py +++ b/tests/TestHarness/transactions.py @@ -152,48 +152,61 @@ def transferFundsAsync(self, source, destination, amountStr, memo="memo", force= return popen, cmdArr # publish contract and return transaction as json object - def publishContract(self, account, contractDir, wasmFile, abiFile, waitForTransBlock=False, shouldFail=False, sign=False): + def publishContract(self, account, contractDir, wasmFile, abiFile, waitForTransBlock=True, shouldFail=False, sign=False, retryNum:int=5): + assert(isinstance(retryNum, int)) signStr = NodeosQueries.sign_str(sign, [ account.activePublicKey ]) - cmd="%s %s -v set contract -j %s %s %s" % (Utils.EosClientPath, self.eosClientArgs(), signStr, account.name, contractDir) + cmd=f"{Utils.EosClientPath} {self.eosClientArgs()} -v set contract -j -f {signStr} {account.name} {contractDir}" cmd += "" if wasmFile is None else (" "+ wasmFile) cmd += "" if abiFile is None else (" " + abiFile) if Utils.Debug: Utils.Print("cmd: %s" % (cmd)) + retries = 0 trans=None - start=time.perf_counter() - try: - trans=Utils.runCmdReturnJson(cmd, trace=False) - self.trackCmdTransaction(trans) - if Utils.Debug: - end=time.perf_counter() - Utils.Print("cmd Duration: %.3f sec" % (end-start)) - except subprocess.CalledProcessError as ex: - if not shouldFail: - end=time.perf_counter() - out=ex.output.decode("utf-8") - msg=ex.stderr.decode("utf-8") - Utils.Print("ERROR: Exception during set contract. stderr: %s. stdout: %s. cmd Duration: %.3f sec." % (msg, out, end-start)) - return None - else: - retMap={} - retMap["returncode"]=ex.returncode - retMap["cmd"]=ex.cmd - retMap["output"]=ex.output - retMap["stderr"]=ex.stderr - return retMap - - if shouldFail: - if trans["processed"]["except"] != None: - retMap={} - retMap["returncode"]=0 - retMap["cmd"]=cmd - retMap["output"]=bytes(str(trans),'utf-8') - return retMap - else: - Utils.Print("ERROR: The publish contract did not fail as expected.") - return None - - NodeosQueries.validateTransaction(trans) - return self.waitForTransBlockIfNeeded(trans, waitForTransBlock, exitOnError=False) + while retries < retryNum: + trans=None + if Utils.Debug and retries > 0: + Utils.Print(f"Retrying: {cmd}") + retries = retries + 1 + start=time.perf_counter() + try: + trans=Utils.runCmdReturnJson(cmd, trace=False) + self.trackCmdTransaction(trans) + if Utils.Debug: + end=time.perf_counter() + Utils.Print("cmd Duration: %.3f sec" % (end-start)) + except subprocess.CalledProcessError as ex: + if not shouldFail: + end=time.perf_counter() + out=ex.output.decode("utf-8") + msg=ex.stderr.decode("utf-8") + Utils.Print("ERROR: Exception during set contract. stderr: %s. stdout: %s. cmd Duration: %.3f sec." % (msg, out, end-start)) + continue + else: + retMap={} + retMap["returncode"]=ex.returncode + retMap["cmd"]=ex.cmd + retMap["output"]=ex.output + retMap["stderr"]=ex.stderr + return retMap + + if shouldFail: + if trans["processed"]["except"] != None: + retMap={} + retMap["returncode"]=0 + retMap["cmd"]=cmd + retMap["output"]=bytes(str(trans),'utf-8') + return retMap + else: + Utils.Print("ERROR: The publish contract did not fail as expected.") + return None + + NodeosQueries.validateTransaction(trans) + if not waitForTransBlock: + return trans + transId=NodeosQueries.getTransId(trans) + if self.waitForTransactionInBlock(transId, timeout=30, exitOnError=False): + break + + return trans # returns tuple with indication if transaction was successfully sent and either the transaction or else the exception output def pushTransaction(self, trans, opts="", silentErrors=False, permissions=None): diff --git a/tests/abieos b/tests/abieos index 08145090b6..7e77b20a39 160000 --- a/tests/abieos +++ b/tests/abieos @@ -1 +1 @@ -Subproject commit 08145090b6407b91fbab5721b624d2b3001ef84f +Subproject commit 7e77b20a3927a41695f7ae969b736bdb4a8e0a74 diff --git a/tests/block_log_util_test.py b/tests/block_log_util_test.py index bd7bff144e..042e1467aa 100755 --- a/tests/block_log_util_test.py +++ b/tests/block_log_util_test.py @@ -70,7 +70,7 @@ def verifyBlockLog(expected_block_num, trimmedBlockLog): node0.kill(signal.SIGTERM) Print("Wait for node0's head block to become irreversible") - node1.waitForBlock(headBlockNum, blockType=BlockType.lib) + node1.waitForBlock(headBlockNum, blockType=BlockType.lib, timeout=90) infoAfter=node1.getInfo(exitOnError=True) headBlockNumAfter=infoAfter["head_block_num"] diff --git a/tests/chain_plugin_tests.cpp b/tests/chain_plugin_tests.cpp index b73d4942c2..ee27bf89b8 100644 --- a/tests/chain_plugin_tests.cpp +++ b/tests/chain_plugin_tests.cpp @@ -131,45 +131,55 @@ BOOST_FIXTURE_TEST_CASE( get_block_with_invalid_abi, validating_tester ) try { } FC_LOG_AND_RETHROW() /// get_block_with_invalid_abi -BOOST_FIXTURE_TEST_CASE( get_consensus_parameters, validating_tester ) try { - produce_blocks(1); +BOOST_AUTO_TEST_CASE( get_consensus_parameters ) try { + tester t{setup_policy::old_wasm_parser}; + t.produce_blocks(1); - chain_apis::read_only plugin(*(this->control), {}, {}, fc::microseconds::maximum(), fc::microseconds::maximum(), nullptr); + chain_apis::read_only plugin(*(t.control), {}, {}, fc::microseconds::maximum(), fc::microseconds::maximum(), nullptr); auto parms = plugin.get_consensus_parameters({}, fc::time_point::maximum()); // verifying chain_config - BOOST_TEST(parms.chain_config.max_block_cpu_usage == control->get_global_properties().configuration.max_block_cpu_usage); - BOOST_TEST(parms.chain_config.target_block_net_usage_pct == control->get_global_properties().configuration.target_block_net_usage_pct); - BOOST_TEST(parms.chain_config.max_transaction_net_usage == control->get_global_properties().configuration.max_transaction_net_usage); - BOOST_TEST(parms.chain_config.base_per_transaction_net_usage == control->get_global_properties().configuration.base_per_transaction_net_usage); - BOOST_TEST(parms.chain_config.net_usage_leeway == control->get_global_properties().configuration.net_usage_leeway); - BOOST_TEST(parms.chain_config.context_free_discount_net_usage_num == control->get_global_properties().configuration.context_free_discount_net_usage_num); - BOOST_TEST(parms.chain_config.context_free_discount_net_usage_den == control->get_global_properties().configuration.context_free_discount_net_usage_den); - BOOST_TEST(parms.chain_config.max_block_cpu_usage == control->get_global_properties().configuration.max_block_cpu_usage); - BOOST_TEST(parms.chain_config.target_block_cpu_usage_pct == control->get_global_properties().configuration.target_block_cpu_usage_pct); - BOOST_TEST(parms.chain_config.max_transaction_cpu_usage == control->get_global_properties().configuration.max_transaction_cpu_usage); - BOOST_TEST(parms.chain_config.min_transaction_cpu_usage == control->get_global_properties().configuration.min_transaction_cpu_usage); - BOOST_TEST(parms.chain_config.max_transaction_lifetime == control->get_global_properties().configuration.max_transaction_lifetime); - BOOST_TEST(parms.chain_config.deferred_trx_expiration_window == control->get_global_properties().configuration.deferred_trx_expiration_window); - BOOST_TEST(parms.chain_config.max_transaction_delay == control->get_global_properties().configuration.max_transaction_delay); - BOOST_TEST(parms.chain_config.max_inline_action_size == control->get_global_properties().configuration.max_inline_action_size); - BOOST_TEST(parms.chain_config.max_inline_action_depth == control->get_global_properties().configuration.max_inline_action_depth); - BOOST_TEST(parms.chain_config.max_authority_depth == control->get_global_properties().configuration.max_authority_depth); - BOOST_TEST(parms.chain_config.max_action_return_value_size == control->get_global_properties().configuration.max_action_return_value_size); + BOOST_TEST(parms.chain_config.max_block_cpu_usage == t.control->get_global_properties().configuration.max_block_cpu_usage); + BOOST_TEST(parms.chain_config.target_block_net_usage_pct == t.control->get_global_properties().configuration.target_block_net_usage_pct); + BOOST_TEST(parms.chain_config.max_transaction_net_usage == t.control->get_global_properties().configuration.max_transaction_net_usage); + BOOST_TEST(parms.chain_config.base_per_transaction_net_usage == t.control->get_global_properties().configuration.base_per_transaction_net_usage); + BOOST_TEST(parms.chain_config.net_usage_leeway == t.control->get_global_properties().configuration.net_usage_leeway); + BOOST_TEST(parms.chain_config.context_free_discount_net_usage_num == t.control->get_global_properties().configuration.context_free_discount_net_usage_num); + BOOST_TEST(parms.chain_config.context_free_discount_net_usage_den == t.control->get_global_properties().configuration.context_free_discount_net_usage_den); + BOOST_TEST(parms.chain_config.max_block_cpu_usage == t.control->get_global_properties().configuration.max_block_cpu_usage); + BOOST_TEST(parms.chain_config.target_block_cpu_usage_pct == t.control->get_global_properties().configuration.target_block_cpu_usage_pct); + BOOST_TEST(parms.chain_config.max_transaction_cpu_usage == t.control->get_global_properties().configuration.max_transaction_cpu_usage); + BOOST_TEST(parms.chain_config.min_transaction_cpu_usage == t.control->get_global_properties().configuration.min_transaction_cpu_usage); + BOOST_TEST(parms.chain_config.max_transaction_lifetime == t.control->get_global_properties().configuration.max_transaction_lifetime); + BOOST_TEST(parms.chain_config.deferred_trx_expiration_window == t.control->get_global_properties().configuration.deferred_trx_expiration_window); + BOOST_TEST(parms.chain_config.max_transaction_delay == t.control->get_global_properties().configuration.max_transaction_delay); + BOOST_TEST(parms.chain_config.max_inline_action_size == t.control->get_global_properties().configuration.max_inline_action_size); + BOOST_TEST(parms.chain_config.max_inline_action_depth == t.control->get_global_properties().configuration.max_inline_action_depth); + BOOST_TEST(parms.chain_config.max_authority_depth == t.control->get_global_properties().configuration.max_authority_depth); + BOOST_TEST(parms.chain_config.max_action_return_value_size == t.control->get_global_properties().configuration.max_action_return_value_size); + + BOOST_TEST(!parms.wasm_config); + + t.preactivate_all_builtin_protocol_features(); + t.produce_block(); + + parms = plugin.get_consensus_parameters({}, fc::time_point::maximum()); + + BOOST_REQUIRE(!!parms.wasm_config); // verifying wasm_config - BOOST_TEST(parms.wasm_config.max_mutable_global_bytes == control->get_global_properties().wasm_configuration.max_mutable_global_bytes); - BOOST_TEST(parms.wasm_config.max_table_elements == control->get_global_properties().wasm_configuration.max_table_elements); - BOOST_TEST(parms.wasm_config.max_section_elements == control->get_global_properties().wasm_configuration.max_section_elements); - BOOST_TEST(parms.wasm_config.max_linear_memory_init == control->get_global_properties().wasm_configuration.max_linear_memory_init); - BOOST_TEST(parms.wasm_config.max_func_local_bytes == control->get_global_properties().wasm_configuration.max_func_local_bytes); - BOOST_TEST(parms.wasm_config.max_nested_structures == control->get_global_properties().wasm_configuration.max_nested_structures); - BOOST_TEST(parms.wasm_config.max_symbol_bytes == control->get_global_properties().wasm_configuration.max_symbol_bytes); - BOOST_TEST(parms.wasm_config.max_module_bytes == control->get_global_properties().wasm_configuration.max_module_bytes); - BOOST_TEST(parms.wasm_config.max_code_bytes == control->get_global_properties().wasm_configuration.max_code_bytes); - BOOST_TEST(parms.wasm_config.max_pages == control->get_global_properties().wasm_configuration.max_pages); - BOOST_TEST(parms.wasm_config.max_call_depth == control->get_global_properties().wasm_configuration.max_call_depth); + BOOST_TEST(parms.wasm_config->max_mutable_global_bytes == t.control->get_global_properties().wasm_configuration.max_mutable_global_bytes); + BOOST_TEST(parms.wasm_config->max_table_elements == t.control->get_global_properties().wasm_configuration.max_table_elements); + BOOST_TEST(parms.wasm_config->max_section_elements == t.control->get_global_properties().wasm_configuration.max_section_elements); + BOOST_TEST(parms.wasm_config->max_linear_memory_init == t.control->get_global_properties().wasm_configuration.max_linear_memory_init); + BOOST_TEST(parms.wasm_config->max_func_local_bytes == t.control->get_global_properties().wasm_configuration.max_func_local_bytes); + BOOST_TEST(parms.wasm_config->max_nested_structures == t.control->get_global_properties().wasm_configuration.max_nested_structures); + BOOST_TEST(parms.wasm_config->max_symbol_bytes == t.control->get_global_properties().wasm_configuration.max_symbol_bytes); + BOOST_TEST(parms.wasm_config->max_module_bytes == t.control->get_global_properties().wasm_configuration.max_module_bytes); + BOOST_TEST(parms.wasm_config->max_code_bytes == t.control->get_global_properties().wasm_configuration.max_code_bytes); + BOOST_TEST(parms.wasm_config->max_pages == t.control->get_global_properties().wasm_configuration.max_pages); + BOOST_TEST(parms.wasm_config->max_call_depth == t.control->get_global_properties().wasm_configuration.max_call_depth); } FC_LOG_AND_RETHROW() //get_consensus_parameters diff --git a/tests/nodeos_chainbase_allocation_test.py b/tests/nodeos_chainbase_allocation_test.py index 5771428b80..4c2ec8ee21 100755 --- a/tests/nodeos_chainbase_allocation_test.py +++ b/tests/nodeos_chainbase_allocation_test.py @@ -31,7 +31,6 @@ # The following is the list of chainbase objects that need to be verified: # - account_object (bootstrap) # - code_object (bootstrap) - # - generated_transaction_object # - global_property_object # - key_value_object (bootstrap) # - protocol_state_object (bootstrap) @@ -55,12 +54,6 @@ irrNode = cluster.getNode(irrNodeId) nonProdNode = cluster.getNode(nonProdNodeId) - # Create delayed transaction to create "generated_transaction_object" - cmd = "create account -j eosio sample EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV\ - EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV --delay-sec 600 -p eosio" - trans = producerNode.processCleosCmd(cmd, cmd, silentErrors=False) - assert trans - # Schedule a new producer to trigger new producer schedule for "global_property_object" newProducerAcc = Account("newprod") newProducerAcc.ownerPublicKey = "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" diff --git a/tests/nodeos_run_test.py b/tests/nodeos_run_test.py index 3b31996a9b..59b6fa68d9 100755 --- a/tests/nodeos_run_test.py +++ b/tests/nodeos_run_test.py @@ -61,8 +61,9 @@ abs_path = os.path.abspath(os.getcwd() + '/unittests/contracts/eosio.token/eosio.token.abi') traceNodeosArgs=" --http-max-response-time-ms 990000 --trace-rpc-abi eosio.token=" + abs_path + extraNodeosArgs=traceNodeosArgs + " --plugin eosio::prometheus_plugin --database-map-mode mapped_private " specificNodeosInstances={0: "bin/nodeos"} - if cluster.launch(totalNodes=2, prodCount=prodCount, onlyBios=onlyBios, dontBootstrap=dontBootstrap, extraNodeosArgs=traceNodeosArgs, specificNodeosInstances=specificNodeosInstances) is False: + if cluster.launch(totalNodes=2, prodCount=prodCount, onlyBios=onlyBios, dontBootstrap=dontBootstrap, extraNodeosArgs=extraNodeosArgs, specificNodeosInstances=specificNodeosInstances) is False: cmdError("launcher") errorExit("Failed to stand up eos cluster.") else: diff --git a/tests/p2p_high_latency_test.py b/tests/p2p_high_latency_test.py index 861fade6a0..2b8028209c 100644 --- a/tests/p2p_high_latency_test.py +++ b/tests/p2p_high_latency_test.py @@ -68,8 +68,7 @@ def exec(cmd): try: TestHelper.printSystemInfo("BEGIN") - traceNodeosArgs=" --plugin eosio::producer_plugin --produce-time-offset-us 0 --last-block-time-offset-us 0 --cpu-effort-percent 100 \ - --last-block-cpu-effort-percent 100 --producer-threads 1 --plugin eosio::net_plugin --net-threads 1" + traceNodeosArgs=" --plugin eosio::producer_plugin --produce-block-offset-ms 0 --producer-threads 1 --plugin eosio::net_plugin --net-threads 1" if cluster.launch(pnodes=1, totalNodes=totalNodes, totalProducers=1, specificExtraNodeosArgs=specificExtraNodeosArgs, extraNodeosArgs=traceNodeosArgs) is False: Utils.cmdError("launcher") Utils.errorExit("Failed to stand up eos cluster.") diff --git a/tests/p2p_multiple_listen_test.py b/tests/p2p_multiple_listen_test.py index 62f1534c63..7f537e9d35 100755 --- a/tests/p2p_multiple_listen_test.py +++ b/tests/p2p_multiple_listen_test.py @@ -75,7 +75,7 @@ assert conn['last_handshake']['p2p_address'].split()[0] == 'localhost:9878', f"Connected node is listening on '{conn['last_handshake']['p2p_address'].split()[0]}' instead of port 9878" elif conn['last_handshake']['agent'] == 'node-04': assert conn['last_handshake']['p2p_address'].split()[0] == 'localhost:9880', f"Connected node is listening on '{conn['last_handshake']['p2p_address'].split()[0]}' instead of port 9880" - assert open_socket_count == 2, 'Node 0 is expected to have only two open sockets' + assert open_socket_count == 2, 'Node 0 is expected to have exactly two open sockets' connections = cluster.nodes[2].processUrllibRequest('net', 'connections') open_socket_count = 0 @@ -84,7 +84,7 @@ open_socket_count += 1 assert conn['last_handshake']['agent'] == 'node-00', f"Connected node identifed as '{conn['last_handshake']['agent']}' instead of node-00" assert conn['last_handshake']['p2p_address'].split()[0] == 'ext-ip0:20000', f"Connected node is advertising '{conn['last_handshake']['p2p_address'].split()[0]}' instead of ext-ip0:20000" - assert open_socket_count == 1, 'Node 2 is expected to have only one open socket' + assert open_socket_count == 1, 'Node 2 is expected to have exactly one open socket' connections = cluster.nodes[4].processUrllibRequest('net', 'connections') open_socket_count = 0 @@ -93,7 +93,7 @@ open_socket_count += 1 assert conn['last_handshake']['agent'] == 'node-00', f"Connected node identifed as '{conn['last_handshake']['agent']}' instead of node-00" assert conn['last_handshake']['p2p_address'].split()[0] == 'ext-ip1:20001', f"Connected node is advertising '{conn['last_handshake']['p2p_address'].split()[0]} 'instead of ext-ip1:20001" - assert open_socket_count == 1, 'Node 4 is expected to have only one open socket' + assert open_socket_count == 1, 'Node 4 is expected to have exactly one open socket' testSuccessful=True finally: diff --git a/tests/p2p_sync_throttle_test.py b/tests/p2p_sync_throttle_test.py new file mode 100755 index 0000000000..421d411243 --- /dev/null +++ b/tests/p2p_sync_throttle_test.py @@ -0,0 +1,236 @@ +#!/usr/bin/env python3 + +import math +import re +import signal +import sys +import time +import urllib + +from TestHarness import Cluster, TestHelper, Utils, WalletMgr, CORE_SYMBOL, createAccountKeys, ReturnType +from TestHarness.TestHelper import AppArgs + +############################################################### +# p2p_sync_throttle_test +# +# Test throttling of a peer during block syncing. +# +############################################################### + +Print=Utils.Print +errorExit=Utils.errorExit + +appArgs = AppArgs() +appArgs.add(flag='--plugin',action='append',type=str,help='Run nodes with additional plugins') +appArgs.add(flag='--connection-cleanup-period',type=int,help='Interval in whole seconds to run the connection reaper and metric collection') + +args=TestHelper.parse_args({"-d","--keep-logs" + ,"--dump-error-details","-v","--leave-running" + ,"--unshared"}, + applicationSpecificArgs=appArgs) +pnodes=1 +delay=args.d +debug=args.v +prod_count = 2 +total_nodes=4 +dumpErrorDetails=args.dump_error_details + +Utils.Debug=debug +testSuccessful=False + +cluster=Cluster(unshared=args.unshared, keepRunning=args.leave_running, keepLogs=args.keep_logs) +walletMgr=WalletMgr(True) + +def extractPrometheusMetric(connID: str, metric: str, text: str): + searchStr = f'nodeos_p2p_{metric}{{connid="{connID}"}} ' + begin = text.find(searchStr) + len(searchStr) + return int(text[begin:text.find('\n', begin)]) + +prometheusHostPortPattern = re.compile(r'^nodeos_p2p_port.connid="([a-f0-9]*)". ([0-9]*)', re.MULTILINE) + +try: + TestHelper.printSystemInfo("BEGIN") + + cluster.setWalletMgr(walletMgr) + + Print(f'producing nodes: {pnodes}, delay between nodes launch: {delay} second{"s" if delay != 1 else ""}') + + Print("Stand up cluster") + extraNodeosArgs = '--plugin eosio::prometheus_plugin --connection-cleanup-period 3' + # Custom topology is a line of singlely connected nodes from highest node number in sequence to lowest, + # the reverse of the usual TestHarness line topology. + if cluster.launch(pnodes=pnodes, unstartedNodes=2, totalNodes=total_nodes, prodCount=prod_count, + topo='./tests/p2p_sync_throttle_test_shape.json', delay=delay, + extraNodeosArgs=extraNodeosArgs) is False: + errorExit("Failed to stand up eos cluster.") + + prodNode = cluster.getNode(0) + nonProdNode = cluster.getNode(1) + + accounts=createAccountKeys(2) + if accounts is None: + Utils.errorExit("FAILURE - create keys") + + accounts[0].name="tester111111" + accounts[1].name="tester222222" + + account1PrivKey = accounts[0].activePrivateKey + account2PrivKey = accounts[1].activePrivateKey + + testWalletName="test" + + Print("Creating wallet \"%s\"." % (testWalletName)) + testWallet=walletMgr.create(testWalletName, [cluster.eosioAccount,accounts[0],accounts[1]]) + + # create accounts via eosio as otherwise a bid is needed + for account in accounts: + Print("Create new account %s via %s" % (account.name, cluster.eosioAccount.name)) + trans=nonProdNode.createInitializeAccount(account, cluster.eosioAccount, stakedDeposit=0, waitForTransBlock=True, stakeNet=1000, stakeCPU=1000, buyRAM=1000, exitOnError=True) + transferAmount="100000000.0000 {0}".format(CORE_SYMBOL) + Print("Transfer funds %s from account %s to %s" % (transferAmount, cluster.eosioAccount.name, account.name)) + nonProdNode.transferFunds(cluster.eosioAccount, account, transferAmount, "test transfer", waitForTransBlock=True) + trans=nonProdNode.delegatebw(account, 20000000.0000, 20000000.0000, waitForTransBlock=True, exitOnError=True) + + beginLargeBlocksHeadBlock = nonProdNode.getHeadBlockNum() + + Print("Configure and launch txn generators") + targetTpsPerGenerator = 500 + testTrxGenDurationSec=60 + trxGeneratorCnt=1 + cluster.launchTrxGenerators(contractOwnerAcctName=cluster.eosioAccount.name, acctNamesList=[accounts[0].name,accounts[1].name], + acctPrivKeysList=[account1PrivKey,account2PrivKey], nodeId=prodNode.nodeId, tpsPerGenerator=targetTpsPerGenerator, + numGenerators=trxGeneratorCnt, durationSec=testTrxGenDurationSec, waitToComplete=True) + + endLargeBlocksHeadBlock = nonProdNode.getHeadBlockNum() + + throttlingNode = cluster.unstartedNodes[0] + i = throttlingNode.cmd.index('--p2p-listen-endpoint') + throttleListenAddr = throttlingNode.cmd[i+1] + # Using 40 Kilobytes per second to allow syncing of ~250 transaction blocks at ~175 bytes per transaction + # (250*175=43750 per block or 87500 per second) + # resulting from the trx generators in a reasonable amount of time, while still being able to capture + # throttling state within the Prometheus update window (3 seconds in this test). + throttlingNode.cmd[i+1] = throttlingNode.cmd[i+1] + ':40KB/s' + throttleListenIP, throttleListenPort = throttleListenAddr.split(':') + throttlingNode.cmd.append('--p2p-listen-endpoint') + throttlingNode.cmd.append(f'{throttleListenIP}:{int(throttleListenPort)+100}:1TB/s') + + cluster.biosNode.kill(signal.SIGTERM) + clusterStart = time.time() + cluster.launchUnstarted(2) + + errorLimit = 40 # Approximately 20 retries required + throttledNode = cluster.getNode(3) + throttledNodeConnId = None + throttlingNodeConnId = None + while errorLimit > 0: + try: + response = throttlingNode.processUrllibRequest('prometheus', 'metrics', returnType=ReturnType.raw, printReturnLimit=16).decode() + except urllib.error.URLError: + # catch ConnectionRefusedEror waiting for node to finish startup and respond + errorLimit -= 1 + time.sleep(0.5) + continue + else: + if len(response) < 100: + # tolerate HTTPError as well (method returns only the exception code) + errorLimit -= 1 + continue + connPorts = prometheusHostPortPattern.findall(response) + Print(connPorts) + if len(connPorts) < 3: + # wait for node to be connected + errorLimit -= 1 + time.sleep(0.5) + continue + Print('Throttling Node Start State') + throttlingNodePortMap = {port: id for id, port in connPorts if id != '' and port != '9877'} + throttlingNodeConnId = next(iter(throttlingNodePortMap.values())) # 9879 + startSyncThrottlingBytesSent = extractPrometheusMetric(throttlingNodeConnId, + 'block_sync_bytes_sent', + response) + startSyncThrottlingState = extractPrometheusMetric(throttlingNodeConnId, + 'block_sync_throttling', + response) + Print(f'Start sync throttling bytes sent: {startSyncThrottlingBytesSent}') + Print(f'Start sync throttling node throttling: {"True" if startSyncThrottlingState else "False"}') + if time.time() > clusterStart + 30: errorExit('Timed out') + break + else: + errorExit('Exceeded error retry limit waiting for throttling node') + + errorLimit = 40 # Few if any retries required but for consistency... + while errorLimit > 0: + try: + response = throttledNode.processUrllibRequest('prometheus', 'metrics', returnType=ReturnType.raw, printReturnLimit=16).decode() + except urllib.error.URLError: + # catch ConnectionRefusedError waiting for node to finish startup and respond + errorLimit -= 1 + time.sleep(0.5) + continue + else: + if len(response) < 100: + # tolerate HTTPError as well (method returns only the exception code) + errorLimit -= 1 + time.sleep(0.5) + continue + connPorts = prometheusHostPortPattern.findall(response) + Print(connPorts) + if len(connPorts) < 2: + # wait for sending node to be connected + errorLimit -= 1 + continue + Print('Throttled Node Start State') + throttledNodePortMap = {port: id for id, port in connPorts if id != ''} + throttledNodeConnId = next(iter(throttledNodePortMap.values())) # 9878 + Print(throttledNodeConnId) + startSyncThrottledBytesReceived = extractPrometheusMetric(throttledNodeConnId, + 'block_sync_bytes_received', + response) + Print(f'Start sync throttled bytes received: {startSyncThrottledBytesReceived}') + break + else: + errorExit('Exceeded error retry limit waiting for throttled node') + + # Throttling node was offline during block generation and once online receives blocks as fast as possible while + # transmitting blocks to the next node in line at the above throttle setting. + assert throttlingNode.waitForBlock(endLargeBlocksHeadBlock), f'wait for block {endLargeBlocksHeadBlock} on throttled node timed out' + endThrottlingSync = time.time() + response = throttlingNode.processUrllibRequest('prometheus', 'metrics', exitOnError=True, returnType=ReturnType.raw, printReturnLimit=16).decode() + Print('Throttling Node End State') + endSyncThrottlingBytesSent = extractPrometheusMetric(throttlingNodeConnId, + 'block_sync_bytes_sent', + response) + Print(f'End sync throttling bytes sent: {endSyncThrottlingBytesSent}') + # Throttled node is connecting to a listen port with a block sync throttle applied so it will receive + # blocks more slowly during syncing than an unthrottled node. + wasThrottled = False + while time.time() < endThrottlingSync + 30: + response = throttlingNode.processUrllibRequest('prometheus', 'metrics', exitOnError=True, + returnType=ReturnType.raw, printReturnLimit=16).decode() + throttledState = extractPrometheusMetric(throttlingNodeConnId, + 'block_sync_throttling', + response) + if throttledState: + wasThrottled = True + break + assert throttledNode.waitForBlock(endLargeBlocksHeadBlock, timeout=90), f'Wait for block {endLargeBlocksHeadBlock} on sync node timed out' + endThrottledSync = time.time() + response = throttledNode.processUrllibRequest('prometheus', 'metrics', exitOnError=True, returnType=ReturnType.raw, printReturnLimit=16).decode() + Print('Throttled Node End State') + endSyncThrottledBytesReceived = extractPrometheusMetric(throttledNodeConnId, + 'block_sync_bytes_received', + response) + Print(f'End sync throttled bytes received: {endSyncThrottledBytesReceived}') + throttlingElapsed = endThrottlingSync - clusterStart + throttledElapsed = endThrottledSync - clusterStart + Print(f'Unthrottled sync time: {throttlingElapsed} seconds') + Print(f'Throttled sync time: {throttledElapsed} seconds') + assert wasThrottled, 'Throttling node never reported throttling its transmission rate' + + testSuccessful=True +finally: + TestHelper.shutdown(cluster, walletMgr, testSuccessful=testSuccessful, dumpErrorDetails=dumpErrorDetails) + +exitCode = 0 if testSuccessful else 1 +exit(exitCode) diff --git a/tests/p2p_sync_throttle_test_shape.json b/tests/p2p_sync_throttle_test_shape.json new file mode 100644 index 0000000000..8cfb5ce9a5 --- /dev/null +++ b/tests/p2p_sync_throttle_test_shape.json @@ -0,0 +1,132 @@ +{ + "name": "testnet_", + "nodes": { + "bios": { + "index": -100, + "name": "bios", + "keys": [ + { + "pubkey": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", + "privkey": "5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3" + } + ], + "peers": [ + "testnet_00" + ], + "producers": [ + "eosio" + ], + "dont_start": false, + "p2p_port": 9776, + "http_port": 8788, + "host_name": "localhost", + "public_name": "localhost", + "listen_addr": "0.0.0.0", + "_dot_label": "localhost:9776\nbios\nprod=eosio" + }, + "testnet_00": { + "index": 0, + "name": "testnet_00", + "keys": [ + { + "pubkey": "EOS7D6jfN6bbJD9cYheyhnBT4bmUWc3Qf4Yphf5GBeAAy58okcwHU", + "privkey": "5KkmnyunnpCQzgFoLMEtU3j7BRBa5aWmsBNru49ke7LdnZKFhmt" + } + ], + "peers": [], + "producers": [ + "defproducera", + "defproducerb", + "defproducerc", + "defproducerd", + "defproducere", + "defproducerf", + "defproducerg", + "defproducerh", + "defproduceri", + "defproducerj", + "defproducerk", + "defproducerl", + "defproducerm", + "defproducern", + "defproducero", + "defproducerp", + "defproducerq", + "defproducerr", + "defproducers", + "defproducert", + "defproduceru" + ], + "dont_start": false, + "p2p_port": 9876, + "http_port": 8888, + "host_name": "localhost", + "public_name": "localhost", + "listen_addr": "0.0.0.0", + "_dot_label": "localhost:9876\ntestnet_00\nprod=defproducera\ndefproducerb\ndefproducerc\ndefproducerd\ndefproducere\ndefproducerf\ndefproducerg\ndefproducerh\ndefproduceri\ndefproducerj\ndefproducerk\ndefproducerl\ndefproducerm\ndefproducern\ndefproducero\ndefproducerp\ndefproducerq\ndefproducerr\ndefproducers\ndefproducert\ndefproduceru" + }, + "testnet_01": { + "index": 1, + "name": "testnet_01", + "keys": [ + { + "pubkey": "EOS5tZqxLB8y9q2yHkgcXU4QFBEV6QKN3NQ54ygaFLWHJbjqYzFhw", + "privkey": "5KBs4qR7T8shJjCJUeFQXd77iKrok5TCtZiQhWJpCpc1VRxpNAs" + } + ], + "peers": [ + "testnet_00" + ], + "producers": [], + "dont_start": false, + "p2p_port": 9877, + "http_port": 8889, + "host_name": "localhost", + "public_name": "localhost", + "listen_addr": "0.0.0.0", + "_dot_label": "localhost:9877\ntestnet_01\nprod=" + }, + "testnet_02": { + "index": 2, + "name": "testnet_02", + "keys": [ + { + "pubkey": "EOS5FBPf5EN9bYEqmsKfPx9bxyUZ9grDiE24zqLFXtPa6UpVzMjE7", + "privkey": "5HtVDiAsD24seDm5sdswTcdZpx672XbBW9gBkyrzbsj2j9Y9JeC" + } + ], + "peers": [ + "testnet_01" + ], + "producers": [], + "dont_start": true, + "p2p_port": 9878, + "http_port": 8890, + "host_name": "localhost", + "public_name": "localhost", + "listen_addr": "0.0.0.0", + "_dot_label": "localhost:9878\ntestnet_02\nprod=" + }, + "testnet_03": { + "index": 3, + "name": "testnet_03", + "keys": [ + { + "pubkey": "EOS8XH2gKxsef9zxmMHm4vaSvxQUhg7W4GC3nK2KSRxyYrNG5gZFS", + "privkey": "5JcoRRhDcgm51dkBrRTmErceTqrYhrq22UnmUjTZToMpH91B9N1" + } + ], + "peers": [ + "testnet_02" + ], + "producers": [], + "dont_start": true, + "p2p_port": 9879, + "http_port": 8891, + "host_name": "localhost", + "public_name": "localhost", + "listen_addr": "0.0.0.0", + "_dot_label": "localhost:9879\ntestnet_03\nprod=" + } + } +} \ No newline at end of file diff --git a/tests/plugin_http_api_test.py b/tests/plugin_http_api_test.py index 0f49f458ee..c11a5cc21f 100755 --- a/tests/plugin_http_api_test.py +++ b/tests/plugin_http_api_test.py @@ -791,7 +791,12 @@ def test_NetApi(self) : ret_json = self.nodeos.processUrllibRequest(resource, command, self.empty_content_dict, endpoint=endpoint) self.assertEqual(ret_json["code"], 400) self.assertEqual(ret_json["error"]["code"], 3200006) + # connect with incomplete content parameter payload = "localhost" + ret_json = self.nodeos.processUrllibRequest(resource, command, payload, endpoint=endpoint) + self.assertEqual(ret_json["code"], 201) + self.assertEqual(ret_json["payload"], 'invalid peer address') + payload = "localhost:9877" ret_str = self.nodeos.processUrllibRequest(resource, command, payload, returnType=ReturnType.raw, endpoint=endpoint).decode('ascii') self.assertEqual("\"added connection\"", ret_str) diff --git a/tests/read_only_trx_test.py b/tests/read_only_trx_test.py index 91f92a8a0b..6af91c5a83 100755 --- a/tests/read_only_trx_test.py +++ b/tests/read_only_trx_test.py @@ -6,6 +6,7 @@ import threading import os import platform +import traceback from TestHarness import Account, Cluster, ReturnType, TestHelper, Utils, WalletMgr from TestHarness.TestHelper import AppArgs @@ -102,6 +103,7 @@ def startCluster(): specificExtraNodeosArgs={} # producer nodes will be mapped to 0 through pnodes-1, so the number pnodes is the no-producing API node specificExtraNodeosArgs[pnodes]=" --plugin eosio::net_api_plugin" + specificExtraNodeosArgs[pnodes]+=" --contracts-console " specificExtraNodeosArgs[pnodes]+=" --read-only-write-window-time-us " specificExtraNodeosArgs[pnodes]+=" 10000 " specificExtraNodeosArgs[pnodes]+=" --read-only-read-window-time-us " @@ -204,6 +206,9 @@ def sendTransaction(account, action, data, auth=[], opts=None): def sendReadOnlyPayloadless(): return sendTransaction('payloadless', action='doit', data={}, auth=[], opts='--read') +def sendReadOnlySlowPayloadless(): + return sendTransaction('payloadless', action='doitslow', data={}, auth=[], opts='--read') + # Send read-only trxs from mutltiple threads to bump load def sendReadOnlyTrxOnThread(startId, numTrxs): Print("start sendReadOnlyTrxOnThread") @@ -219,8 +224,14 @@ def sendReadOnlyTrxOnThread(startId, numTrxs): results = sendReadOnlyPayloadless() assert(results[0]) assert(results[1]['processed']['action_traces'][0]['console'] == "Im a payloadless action") + + results = sendReadOnlySlowPayloadless() + assert(results[0]) + assert(results[1]['processed']['action_traces'][0]['console'] == "Im a payloadless slow action") + assert(int(results[1]['processed']['elapsed']) > 100) except Exception as e: - Print("Exception in sendReadOnlyTrxOnThread: ", e) + Print("Exception in sendReadOnlyTrxOnThread: ", repr(e)) + traceback.print_exc() errorInThread = True # Send regular trxs from mutltiple threads to bump load @@ -234,7 +245,8 @@ def sendTrxsOnThread(startId, numTrxs, opts=None): results = sendTransaction(testAccountName, 'age', {"user": userAccountName, "id": startId + i}, auth=[{"actor": userAccountName, "permission":"active"}], opts=opts) assert(results[0]) except Exception as e: - Print("Exception in sendTrxsOnThread: ", e) + Print("Exception in sendTrxsOnThread: ", repr(e)) + traceback.print_exc() errorInThread = True def doRpc(resource, command, numRuns, fieldIn, expectedValue, code, payload={}): @@ -250,7 +262,8 @@ def doRpc(resource, command, numRuns, fieldIn, expectedValue, code, payload={}): else: assert(ret_json["code"] == code) except Exception as e: - Print("Exception in doRpc: ", e) + Print("Exception in doRpc: ", repr(e)) + traceback.print_exc() errorInThread = True def runReadOnlyTrxAndRpcInParallel(resource, command, fieldIn=None, expectedValue=None, code=None, payload={}): diff --git a/tests/resource_monitor_plugin_test.py b/tests/resource_monitor_plugin_test.py index 5b53793620..4370d529dc 100755 --- a/tests/resource_monitor_plugin_test.py +++ b/tests/resource_monitor_plugin_test.py @@ -23,6 +23,7 @@ stderrFile=dataDir + "/stderr.txt" testNum=0 +max_start_time_secs=10 # time nodeos takes to start # We need debug level to get more information about nodeos process logging="""{ @@ -105,7 +106,7 @@ def testCommon(title, extraNodeosArgs, expectedMsgs): prepareDirectories() - timeout=120 # Leave sufficient time such nodeos can start up fully in any platforms + timeout=max_start_time_secs # Leave sufficient time such nodeos can start up fully in any platforms runNodeos(extraNodeosArgs, timeout) for msg in expectedMsgs: @@ -156,7 +157,7 @@ def testInterval(title, extraNodeosArgs, interval, expectedMsgs, warningThreshol prepareDirectories() fillFS(dataDir, warningThreshold) - timeout = 120 + interval * 2 # Leave sufficient time so nodeos can start up fully in any platforms, and at least two warnings can be output + timeout = max_start_time_secs + interval * 2 # Leave sufficient time so nodeos can start up fully in any platforms, and at least two warnings can be output if timeout > testIntervalMaxTimeout: errorExit ("Max timeout for testInterval is %d sec" % (testIntervalMaxTimeout)) runNodeos(extraNodeosArgs, timeout) @@ -169,15 +170,15 @@ def testInterval(title, extraNodeosArgs, interval, expectedMsgs, warningThreshol errorExit ("Log containing \"%s\" should be output every %d seconds" % (msg, interval)) def testAll(): - testCommon("Resmon enabled: all arguments", "--plugin eosio::resource_monitor_plugin --resource-monitor-space-threshold=85 --resource-monitor-interval-seconds=5 --resource-monitor-not-shutdown-on-threshold-exceeded", ["threshold set to 85", "interval set to 5", "Shutdown flag when threshold exceeded set to false", "Creating and starting monitor thread"]) + testCommon("Resmon enabled: all arguments", "--plugin eosio::resource_monitor_plugin --resource-monitor-space-threshold=85 --resource-monitor-interval-seconds=5 --resource-monitor-not-shutdown-on-threshold-exceeded", ["threshold set to 85", "interval set to 5", "Shutdown flag when threshold exceeded set to false"]) # default arguments and default directories to be monitored - testCommon("Resmon not enabled: no arguments", "", ["interval set to 2", "threshold set to 90", "Shutdown flag when threshold exceeded set to true", "Creating and starting monitor thread", "snapshots's file system to be monitored", "blocks's file system to be monitored", "state's file system to be monitored"]) + testCommon("Resmon not enabled: no arguments", "", ["interval set to 2", "threshold set to 90", "Shutdown flag when threshold exceeded set to true", "snapshots's file system to be monitored", "blocks's file system to be monitored", "state's file system to be monitored"]) # default arguments with registered directories - testCommon("Resmon not enabled: Producer, Chain, State History and Trace Api", "--plugin eosio::state_history_plugin --state-history-dir=/tmp/state-history --plugin eosio::trace_api_plugin --trace-dir=/tmp/trace --trace-no-abis", ["interval set to 2", "threshold set to 90", "Shutdown flag when threshold exceeded set to true", "snapshots's file system to be monitored", "blocks's file system to be monitored", "state's file system to be monitored", "state-history's file system to be monitored", "trace's file system to be monitored", "Creating and starting monitor thread"]) + testCommon("Resmon not enabled: Producer, Chain, State History and Trace Api", "--plugin eosio::state_history_plugin --state-history-dir=/tmp/state-history --disable-replay-opts --plugin eosio::trace_api_plugin --trace-dir=/tmp/trace --trace-no-abis", ["interval set to 2", "threshold set to 90", "Shutdown flag when threshold exceeded set to true", "snapshots's file system to be monitored", "blocks's file system to be monitored", "state's file system to be monitored", "state-history's file system to be monitored", "trace's file system to be monitored"]) - testCommon("Resmon enabled: Producer, Chain, State History and Trace Api", "--plugin eosio::resource_monitor_plugin --plugin eosio::state_history_plugin --state-history-dir=/tmp/state-history --plugin eosio::trace_api_plugin --trace-dir=/tmp/trace --trace-no-abis --resource-monitor-space-threshold=80 --resource-monitor-interval-seconds=3", ["snapshots's file system to be monitored", "blocks's file system to be monitored", "state's file system to be monitored", "state-history's file system to be monitored", "trace's file system to be monitored", "Creating and starting monitor thread", "threshold set to 80", "interval set to 3", "Shutdown flag when threshold exceeded set to true"]) + testCommon("Resmon enabled: Producer, Chain, State History and Trace Api", "--plugin eosio::resource_monitor_plugin --plugin eosio::state_history_plugin --state-history-dir=/tmp/state-history --disable-replay-opts --plugin eosio::trace_api_plugin --trace-dir=/tmp/trace --trace-no-abis --resource-monitor-space-threshold=80 --resource-monitor-interval-seconds=3", ["snapshots's file system to be monitored", "blocks's file system to be monitored", "state's file system to be monitored", "state-history's file system to be monitored", "trace's file system to be monitored", "threshold set to 80", "interval set to 3", "Shutdown flag when threshold exceeded set to true"]) # Only test minimum warning threshold (i.e. 6) to trigger warning as much as possible testInterval("Resmon enabled: set warning interval", diff --git a/tests/ship_streamer_test.py b/tests/ship_streamer_test.py index e5710c5e36..710ab90db4 100755 --- a/tests/ship_streamer_test.py +++ b/tests/ship_streamer_test.py @@ -70,7 +70,7 @@ def getLatestSnapshot(nodeId): shipNodeNum = 1 specificExtraNodeosArgs={} - specificExtraNodeosArgs[shipNodeNum]="--plugin eosio::state_history_plugin --trace-history --chain-state-history --plugin eosio::net_api_plugin --plugin eosio::producer_api_plugin " + specificExtraNodeosArgs[shipNodeNum]="--plugin eosio::state_history_plugin --trace-history --chain-state-history --state-history-stride 200 --plugin eosio::net_api_plugin --plugin eosio::producer_api_plugin " # producer nodes will be mapped to 0 through totalProducerNodes-1, so the number totalProducerNodes will be the non-producing node specificExtraNodeosArgs[totalProducerNodes]="--plugin eosio::test_control_api_plugin " @@ -206,7 +206,7 @@ def getLatestSnapshot(nodeId): prodNode0.waitForProducer(forkAtProducer) prodNode1.waitForProducer(prodNode1Prod) if nonProdNode.verifyAlive(): - Utils.errorExit("Bridge did not shutdown"); + Utils.errorExit("Bridge did not shutdown") Print("Fork started") forkProgress="defproducer" + chr(ord(forkAtProducer[-1])+3) @@ -215,7 +215,7 @@ def getLatestSnapshot(nodeId): Print("Restore fork") Print("Relaunching the non-producing bridge node to connect the producing nodes again") if nonProdNode.verifyAlive(): - Utils.errorExit("Bridge is already running"); + Utils.errorExit("Bridge is already running") if not nonProdNode.relaunch(): Utils.errorExit(f"Failure - (non-production) node {nonProdNode.nodeNum} should have restarted") diff --git a/tests/test_read_only_trx.cpp b/tests/test_read_only_trx.cpp index b2e615ef14..56b684da86 100644 --- a/tests/test_read_only_trx.cpp +++ b/tests/test_read_only_trx.cpp @@ -73,12 +73,6 @@ BOOST_AUTO_TEST_CASE(read_only_on_producer) { test_configs_common(specific_args, app_init_status::failed); } -// read_window_time must be greater than max_transaction_time + 10ms -BOOST_AUTO_TEST_CASE(invalid_read_window_time) { - std::vector specific_args = { "--read-only-threads", "2", "--max-transaction-time", "10", "--read-only-write-window-time-us", "50000", "--read-only-read-window-time-us", "20000" }; // 20000 not greater than --max-transaction-time (10ms) + 10000us (minimum margin) - test_configs_common(specific_args, app_init_status::failed); -} - // if --read-only-threads is not configured, read-only trx related configs should // not be checked BOOST_AUTO_TEST_CASE(not_check_configs_if_no_read_only_threads) { @@ -112,7 +106,16 @@ void test_trxs_common(std::vector& specific_args, bool test_disable std::thread app_thread( [&]() { try { fc::logger::get(DEFAULT_LOGGER).set_log_level(fc::log_level::debug); - std::vector argv = {"test", "--data-dir", temp_dir_str.c_str(), "--config-dir", temp_dir_str.c_str()}; + std::vector argv = { + "test", // dummy executible name + "-p", "eosio", "-e", // actual arguments follow + "--data-dir", temp_dir_str.c_str(), + "--config-dir", temp_dir_str.c_str(), + "--max-transaction-time=100", + "--abi-serializer-max-time-ms=999", + "--read-only-write-window-time-us=100000", + "--read-only-read-window-time-us=400000" + }; argv.insert(argv.end(), specific_args.begin(), specific_args.end()); app->initialize(argv.size(), (char**)&argv[0]); app->find_plugin()->chain(); @@ -124,6 +127,7 @@ void test_trxs_common(std::vector& specific_args, bool test_disable BOOST_CHECK(!"app threw exception see logged error"); } ); fc::scoped_exit> on_except = [&](){ + app->quit(); if (app_thread.joinable()) app_thread.join(); }; @@ -138,7 +142,7 @@ void test_trxs_common(std::vector& specific_args, bool test_disable chain_plug->get_read_only_api(fc::seconds(90)).get_account(chain_apis::read_only::get_account_params{.account_name=config::system_account_name}, fc::time_point::now()+fc::seconds(90)); ++num_get_account_calls; }); - app->executor().post( priority::low, exec_queue::read_only, [ptrx, &next_calls, &num_posts, &trace_with_except, &trx_match, &app]() { + app->executor().post( priority::low, exec_queue::read_exclusive, [ptrx, &next_calls, &num_posts, &trace_with_except, &trx_match, &app]() { ++num_posts; bool return_failure_traces = true; app->get_method()(ptrx, @@ -172,8 +176,6 @@ void test_trxs_common(std::vector& specific_args, bool test_disable while ( (next_calls < num_pushes || num_get_account_calls < num_pushes) && fc::time_point::now() < hard_deadline ){ std::this_thread::sleep_for( 100ms ); } - - app->quit(); } BOOST_CHECK_EQUAL( trace_with_except, 0u ); // should not have any traces with except in it @@ -184,66 +186,41 @@ void test_trxs_common(std::vector& specific_args, bool test_disable } FC_LOG_AND_RETHROW() } -// test read-only trxs on main thread (no --read-only-threads) -BOOST_AUTO_TEST_CASE(no_read_only_threads) { - std::vector specific_args = { "-p", "eosio", "-e", "--abi-serializer-max-time-ms=999" }; - test_trxs_common(specific_args); -} - // test read-only trxs on 1 threads (with --read-only-threads) BOOST_AUTO_TEST_CASE(with_1_read_only_threads) { - std::vector specific_args = { "-p", "eosio", "-e", - "--read-only-threads=1", - "--max-transaction-time=10", - "--abi-serializer-max-time-ms=999", - "--read-only-write-window-time-us=100000", - "--read-only-read-window-time-us=40000" }; + std::vector specific_args = { "--read-only-threads=1" }; test_trxs_common(specific_args); } // test read-only trxs on 3 threads (with --read-only-threads) BOOST_AUTO_TEST_CASE(with_3_read_only_threads) { - std::vector specific_args = { "-p", "eosio", "-e", - "--read-only-threads=3", - "--max-transaction-time=10", - "--abi-serializer-max-time-ms=999", - "--read-only-write-window-time-us=100000", - "--read-only-read-window-time-us=40000" }; + std::vector specific_args = { "--read-only-threads=3" }; test_trxs_common(specific_args); } // test read-only trxs on 3 threads (with --read-only-threads) BOOST_AUTO_TEST_CASE(with_3_read_only_threads_no_tierup) { - std::vector specific_args = { "-p", "eosio", "-e", - "--read-only-threads=3", - "--max-transaction-time=10", - "--abi-serializer-max-time-ms=999", - "--read-only-write-window-time-us=100000", - "--read-only-read-window-time-us=40000" }; + std::vector specific_args = { "--read-only-threads=3", +#ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED + "--eos-vm-oc-enable=none", +#endif + }; test_trxs_common(specific_args, true); } // test read-only trxs on 8 separate threads (with --read-only-threads) BOOST_AUTO_TEST_CASE(with_8_read_only_threads) { - std::vector specific_args = { "-p", "eosio", "-e", - "--read-only-threads=8", - "--eos-vm-oc-enable=none", - "--max-transaction-time=10", - "--abi-serializer-max-time-ms=999", - "--read-only-write-window-time-us=10000", - "--read-only-read-window-time-us=400000" }; + std::vector specific_args = { "--read-only-threads=8" }; test_trxs_common(specific_args); } // test read-only trxs on 8 separate threads (with --read-only-threads) BOOST_AUTO_TEST_CASE(with_8_read_only_threads_no_tierup) { - std::vector specific_args = { "-p", "eosio", "-e", - "--read-only-threads=8", + std::vector specific_args = { "--read-only-threads=8", +#ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED "--eos-vm-oc-enable=none", - "--max-transaction-time=10", - "--abi-serializer-max-time-ms=999", - "--read-only-write-window-time-us=10000", - "--read-only-read-window-time-us=400000" }; +#endif + }; test_trxs_common(specific_args, true); } diff --git a/tests/test_snapshot_information.cpp b/tests/test_snapshot_information.cpp index 5c45b38ed4..49aa25c431 100644 --- a/tests/test_snapshot_information.cpp +++ b/tests/test_snapshot_information.cpp @@ -2,8 +2,8 @@ #include #include #include "snapshot_suites.hpp" -#include #include +#include #include #include @@ -18,7 +18,7 @@ namespace { BOOST_AUTO_TEST_SUITE(producer_snapshot_tests) -using next_t = eosio::producer_plugin::next_function; +using next_t = pending_snapshot::next_t; BOOST_AUTO_TEST_CASE_TEMPLATE(test_snapshot_information, SNAPSHOT_SUITE, snapshot_suites) { tester chain; diff --git a/tests/test_snapshot_scheduler.cpp b/tests/test_snapshot_scheduler.cpp index ed1f5286d7..1a560ca079 100644 --- a/tests/test_snapshot_scheduler.cpp +++ b/tests/test_snapshot_scheduler.cpp @@ -60,6 +60,9 @@ BOOST_AUTO_TEST_CASE(snapshot_scheduler_test) { std::promise> plugin_promise; std::future> plugin_fut = plugin_promise.get_future(); + std::promise at_block_20_promise; + std::future at_block_20_fut = at_block_20_promise.get_future(); + std::thread app_thread([&]() { try { fc::logger::get(DEFAULT_LOGGER).set_log_level(fc::log_level::debug); @@ -68,8 +71,48 @@ BOOST_AUTO_TEST_CASE(snapshot_scheduler_test) { "-p", "eosio", "-e"}; app->initialize(argv.size(), (char**) &argv[0]); app->startup(); - plugin_promise.set_value( - {app->find_plugin(), app->find_plugin()}); + + producer_plugin* prod_plug = app->find_plugin(); + chain_plugin* chain_plug = app->find_plugin(); + plugin_promise.set_value({prod_plug, chain_plug}); + + auto bs = chain_plug->chain().block_start.connect([&prod_plug, &at_block_20_promise](uint32_t bn) { + if(bn == 20u) + at_block_20_promise.set_value(); + // catching pending snapshot + if (!prod_plug->get_snapshot_requests().snapshot_requests.empty()) { + const auto& snapshot_requests = prod_plug->get_snapshot_requests().snapshot_requests; + + auto validate_snapshot_request = [&](uint32_t sid, uint32_t block_num, uint32_t spacing = 0, bool fuzzy_start = false) { + auto it = find_if(snapshot_requests.begin(), snapshot_requests.end(), [sid](const snapshot_scheduler::snapshot_schedule_information& obj) {return obj.snapshot_request_id == sid;}); + if (it != snapshot_requests.end()) { + auto& pending = it->pending_snapshots; + if (pending.size()==1u) { + // pending snapshot block number + auto pbn = pending.begin()->head_block_num; + + // first pending snapshot + auto ps_start = (spacing != 0) ? (spacing + (pbn%spacing)) : pbn; + + if (!fuzzy_start) { + BOOST_CHECK_EQUAL(block_num, ps_start); + } + else { + int diff = block_num - ps_start; + BOOST_CHECK(std::abs(diff) <= 5); // accept +/- 5 blocks if start block not specified + } + } + return true; + } + return false; + }; + + BOOST_REQUIRE(validate_snapshot_request(0, 9, 8)); // snapshot #0 should have pending snapshot at block #9 (8 + 1) and it never expires + BOOST_REQUIRE(validate_snapshot_request(4, 12, 10, true)); // snapshot #4 should have pending snapshot at block # at the moment of scheduling (2) plus 10 = 12 + BOOST_REQUIRE(validate_snapshot_request(5, 10, 10)); // snapshot #5 should have pending snapshot at block #10, #20 etc + } + }); + app->exec(); return; } FC_LOG_AND_DROP() @@ -77,45 +120,6 @@ BOOST_AUTO_TEST_CASE(snapshot_scheduler_test) { }); auto [prod_plug, chain_plug] = plugin_fut.get(); - std::deque all_blocks; - std::promise empty_blocks_promise; - std::future empty_blocks_fut = empty_blocks_promise.get_future(); - auto pp = app->find_plugin(); - - auto bs = chain_plug->chain().block_start.connect([&pp](uint32_t bn) { - // catching pending snapshot - if (!pp->get_snapshot_requests().snapshot_requests.empty()) { - const auto& snapshot_requests = pp->get_snapshot_requests().snapshot_requests; - - auto validate_snapshot_request = [&](uint32_t sid, uint32_t block_num, uint32_t spacing = 0, bool fuzzy_start = false) { - auto it = find_if(snapshot_requests.begin(), snapshot_requests.end(), [sid](const snapshot_scheduler::snapshot_schedule_information& obj) {return obj.snapshot_request_id == sid;}); - if (it != snapshot_requests.end()) { - auto& pending = it->pending_snapshots; - if (pending.size()==1u) { - // pending snapshot block number - auto pbn = pending.begin()->head_block_num; - - // first pending snapshot - auto ps_start = (spacing != 0) ? (spacing + (pbn%spacing)) : pbn; - - if (!fuzzy_start) { - BOOST_CHECK_EQUAL(block_num, ps_start); - } - else { - int diff = block_num - ps_start; - BOOST_CHECK(std::abs(diff) <= 5); // accept +/- 5 blocks if start block not specified - } - } - return true; - } - return false; - }; - - BOOST_REQUIRE(validate_snapshot_request(0, 9, 8)); // snapshot #0 should have pending snapshot at block #9 (8 + 1) and it never expires - BOOST_REQUIRE(validate_snapshot_request(4, 12, 10, true)); // snapshot #4 should have pending snapshot at block # at the moment of scheduling (2) plus 10 = 12 - BOOST_REQUIRE(validate_snapshot_request(5, 10, 10)); // snapshot #5 should have pending snapshot at block #10, #20 etc - } - }); snapshot_request_params sri1 = {.block_spacing = 8, .start_block_num = 1, .end_block_num = 300000, .snapshot_description = "Example of recurring snapshot 1"}; snapshot_request_params sri2 = {.block_spacing = 5000, .start_block_num = 100000, .end_block_num = 300000, .snapshot_description = "Example of recurring snapshot 2 that wont happen in test"}; @@ -124,31 +128,35 @@ BOOST_AUTO_TEST_CASE(snapshot_scheduler_test) { snapshot_request_params sri5 = {.block_spacing = 10, .snapshot_description = "Recurring every 10 blocks snapshot starting now"}; snapshot_request_params sri6 = {.block_spacing = 10, .start_block_num = 0, .snapshot_description = "Recurring every 10 blocks snapshot starting from 0"}; - pp->schedule_snapshot(sri1); - pp->schedule_snapshot(sri2); - pp->schedule_snapshot(sri3); - pp->schedule_snapshot(sri4); - pp->schedule_snapshot(sri5); - pp->schedule_snapshot(sri6); + app->post(appbase::priority::medium_low, [&]() { + prod_plug->schedule_snapshot(sri1); + prod_plug->schedule_snapshot(sri2); + prod_plug->schedule_snapshot(sri3); + prod_plug->schedule_snapshot(sri4); + prod_plug->schedule_snapshot(sri5); + prod_plug->schedule_snapshot(sri6); - // all six snapshot requests should be present now - BOOST_CHECK_EQUAL(6u, pp->get_snapshot_requests().snapshot_requests.size()); + // all six snapshot requests should be present now + BOOST_CHECK_EQUAL(6u, prod_plug->get_snapshot_requests().snapshot_requests.size()); + }); - empty_blocks_fut.wait_for(std::chrono::seconds(10)); + at_block_20_fut.get(); - // two of the snapshots are done here and requests, corresponding to them should be deleted - BOOST_CHECK_EQUAL(4u, pp->get_snapshot_requests().snapshot_requests.size()); + app->post(appbase::priority::medium_low, [&]() { + // two of the snapshots are done here and requests, corresponding to them should be deleted + BOOST_CHECK_EQUAL(4u, prod_plug->get_snapshot_requests().snapshot_requests.size()); - // check whether no pending snapshots present for a snapshot with id 0 - const auto& snapshot_requests = pp->get_snapshot_requests().snapshot_requests; - auto it = find_if(snapshot_requests.begin(), snapshot_requests.end(),[](const snapshot_scheduler::snapshot_schedule_information& obj) {return obj.snapshot_request_id == 0;}); + // check whether no pending snapshots present for a snapshot with id 0 + const auto& snapshot_requests = prod_plug->get_snapshot_requests().snapshot_requests; + auto it = find_if(snapshot_requests.begin(), snapshot_requests.end(),[](const snapshot_scheduler::snapshot_schedule_information& obj) {return obj.snapshot_request_id == 0;}); - // snapshot request with id = 0 should be found and should not have any pending snapshots - BOOST_REQUIRE(it != snapshot_requests.end()); - BOOST_CHECK(!it->pending_snapshots.size()); + // snapshot request with id = 0 should be found and should not have any pending snapshots + BOOST_REQUIRE(it != snapshot_requests.end()); + BOOST_CHECK(!it->pending_snapshots.size()); - // quit app - app->quit(); + // quit app + app->quit(); + }); app_thread.join(); // lets check whether schedule can be read back after restart diff --git a/tests/trx_generator/CMakeLists.txt b/tests/trx_generator/CMakeLists.txt index fab2a72eeb..d1946a156b 100644 --- a/tests/trx_generator/CMakeLists.txt +++ b/tests/trx_generator/CMakeLists.txt @@ -2,9 +2,9 @@ add_executable(trx_generator main.cpp trx_generator.cpp trx_provider.cpp) target_include_directories(trx_generator PUBLIC ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}) -target_link_libraries(trx_generator PRIVATE eosio_chain fc chain_plugin ${CMAKE_DL_LIBS} ${PLATFORM_SPECIFIC_LIBS}) +target_link_libraries(trx_generator PRIVATE eosio_chain fc Boost::program_options ${CMAKE_DL_LIBS} ${PLATFORM_SPECIFIC_LIBS}) add_executable(trx_generator_tests trx_generator_tests.cpp trx_provider.cpp trx_generator.cpp) -target_link_libraries(trx_generator_tests PRIVATE eosio_chain fc chain_plugin ${CMAKE_DL_LIBS} ${PLATFORM_SPECIFIC_LIBS}) +target_link_libraries(trx_generator_tests PRIVATE eosio_chain fc Boost::program_options ${CMAKE_DL_LIBS} ${PLATFORM_SPECIFIC_LIBS}) target_include_directories(trx_generator_tests PUBLIC ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}) add_test(trx_generator_tests trx_generator_tests) diff --git a/tests/trx_generator/http_client_async.hpp b/tests/trx_generator/http_client_async.hpp index d55dff5e46..7aad239e5c 100644 --- a/tests/trx_generator/http_client_async.hpp +++ b/tests/trx_generator/http_client_async.hpp @@ -74,6 +74,9 @@ class session : public std::enable_shared_from_this { req_.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING); req_.set(http::field::content_type, content_type); req_.body() = std::move(request_body); + // current implementation does not reuse socket, disable keep_alive + req_.set(http::field::connection, "close"); + req_.keep_alive(false); req_.prepare_payload(); // Look up the domain name @@ -129,16 +132,12 @@ class session : public std::enable_shared_from_this { void on_read(beast::error_code ec, std::size_t bytes_transferred) { boost::ignore_unused(bytes_transferred); - if (ec) { - response_callback_(ec, {}); - return fail(ec, "read"); - } - // Write the response message to the callback response_callback_(ec, res_); // Gracefully close the socket stream_.socket().shutdown(tcp::socket::shutdown_both, ec); + stream_.close(); // not_connected happens sometimes so don't bother reporting it. if (ec && ec != beast::errc::not_connected) diff --git a/tests/trx_generator/main.cpp b/tests/trx_generator/main.cpp index 60c20e3f7e..fab8fba31c 100644 --- a/tests/trx_generator/main.cpp +++ b/tests/trx_generator/main.cpp @@ -1,7 +1,7 @@ -#include #include #include #include +#include #include #include #include diff --git a/tests/trx_generator/trx_generator.cpp b/tests/trx_generator/trx_generator.cpp index dda297422f..f3c57082ca 100644 --- a/tests/trx_generator/trx_generator.cpp +++ b/tests/trx_generator/trx_generator.cpp @@ -1,9 +1,9 @@ #include -#include #include #include #include #include +#include #include #include #include @@ -235,7 +235,7 @@ namespace eosio::testing { stop_generation(); ilog("Create Initial Transaction with action data."); - _abi = abi_serializer(fc::json::from_file(_usr_trx_config._abi_data_file_path).as(), abi_serializer::create_yield_function( abi_serializer_max_time )); + _abi = chain::abi_serializer(fc::json::from_file(_usr_trx_config._abi_data_file_path).as(), chain::abi_serializer::create_yield_function( abi_serializer_max_time )); fc::variant unpacked_actions_data_json = json_from_file_or_string(_usr_trx_config._actions_data_json_file_or_str); fc::variant unpacked_actions_auths_data_json = json_from_file_or_string(_usr_trx_config._actions_auths_json_file_or_str); ilog("Loaded actions data: ${data}", ("data", fc::json::to_pretty_string(unpacked_actions_data_json))); diff --git a/tests/trx_generator/trx_generator.hpp b/tests/trx_generator/trx_generator.hpp index 1112444777..83736cd83b 100644 --- a/tests/trx_generator/trx_generator.hpp +++ b/tests/trx_generator/trx_generator.hpp @@ -2,7 +2,6 @@ #include #include #include -#include #include #include #include diff --git a/tests/trx_generator/trx_provider.cpp b/tests/trx_generator/trx_provider.cpp index 9e6a51f817..190c6b4632 100644 --- a/tests/trx_generator/trx_provider.cpp +++ b/tests/trx_generator/trx_provider.cpp @@ -35,8 +35,7 @@ namespace eosio::testing { } void provider_connection::init_and_connect() { - _connection_thread_pool.start( - 1, [](const fc::exception& e) { elog("provider_connection exception ${e}", ("e", e)); }); + _connection_thread_pool.start(1, {}); connect(); }; @@ -107,6 +106,10 @@ namespace eosio::testing { } bool http_connection::needs_response_trace_info() { + return is_read_only_transaction(); + } + + bool http_connection::is_read_only_transaction() { return _config._api_endpoint == "/v1/chain/send_read_only_transaction"; } @@ -129,8 +132,11 @@ namespace eosio::testing { params, std::move(msg_body), [this, trx_id = trx.id()](boost::beast::error_code ec, boost::beast::http::response response) { - ++this->_acknowledged; trx_acknowledged(trx_id, fc::time_point::now()); + if (ec) { + elog("http error: ${c}: ${m}", ("c", ec.value())("m", ec.message())); + throw std::runtime_error(ec.message()); + } if (this->needs_response_trace_info() && response.result() == boost::beast::http::status::ok) { try { @@ -139,6 +145,7 @@ namespace eosio::testing { const auto& processed = resp_json["processed"]; const auto& block_num = processed["block_num"].as_uint64(); const auto& block_time = processed["block_time"].as_string(); + const auto& elapsed_time = processed["elapsed"].as_uint64(); std::string status = "failed"; uint32_t net = 0; uint32_t cpu = 0; @@ -150,7 +157,7 @@ namespace eosio::testing { cpu = receipt["cpu_usage_us"].as_uint64(); } if (status == "executed") { - record_trx_info(trx_id, block_num, cpu, net, block_time); + record_trx_info(trx_id, block_num, this->is_read_only_transaction() ? elapsed_time : cpu, net, block_time); } else { elog("async_http_request Transaction receipt status not executed: ${string}", ("string", response.body())); @@ -173,6 +180,7 @@ namespace eosio::testing { elog("async_http_request Failed with response http status code: ${status}", ("status", response.result_int())); } + ++this->_acknowledged; }); ++_sent; } diff --git a/tests/trx_generator/trx_provider.hpp b/tests/trx_generator/trx_provider.hpp index 8f8dd9200d..f11cb13f09 100644 --- a/tests/trx_generator/trx_provider.hpp +++ b/tests/trx_generator/trx_provider.hpp @@ -99,6 +99,7 @@ namespace eosio::testing { void connect() override final; void disconnect() override final; bool needs_response_trace_info(); + bool is_read_only_transaction(); }; struct p2p_connection : public provider_connection { diff --git a/tools/net-util.py b/tools/net-util.py index 01d0862749..2305d175e1 100755 --- a/tools/net-util.py +++ b/tools/net-util.py @@ -35,7 +35,7 @@ def humanReadableBytesPerSecond(bytes: int, telco:bool = False): while bytes > power: bytes /= power n += 1 - return f'{"~0" if bytes < 0.01 else format(bytes, ".2f")} {labels[n]}B/s' + return f'{"-" if bytes == 0.0 else "~0" if bytes < 0.01 else format(bytes, ".2f")} {labels[n]}B/s' class TextSimpleFocusListWalker(urwid.SimpleFocusListWalker): @@ -96,17 +96,16 @@ def __init__(self): ('nodeos_info', 'earliest_available_block_num'): 'Earliest Available Block:', 'nodeos_head_block_num': 'Head Block Num:', 'nodeos_last_irreversible': 'LIB:', - ('nodeos_p2p_connections','in'): 'Inbound P2P Connections:', - ('nodeos_p2p_connections','out'): 'Outbound P2P Connections:', + 'nodeos_p2p_clients': 'Inbound P2P Connections:', + 'nodeos_p2p_peers': 'Outbound P2P Connections:', 'nodeos_blocks_incoming_total': 'Total Incoming Blocks:', 'nodeos_trxs_incoming_total': 'Total Incoming Trxs:', 'nodeos_blocks_produced_total': 'Blocks Produced:', 'nodeos_trxs_produced_total': 'Trxs Produced:', 'nodeos_scheduled_trxs_total': 'Scheduled Trxs:', - 'nodeos_blacklisted_transactions_total': 'Blacklisted Trxs:', 'nodeos_unapplied_transactions_total': 'Unapplied Trxs:', - 'nodeos_dropped_trxs_total': 'Dropped Trxs:', - 'nodeos_failed_p2p_connections_total': 'Failed P2P Connections:', + 'nodeos_p2p_dropped_trxs_total': 'Dropped Trxs:', + 'nodeos_p2p_failed_connections_total': 'Failed P2P Connections:', 'nodeos_http_requests_total': 'HTTP Requests:', } self.ignoredPrometheusMetrics = [ @@ -165,6 +164,7 @@ def __init__(self): ('\nRcv\nRate', 'receiveBandwidthLW'), ('Last\nRcv\nTime', 'lastBytesReceivedLW'), ('Last\nRcvd\nBlock', 'lastReceivedBlockLW'), + ('Blk\nSync\nRate', 'blockSyncBandwidthLW'), ('Unique\nFirst\nBlks', 'uniqueFirstBlockCountLW'), ('First\nAvail\nBlk', 'firstAvailableBlockLW'), ('Last\nAvail\nBlk', 'lastAvailableBlockLW'), @@ -298,57 +298,61 @@ class bandwidthStats(): def __init__(self, bytesReceived=0, bytesSent=0, connectionStarted=0): self.bytesReceived = 0 self.bytesSent = 0 + self.blockSyncBytesSent = 0 self.connectionStarted = 0 for family in text_string_to_metric_families(response.text): bandwidths = {} for sample in family.samples: + listwalker = getattr(self, 'connectionIDLW') + if "connid" in sample.labels: + connID = sample.labels["connid"] + if connID not in listwalker: + startOffset = endOffset = len(listwalker) + listwalker.append(AttrMap(Text(connID), None, 'reversed')) + else: + startOffset = listwalker.index(connID) + endOffset = startOffset + 1 if sample.name in self.prometheusMetrics: fieldName = self.fields.get(self.prometheusMetrics[sample.name]) field = getattr(self, fieldName) field.set_text(str(int(sample.value))) + elif sample.name == 'nodeos_p2p_addr': + listwalker = getattr(self, 'ipAddressLW') + addr = ipaddress.ip_address(sample.labels["ipv6"]) + host = f'{str(addr.ipv4_mapped) if addr.ipv4_mapped else str(addr)}' + listwalker[startOffset:endOffset] = [AttrMap(Text(host), None, 'reversed')] + listwalker = getattr(self, 'hostnameLW') + addr = sample.labels["address"] + listwalker[startOffset:endOffset] = [AttrMap(Text(addr), None, 'reversed')] + elif sample.name == 'nodeos_p2p_bytes_sent': + stats = bandwidths.get(connID, bandwidthStats()) + stats.bytesSent = int(sample.value) + bandwidths[connID] = stats + elif fieldName == 'nodeos_p2p_block_sync_bytes_sent': + stats = bandwidths.get(connID, bandwidthStats()) + stats.blockSyncBytesSent = int(sample.value) + bandwidths[connID] = stats + elif sample.name == 'nodeos_p2p_bytes_received': + stats = bandwidths.get(connID, bandwidthStats()) + stats.bytesReceived = int(sample.value) + bandwidths[connID] = stats + elif sample.name == 'nodeos_p2p_connection_start_time': + stats = bandwidths.get(connID, bandwidthStats()) + stats.connectionStarted = int(sample.value) + bandwidths[connID] = stats + elif sample.name == 'nodeos_p2p_connection_number': + pass + elif sample.name.startswith('nodeos_p2p_'): + fieldName = sample.name[len('nodeos_p2p_'):] + attrname = fieldName[:1] + fieldName.replace('_', ' ').title().replace(' ', '')[1:] + 'LW' + if hasattr(self, attrname): + listwalker = getattr(self, attrname) + listwalker[startOffset:endOffset] = [AttrMap(Text(self.peerMetricConversions[fieldName](sample.value)), None, 'reversed')] elif sample.name == 'nodeos_p2p_connections': if 'direction' in sample.labels: fieldName = self.fields.get(self.prometheusMetrics[(sample.name, sample.labels['direction'])]) field = getattr(self, fieldName) field.set_text(str(int(sample.value))) - else: - connID = next(iter(sample.labels)) - fieldName = sample.labels[connID] - listwalker = getattr(self, 'connectionIDLW') - if connID not in listwalker: - startOffset = endOffset = len(listwalker) - listwalker.append(AttrMap(Text(connID), None, 'reversed')) - else: - startOffset = listwalker.index(connID) - endOffset = startOffset + 1 - if fieldName.startswith('addr_'): - listwalker = getattr(self, 'ipAddressLW') - addr = ipaddress.ip_address(fieldName[len('addr_'):]) - host = f'{str(addr.ipv4_mapped) if addr.ipv4_mapped else str(addr)}' - listwalker[startOffset:endOffset] = [AttrMap(Text(host), None, 'reversed')] - elif fieldName == 'bytes_received': - bytesReceived = int(sample.value) - stats = bandwidths.get(connID, bandwidthStats()) - stats.bytesReceived = bytesReceived - bandwidths[connID] = stats - elif fieldName == 'bytes_sent': - bytesSent = int(sample.value) - stats = bandwidths.get(connID, bandwidthStats()) - stats.bytesSent = bytesSent - bandwidths[connID] = stats - elif fieldName == 'connection_start_time': - connectionStarted = int(sample.value) - stats = bandwidths.get(connID, bandwidthStats()) - stats.connectionStarted = connectionStarted - bandwidths[connID] = stats - else: - attrname = fieldName[:1] + fieldName.replace('_', ' ').title().replace(' ', '')[1:] + 'LW' - if hasattr(self, attrname): - listwalker = getattr(self, attrname) - listwalker[startOffset:endOffset] = [AttrMap(Text(self.peerMetricConversions[fieldName](sample.value)), None, 'reversed')] - else: - listwalker = getattr(self, 'hostnameLW') - listwalker[startOffset:endOffset] = [AttrMap(Text(fieldName.replace('_', '.')), None, 'reversed')] elif sample.name == 'nodeos_info': for infoLabel, infoValue in sample.labels.items(): fieldName = self.fields.get(self.prometheusMetrics[(sample.name, infoLabel)]) @@ -361,19 +365,21 @@ def __init__(self, bytesReceived=0, bytesSent=0, connectionStarted=0): if sample.name not in self.ignoredPrometheusMetrics: logger.warning(f'Received unhandled Prometheus metric {sample.name}') else: - if sample.name == 'nodeos_p2p_connections': + if sample.name == 'nodeos_p2p_bytes_sent' or sample.name == 'nodeos_p2p_bytes_received' or sample.name == 'nodeos_p2p_block_sync_bytes_sent': now = time.time_ns() + def updateBandwidth(connectedSeconds, listwalker, byteCount, startOffset, endOffset): + bps = byteCount/connectedSeconds + listwalker[startOffset:endOffset] = [AttrMap(Text(humanReadableBytesPerSecond(bps)), None, 'reversed')] connIDListwalker = getattr(self, 'connectionIDLW') for connID, stats in bandwidths.items(): startOffset = connIDListwalker.index(connID) endOffset = startOffset + 1 - connected_seconds = (now - stats.connectionStarted)/1000000000 - listwalker = getattr(self, 'receiveBandwidthLW') - bps = stats.bytesReceived/connected_seconds - listwalker[startOffset:endOffset] = [AttrMap(Text(humanReadableBytesPerSecond(bps)), None, 'reversed')] - listwalker = getattr(self, 'sendBandwidthLW') - bps = stats.bytesSent/connected_seconds - listwalker[startOffset:endOffset] = [AttrMap(Text(humanReadableBytesPerSecond(bps)), None, 'reversed')] + connectedSeconds = (now - stats.connectionStarted)/1000000000 + for listwalkerName, attrName in [('receiveBandwidthLW', 'bytesReceived'), + ('sendBandwidthLW', 'bytesSent'), + ('blockSyncBandwidthLW', 'blockSyncBytesSent')]: + listwalker = getattr(self, listwalkerName) + updateBandwidth(connectedSeconds, listwalker, getattr(stats, attrName), startOffset, endOffset) mainLoop.set_alarm_in(float(self.args.refresh_interval), self.update) def exitOnQ(key): diff --git a/tools/reproducible.Dockerfile b/tools/reproducible.Dockerfile new file mode 100644 index 0000000000..59a19f9d51 --- /dev/null +++ b/tools/reproducible.Dockerfile @@ -0,0 +1,108 @@ +# syntax=docker/dockerfile:1 +# debian:buster on Sep 20 2023 +FROM debian@sha256:d774a984460a74973e6ce4d1f87ab90f2818e41fcdd4802bcbdc4e0b67f9dadf AS builder + +# If enabling the snapshot repo below, this ought to be after the base image time from above. +# date -u -d @1695620708 = Mon Sep 25 05:45:08 AM UTC 2023 +ENV SOURCE_DATE_EPOCH=1695620708 + +# The snapshot repo is currently disabled due to poor performance. Re-eval in the future. +# When the package repo is signed, a message in the payload indicates the time when the repo becomes stale. This protection +# nominally exists to ensure older versions of the package repo which may contain defective packages aren't served in the far +# future. But in our case, we want this pinned package repo at any future date. So [check-valid-until=no] to disable this check. +##RUN < /etc/apt/sources.list +##deb [check-valid-until=no] http://snapshot.debian.org/archive/debian/$(date -d @${SOURCE_DATE_EPOCH} +%Y%m%dT%H%M%SZ)/ buster main +##deb [check-valid-until=no] http://snapshot.debian.org/archive/debian-security/$(date -d @${SOURCE_DATE_EPOCH} +%Y%m%dT%H%M%SZ)/ buster/updates main +##EOS +##EOF + +RUN apt-get update && apt-get -y upgrade && DEBIAN_FRONTEND=noninteractive apt-get -y install build-essential \ + file \ + git \ + libcurl4-openssl-dev \ + libgmp-dev \ + ninja-build \ + python3 \ + zlib1g-dev \ + zstd \ + ; + +ARG _LEAP_CLANG_VERSION=17.0.2 +ARG _LEAP_LLVM_VERSION=11.1.0 +ARG _LEAP_CMAKE_VERSION=3.27.6 + +ADD https://github.com/llvm/llvm-project/releases/download/llvmorg-${_LEAP_CLANG_VERSION}/llvm-project-${_LEAP_CLANG_VERSION}.src.tar.xz \ + https://github.com/llvm/llvm-project/releases/download/llvmorg-${_LEAP_CLANG_VERSION}/llvm-project-${_LEAP_CLANG_VERSION}.src.tar.xz.sig \ + https://github.com/llvm/llvm-project/releases/download/llvmorg-${_LEAP_LLVM_VERSION}/llvm-project-${_LEAP_LLVM_VERSION}.src.tar.xz \ + https://github.com/llvm/llvm-project/releases/download/llvmorg-${_LEAP_LLVM_VERSION}/llvm-project-${_LEAP_LLVM_VERSION}.src.tar.xz.sig \ + https://github.com/Kitware/CMake/releases/download/v${_LEAP_CMAKE_VERSION}/cmake-${_LEAP_CMAKE_VERSION}.tar.gz \ + https://github.com/Kitware/CMake/releases/download/v${_LEAP_CMAKE_VERSION}/cmake-${_LEAP_CMAKE_VERSION}-SHA-256.txt \ + https://github.com/Kitware/CMake/releases/download/v${_LEAP_CMAKE_VERSION}/cmake-${_LEAP_CMAKE_VERSION}-SHA-256.txt.asc \ + / + +# CBA23971357C2E6590D9EFD3EC8FEF3A7BFB4EDA - Brad King (cmake) +# 474E22316ABF4785A88C6E8EA2C794A986419D8A - Tom Stellard (llvm) +# D574BD5D1D0E98895E3BF90044F2485E45D59042 - Tobias Hieta (llvm) + +RUN gpg --keyserver hkps://keyserver.ubuntu.com --recv-keys CBA23971357C2E6590D9EFD3EC8FEF3A7BFB4EDA \ + 474E22316ABF4785A88C6E8EA2C794A986419D8A \ + D574BD5D1D0E98895E3BF90044F2485E45D59042 + +RUN ls *.sig *.asc | xargs -n 1 gpg --verify && \ + sha256sum -c --ignore-missing cmake-*-SHA-256.txt + +RUN tar xf cmake-*.tar.gz && \ + cd cmake*[0-9] && \ + echo 'set(CMAKE_USE_OPENSSL OFF CACHE BOOL "" FORCE)' > leap-init.cmake && \ + ./bootstrap --parallel=$(nproc) --init=leap-init.cmake --generator=Ninja && \ + ninja install + +RUN tar xf llvm-project-${_LEAP_CLANG_VERSION}.src.tar.xz && \ + cmake -S llvm-project-${_LEAP_CLANG_VERSION}.src/llvm -B build-toolchain -GNinja -DLLVM_INCLUDE_DOCS=Off -DLLVM_TARGETS_TO_BUILD=host -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX=/pinnedtoolchain \ + -DCOMPILER_RT_BUILD_SANITIZERS=Off \ + -DLLVM_ENABLE_PROJECTS='lld;clang;clang-tools-extra' \ + -DLLVM_ENABLE_RUNTIMES='compiler-rt;libc;libcxx;libcxxabi;libunwind' && \ + cmake --build build-toolchain -t install + +COPY <<-"EOF" /pinnedtoolchain/pinnedtoolchain.cmake + set(CMAKE_C_COMPILER ${CMAKE_CURRENT_LIST_DIR}/bin/clang) + set(CMAKE_CXX_COMPILER ${CMAKE_CURRENT_LIST_DIR}/bin/clang++) + + set(CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_LIST_DIR}/include/c++/v1 ${CMAKE_CURRENT_LIST_DIR}/include/x86_64-unknown-linux-gnu/c++/v1 /usr/local/include /usr/include) + + set(CMAKE_C_FLAGS_INIT "-D_FORTIFY_SOURCE=2 -fstack-protector-strong -fpie -pthread") + set(CMAKE_CXX_FLAGS_INIT "-nostdinc++ -D_FORTIFY_SOURCE=2 -fstack-protector-strong -fpie -pthread") + + set(CMAKE_EXE_LINKER_FLAGS_INIT "-stdlib=libc++ -nostdlib++ -pie -pthread -Wl,-z,relro,-z,now") + set(CMAKE_SHARED_LINKER_FLAGS_INIT "-stdlib=libc++ -nostdlib++") + set(CMAKE_MODULE_LINKER_FLAGS_INIT "-stdlib=libc++ -nostdlib++") + + set(CMAKE_CXX_STANDARD_LIBRARIES "${CMAKE_CURRENT_LIST_DIR}/lib/x86_64-unknown-linux-gnu/libc++.a ${CMAKE_CURRENT_LIST_DIR}/lib/x86_64-unknown-linux-gnu/libc++abi.a") + + set(CMAKE_SYSTEM_PREFIX_PATH "${CMAKE_CURRENT_LIST_DIR}/pinllvm") +EOF +ENV CMAKE_TOOLCHAIN_FILE=/pinnedtoolchain/pinnedtoolchain.cmake + +RUN tar xf llvm-project-${_LEAP_LLVM_VERSION}.src.tar.xz && \ + cmake -S llvm-project-${_LEAP_LLVM_VERSION}.src/llvm -B build-pinllvm -GNinja -DCMAKE_BUILD_TYPE=Release -DLLVM_TARGETS_TO_BUILD=host -DLLVM_BUILD_TOOLS=Off \ + -DLLVM_ENABLE_RTTI=On -DLLVM_ENABLE_TERMINFO=Off -DLLVM_ENABLE_PIC=Off \ + -DCMAKE_INSTALL_PREFIX=/pinnedtoolchain/pinllvm && \ + cmake --build build-pinllvm -t install + +RUN rm -rf llvm* build* cmake* + +FROM builder AS build + +ARG LEAP_BUILD_JOBS + +# Yuck: This places the source at the same location as leap's CI (build.yaml, build_base.yaml). Unfortunately this location only matches +# when build.yaml etc are being run from a repository named leap. +COPY / /__w/leap/leap +RUN cmake -S /__w/leap/leap -B build -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release -GNinja && \ + cmake --build build -t package -- ${LEAP_BUILD_JOBS:+-j$LEAP_BUILD_JOBS} && \ + /__w/leap/leap/tools/tweak-deb.sh build/leap_*.deb + +FROM scratch AS exporter +COPY --from=build /build/*.deb /build/*.tar.* / diff --git a/tools/tweak-deb.sh b/tools/tweak-deb.sh new file mode 100755 index 0000000000..e1dd6854c2 --- /dev/null +++ b/tools/tweak-deb.sh @@ -0,0 +1,37 @@ +#!/bin/bash +set -euo pipefail + +# Tweaks a couple aspects of the built .deb's control file: +# 1. Removes Installed-Size field; this isn't reproducible for some reason, possibly different filesystems +# reporting different sizes for directories? +# 2. Removes all but the first libc Depends rule as the rest are unnecessarily restrictive. The original was being +# generated as, +# libc6 (>= 2.27), libc6 (>> 2.28), libc6 (<< 2.29), libcurl4 (>= 7.16.2), libgcc1 (>= 1:3.3), libgmp10, zlib1g (>= 1:1.2.0) +# and the included sed rule within this script will reduce it to +# libc6 (>= 2.27), libcurl4 (>= 7.16.2), libgcc1 (>= 1:3.3), libgmp10, zlib1g (>= 1:1.2.0) +# This may need to be tweaked in the future further; clearly not ideal. + +WORKDIR="$(mktemp -d)" +trap 'rm -rf -- "${WORKDIR}"' EXIT + +if [ $# -lt 1 ]; then + echo "Must specify .deb file to tweak as argument to script" + exit 1 +fi + +if [ ! -f "$1" ]; then + echo "Argument passed is not a file" + exit 1 +fi + +DEB_PATH="$(realpath ${1})" +cd "${WORKDIR}" + +ar x "${DEB_PATH}" control.tar.gz +gzip -d control.tar.gz +tar xf control.tar ./control +tar --delete -f control.tar ./control +sed -i -E -e '/Installed-Size/d' -e 's/, libc6[^,]+//g' control +tar --update --mtime "@0" --owner=0 --group=0 --numeric-owner -f control.tar ./control +gzip -n control.tar +ar rD "${DEB_PATH}" control.tar.gz diff --git a/tutorials/bios-boot-tutorial/README.md b/tutorials/bios-boot-tutorial/README.md index 036a19401b..428db4b742 100644 --- a/tutorials/bios-boot-tutorial/README.md +++ b/tutorials/bios-boot-tutorial/README.md @@ -7,27 +7,22 @@ The `bios-boot-tutorial.py` script simulates the bios boot sequence. 1. Python 3.x 2. CMake 3. git -4. g++ -5. build-essentials -6. pip3 -7. openssl -8. curl -9. jq -10. psmisc +4. curl +5. libcurl4-gnutls-dev ## Steps -1. Install Leap 3.1 binaries by following the steps provided in the [Leap README](https://github.com/AntelopeIO/leap/tree/release/3.1#software-installation). +1. Install the latest [Leap binaries](https://github.com/AntelopeIO/leap/releases) by following the steps provided in the README. -2. Install CDT 3.0 binaries by following the steps provided in the [CDT README](https://github.com/AntelopeIO/cdt/tree/release/3.0#binary-releases). +2. Install the latest [CDT binaries](https://github.com/AntelopeIO/cdt/releases) by following the steps provided in the README. -3. Compile EOS System Contracts 3.1: +3. Compile the latest [EOS System Contracts](https://github.com/eosnetworkfoundation/eos-system-contracts/releases). Replaces `release/*latest*` with the latest release branch. ```bash $ cd ~ -$ git clone https://github.com/eosnetworkfoundation/eos-system-contracts system-contracts-3.1 -$ cd ./system-contracts-3.1/ -$ git checkout release/3.1 +$ git clone https://github.com/eosnetworkfoundation/eos-system-contracts +$ cd ./eos-system-contracts/ +$ git checkout release/*latest* $ mkdir build $ cd ./build $ cmake -DCMAKE_BUILD_TYPE=Release .. @@ -42,8 +37,9 @@ The last command in the previous step printed the contracts directory. Make note 5. Launch the `bios-boot-tutorial.py` script: ```bash +$ pip install numpy $ cd ~ -$ git clone https://github.com/AntelopeIO/leap +$ git clone -b release/*latest* https://github.com/AntelopeIO/leap $ cd ./leap/tutorials/bios-boot-tutorial/ $ python3 bios-boot-tutorial.py --cleos=cleos --nodeos=nodeos --keosd=keosd --contracts-dir="${CONTRACTS_DIRECTORY}" -w -a ``` diff --git a/tutorials/bios-boot-tutorial/bios-boot-tutorial.py b/tutorials/bios-boot-tutorial/bios-boot-tutorial.py index a343929309..e730247ff6 100755 --- a/tutorials/bios-boot-tutorial/bios-boot-tutorial.py +++ b/tutorials/bios-boot-tutorial/bios-boot-tutorial.py @@ -349,6 +349,13 @@ def stepSetSystemContract(): retry(args.cleos + 'push action eosio activate \'["35c2186cc36f7bb4aeaf4487b36e57039ccf45a9136aa856a5d569ecca55ef2b"]\' -p eosio@active') # CRYPTO_PRIMITIVES retry(args.cleos + 'push action eosio activate \'["6bcb40a24e49c26d0a60513b6aeb8551d264e4717f306b81a37a5afb3b47cedc"]\' -p eosio@active') + # BLS_PRIMITIVES + retry(args.cleos + 'push action eosio activate \'["98c4175db53ed27e7911a1b5adf0e7db0fc96c2cae172cf594dfa9a742ca9e88"]\' -p eosio@active') + # DISABLE_DEFERRED_TRXS_STAGE_1 - DISALLOW NEW DEFERRED TRANSACTIONS + retry(args.cleos + 'push action eosio activate \'["fce57d2331667353a0eac6b4209b67b843a7262a848af0a49a6e2fa9f6584eb4"]\' -p eosio@active') + # DISABLE_DEFERRED_TRXS_STAGE_2 - PREVENT PREVIOUSLY SCHEDULED DEFERRED TRANSACTIONS FROM REACHING OTHER NODE + # THIS DEPENDS ON DISABLE_DEFERRED_TRXS_STAGE_1 + retry(args.cleos + 'push action eosio activate \'["09e86cb0accf8d81c9e85d34bea4b925ae936626d00c984e4691186891f5bc16"]\' -p eosio@active') sleep(1) # install eosio.system latest version diff --git a/unittests/api_tests.cpp b/unittests/api_tests.cpp index 3d3d773c0f..20eced06f6 100644 --- a/unittests/api_tests.cpp +++ b/unittests/api_tests.cpp @@ -767,7 +767,7 @@ BOOST_FIXTURE_TEST_CASE(cfa_stateful_api, validating_tester) try { BOOST_REQUIRE_EQUAL( validate(), true ); } FC_LOG_AND_RETHROW() -BOOST_FIXTURE_TEST_CASE(deferred_cfa_failed, validating_tester) try { +BOOST_FIXTURE_TEST_CASE(deferred_cfa_failed, validating_tester_no_disable_deferred_trx) try { create_account( "testapi"_n ); produce_blocks(1); @@ -803,7 +803,7 @@ BOOST_FIXTURE_TEST_CASE(deferred_cfa_failed, validating_tester) try { BOOST_REQUIRE_EQUAL( validate(), true ); } FC_LOG_AND_RETHROW() -BOOST_FIXTURE_TEST_CASE(deferred_cfa_success, validating_tester) try { +BOOST_FIXTURE_TEST_CASE(deferred_cfa_success, validating_tester_no_disable_deferred_trx) try { create_account( "testapi"_n ); produce_blocks(1); @@ -811,9 +811,7 @@ BOOST_FIXTURE_TEST_CASE(deferred_cfa_success, validating_tester) try { account_name a = "testapi2"_n; account_name creator = config::system_account_name; - signed_transaction trx; - trx.actions.emplace_back( vector{{creator,config::active_name}}, newaccount{ .creator = creator, @@ -1405,14 +1403,15 @@ BOOST_FIXTURE_TEST_CASE(checktime_start, validating_tester) try { } FC_LOG_AND_RETHROW() /************************************************************************************* - * transaction_tests test case + * transaction_tests common function *************************************************************************************/ -BOOST_FIXTURE_TEST_CASE(transaction_tests, validating_tester) { try { - produce_blocks(2); - create_account( "testapi"_n ); - produce_blocks(100); - set_code( "testapi"_n, test_contracts::test_api_wasm() ); - produce_blocks(1); +template +void transaction_tests(T& chain) { + chain.produce_blocks(2); + chain.create_account( "testapi"_n ); + chain.produce_blocks(100); + chain.set_code( "testapi"_n, test_contracts::test_api_wasm() ); + chain.produce_blocks(1); // test for zero auth { @@ -1421,8 +1420,8 @@ BOOST_FIXTURE_TEST_CASE(transaction_tests, validating_tester) { try { action act({}, tm); trx.actions.push_back(act); - set_transaction_headers(trx); - BOOST_CHECK_EXCEPTION(push_transaction(trx), transaction_exception, + chain.set_transaction_headers(trx); + BOOST_CHECK_EXCEPTION(chain.push_transaction(trx), transaction_exception, [](const fc::exception& e) { return expect_assert_message(e, "transaction must have at least one authorization"); } @@ -1430,96 +1429,104 @@ BOOST_FIXTURE_TEST_CASE(transaction_tests, validating_tester) { try { } // test send_action - CALL_TEST_FUNCTION(*this, "test_transaction", "send_action", {}); + CALL_TEST_FUNCTION(chain, "test_transaction", "send_action", {}); // test send_action_empty - CALL_TEST_FUNCTION(*this, "test_transaction", "send_action_empty", {}); + CALL_TEST_FUNCTION(chain, "test_transaction", "send_action_empty", {}); - // test send_action_large - BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION(*this, "test_transaction", "send_action_large", {}), inline_action_too_big_nonprivileged, + // test send_action_large (512k) + CALL_TEST_FUNCTION( chain, "test_transaction", "send_action_512k", {}); + + // test send_many_actions_512k (512k) + CALL_TEST_FUNCTION( chain, "test_transaction", "send_many_actions_512k", {}); + + // test send_action_large (512k + 1) + BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION(chain, "test_transaction", "send_action_large", {}), inline_action_too_big, [](const fc::exception& e) { - return expect_assert_message(e, "inline action too big for nonprivileged account"); + return expect_assert_message(e, "inline action too big"); } ); // test send_action_inline_fail - BOOST_CHECK_EXCEPTION( CALL_TEST_FUNCTION(*this, "test_transaction", "send_action_inline_fail", {}), + BOOST_CHECK_EXCEPTION( CALL_TEST_FUNCTION(chain, "test_transaction", "send_action_inline_fail", {}), eosio_assert_message_exception, eosio_assert_message_is("test_action::assert_false") ); // test send_transaction - CALL_TEST_FUNCTION(*this, "test_transaction", "send_transaction", {}); - - // test send_transaction_empty - BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION(*this, "test_transaction", "send_transaction_empty", {}), tx_no_auths, - [](const fc::exception& e) { - return expect_assert_message(e, "transaction must have at least one authorization"); - } - ); + CALL_TEST_FUNCTION(chain, "test_transaction", "send_transaction", {}); - { - produce_blocks(10); - transaction_trace_ptr trace; - auto c = control->applied_transaction.connect([&](std::tuple x) { - auto& t = std::get<0>(x); - if (t && t->receipt && t->receipt->status != transaction_receipt::executed) { trace = t; } - } ); - block_state_ptr bsp; - auto c2 = control->accepted_block.connect([&](const block_state_ptr& b) { bsp = b; }); + if (std::is_same::value) { + // test send_transaction_empty + BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION(chain, "test_transaction", "send_transaction_empty", {}), tx_no_auths, + [](const fc::exception& e) { + return expect_assert_message(e, "transaction must have at least one authorization"); + } + ); - // test error handling on deferred transaction failure - auto test_trace = CALL_TEST_FUNCTION(*this, "test_transaction", "send_transaction_trigger_error_handler", {}); - - BOOST_REQUIRE(trace); - BOOST_CHECK_EQUAL(trace->receipt->status, transaction_receipt::soft_fail); - - std::set block_ids; - for( const auto& receipt : bsp->block->transactions ) { - transaction_id_type id; - if( std::holds_alternative(receipt.trx) ) { - const auto& pt = std::get(receipt.trx); - id = pt.id(); - } else { - id = std::get(receipt.trx); + { + chain.produce_blocks(10); + transaction_trace_ptr trace; + auto c = chain.control->applied_transaction.connect([&](std::tuple x) { + auto& t = std::get<0>(x); + if (t && t->receipt && t->receipt->status != transaction_receipt::executed) { trace = t; } + } ); + block_state_ptr bsp; + auto c2 = chain.control->accepted_block.connect([&](const block_state_ptr& b) { bsp = b; }); + + // test error handling on deferred transaction failure + auto test_trace = CALL_TEST_FUNCTION(chain, "test_transaction", "send_transaction_trigger_error_handler", {}); + + BOOST_REQUIRE(trace); + BOOST_CHECK_EQUAL(trace->receipt->status, transaction_receipt::soft_fail); + + std::set block_ids; + for( const auto& receipt : bsp->block->transactions ) { + transaction_id_type id; + if( std::holds_alternative(receipt.trx) ) { + const auto& pt = std::get(receipt.trx); + id = pt.id(); + } else { + id = std::get(receipt.trx); + } + block_ids.insert( id ); } - block_ids.insert( id ); - } - BOOST_CHECK_EQUAL(2, block_ids.size() ); // originating trx and deferred - BOOST_CHECK_EQUAL(1, block_ids.count( test_trace->id ) ); // originating - BOOST_CHECK( !test_trace->failed_dtrx_trace ); - BOOST_CHECK_EQUAL(0, block_ids.count( trace->id ) ); // onerror id, not in block - BOOST_CHECK_EQUAL(1, block_ids.count( trace->failed_dtrx_trace->id ) ); // deferred id since trace moved to failed_dtrx_trace - BOOST_CHECK( trace->action_traces.at(0).act.name == "onerror"_n ); + BOOST_CHECK_EQUAL(2, block_ids.size() ); // originating trx and deferred + BOOST_CHECK_EQUAL(1, block_ids.count( test_trace->id ) ); // originating + BOOST_CHECK( !test_trace->failed_dtrx_trace ); + BOOST_CHECK_EQUAL(0, block_ids.count( trace->id ) ); // onerror id, not in block + BOOST_CHECK_EQUAL(1, block_ids.count( trace->failed_dtrx_trace->id ) ); // deferred id since trace moved to failed_dtrx_trace + BOOST_CHECK( trace->action_traces.at(0).act.name == "onerror"_n ); - c.disconnect(); - c2.disconnect(); + c.disconnect(); + c2.disconnect(); + } } // test test_transaction_size - CALL_TEST_FUNCTION(*this, "test_transaction", "test_transaction_size", fc::raw::pack(54) ); // TODO: Need a better way to test this. + CALL_TEST_FUNCTION(chain, "test_transaction", "test_transaction_size", fc::raw::pack(54) ); // TODO: Need a better way to test this. // test test_read_transaction // this is a bit rough, but I couldn't figure out a better way to compare the hashes - auto tx_trace = CALL_TEST_FUNCTION( *this, "test_transaction", "test_read_transaction", {} ); + auto tx_trace = CALL_TEST_FUNCTION( chain, "test_transaction", "test_read_transaction", {} ); string sha_expect = tx_trace->id; BOOST_TEST_MESSAGE( "tx_trace->action_traces.front().console: = " << tx_trace->action_traces.front().console ); BOOST_TEST_MESSAGE( "sha_expect = " << sha_expect ); BOOST_CHECK_EQUAL(tx_trace->action_traces.front().console == sha_expect, true); // test test_tapos_block_num - CALL_TEST_FUNCTION(*this, "test_transaction", "test_tapos_block_num", fc::raw::pack(control->head_block_num()) ); + CALL_TEST_FUNCTION(chain, "test_transaction", "test_tapos_block_num", fc::raw::pack(chain.control->head_block_num()) ); // test test_tapos_block_prefix - CALL_TEST_FUNCTION(*this, "test_transaction", "test_tapos_block_prefix", fc::raw::pack(control->head_block_id()._hash[1]) ); + CALL_TEST_FUNCTION(chain, "test_transaction", "test_tapos_block_prefix", fc::raw::pack(chain.control->head_block_id()._hash[1]) ); // test send_action_recurse - BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION(*this, "test_transaction", "send_action_recurse", {}), eosio::chain::transaction_exception, + BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION(chain, "test_transaction", "send_action_recurse", {}), eosio::chain::transaction_exception, [](const eosio::chain::transaction_exception& e) { return expect_assert_message(e, "max inline action depth per transaction reached"); } ); - BOOST_REQUIRE_EQUAL( validate(), true ); + BOOST_REQUIRE_EQUAL( chain.validate(), true ); // test read_transaction only returns packed transaction { @@ -1531,8 +1538,8 @@ BOOST_FIXTURE_TEST_CASE(transaction_tests, validating_tester) { try { act.authorization = {{"testapi"_n, config::active_name}}; trx.actions.push_back( act ); - set_transaction_headers( trx, DEFAULT_EXPIRATION_DELTA ); - auto sigs = trx.sign( get_private_key( "testapi"_n, "active" ), control->get_chain_id() ); + chain.set_transaction_headers( trx, chain.DEFAULT_EXPIRATION_DELTA ); + auto sigs = trx.sign( chain.get_private_key( "testapi"_n, "active" ), chain.control->get_chain_id() ); auto time_limit = fc::microseconds::maximum(); auto ptrx = std::make_shared( signed_transaction(trx), packed_transaction::compression_type::none ); @@ -1547,24 +1554,39 @@ BOOST_FIXTURE_TEST_CASE(transaction_tests, validating_tester) { try { BOOST_CHECK(pkt.get_packed_transaction() == packed_copy); ptrx = std::make_shared( pkt ); - auto fut = transaction_metadata::start_recover_keys( std::move( ptrx ), control->get_thread_pool(), control->get_chain_id(), time_limit, transaction_metadata::trx_type::input ); - auto r = control->push_transaction( fut.get(), fc::time_point::maximum(), fc::microseconds::maximum(), DEFAULT_BILLED_CPU_TIME_US, true, 0 ); + auto fut = transaction_metadata::start_recover_keys( std::move( ptrx ), chain.control->get_thread_pool(), chain.control->get_chain_id(), time_limit, transaction_metadata::trx_type::input ); + auto r = chain.control->push_transaction( fut.get(), fc::time_point::maximum(), fc::microseconds::maximum(), T::DEFAULT_BILLED_CPU_TIME_US, true, 0 ); if( r->except_ptr ) std::rethrow_exception( r->except_ptr ); if( r->except) throw *r->except; tx_trace = r; - produce_block(); + chain.produce_block(); BOOST_CHECK(tx_trace->action_traces.front().console == sha_expect); } +} - } FC_LOG_AND_RETHROW() } +/************************************************************************************* + * transaction tests for before disable_trxs_protocol_features are activated + *************************************************************************************/ +BOOST_AUTO_TEST_CASE(transaction_tests_before_disable_trxs_protocol_features) { try { + validating_tester_no_disable_deferred_trx chain; + transaction_tests(chain); +} FC_LOG_AND_RETHROW() } /************************************************************************************* - * verify subjective limit test case + * transaction tests after before disable_trxs_protocol_features are activated *************************************************************************************/ -BOOST_AUTO_TEST_CASE(inline_action_subjective_limit) { try { +BOOST_AUTO_TEST_CASE(transaction_tests_after_disable_trxs_protocol_features) { try { + validating_tester chain; + transaction_tests(chain); +} FC_LOG_AND_RETHROW() } + +/************************************************************************************* + * verify objective limit test case + *************************************************************************************/ +BOOST_AUTO_TEST_CASE(inline_action_with_over_4k_limit) { try { const uint32_t _4k = 4 * 1024; - tester chain(setup_policy::full, db_read_mode::HEAD, {_4k + 100}, {_4k + 1}); - tester chain2(setup_policy::full, db_read_mode::HEAD, {_4k + 100}, {_4k}); + tester chain(setup_policy::full, db_read_mode::HEAD, {_4k + 100}); + tester chain2(setup_policy::full, db_read_mode::HEAD, {_4k + 100}); signed_block_ptr block; for (int n=0; n < 2; ++n) { block = chain.produce_block(); @@ -1591,7 +1613,7 @@ BOOST_AUTO_TEST_CASE(inline_action_subjective_limit) { try { *************************************************************************************/ BOOST_AUTO_TEST_CASE(inline_action_objective_limit) { try { const uint32_t _4k = 4 * 1024; - tester chain(setup_policy::full, db_read_mode::HEAD, {_4k}, {_4k - 1}); + tester chain(setup_policy::full, db_read_mode::HEAD, {_4k}); chain.produce_blocks(2); chain.create_account( "testapi"_n ); chain.produce_blocks(100); @@ -1611,42 +1633,10 @@ BOOST_AUTO_TEST_CASE(inline_action_objective_limit) { try { } FC_LOG_AND_RETHROW() } -BOOST_AUTO_TEST_CASE(deferred_inline_action_subjective_limit_failure) { try { - const uint32_t _4k = 4 * 1024; - tester chain(setup_policy::full, db_read_mode::HEAD, {_4k + 100}, {_4k}); - chain.produce_blocks(2); - chain.create_accounts( {"testapi"_n, "testapi2"_n, "alice"_n} ); - chain.set_code( "testapi"_n, test_contracts::test_api_wasm() ); - chain.set_code( "testapi2"_n, test_contracts::test_api_wasm() ); - chain.produce_block(); - - transaction_trace_ptr trace; - auto c = chain.control->applied_transaction.connect([&](std::tuple x) { - auto& t = std::get<0>(x); - if (t->scheduled) { trace = t; } - } ); - CALL_TEST_FUNCTION(chain, "test_transaction", "send_deferred_transaction_4k_action", {} ); - BOOST_CHECK(!trace); - BOOST_CHECK_EXCEPTION(chain.produce_block( fc::seconds(2) ), fc::exception, - [](const fc::exception& e) { - return expect_assert_message(e, "inline action too big for nonprivileged account"); - } - ); - - //check that it populates exception fields - BOOST_REQUIRE(trace); - BOOST_REQUIRE(trace->except); - BOOST_REQUIRE(trace->error_code); - - BOOST_REQUIRE_EQUAL(1, trace->action_traces.size()); - c.disconnect(); - -} FC_LOG_AND_RETHROW() } - -BOOST_AUTO_TEST_CASE(deferred_inline_action_subjective_limit) { try { +BOOST_AUTO_TEST_CASE(deferred_inline_action_limit) { try { const uint32_t _4k = 4 * 1024; - tester chain(setup_policy::full, db_read_mode::HEAD, {_4k + 100}, {_4k + 1}); - tester chain2(setup_policy::full, db_read_mode::HEAD, {_4k + 100}, {_4k}); + tester chain(setup_policy::full_except_do_not_disable_deferred_trx, db_read_mode::HEAD, {_4k + 100}); + tester chain2(setup_policy::full_except_do_not_disable_deferred_trx, db_read_mode::HEAD, {_4k + 100}); signed_block_ptr block; for (int n=0; n < 2; ++n) { block = chain.produce_block(); @@ -1674,7 +1664,7 @@ BOOST_AUTO_TEST_CASE(deferred_inline_action_subjective_limit) { try { //confirm printed message BOOST_TEST(!trace->action_traces.empty()); - BOOST_TEST(trace->action_traces.back().console == "exec 8"); + BOOST_TEST(trace->action_traces.back().console == "action size: 4096"); c.disconnect(); for (int n=0; n < 10; ++n) { @@ -1684,7 +1674,7 @@ BOOST_AUTO_TEST_CASE(deferred_inline_action_subjective_limit) { try { } FC_LOG_AND_RETHROW() } -BOOST_FIXTURE_TEST_CASE(deferred_transaction_tests, validating_tester) { try { +BOOST_FIXTURE_TEST_CASE(deferred_transaction_tests, validating_tester_no_disable_deferred_trx) { try { produce_blocks(2); create_accounts( {"testapi"_n, "testapi2"_n, "alice"_n} ); set_code( "testapi"_n, test_contracts::test_api_wasm() ); diff --git a/unittests/auth_tests.cpp b/unittests/auth_tests.cpp index f4a9cebdf2..02fa619866 100644 --- a/unittests/auth_tests.cpp +++ b/unittests/auth_tests.cpp @@ -9,6 +9,8 @@ #include +#include + using namespace eosio; using namespace eosio::chain; using namespace eosio::testing; @@ -550,5 +552,139 @@ BOOST_AUTO_TEST_CASE( linkauth_special ) { try { } FC_LOG_AND_RETHROW() } +BOOST_AUTO_TEST_CASE(delete_auth) { try { + validating_tester chain; + + const auto& tester_account = "tester"_n; + + chain.produce_blocks(); + chain.create_account("eosio.token"_n); + chain.produce_blocks(10); + + chain.set_code("eosio.token"_n, test_contracts::eosio_token_wasm()); + chain.set_abi("eosio.token"_n, test_contracts::eosio_token_abi()); + + chain.produce_blocks(); + chain.create_account("tester"_n); + chain.create_account("tester2"_n); + chain.produce_blocks(10); + + transaction_trace_ptr trace; + + // can't delete auth because it doesn't exist + BOOST_REQUIRE_EXCEPTION( + trace = chain.push_action(config::system_account_name, deleteauth::get_name(), tester_account, fc::mutable_variant_object() + ("account", "tester") + ("permission", "first")), + permission_query_exception, + [] (const permission_query_exception &e)->bool { + expect_assert_message(e, "permission_query_exception: Permission Query Exception\nFailed to retrieve permission"); + return true; + }); + + // update auth + chain.push_action(config::system_account_name, updateauth::get_name(), tester_account, fc::mutable_variant_object() + ("account", "tester") + ("permission", "first") + ("parent", "active") + ("auth", authority(chain.get_public_key(tester_account, "first"))) + ); + + // link auth + chain.push_action(config::system_account_name, linkauth::get_name(), tester_account, fc::mutable_variant_object() + ("account", "tester") + ("code", "eosio.token") + ("type", "transfer") + ("requirement", "first")); + + // create CUR token + chain.produce_blocks(); + chain.push_action("eosio.token"_n, "create"_n, "eosio.token"_n, mutable_variant_object() + ("issuer", "eosio.token" ) + ("maximum_supply", "9000000.0000 CUR" ) + ); + + // issue to account "eosio.token" + chain.push_action("eosio.token"_n, name("issue"), "eosio.token"_n, fc::mutable_variant_object() + ("to", "eosio.token") + ("quantity", "1000000.0000 CUR") + ("memo", "for stuff") + ); + + // transfer from eosio.token to tester + trace = chain.push_action("eosio.token"_n, name("transfer"), "eosio.token"_n, fc::mutable_variant_object() + ("from", "eosio.token") + ("to", "tester") + ("quantity", "100.0000 CUR") + ("memo", "hi" ) + ); + BOOST_REQUIRE_EQUAL(transaction_receipt::executed, trace->receipt->status); + + chain.produce_blocks(); + + auto liquid_balance = chain.get_currency_balance("eosio.token"_n, symbol(SY(4,CUR)), "eosio.token"_n); + BOOST_REQUIRE_EQUAL(asset::from_string("999900.0000 CUR"), liquid_balance); + liquid_balance = chain.get_currency_balance("eosio.token"_n, symbol(SY(4,CUR)), "tester"_n); + BOOST_REQUIRE_EQUAL(asset::from_string("100.0000 CUR"), liquid_balance); + + trace = chain.push_action("eosio.token"_n, name("transfer"), "tester"_n, fc::mutable_variant_object() + ("from", "tester") + ("to", "tester2") + ("quantity", "1.0000 CUR") + ("memo", "hi" ) + ); + + BOOST_REQUIRE_EQUAL(transaction_receipt::executed, trace->receipt->status); + + liquid_balance = chain.get_currency_balance("eosio.token"_n, symbol(SY(4,CUR)), "eosio.token"_n); + BOOST_REQUIRE_EQUAL(asset::from_string("999900.0000 CUR"), liquid_balance); + liquid_balance = chain.get_currency_balance("eosio.token"_n, symbol(SY(4,CUR)), "tester"_n); + BOOST_REQUIRE_EQUAL(asset::from_string("99.0000 CUR"), liquid_balance); + liquid_balance = chain.get_currency_balance("eosio.token"_n, symbol(SY(4,CUR)), "tester2"_n); + BOOST_REQUIRE_EQUAL(asset::from_string("1.0000 CUR"), liquid_balance); + + // can't delete auth because it's linked + BOOST_REQUIRE_EXCEPTION( + trace = chain.push_action(config::system_account_name, deleteauth::get_name(), tester_account, fc::mutable_variant_object() + ("account", "tester") + ("permission", "first")), + action_validate_exception, + [] (const action_validate_exception &e)->bool { + expect_assert_message(e, "action_validate_exception: message validation exception\nCannot delete a linked authority"); + return true; + }); + + // unlink auth + trace = chain.push_action(config::system_account_name, unlinkauth::get_name(), tester_account, fc::mutable_variant_object() + ("account", "tester") + ("code", "eosio.token") + ("type", "transfer")); + BOOST_REQUIRE_EQUAL(transaction_receipt::executed, trace->receipt->status); + + // delete auth + trace = chain.push_action(config::system_account_name, deleteauth::get_name(), tester_account, fc::mutable_variant_object() + ("account", "tester") + ("permission", "first")); + + BOOST_REQUIRE_EQUAL(transaction_receipt::executed, trace->receipt->status); + + chain.produce_blocks(1);; + + trace = chain.push_action("eosio.token"_n, name("transfer"), "tester"_n, fc::mutable_variant_object() + ("from", "tester") + ("to", "tester2") + ("quantity", "3.0000 CUR") + ("memo", "hi" ) + ); + BOOST_REQUIRE_EQUAL(transaction_receipt::executed, trace->receipt->status); + + chain.produce_blocks(); + + liquid_balance = chain.get_currency_balance("eosio.token"_n, symbol(SY(4,CUR)), "tester"_n); + BOOST_REQUIRE_EQUAL(asset::from_string("96.0000 CUR"), liquid_balance); + liquid_balance = chain.get_currency_balance("eosio.token"_n, symbol(SY(4,CUR)), "tester2"_n); + BOOST_REQUIRE_EQUAL(asset::from_string("4.0000 CUR"), liquid_balance); + +} FC_LOG_AND_RETHROW() }/// delete_auth BOOST_AUTO_TEST_SUITE_END() diff --git a/unittests/chain_tests.cpp b/unittests/chain_tests.cpp index c94c10c2bd..7079baac99 100644 --- a/unittests/chain_tests.cpp +++ b/unittests/chain_tests.cpp @@ -179,9 +179,11 @@ BOOST_AUTO_TEST_CASE( signal_validated_blocks ) try { chain.produce_blocks(1); validator.push_block(accepted_bsp->block); - auto trace_ptr = chain.create_account("hello"_n); - chain.produce_block(); + chain.create_account("hello"_n); + auto produced_block = chain.produce_block(); validator.push_block(accepted_bsp->block); + BOOST_CHECK(produced_block->calculate_id() == accepted_bsp->id); + BOOST_CHECK(accepted_bsp->id == validated_bsp->id); } FC_LOG_AND_RETHROW() diff --git a/unittests/currency_tests.cpp b/unittests/currency_tests.cpp index 7e821c489c..cd8398c452 100644 --- a/unittests/currency_tests.cpp +++ b/unittests/currency_tests.cpp @@ -63,8 +63,8 @@ class currency_tester : public validating_tester { return trace; } - currency_tester() - :validating_tester(),abi_ser(json::from_string(test_contracts::eosio_token_abi()).as(), abi_serializer::create_yield_function( abi_serializer_max_time )) + currency_tester(setup_policy p = setup_policy::full) + :validating_tester({}, nullptr, p), abi_ser(json::from_string(test_contracts::eosio_token_abi()).as(), abi_serializer::create_yield_function( abi_serializer_max_time )) { create_account( "eosio.token"_n); set_code( "eosio.token"_n, test_contracts::eosio_token_wasm() ); @@ -91,6 +91,11 @@ class currency_tester : public validating_tester { static const name eosio_token; }; +class pre_disable_deferred_trx_currency_tester : public currency_tester { + public: + pre_disable_deferred_trx_currency_tester() : currency_tester(setup_policy::full_except_do_not_disable_deferred_trx) {} +}; + const name currency_tester::eosio_token = "eosio.token"_n; BOOST_AUTO_TEST_SUITE(currency_tests) @@ -389,7 +394,7 @@ BOOST_FIXTURE_TEST_CASE(test_symbol, validating_tester) try { } FC_LOG_AND_RETHROW() /// test_symbol -BOOST_FIXTURE_TEST_CASE( test_proxy, currency_tester ) try { +BOOST_FIXTURE_TEST_CASE( test_proxy_deferred, pre_disable_deferred_trx_currency_tester ) try { produce_blocks(2); create_accounts( {"alice"_n, "proxy"_n} ); @@ -442,9 +447,9 @@ BOOST_FIXTURE_TEST_CASE( test_proxy, currency_tester ) try { BOOST_REQUIRE_EQUAL(get_balance( "proxy"_n), asset::from_string("0.0000 CUR")); BOOST_REQUIRE_EQUAL(get_balance( "alice"_n), asset::from_string("5.0000 CUR")); -} FC_LOG_AND_RETHROW() /// test_currency +} FC_LOG_AND_RETHROW() /// test_proxy_deferred -BOOST_FIXTURE_TEST_CASE( test_deferred_failure, currency_tester ) try { +BOOST_FIXTURE_TEST_CASE( test_deferred_failure, pre_disable_deferred_trx_currency_tester ) try { produce_blocks(2); create_accounts( {"alice"_n, "bob"_n, "proxy"_n} ); diff --git a/unittests/deep-mind/deep-mind.log b/unittests/deep-mind/deep-mind.log index 864645238c..a23ffbd46d 100644 --- a/unittests/deep-mind/deep-mind.log +++ b/unittests/deep-mind/deep-mind.log @@ -34,11 +34,11 @@ DMLOG START_BLOCK 3 DMLOG CREATION_OP ROOT 0 DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304002,"value_ex":0,"consumed":0},"cpu_usage":{"last_ordinal":1262304002,"value_ex":1157,"consumed":101},"ram_usage":2724} DMLOG TRX_OP CREATE onblock da9fbe9042e1bc9bd64d7a4506534d492107a29f79ad671c1fea19ae3fb70eb4 01e10b5e02005132b41600000000010000000000ea305500000000221acfa4010000000000ea305500000000a8ed32329801013b3d4b0000000000ea30550000000000015ab65a885a31e441ac485ebd2aeba87bf7ee6e7bcc40bf3a24506ba1000000000000000000000000000000000000000000000000000000000000000062267e8b11d7d8f28e1f991a4de2b08cf92500861af2795765bdc9263cd6f4cd000000000001000021010ec7e080177b2c02b278d5088611686b49d739925a92d9bfcacd7fc6b74053bd000000 -DMLOG APPLIED_TRANSACTION 3 da9fbe9042e1bc9bd64d7a4506534d492107a29f79ad671c1fea19ae3fb70eb403000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df71901006400000000000000000000000000000000000000000001010000010000000000ea3055ccfe3b56076237b0b6da2f580652ee1420231b96d3d96b28183769ac932c9e5902000000000000000200000000000000010000000000ea3055020000000000000000000000000000ea30550000000000ea305500000000221acfa4010000000000ea305500000000a8ed32329801013b3d4b0000000000ea30550000000000015ab65a885a31e441ac485ebd2aeba87bf7ee6e7bcc40bf3a24506ba1000000000000000000000000000000000000000000000000000000000000000062267e8b11d7d8f28e1f991a4de2b08cf92500861af2795765bdc9263cd6f4cd000000000001000021010ec7e080177b2c02b278d5088611686b49d739925a92d9bfcacd7fc6b74053bd00000000000000000000da9fbe9042e1bc9bd64d7a4506534d492107a29f79ad671c1fea19ae3fb70eb403000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190000000000000000 +DMLOG APPLIED_TRANSACTION 3 da9fbe9042e1bc9bd64d7a4506534d492107a29f79ad671c1fea19ae3fb70eb403000000023b3d4b01000000034097ed362ec2a0eecb45779129e26e7b0c11ee9149a27c43f4e71bf101006400000000000000000000000000000000000000000001010000010000000000ea3055ccfe3b56076237b0b6da2f580652ee1420231b96d3d96b28183769ac932c9e5902000000000000000200000000000000010000000000ea3055020000000000000000000000000000ea30550000000000ea305500000000221acfa4010000000000ea305500000000a8ed32329801013b3d4b0000000000ea30550000000000015ab65a885a31e441ac485ebd2aeba87bf7ee6e7bcc40bf3a24506ba1000000000000000000000000000000000000000000000000000000000000000062267e8b11d7d8f28e1f991a4de2b08cf92500861af2795765bdc9263cd6f4cd000000000001000021010ec7e080177b2c02b278d5088611686b49d739925a92d9bfcacd7fc6b74053bd00000000000000000000da9fbe9042e1bc9bd64d7a4506534d492107a29f79ad671c1fea19ae3fb70eb403000000023b3d4b01000000034097ed362ec2a0eecb45779129e26e7b0c11ee9149a27c43f4e71bf10000000000000000 DMLOG CREATION_OP ROOT 0 DMLOG RAM_OP 0 eosio code add setcode eosio 180494 177770 DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304002,"value_ex":35325,"consumed":6104},"cpu_usage":{"last_ordinal":1262304002,"value_ex":12732,"consumed":2101},"ram_usage":180494} -DMLOG APPLIED_TRANSACTION 3 03917c562680b415b93db73416ff29230dfbe7ab1ba4d208b46029d01333cd3a03000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190100d0070000fb050000000000000000d8170000000000000001010000010000000000ea30559a90c525172f87bbac0a6378610727f0fe1d7ebe908df973923d29a1606f9a5703000000000000000300000000000000010000000000ea3055030000000000000001000000000000ea30550000000000ea305500000040258ab2c2010000000000ea305500000000a8ed3232fe8a010000000000ea30550000f18a010061736d01000000019d011a60000060037f7e7f0060027f7e0060027f7f0060057f7e7e7e7e0060047f7e7e7e0060017f017f60017f0060037f7f7f017f6000017f60027f7f017f60017e0060027e7f0060047e7e7e7e0060027f7f017e6000017e60047e7e7e7e017f60047f7e7e7f0060037f7f7f0060067e7e7e7e7f7f017f60047f7e7f7f0060037e7e7e0060037e7e7f017f60047f7f7e7f0060027e7e0060047f7f7f7f00028e041803656e761469735f666561747572655f616374697661746564000603656e761370726561637469766174655f66656174757265000703656e760c656f73696f5f617373657274000303656e76066d656d736574000803656e7610616374696f6e5f646174615f73697a65000903656e7610726561645f616374696f6e5f64617461000a03656e76066d656d637079000803656e760c726571756972655f61757468000b03656e760e7365745f70726976696c65676564000c03656e76137365745f7265736f757263655f6c696d697473000d03656e760561626f7274000003656e76167365745f70726f706f7365645f70726f647563657273000e03656e76207365745f626c6f636b636861696e5f706172616d65746572735f7061636b6564000303656e76206765745f626c6f636b636861696e5f706172616d65746572735f7061636b6564000a03656e760c63757272656e745f74696d65000f03656e76146765745f6163746976655f70726f647563657273000a03656e760b64625f66696e645f693634001003656e76095f5f6173686c746933001103656e7611656f73696f5f6173736572745f636f6465000203656e761063757272656e745f7265636569766572000f03656e760a64625f6765745f693634000803656e7606736861323536001203656e760c64625f73746f72655f693634001303656e760d64625f7570646174655f69363400140347460006070007090a08060607070a0a030307070a060715011602160316041603160316030516011603030a0a0a030a17170318181818181818180318181818031818181818081904050170010a0a05030100010616037f014180c0000b7f0041abc3000b7f0041abc3000b070901056170706c79002d090f010041010b092e30323436383a3b3d0ac98001460400101b0b800101037f02400240024002402000450d004100410028028c40200041107622016a220236028c404100410028028440220320006a41076a417871220036028440200241107420004d0d0120014000417f460d020c030b41000f0b4100200241016a36028c40200141016a4000417f470d010b4100419cc000100220030f0b20030b02000b3601017f230041106b2200410036020c4100200028020c28020041076a417871220036028440410020003602804041003f0036028c400b02000b06004190c0000bf50101067f4100210202400240410020006b22032000712000470d00200041104b0d01200110190f0b101d411636020041000f0b0240024002402000417f6a220420016a10192200450d002000200420006a2003712202460d012000417c6a220328020022044107712201450d02200020044178716a220441786a2205280200210620032001200220006b2207723602002002417c6a200420026b2203200172360200200241786a20064107712201200772360200200520012003723602002000101a0b20020f0b20000f0b200241786a200041786a280200200220006b22006a3602002002417c6a200328020020006b36020020020b3301017f411621030240024020014104490d0020012002101e2201450d0120002001360200410021030b20030f0b101d2802000b3801027f02402000410120001b2201101922000d000340410021004100280298402202450d012002110000200110192200450d000b0b20000b0600200010200b0e0002402000450d002000101a0b0b0600200010220b6b01027f230041106b2202240002402002410c6a20014104200141044b1b22012000410120001b2203101f450d00024003404100280298402200450d0120001100002002410c6a20012003101f0d000c020b0b2002410036020c0b200228020c2100200241106a240020000b08002000200110240b0e0002402000450d002000101a0b0b08002000200110260b0500100a000b4e01017f230041e0006b220124002001200141d8006a3602082001200141106a3602042001200141106a36020020012000102a1a200141106a200128020420012802006b100c200141e0006a24000b920901047f02402000280208200028020422026b41074a0d00410041e8c0001002200041046a28020021020b20022001410810061a200041046a2202200228020041086a2203360200200141086a21040240200041086a220528020020036b41034a0d00410041e8c0001002200228020021030b20032004410410061a2002200228020041046a22033602002001410c6a21020240200528020020036b41034a0d00410041e8c0001002200041046a28020021030b20032002410410061a200041046a2202200228020041046a2203360200200141106a21040240200041086a220528020020036b41034a0d00410041e8c0001002200228020021030b20032004410410061a2002200228020041046a2203360200200141146a21020240200528020020036b41034a0d00410041e8c0001002200041046a28020021030b20032002410410061a200041046a2202200228020041046a2203360200200141186a21040240200041086a220528020020036b41034a0d00410041e8c0001002200228020021030b20032004410410061a2002200228020041046a22033602002001411c6a21020240200528020020036b41034a0d00410041e8c0001002200041046a28020021030b20032002410410061a200041046a2202200228020041046a2203360200200141206a21040240200041086a220528020020036b41034a0d00410041e8c0001002200228020021030b20032004410410061a2002200228020041046a2203360200200141246a21020240200528020020036b41034a0d00410041e8c0001002200041046a28020021030b20032002410410061a200041046a2202200228020041046a2203360200200141286a21040240200041086a220528020020036b41034a0d00410041e8c0001002200228020021030b20032004410410061a2002200228020041046a22033602002001412c6a21020240200528020020036b41034a0d00410041e8c0001002200041046a28020021030b20032002410410061a200041046a2202200228020041046a2203360200200141306a21040240200041086a220528020020036b41034a0d00410041e8c0001002200228020021030b20032004410410061a2002200228020041046a2203360200200141346a21020240200528020020036b41034a0d00410041e8c0001002200041046a28020021030b20032002410410061a200041046a2202200228020041046a2203360200200141386a21040240200041086a220528020020036b41034a0d00410041e8c0001002200228020021030b20032004410410061a2002200228020041046a22033602002001413c6a21020240200528020020036b41034a0d00410041e8c0001002200041046a28020021030b20032002410410061a200041046a2202200228020041046a2203360200200141c0006a21040240200041086a220528020020036b41014a0d00410041e8c0001002200228020021030b20032004410210061a2002200228020041026a2203360200200141c2006a21010240200528020020036b41014a0d00410041e8c0001002200041046a28020021030b20032001410210061a200041046a2201200128020041026a36020020000bfa0203017f027e017f230041206b220124002001200029030022024220883c000b200120024228883c000a200120024230883c0009200120024238883c00082001200041086a29030022034220883c0003200120034228883c0002200120034230883c0001200120034238883c000020012002a722043a000f200120044108763a000e200120044110763a000d200120044118763a000c20012003a722043a0007200120044108763a0006200120044110763a0005200120044118763a00042001200041186a29030022023c00172001200029031022034220883c001b200120034228883c001a200120034230883c0019200120034238883c0018200120024220883c0013200120024228883c0012200120024230883c0011200120024238883c001020012002a722004108763a0016200120004110763a0015200120004118763a001420012003a722003a001f200120004108763a001e200120004110763a001d200120004118763a001c200110002100200141206a240020000bf60203017f027e017f230041206b220124002001200029030022024220883c000b200120024228883c000a200120024230883c0009200120024238883c00082001200041086a29030022034220883c0003200120034228883c0002200120034230883c0001200120034238883c000020012002a722043a000f200120044108763a000e200120044110763a000d200120044118763a000c20012003a722043a0007200120044108763a0006200120044110763a0005200120044118763a00042001200041186a29030022023c00172001200029031022034220883c001b200120034228883c001a200120034230883c0019200120034238883c0018200120024220883c0013200120024228883c0012200120024230883c0011200120024238883c001020012002a722004108763a0016200120004110763a0015200120004118763a001420012003a722003a001f200120004108763a001e200120004110763a001d200120004118763a001c20011001200141206a24000bcc0401017f23004190016b220324001018024020012000520d0002400240024002400240024002400240200242ffffb7f6a497b2d942570d00200242ffffffffb5f7d6d942570d01200242808080d0b2b3bb9932510d03200242808080c093fad6d942510d0420024280808080b6f7d6d942520d082003410036028c0120034101360288012003200329038801370300200120012003102f1a0c080b200242fffffffffff698d942550d0120024290a9d9d9dd8c99d6ba7f510d0420024280808080daac9bd6ba7f520d0720034100360264200341023602602003200329036037032820012001200341286a10311a0c070b2002428080b8f6a497b2d942510d0420024280808096cdebd4d942520d062003410036026c200341033602682003200329036837032020012001200341206a10331a0c060b2002428080808080f798d942510d042002428080b8f6a4979ad942520d0520034100360284012003410436028001200320032903800137030820012001200341086a10351a0c050b20034100360254200341053602502003200329035037033820012001200341386a10371a0c040b20034100360274200341063602702003200329037037031820012001200341186a10391a0c030b2003410036024c200341073602482003200329034837034020012001200341c0006a10371a0c020b2003410036027c200341083602782003200329037837031020012001200341106a103c1a0c010b2003410036025c200341093602582003200329035837033020012001200341306a103e1a0b4100101c20034190016a24000b1200200029030010072001200241004710080bd30201077f230041306b2203210420032400200228020421052002280200210641002102024010042207450d00024002402007418104490d002007101921020c010b20032007410f6a4170716b220224000b2002200710051a0b200441003a002820044200370320200220076a2103200441206a41086a210802400240200741074b0d0041004185c1001002200441206a2002410810061a200241086a21090c010b200441206a2002410810061a200241086a210920074108470d0041004185c10010020b20082009410110061a200441186a200336020020042002360210200441146a200241096a3602002004200137030820042000370300200420054101756a2103200441286a2d000021082004290320210002402005410171450d00200328020020066a28020021060b20032000200841ff0171200611010002402007418104490d002002101a0b200441306a240041010b0600200110070b830201057f230041306b22032104200324002002280204210520022802002106024002400240024010042207450d002007418104490d012007101921020c020b410021020c020b20032007410f6a4170716b220224000b2002200710051a0b20044200370328200220076a21030240200741074b0d0041004185c10010020b200441286a2002410810061a2004411c6a200241086a360200200441206a2003360200200420013703102004200037030820042002360218200441086a20054101756a21032004290328210002402005410171450d00200328020020066a28020021060b20032000200611020002402007418104490d002002101a0b200441306a240041010b0d0020002903001007200110290bf70201067f230041a0026b2203210420032400200228020421052002280200210641002102024010042207450d00024002402007418104490d002007101921020c010b20032007410f6a4170716b220224000b2002200710051a0b200441c8006a410041c80010031a2004200236023c200420023602382004200220076a360240200441386a200441c8006a10421a200441086a41086a220320042802403602002004200429033837030820044190016a41086a220820032802003602002004200429030837039001200441d8016a41086a20082802002203360200200441306a2003360200200420003703182004200137032020042004290390012200370328200420003703d80120044190016a200441c8006a41c80010061a200441d8016a20044190016a41c80010061a200441186a20054101756a210302402005410171450d00200328020020066a28020021060b2003200441d8016a200611030002402007418104490d002002101a0b200441a0026a240041010b130020002903001007200120022003200410090b940302067f027e23004180016b22032104200324002002280204210520022802002106024002400240024010042207450d002007418104490d012007101921020c020b410021020c020b20032007410f6a4170716b220224000b2002200710051a0b2004420037034820044200370340200442003703502004420037035820042002360234200420023602302004200220076a3602382004200441306a3602702004200441c0006a360210200441106a200441f0006a103f200441086a2203200428023836020020042004290330370300200441e0006a41086a2208200328020036020020042004290300370360200441f0006a41086a20082802002203360200200441286a2003360200200420003703102004200137031820042004290360220037032020042000370370200441106a20054101756a21032004290358210020042903502101200429034821092004290340210a02402005410171450d00200328020020066a28020021060b2003200a200920012000200611040002402007418104490d002002101a0b20044180016a240041010b0d00200029030010072001102c0bfe0301087f230041a0016b22032104200324002002280204210520022802002106024002400240024010042207450d002007418104490d012007101921020c020b410021020c020b20032007410f6a4170716b220224000b2002200710051a0b200441c0006a41186a22034200370300200441c0006a41106a22084200370300200442003703482004420037034020042002360234200420023602302004200220076a3602382004200441306a3602602004200441c0006a3602800120044180016a200441e0006a1048200441086a2209200428023836020020042004290330370300200441e0006a41086a220a20092802003602002004200429030037036020044180016a41086a200a2802002209360200200441106a41186a200936020020042000370310200420013703182004200429036022003703202004200037038001200441e0006a41186a22092003290300370300200441e0006a41106a22032008290300370300200420042903483703682004200429034037036020044180016a41186a200929030037030020044180016a41106a200329030037030020042004290368370388012004200429036037038001200441106a20054101756a210302402005410171450d00200328020020066a28020021060b200320044180016a200611030002402007418104490d002002101a0b200441a0016a240041010b5601027f23002202210320002903001007024010042200418104490d00200010192202200010051a20022000100b1a200324000f0b20022000410f6a4170716b220224002002200010051a20022000100b1a200324000bb80501077f230041f0006b220321042003240020022802042105200228020021064100210741002102024010042208450d00024002402008418104490d002008101921020c010b20032008410f6a4170716b220224000b2002200810051a0b200441003602482004420037034020042002360234200420023602302004200220086a360238200441306a200441c0006a10411a200441086a2203200428023836020020042004290330370300200441d0006a41086a2209200328020036020020042004290300370350200441e0006a41086a20092802002203360200200441286a20033602002004200037031020042001370318200420042903502200370320200420003703602004410036025820044200370350200428024420042802406b220341306d21090240024002402003450d00200941d6aad52a4f0d01200441d8006a200310202207200941306c6a36020020042007360250200420073602542004280244200428024022096b22034101480d0020072009200310061a20042004280254200341306e41306c6a22073602540b200441106a20054101756a210302402005410171450d00200328020020066a28020021060b2004410036026820044200370360200720042802506b220741306d210502402007450d00200541d6aad52a4f0d02200441e8006a200710202207200541306c6a36020020042007360260200420073602642004280254200428025022096b22054101480d0020072009200510061a20042007200541306e41306c6a3602640b2003200441e0006a2006110300024020042802602207450d0020042007360264200710220b024020042802502207450d0020042007360254200710220b02402008418104490d002002101a0b024020042802402202450d0020042002360244200210220b200441f0006a240041010f0b200441d0006a1028000b200441e0006a1028000b130002402001102b0d00410041d9c20010020b0b0900200029030010070b870302067f017e23004180016b22032104200324002002280204210520022802002106024002400240024010042207450d002007418104490d012007101921020c020b410021020c020b20032007410f6a4170716b220224000b2002200710051a0b2004420037035020044200370348200442003703582004200236023c200420023602382004200220076a3602402004200441386a3602702004200441c8006a360218200441186a200441f0006a1040200441086a41086a2203200428024036020020042004290338370308200441e0006a41086a2208200328020036020020042004290308370360200441f0006a41086a20082802002203360200200441306a2003360200200420003703182004200137032020042004290360220037032820042000370370200441186a20054101756a210320042903582100200429035021012004290348210902402005410171450d00200328020020066a28020021060b2003200920012000200611050002402007418104490d002002101a0b20044180016a240041010bc00203017f017e027f230041c0006b2203240020032001370338200341306a41003602002003427f37032020034200370328200320002903002204370310200320043703180240024002402004200442808080809aecb4ee312001101022004100480d000240200341106a200010452200280230200341106a460d00410041b5c00010020b20032002360208200341106a20004200200341086a1046200328022822050d010c020b2003200236020c2003200341386a3602082003200341106a2001200341086a104720032802282205450d010b024002402003412c6a220628020022002005460d000340200041686a220028020021022000410036020002402002450d00200210220b20052000470d000b200341286a28020021000c010b200521000b2006200536020020001022200341c0006a24000f0b200341c0006a24000b9e0301057f23004180016b2203240020032204200229020037035841002102024010042205450d00024002402005418104490d002005101921020c010b20032005410f6a4170716b220224000b2002200510051a0b200441d0006a4100360200200442003703402004420037034820042002360234200420023602302004200220056a360238200221030240200541074b0d0041004185c1001002200428023421030b200441c0006a2003410810061a2004200341086a360234200441306a200441c0006a41086a220310431a200441086a2206200441306a41086a28020036020020042004290330370300200441e0006a41086a2207200628020036020020042004290300370360200441f0006a41086a20072802002206360200200441286a20063602002004200037031020042001370318200420042903602200370320200420003703702004200441d8006a3602742004200441106a360270200441f0006a200441c0006a104402402005418104490d002002101a0b024020032802002202450d00200441cc006a2002360200200210220b20044180016a240041010bc10201037f20002802002102024020012802002203280208200328020422046b41074b0d0041004185c1001002200341046a28020021040b20022004410810061a200341046a2203200328020041086a3602002000280200220041086a2102024020012802002203280208200328020422046b41074b0d0041004185c1001002200341046a28020021040b20022004410810061a200341046a2203200328020041086a360200200041106a2102024020012802002203280208200328020422046b41074b0d0041004185c1001002200341046a28020021040b20022004410810061a200341046a2203200328020041086a360200200041186a2100024020012802002201280208200128020422036b41074b0d0041004185c1001002200141046a28020021030b20002003410810061a200141046a2201200128020041086a3602000bf30101037f20002802002102024020012802002203280208200328020422046b41074b0d0041004185c1001002200341046a28020021040b20022004410810061a200341046a2203200328020041086a3602002000280200220441086a2102024020012802002203280208200328020422006b41074b0d0041004185c1001002200341046a28020021000b20022000410810061a200341046a2203200328020041086a360200200441106a2100024020012802002201280208200128020422036b41074b0d0041004185c1001002200141046a28020021030b20002003410810061a200141046a2201200128020041086a3602000be80303017f017e067f2000280204210242002103200041086a2104200041046a2105410021060340024020022004280200490d00410041fbc2001002200528020021020b20022d000021072005200241016a22023602002003200741ff0071200641ff0171220674ad842103200641076a2106200221022007418001710d000b02400240024020012802042208200128020022096b41306d22072003a722024f0d002001200220076b105620012802002209200141046a2802002208470d010c020b0240200720024d0d00200141046a2009200241306c6a22083602000b20092008460d010b200041046a22042802002102200041086a210103400240200128020020026b41074b0d0041004185c1001002200428020021020b20092002410810061a2004200428020041086a220236020041002105420021030340024020022001280200490d00410041fbc2001002200428020021020b20022d000021072004200241016a22063602002003200741ff0071200541ff0171220274ad842103200241076a2105200621022007418001710d000b200920033e02082009410c6a21020240200128020020066b41204b0d0041004185c1001002200428020021060b20022006412110061a2004200428020041216a2202360200200941306a22092008470d000b0b20000b920901047f02402000280208200028020422026b41074b0d0041004185c1001002200041046a28020021020b20012002410810061a200041046a2202200228020041086a2203360200200141086a21040240200041086a220528020020036b41034b0d0041004185c1001002200228020021030b20042003410410061a2002200228020041046a22033602002001410c6a21020240200528020020036b41034b0d0041004185c1001002200041046a28020021030b20022003410410061a200041046a2202200228020041046a2203360200200141106a21040240200041086a220528020020036b41034b0d0041004185c1001002200228020021030b20042003410410061a2002200228020041046a2203360200200141146a21020240200528020020036b41034b0d0041004185c1001002200041046a28020021030b20022003410410061a200041046a2202200228020041046a2203360200200141186a21040240200041086a220528020020036b41034b0d0041004185c1001002200228020021030b20042003410410061a2002200228020041046a22033602002001411c6a21020240200528020020036b41034b0d0041004185c1001002200041046a28020021030b20022003410410061a200041046a2202200228020041046a2203360200200141206a21040240200041086a220528020020036b41034b0d0041004185c1001002200228020021030b20042003410410061a2002200228020041046a2203360200200141246a21020240200528020020036b41034b0d0041004185c1001002200041046a28020021030b20022003410410061a200041046a2202200228020041046a2203360200200141286a21040240200041086a220528020020036b41034b0d0041004185c1001002200228020021030b20042003410410061a2002200228020041046a22033602002001412c6a21020240200528020020036b41034b0d0041004185c1001002200041046a28020021030b20022003410410061a200041046a2202200228020041046a2203360200200141306a21040240200041086a220528020020036b41034b0d0041004185c1001002200228020021030b20042003410410061a2002200228020041046a2203360200200141346a21020240200528020020036b41034b0d0041004185c1001002200041046a28020021030b20022003410410061a200041046a2202200228020041046a2203360200200141386a21040240200041086a220528020020036b41034b0d0041004185c1001002200228020021030b20042003410410061a2002200228020041046a22033602002001413c6a21020240200528020020036b41034b0d0041004185c1001002200041046a28020021030b20022003410410061a200041046a2202200228020041046a2203360200200141c0006a21040240200041086a220528020020036b41014b0d0041004185c1001002200228020021030b20042003410210061a2002200228020041026a2203360200200141c2006a21010240200528020020036b41014b0d0041004185c1001002200041046a28020021030b20012003410210061a200041046a2201200128020041026a36020020000ba10203017f017e057f2000280204210242002103200041086a2104200041046a2105410021060340024020022004280200490d00410041fbc2001002200528020021020b20022d000021072005200241016a22083602002003200741ff0071200641ff0171220274ad842103200241076a2106200821022007418001710d000b0240024020012802042207200128020022026b22052003a722064f0d002001200620056b1051200041046a2802002108200141046a2802002107200128020021020c010b200520064d0d00200141046a200220066a22073602000b0240200041086a28020020086b200720026b22074f0d0041004185c1001002200041046a28020021080b20022008200710061a200041046a2202200228020020076a36020020000bf80103017f017e027f230041106b22022400200242003703002002410036020820012903002103024002402001410c6a28020020012802086b2204450d002004417f4c0d01200241086a20041020220520046a36020020022005360200200220053602042001410c6a280200200141086a28020022046b22014101480d0020052004200110061a2002200520016a3602040b20002802002000280204220128020422044101756a21002001280200210102402004410171450d00200028020020016a28020021010b2000200320022001110100024020022802002201450d0020022001360204200110220b200241106a24000f0b20021028000bbf0302077f017e230041206b22022103200224000240200028021822042000411c6a2802002205460d0002400340200541786a2802002001460d012004200541686a2205470d000c020b0b20042005460d00200541686a2802002105200341206a240020050f0b02400240024020014100410010142204417f4c0d0020044181044f0d0120022004410f6a4170716b22022400410021060c020b410041eec00010020b200410192102410121060b20012002200410141a41c000102022052000360230200542003703000240200441074b0d0041004185c10010020b20052002410810061a200541106a2107200241086a21080240200441786a411f4b0d0041004185c10010020b20072008412010061a20052001360234200320053602182003200529030022093703102003200136020c0240024002402000411c6a22072802002204200041206a2802004f0d00200420093703082004200136021020034100360218200420053602002007200441186a36020020060d010c020b200041186a200341186a200341106a2003410c6a105d2006450d010b2002101a0b200328021821012003410036021802402001450d00200110220b200341206a240020050bc40103027f017e017f230022042105024020012802302000460d00410041bdc10010020b024020002903001013510d00410041ebc10010020b20012903002106200328020022032802002207200328020420076b200141106a22071015024020062001290300510d004100419ec20010020b2004220441506a2203240020032001410810061a200441586a2007412010061a20012802342002200341281017024020062000290310540d00200041106a427e200642017c2006427d561b3703000b200524000bfb0101047f230041306b2204240020042002370328024020012903001013510d004100418ac10010020b20042003360214200420013602102004200441286a36021841c000102022032001200441106a105c1a2004200336022020042003290300220237031020042003280234220536020c024002402001411c6a22062802002207200141206a2802004f0d00200720023703082007200536021020044100360220200720033602002006200741186a3602000c010b200141186a200441206a200441106a2004410c6a105d0b2000200336020420002001360200200428022021012004410036022002402001450d00200110220b200441306a24000b960305027f017e017f017e017f230041d0006b2202240020002802002103024020012802002201280208200128020422006b411f4b0d0041004185c1001002200141046a28020021000b200241306a2000412010061a200141046a2201200128020041206a3602004200210441102101200241106a2105410021004200210602400340200241306a20006a2107024020014102490d002006420886200420073100008422044238888421062001417f6a210120044208862104200041016a22004120470d010c020b024020014101460d00410041ffc20010020b200520063703082005200420073100008437030041102101200541106a21054200210442002106200041016a22004120470d000b0b024020014110460d00024020014102490d00200220042006200141037441786a1011200241086a2903002106200229030021040b20052004370300200520063703080b20032002290310370300200341086a2002290318370300200341186a200241106a41186a290300370300200341106a200241106a41106a290300370300200241d0006a24000bba0101047f230041106b22022103200224000240024002400240024010042204450d002004418004490d012004101921020c020b2003420037030841002102200341086a21050c020b20022004410f6a4170716b220224000b2002200410051a20034200370308200341086a2105200441074b0d010b41004185c10010020b20052002410810061a20034200370300200241086a2102024020044178714108470d0041004185c10010020b20032002410810061a200341106a24000b4401037f230022022103024010042204450d00024002402004418004490d002004101921020c010b20022004410f6a4170716b220224000b2002200410051a0b200324000b4401037f230022022103024010042204450d00024002402004418004490d002004101921020c010b20022004410f6a4170716b220224000b2002200410051a0b200324000b4401037f230022022103024010042204450d00024002402004418004490d002004101921020c010b20022004410f6a4170716b220224000b2002200410051a0b200324000b4401037f230022022103024010042204450d00024002402004418004490d002004101921020c010b20022004410f6a4170716b220224000b2002200410051a0b200324000b4401037f230022022103024010042204450d00024002402004418004490d002004101921020c010b20022004410f6a4170716b220224000b2002200410051a0b200324000b4401037f230022022103024010042204450d00024002402004418004490d002004101921020c010b20022004410f6a4170716b220224000b2002200410051a0b200324000bd30201047f230041306b2202210320022400024002400240024010042204450d002004418004490d012004101921020c020b410021020c020b20022004410f6a4170716b220224000b2002200410051a0b20032002360224200320023602202003200220046a2205360228200342003703180240200441074b0d0041004185c1001002200341286a2802002105200328022421020b200341186a2002410810061a2003200241086a2202360224024020052002470d0041004185c1001002200341206a41086a2802002105200328022421020b200341176a2002410110061a2003200241016a2202360224024020052002470d0041004185c1001002200328022421020b200341166a2002410110061a2003200241016a3602242003410036021020034200370308200341206a200341086a10431a024020032802082202450d002003200236020c200210220b200341306a24000bbe0201067f0240024002400240024020002802082202200028020422036b20014f0d002003200028020022046b220520016a2206417f4c0d0241ffffffff0721070240200220046b220241feffffff034b0d0020062002410174220220022006491b2207450d020b2007102021020c030b200041046a21000340200341003a00002000200028020041016a22033602002001417f6a22010d000c040b0b41002107410021020c010b20001028000b200220076a2107200320016a20046b2104200220056a220521030340200341003a0000200341016a21032001417f6a22010d000b200220046a21042005200041046a2206280200200028020022016b22036b2102024020034101480d0020022001200310061a200028020021010b2000200236020020062004360200200041086a20073602002001450d00200110220f0b0bd00102047f017e230041106b22022103200224000240024002400240024010042204450d002004418004490d012004101921020c020b2003420037030841002102200341086a21050c020b20022004410f6a4170716b220224000b2002200410051a20034200370308200341086a2105200441074b0d010b41004185c10010020b20052002410810061a200241086a2102024020044108470d0041004185c10010020b200341076a2002410110061a2003290308210620032d0007210420001007200620044100471008200341106a24000bab0202047f047e230041206b22022103200224000240024002400240024010042204450d002004418004490d012004101921020c020b2003420037031841002102200341186a21050c020b20022004410f6a4170716b220224000b2002200410051a20034200370318200341186a2105200441074b0d010b41004185c10010020b20052002410810061a200241086a21050240200441787122044108470d0041004185c10010020b200341106a2005410810061a200241106a2105024020044110470d0041004185c10010020b200341086a2005410810061a200241186a2102024020044118470d0041004185c10010020b20032002410810061a200329030021062003290308210720032903102108200329031821092000100720092008200720061009200341206a24000bd30101047f230041206b22022103200224000240024002400240024010042204450d002004418004490d012004101921020c020b41002102200341186a21050c020b20022004410f6a4170716b220224000b2002200410051a200341186a2105200441074b0d010b41004185c10010020b20052002410810061a200241086a21050240200441787122044108470d0041004185c10010020b200341106a2005410810061a200241106a2102024020044110470d0041004185c10010020b200341086a2002410810061a20001007200341206a24000bc60301047f23004180016b220221032002240041002104024010042205450d00024002402005418004490d002005101921040c010b20022005410f6a4170716b220424000b2004200510051a0b20032004360254200320043602502003200420056a3602582003410036024820034200370340200341d0006a200341c0006a10411a200341106a41086a2204200328025836020020032003290350370310200341e0006a41086a2205200428020036020020032003290310370360200341f0006a41086a20052802002204360200200341386a20043602002003200037032020032001370328200320032903602200370330200320003703702003410036020820034200370300200328024420032802406b220441306d2105024002402004450d00200541d6aad52a4f0d01200341086a200410202204200541306c6a36020020032004360200200320043602042003280244200328024022026b22054101480d0020042002200510061a20032003280204200541306e41306c6a3602040b200341206a20031038024020032802002204450d0020032004360204200410220b024020032802402204450d0020032004360244200410220b20034180016a24000f0b20031028000bc60301067f0240024002400240024020002802082202200028020422036b41306d20014f0d002003200028020022046b41306d220520016a220641d6aad52a4f0d0241d5aad52a21030240200220046b41306d220241a9d5aa154b0d0020062002410174220320032006491b2203450d020b200341306c102021040c030b200041046a21020340200341086a2200420037030020034200370300200341286a4200370300200341206a4200370300200341186a4200370300200341106a4200370300200041003602002002200228020041306a22033602002001417f6a22010d000c040b0b41002103410021040c010b20001028000b2004200341306c6a21072004200541306c6a220521030340200341086a2202420037030020034200370300200341286a4200370300200341206a4200370300200341186a4200370300200341106a420037030020024100360200200341306a21032001417f6a22010d000b2004200641306c6a21042005200041046a2206280200200028020022036b220141506d41306c6a2102024020014101480d0020022003200110061a200028020021030b2000200236020020062004360200200041086a20073602002003450d00200310220f0b0b8a0101037f230041e0006b2202210320022400024002400240024010042204450d002004418004490d012004101921020c020b410021020c020b20022004410f6a4170716b220224000b2002200410051a0b20032002360254200320023602502003200220046a360258200341d0006a200341086a10421a20001007200341086a1029200341e0006a24000b950101047f230041106b22022103200224000240024002400240024010042204450d002004418004490d012004101921020c020b2003420037030841002102200341086a21050c020b20022004410f6a4170716b220224000b2002200410051a20034200370308200341086a2105200441074b0d010b41004185c10010020b20052002410810061a20032903081007200341106a24000bd70303047f027e017f230041f0006b2202210320022400024002400240024010042204450d002004418004490d012004101921050c020b410021050c020b20022004410f6a4170716b220524000b2005200410051a0b42002106200341286a420037030041102102200341106a41106a4200370300200342003703182003420037031002402004411f4b0d0041004185c10010020b200341d0006a2005412010061a200341306a2105410021044200210702400340200341d0006a20046a2108024020024102490d002007420886200620083100008422064238888421072002417f6a210220064208862106200441016a22044120470d010c020b024020024101460d00410041ffc20010020b200520073703082005200620083100008437030041102102200541106a21054200210642002107200441016a22044120470d000b0b024020024110460d00024020024102490d00200320062007200241037441786a1011200341086a2903002107200329030021060b20052006370300200520073703080b200341106a41186a200341306a41186a290300370300200341106a41106a200341306a41106a290300370300200320032903383703182003200329033037031020001007200341106a102c200341f0006a24000be00303047f027e017f230041f0006b2202210320022400024002400240024010042204450d002004418004490d012004101921050c020b410021050c020b20022004410f6a4170716b220524000b2005200410051a0b42002106200341286a420037030041102102200341106a41106a4200370300200342003703182003420037031002402004411f4b0d0041004185c10010020b200341d0006a2005412010061a200341306a2105410021044200210702400340200341d0006a20046a2108024020024102490d002007420886200620083100008422064238888421072002417f6a210220064208862106200441016a22044120470d010c020b024020024101460d00410041ffc20010020b200520073703082005200620083100008437030041102102200541106a21054200210642002107200441016a22044120470d000b0b024020024110460d00024020024102490d00200320062007200241037441786a1011200341086a2903002107200329030021060b20052006370300200520073703080b200341106a41186a200341306a41186a290300370300200341106a41106a200341306a41106a29030037030020032003290338370318200320032903303703100240200341106a102b0d00410041d9c20010020b200341f0006a24000beb0201037f23004180016b2202210320022400024002400240024010042204450d002004418004490d012004101921020c020b410021020c020b20022004410f6a4170716b220224000b2002200410051a0b20032002360254200320023602502003200220046a360258200342003703480240200441074b0d0041004185c1001002200328025421020b200341c8006a2002410810061a2003200241086a3602542003410036024020034200370338200341d0006a200341386a10431a200341086a41086a2202200341d0006a41086a28020036020020032003290350370308200341e0006a41086a2204200228020036020020032003290308370360200341f0006a41086a20042802002202360200200341306a2002360200200320003703182003200137032020032003290360220037032820032000370370200341186a2003290348200341386a103d024020032802382202450d002003200236023c200210220b20034180016a24000bbc0102037f017e230041306b22032400200020013602302000420037030020002002280204220428020029030037030020022802002101200428020422042802002205200428020420056b200041106a2204101520032000410810061a20034108722004412010061a2000200129030842808080809aecb4ee31200228020829030020002903002206200341281016360234024020062001290310540d00200141106a427e200642017c2006427d561b3703000b200341306a240020000baa0301057f024002402000280204200028020022046b41186d220541016a220641abd5aad5004f0d0041aad5aad500210702400240200028020820046b41186d220441d4aad52a4b0d0020062004410174220720072006491b2207450d010b200741186c102021040c020b41002107410021040c010b20001028000b20012802002106200141003602002004200541186c22086a2201200636020020012002290300370308200120032802003602102004200741186c6a2105200141186a210602400240200041046a280200220220002802002207460d00200420086a41686a21010340200241686a220428020021032004410036020020012003360200200141106a200241786a280200360200200141086a200241706a290300370300200141686a21012004210220072004470d000b200141186a2101200041046a2802002107200028020021020c010b200721020b20002001360200200041046a2006360200200041086a2005360200024020072002460d000340200741686a220728020021012007410036020002402001450d00200110220b20022007470d000b0b02402002450d00200210220b0b0bdf030b00419cc0000b4c6661696c656420746f20616c6c6f63617465207061676573006f626a6563742070617373656420746f206974657261746f725f746f206973206e6f7420696e206d756c74695f696e646578000041e8c0000b1d7772697465006572726f722072656164696e67206974657261746f7200004185c1000b05726561640000418ac1000b3363616e6e6f7420637265617465206f626a6563747320696e207461626c65206f6620616e6f7468657220636f6e7472616374000041bdc1000b2e6f626a6563742070617373656420746f206d6f64696679206973206e6f7420696e206d756c74695f696e646578000041ebc1000b3363616e6e6f74206d6f64696679206f626a6563747320696e207461626c65206f6620616e6f7468657220636f6e74726163740000419ec2000b3b757064617465722063616e6e6f74206368616e6765207072696d617279206b6579207768656e206d6f64696679696e6720616e206f626a656374000041d9c2000b2270726f746f636f6c2066656174757265206973206e6f7420616374697661746564000041fbc2000b04676574000041ffc2000b2c756e6578706563746564206572726f7220696e2066697865645f627974657320636f6e7374727563746f72000041000b04b02100000000000000000000000003917c562680b415b93db73416ff29230dfbe7ab1ba4d208b46029d01333cd3a03000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df719010000000000ea30556ab602000000000000000000000000 +DMLOG APPLIED_TRANSACTION 3 03917c562680b415b93db73416ff29230dfbe7ab1ba4d208b46029d01333cd3a03000000023b3d4b01000000034097ed362ec2a0eecb45779129e26e7b0c11ee9149a27c43f4e71bf10100d0070000fb050000000000000000d8170000000000000001010000010000000000ea30559a90c525172f87bbac0a6378610727f0fe1d7ebe908df973923d29a1606f9a5703000000000000000300000000000000010000000000ea3055030000000000000001000000000000ea30550000000000ea305500000040258ab2c2010000000000ea305500000000a8ed3232fe8a010000000000ea30550000f18a010061736d01000000019d011a60000060037f7e7f0060027f7e0060027f7f0060057f7e7e7e7e0060047f7e7e7e0060017f017f60017f0060037f7f7f017f6000017f60027f7f017f60017e0060027e7f0060047e7e7e7e0060027f7f017e6000017e60047e7e7e7e017f60047f7e7e7f0060037f7f7f0060067e7e7e7e7f7f017f60047f7e7f7f0060037e7e7e0060037e7e7f017f60047f7f7e7f0060027e7e0060047f7f7f7f00028e041803656e761469735f666561747572655f616374697661746564000603656e761370726561637469766174655f66656174757265000703656e760c656f73696f5f617373657274000303656e76066d656d736574000803656e7610616374696f6e5f646174615f73697a65000903656e7610726561645f616374696f6e5f64617461000a03656e76066d656d637079000803656e760c726571756972655f61757468000b03656e760e7365745f70726976696c65676564000c03656e76137365745f7265736f757263655f6c696d697473000d03656e760561626f7274000003656e76167365745f70726f706f7365645f70726f647563657273000e03656e76207365745f626c6f636b636861696e5f706172616d65746572735f7061636b6564000303656e76206765745f626c6f636b636861696e5f706172616d65746572735f7061636b6564000a03656e760c63757272656e745f74696d65000f03656e76146765745f6163746976655f70726f647563657273000a03656e760b64625f66696e645f693634001003656e76095f5f6173686c746933001103656e7611656f73696f5f6173736572745f636f6465000203656e761063757272656e745f7265636569766572000f03656e760a64625f6765745f693634000803656e7606736861323536001203656e760c64625f73746f72655f693634001303656e760d64625f7570646174655f69363400140347460006070007090a08060607070a0a030307070a060715011602160316041603160316030516011603030a0a0a030a17170318181818181818180318181818031818181818081904050170010a0a05030100010616037f014180c0000b7f0041abc3000b7f0041abc3000b070901056170706c79002d090f010041010b092e30323436383a3b3d0ac98001460400101b0b800101037f02400240024002402000450d004100410028028c40200041107622016a220236028c404100410028028440220320006a41076a417871220036028440200241107420004d0d0120014000417f460d020c030b41000f0b4100200241016a36028c40200141016a4000417f470d010b4100419cc000100220030f0b20030b02000b3601017f230041106b2200410036020c4100200028020c28020041076a417871220036028440410020003602804041003f0036028c400b02000b06004190c0000bf50101067f4100210202400240410020006b22032000712000470d00200041104b0d01200110190f0b101d411636020041000f0b0240024002402000417f6a220420016a10192200450d002000200420006a2003712202460d012000417c6a220328020022044107712201450d02200020044178716a220441786a2205280200210620032001200220006b2207723602002002417c6a200420026b2203200172360200200241786a20064107712201200772360200200520012003723602002000101a0b20020f0b20000f0b200241786a200041786a280200200220006b22006a3602002002417c6a200328020020006b36020020020b3301017f411621030240024020014104490d0020012002101e2201450d0120002001360200410021030b20030f0b101d2802000b3801027f02402000410120001b2201101922000d000340410021004100280298402202450d012002110000200110192200450d000b0b20000b0600200010200b0e0002402000450d002000101a0b0b0600200010220b6b01027f230041106b2202240002402002410c6a20014104200141044b1b22012000410120001b2203101f450d00024003404100280298402200450d0120001100002002410c6a20012003101f0d000c020b0b2002410036020c0b200228020c2100200241106a240020000b08002000200110240b0e0002402000450d002000101a0b0b08002000200110260b0500100a000b4e01017f230041e0006b220124002001200141d8006a3602082001200141106a3602042001200141106a36020020012000102a1a200141106a200128020420012802006b100c200141e0006a24000b920901047f02402000280208200028020422026b41074a0d00410041e8c0001002200041046a28020021020b20022001410810061a200041046a2202200228020041086a2203360200200141086a21040240200041086a220528020020036b41034a0d00410041e8c0001002200228020021030b20032004410410061a2002200228020041046a22033602002001410c6a21020240200528020020036b41034a0d00410041e8c0001002200041046a28020021030b20032002410410061a200041046a2202200228020041046a2203360200200141106a21040240200041086a220528020020036b41034a0d00410041e8c0001002200228020021030b20032004410410061a2002200228020041046a2203360200200141146a21020240200528020020036b41034a0d00410041e8c0001002200041046a28020021030b20032002410410061a200041046a2202200228020041046a2203360200200141186a21040240200041086a220528020020036b41034a0d00410041e8c0001002200228020021030b20032004410410061a2002200228020041046a22033602002001411c6a21020240200528020020036b41034a0d00410041e8c0001002200041046a28020021030b20032002410410061a200041046a2202200228020041046a2203360200200141206a21040240200041086a220528020020036b41034a0d00410041e8c0001002200228020021030b20032004410410061a2002200228020041046a2203360200200141246a21020240200528020020036b41034a0d00410041e8c0001002200041046a28020021030b20032002410410061a200041046a2202200228020041046a2203360200200141286a21040240200041086a220528020020036b41034a0d00410041e8c0001002200228020021030b20032004410410061a2002200228020041046a22033602002001412c6a21020240200528020020036b41034a0d00410041e8c0001002200041046a28020021030b20032002410410061a200041046a2202200228020041046a2203360200200141306a21040240200041086a220528020020036b41034a0d00410041e8c0001002200228020021030b20032004410410061a2002200228020041046a2203360200200141346a21020240200528020020036b41034a0d00410041e8c0001002200041046a28020021030b20032002410410061a200041046a2202200228020041046a2203360200200141386a21040240200041086a220528020020036b41034a0d00410041e8c0001002200228020021030b20032004410410061a2002200228020041046a22033602002001413c6a21020240200528020020036b41034a0d00410041e8c0001002200041046a28020021030b20032002410410061a200041046a2202200228020041046a2203360200200141c0006a21040240200041086a220528020020036b41014a0d00410041e8c0001002200228020021030b20032004410210061a2002200228020041026a2203360200200141c2006a21010240200528020020036b41014a0d00410041e8c0001002200041046a28020021030b20032001410210061a200041046a2201200128020041026a36020020000bfa0203017f027e017f230041206b220124002001200029030022024220883c000b200120024228883c000a200120024230883c0009200120024238883c00082001200041086a29030022034220883c0003200120034228883c0002200120034230883c0001200120034238883c000020012002a722043a000f200120044108763a000e200120044110763a000d200120044118763a000c20012003a722043a0007200120044108763a0006200120044110763a0005200120044118763a00042001200041186a29030022023c00172001200029031022034220883c001b200120034228883c001a200120034230883c0019200120034238883c0018200120024220883c0013200120024228883c0012200120024230883c0011200120024238883c001020012002a722004108763a0016200120004110763a0015200120004118763a001420012003a722003a001f200120004108763a001e200120004110763a001d200120004118763a001c200110002100200141206a240020000bf60203017f027e017f230041206b220124002001200029030022024220883c000b200120024228883c000a200120024230883c0009200120024238883c00082001200041086a29030022034220883c0003200120034228883c0002200120034230883c0001200120034238883c000020012002a722043a000f200120044108763a000e200120044110763a000d200120044118763a000c20012003a722043a0007200120044108763a0006200120044110763a0005200120044118763a00042001200041186a29030022023c00172001200029031022034220883c001b200120034228883c001a200120034230883c0019200120034238883c0018200120024220883c0013200120024228883c0012200120024230883c0011200120024238883c001020012002a722004108763a0016200120004110763a0015200120004118763a001420012003a722003a001f200120004108763a001e200120004110763a001d200120004118763a001c20011001200141206a24000bcc0401017f23004190016b220324001018024020012000520d0002400240024002400240024002400240200242ffffb7f6a497b2d942570d00200242ffffffffb5f7d6d942570d01200242808080d0b2b3bb9932510d03200242808080c093fad6d942510d0420024280808080b6f7d6d942520d082003410036028c0120034101360288012003200329038801370300200120012003102f1a0c080b200242fffffffffff698d942550d0120024290a9d9d9dd8c99d6ba7f510d0420024280808080daac9bd6ba7f520d0720034100360264200341023602602003200329036037032820012001200341286a10311a0c070b2002428080b8f6a497b2d942510d0420024280808096cdebd4d942520d062003410036026c200341033602682003200329036837032020012001200341206a10331a0c060b2002428080808080f798d942510d042002428080b8f6a4979ad942520d0520034100360284012003410436028001200320032903800137030820012001200341086a10351a0c050b20034100360254200341053602502003200329035037033820012001200341386a10371a0c040b20034100360274200341063602702003200329037037031820012001200341186a10391a0c030b2003410036024c200341073602482003200329034837034020012001200341c0006a10371a0c020b2003410036027c200341083602782003200329037837031020012001200341106a103c1a0c010b2003410036025c200341093602582003200329035837033020012001200341306a103e1a0b4100101c20034190016a24000b1200200029030010072001200241004710080bd30201077f230041306b2203210420032400200228020421052002280200210641002102024010042207450d00024002402007418104490d002007101921020c010b20032007410f6a4170716b220224000b2002200710051a0b200441003a002820044200370320200220076a2103200441206a41086a210802400240200741074b0d0041004185c1001002200441206a2002410810061a200241086a21090c010b200441206a2002410810061a200241086a210920074108470d0041004185c10010020b20082009410110061a200441186a200336020020042002360210200441146a200241096a3602002004200137030820042000370300200420054101756a2103200441286a2d000021082004290320210002402005410171450d00200328020020066a28020021060b20032000200841ff0171200611010002402007418104490d002002101a0b200441306a240041010b0600200110070b830201057f230041306b22032104200324002002280204210520022802002106024002400240024010042207450d002007418104490d012007101921020c020b410021020c020b20032007410f6a4170716b220224000b2002200710051a0b20044200370328200220076a21030240200741074b0d0041004185c10010020b200441286a2002410810061a2004411c6a200241086a360200200441206a2003360200200420013703102004200037030820042002360218200441086a20054101756a21032004290328210002402005410171450d00200328020020066a28020021060b20032000200611020002402007418104490d002002101a0b200441306a240041010b0d0020002903001007200110290bf70201067f230041a0026b2203210420032400200228020421052002280200210641002102024010042207450d00024002402007418104490d002007101921020c010b20032007410f6a4170716b220224000b2002200710051a0b200441c8006a410041c80010031a2004200236023c200420023602382004200220076a360240200441386a200441c8006a10421a200441086a41086a220320042802403602002004200429033837030820044190016a41086a220820032802003602002004200429030837039001200441d8016a41086a20082802002203360200200441306a2003360200200420003703182004200137032020042004290390012200370328200420003703d80120044190016a200441c8006a41c80010061a200441d8016a20044190016a41c80010061a200441186a20054101756a210302402005410171450d00200328020020066a28020021060b2003200441d8016a200611030002402007418104490d002002101a0b200441a0026a240041010b130020002903001007200120022003200410090b940302067f027e23004180016b22032104200324002002280204210520022802002106024002400240024010042207450d002007418104490d012007101921020c020b410021020c020b20032007410f6a4170716b220224000b2002200710051a0b2004420037034820044200370340200442003703502004420037035820042002360234200420023602302004200220076a3602382004200441306a3602702004200441c0006a360210200441106a200441f0006a103f200441086a2203200428023836020020042004290330370300200441e0006a41086a2208200328020036020020042004290300370360200441f0006a41086a20082802002203360200200441286a2003360200200420003703102004200137031820042004290360220037032020042000370370200441106a20054101756a21032004290358210020042903502101200429034821092004290340210a02402005410171450d00200328020020066a28020021060b2003200a200920012000200611040002402007418104490d002002101a0b20044180016a240041010b0d00200029030010072001102c0bfe0301087f230041a0016b22032104200324002002280204210520022802002106024002400240024010042207450d002007418104490d012007101921020c020b410021020c020b20032007410f6a4170716b220224000b2002200710051a0b200441c0006a41186a22034200370300200441c0006a41106a22084200370300200442003703482004420037034020042002360234200420023602302004200220076a3602382004200441306a3602602004200441c0006a3602800120044180016a200441e0006a1048200441086a2209200428023836020020042004290330370300200441e0006a41086a220a20092802003602002004200429030037036020044180016a41086a200a2802002209360200200441106a41186a200936020020042000370310200420013703182004200429036022003703202004200037038001200441e0006a41186a22092003290300370300200441e0006a41106a22032008290300370300200420042903483703682004200429034037036020044180016a41186a200929030037030020044180016a41106a200329030037030020042004290368370388012004200429036037038001200441106a20054101756a210302402005410171450d00200328020020066a28020021060b200320044180016a200611030002402007418104490d002002101a0b200441a0016a240041010b5601027f23002202210320002903001007024010042200418104490d00200010192202200010051a20022000100b1a200324000f0b20022000410f6a4170716b220224002002200010051a20022000100b1a200324000bb80501077f230041f0006b220321042003240020022802042105200228020021064100210741002102024010042208450d00024002402008418104490d002008101921020c010b20032008410f6a4170716b220224000b2002200810051a0b200441003602482004420037034020042002360234200420023602302004200220086a360238200441306a200441c0006a10411a200441086a2203200428023836020020042004290330370300200441d0006a41086a2209200328020036020020042004290300370350200441e0006a41086a20092802002203360200200441286a20033602002004200037031020042001370318200420042903502200370320200420003703602004410036025820044200370350200428024420042802406b220341306d21090240024002402003450d00200941d6aad52a4f0d01200441d8006a200310202207200941306c6a36020020042007360250200420073602542004280244200428024022096b22034101480d0020072009200310061a20042004280254200341306e41306c6a22073602540b200441106a20054101756a210302402005410171450d00200328020020066a28020021060b2004410036026820044200370360200720042802506b220741306d210502402007450d00200541d6aad52a4f0d02200441e8006a200710202207200541306c6a36020020042007360260200420073602642004280254200428025022096b22054101480d0020072009200510061a20042007200541306e41306c6a3602640b2003200441e0006a2006110300024020042802602207450d0020042007360264200710220b024020042802502207450d0020042007360254200710220b02402008418104490d002002101a0b024020042802402202450d0020042002360244200210220b200441f0006a240041010f0b200441d0006a1028000b200441e0006a1028000b130002402001102b0d00410041d9c20010020b0b0900200029030010070b870302067f017e23004180016b22032104200324002002280204210520022802002106024002400240024010042207450d002007418104490d012007101921020c020b410021020c020b20032007410f6a4170716b220224000b2002200710051a0b2004420037035020044200370348200442003703582004200236023c200420023602382004200220076a3602402004200441386a3602702004200441c8006a360218200441186a200441f0006a1040200441086a41086a2203200428024036020020042004290338370308200441e0006a41086a2208200328020036020020042004290308370360200441f0006a41086a20082802002203360200200441306a2003360200200420003703182004200137032020042004290360220037032820042000370370200441186a20054101756a210320042903582100200429035021012004290348210902402005410171450d00200328020020066a28020021060b2003200920012000200611050002402007418104490d002002101a0b20044180016a240041010bc00203017f017e027f230041c0006b2203240020032001370338200341306a41003602002003427f37032020034200370328200320002903002204370310200320043703180240024002402004200442808080809aecb4ee312001101022004100480d000240200341106a200010452200280230200341106a460d00410041b5c00010020b20032002360208200341106a20004200200341086a1046200328022822050d010c020b2003200236020c2003200341386a3602082003200341106a2001200341086a104720032802282205450d010b024002402003412c6a220628020022002005460d000340200041686a220028020021022000410036020002402002450d00200210220b20052000470d000b200341286a28020021000c010b200521000b2006200536020020001022200341c0006a24000f0b200341c0006a24000b9e0301057f23004180016b2203240020032204200229020037035841002102024010042205450d00024002402005418104490d002005101921020c010b20032005410f6a4170716b220224000b2002200510051a0b200441d0006a4100360200200442003703402004420037034820042002360234200420023602302004200220056a360238200221030240200541074b0d0041004185c1001002200428023421030b200441c0006a2003410810061a2004200341086a360234200441306a200441c0006a41086a220310431a200441086a2206200441306a41086a28020036020020042004290330370300200441e0006a41086a2207200628020036020020042004290300370360200441f0006a41086a20072802002206360200200441286a20063602002004200037031020042001370318200420042903602200370320200420003703702004200441d8006a3602742004200441106a360270200441f0006a200441c0006a104402402005418104490d002002101a0b024020032802002202450d00200441cc006a2002360200200210220b20044180016a240041010bc10201037f20002802002102024020012802002203280208200328020422046b41074b0d0041004185c1001002200341046a28020021040b20022004410810061a200341046a2203200328020041086a3602002000280200220041086a2102024020012802002203280208200328020422046b41074b0d0041004185c1001002200341046a28020021040b20022004410810061a200341046a2203200328020041086a360200200041106a2102024020012802002203280208200328020422046b41074b0d0041004185c1001002200341046a28020021040b20022004410810061a200341046a2203200328020041086a360200200041186a2100024020012802002201280208200128020422036b41074b0d0041004185c1001002200141046a28020021030b20002003410810061a200141046a2201200128020041086a3602000bf30101037f20002802002102024020012802002203280208200328020422046b41074b0d0041004185c1001002200341046a28020021040b20022004410810061a200341046a2203200328020041086a3602002000280200220441086a2102024020012802002203280208200328020422006b41074b0d0041004185c1001002200341046a28020021000b20022000410810061a200341046a2203200328020041086a360200200441106a2100024020012802002201280208200128020422036b41074b0d0041004185c1001002200141046a28020021030b20002003410810061a200141046a2201200128020041086a3602000be80303017f017e067f2000280204210242002103200041086a2104200041046a2105410021060340024020022004280200490d00410041fbc2001002200528020021020b20022d000021072005200241016a22023602002003200741ff0071200641ff0171220674ad842103200641076a2106200221022007418001710d000b02400240024020012802042208200128020022096b41306d22072003a722024f0d002001200220076b105620012802002209200141046a2802002208470d010c020b0240200720024d0d00200141046a2009200241306c6a22083602000b20092008460d010b200041046a22042802002102200041086a210103400240200128020020026b41074b0d0041004185c1001002200428020021020b20092002410810061a2004200428020041086a220236020041002105420021030340024020022001280200490d00410041fbc2001002200428020021020b20022d000021072004200241016a22063602002003200741ff0071200541ff0171220274ad842103200241076a2105200621022007418001710d000b200920033e02082009410c6a21020240200128020020066b41204b0d0041004185c1001002200428020021060b20022006412110061a2004200428020041216a2202360200200941306a22092008470d000b0b20000b920901047f02402000280208200028020422026b41074b0d0041004185c1001002200041046a28020021020b20012002410810061a200041046a2202200228020041086a2203360200200141086a21040240200041086a220528020020036b41034b0d0041004185c1001002200228020021030b20042003410410061a2002200228020041046a22033602002001410c6a21020240200528020020036b41034b0d0041004185c1001002200041046a28020021030b20022003410410061a200041046a2202200228020041046a2203360200200141106a21040240200041086a220528020020036b41034b0d0041004185c1001002200228020021030b20042003410410061a2002200228020041046a2203360200200141146a21020240200528020020036b41034b0d0041004185c1001002200041046a28020021030b20022003410410061a200041046a2202200228020041046a2203360200200141186a21040240200041086a220528020020036b41034b0d0041004185c1001002200228020021030b20042003410410061a2002200228020041046a22033602002001411c6a21020240200528020020036b41034b0d0041004185c1001002200041046a28020021030b20022003410410061a200041046a2202200228020041046a2203360200200141206a21040240200041086a220528020020036b41034b0d0041004185c1001002200228020021030b20042003410410061a2002200228020041046a2203360200200141246a21020240200528020020036b41034b0d0041004185c1001002200041046a28020021030b20022003410410061a200041046a2202200228020041046a2203360200200141286a21040240200041086a220528020020036b41034b0d0041004185c1001002200228020021030b20042003410410061a2002200228020041046a22033602002001412c6a21020240200528020020036b41034b0d0041004185c1001002200041046a28020021030b20022003410410061a200041046a2202200228020041046a2203360200200141306a21040240200041086a220528020020036b41034b0d0041004185c1001002200228020021030b20042003410410061a2002200228020041046a2203360200200141346a21020240200528020020036b41034b0d0041004185c1001002200041046a28020021030b20022003410410061a200041046a2202200228020041046a2203360200200141386a21040240200041086a220528020020036b41034b0d0041004185c1001002200228020021030b20042003410410061a2002200228020041046a22033602002001413c6a21020240200528020020036b41034b0d0041004185c1001002200041046a28020021030b20022003410410061a200041046a2202200228020041046a2203360200200141c0006a21040240200041086a220528020020036b41014b0d0041004185c1001002200228020021030b20042003410210061a2002200228020041026a2203360200200141c2006a21010240200528020020036b41014b0d0041004185c1001002200041046a28020021030b20012003410210061a200041046a2201200128020041026a36020020000ba10203017f017e057f2000280204210242002103200041086a2104200041046a2105410021060340024020022004280200490d00410041fbc2001002200528020021020b20022d000021072005200241016a22083602002003200741ff0071200641ff0171220274ad842103200241076a2106200821022007418001710d000b0240024020012802042207200128020022026b22052003a722064f0d002001200620056b1051200041046a2802002108200141046a2802002107200128020021020c010b200520064d0d00200141046a200220066a22073602000b0240200041086a28020020086b200720026b22074f0d0041004185c1001002200041046a28020021080b20022008200710061a200041046a2202200228020020076a36020020000bf80103017f017e027f230041106b22022400200242003703002002410036020820012903002103024002402001410c6a28020020012802086b2204450d002004417f4c0d01200241086a20041020220520046a36020020022005360200200220053602042001410c6a280200200141086a28020022046b22014101480d0020052004200110061a2002200520016a3602040b20002802002000280204220128020422044101756a21002001280200210102402004410171450d00200028020020016a28020021010b2000200320022001110100024020022802002201450d0020022001360204200110220b200241106a24000f0b20021028000bbf0302077f017e230041206b22022103200224000240200028021822042000411c6a2802002205460d0002400340200541786a2802002001460d012004200541686a2205470d000c020b0b20042005460d00200541686a2802002105200341206a240020050f0b02400240024020014100410010142204417f4c0d0020044181044f0d0120022004410f6a4170716b22022400410021060c020b410041eec00010020b200410192102410121060b20012002200410141a41c000102022052000360230200542003703000240200441074b0d0041004185c10010020b20052002410810061a200541106a2107200241086a21080240200441786a411f4b0d0041004185c10010020b20072008412010061a20052001360234200320053602182003200529030022093703102003200136020c0240024002402000411c6a22072802002204200041206a2802004f0d00200420093703082004200136021020034100360218200420053602002007200441186a36020020060d010c020b200041186a200341186a200341106a2003410c6a105d2006450d010b2002101a0b200328021821012003410036021802402001450d00200110220b200341206a240020050bc40103027f017e017f230022042105024020012802302000460d00410041bdc10010020b024020002903001013510d00410041ebc10010020b20012903002106200328020022032802002207200328020420076b200141106a22071015024020062001290300510d004100419ec20010020b2004220441506a2203240020032001410810061a200441586a2007412010061a20012802342002200341281017024020062000290310540d00200041106a427e200642017c2006427d561b3703000b200524000bfb0101047f230041306b2204240020042002370328024020012903001013510d004100418ac10010020b20042003360214200420013602102004200441286a36021841c000102022032001200441106a105c1a2004200336022020042003290300220237031020042003280234220536020c024002402001411c6a22062802002207200141206a2802004f0d00200720023703082007200536021020044100360220200720033602002006200741186a3602000c010b200141186a200441206a200441106a2004410c6a105d0b2000200336020420002001360200200428022021012004410036022002402001450d00200110220b200441306a24000b960305027f017e017f017e017f230041d0006b2202240020002802002103024020012802002201280208200128020422006b411f4b0d0041004185c1001002200141046a28020021000b200241306a2000412010061a200141046a2201200128020041206a3602004200210441102101200241106a2105410021004200210602400340200241306a20006a2107024020014102490d002006420886200420073100008422044238888421062001417f6a210120044208862104200041016a22004120470d010c020b024020014101460d00410041ffc20010020b200520063703082005200420073100008437030041102101200541106a21054200210442002106200041016a22004120470d000b0b024020014110460d00024020014102490d00200220042006200141037441786a1011200241086a2903002106200229030021040b20052004370300200520063703080b20032002290310370300200341086a2002290318370300200341186a200241106a41186a290300370300200341106a200241106a41106a290300370300200241d0006a24000bba0101047f230041106b22022103200224000240024002400240024010042204450d002004418004490d012004101921020c020b2003420037030841002102200341086a21050c020b20022004410f6a4170716b220224000b2002200410051a20034200370308200341086a2105200441074b0d010b41004185c10010020b20052002410810061a20034200370300200241086a2102024020044178714108470d0041004185c10010020b20032002410810061a200341106a24000b4401037f230022022103024010042204450d00024002402004418004490d002004101921020c010b20022004410f6a4170716b220224000b2002200410051a0b200324000b4401037f230022022103024010042204450d00024002402004418004490d002004101921020c010b20022004410f6a4170716b220224000b2002200410051a0b200324000b4401037f230022022103024010042204450d00024002402004418004490d002004101921020c010b20022004410f6a4170716b220224000b2002200410051a0b200324000b4401037f230022022103024010042204450d00024002402004418004490d002004101921020c010b20022004410f6a4170716b220224000b2002200410051a0b200324000b4401037f230022022103024010042204450d00024002402004418004490d002004101921020c010b20022004410f6a4170716b220224000b2002200410051a0b200324000b4401037f230022022103024010042204450d00024002402004418004490d002004101921020c010b20022004410f6a4170716b220224000b2002200410051a0b200324000bd30201047f230041306b2202210320022400024002400240024010042204450d002004418004490d012004101921020c020b410021020c020b20022004410f6a4170716b220224000b2002200410051a0b20032002360224200320023602202003200220046a2205360228200342003703180240200441074b0d0041004185c1001002200341286a2802002105200328022421020b200341186a2002410810061a2003200241086a2202360224024020052002470d0041004185c1001002200341206a41086a2802002105200328022421020b200341176a2002410110061a2003200241016a2202360224024020052002470d0041004185c1001002200328022421020b200341166a2002410110061a2003200241016a3602242003410036021020034200370308200341206a200341086a10431a024020032802082202450d002003200236020c200210220b200341306a24000bbe0201067f0240024002400240024020002802082202200028020422036b20014f0d002003200028020022046b220520016a2206417f4c0d0241ffffffff0721070240200220046b220241feffffff034b0d0020062002410174220220022006491b2207450d020b2007102021020c030b200041046a21000340200341003a00002000200028020041016a22033602002001417f6a22010d000c040b0b41002107410021020c010b20001028000b200220076a2107200320016a20046b2104200220056a220521030340200341003a0000200341016a21032001417f6a22010d000b200220046a21042005200041046a2206280200200028020022016b22036b2102024020034101480d0020022001200310061a200028020021010b2000200236020020062004360200200041086a20073602002001450d00200110220f0b0bd00102047f017e230041106b22022103200224000240024002400240024010042204450d002004418004490d012004101921020c020b2003420037030841002102200341086a21050c020b20022004410f6a4170716b220224000b2002200410051a20034200370308200341086a2105200441074b0d010b41004185c10010020b20052002410810061a200241086a2102024020044108470d0041004185c10010020b200341076a2002410110061a2003290308210620032d0007210420001007200620044100471008200341106a24000bab0202047f047e230041206b22022103200224000240024002400240024010042204450d002004418004490d012004101921020c020b2003420037031841002102200341186a21050c020b20022004410f6a4170716b220224000b2002200410051a20034200370318200341186a2105200441074b0d010b41004185c10010020b20052002410810061a200241086a21050240200441787122044108470d0041004185c10010020b200341106a2005410810061a200241106a2105024020044110470d0041004185c10010020b200341086a2005410810061a200241186a2102024020044118470d0041004185c10010020b20032002410810061a200329030021062003290308210720032903102108200329031821092000100720092008200720061009200341206a24000bd30101047f230041206b22022103200224000240024002400240024010042204450d002004418004490d012004101921020c020b41002102200341186a21050c020b20022004410f6a4170716b220224000b2002200410051a200341186a2105200441074b0d010b41004185c10010020b20052002410810061a200241086a21050240200441787122044108470d0041004185c10010020b200341106a2005410810061a200241106a2102024020044110470d0041004185c10010020b200341086a2002410810061a20001007200341206a24000bc60301047f23004180016b220221032002240041002104024010042205450d00024002402005418004490d002005101921040c010b20022005410f6a4170716b220424000b2004200510051a0b20032004360254200320043602502003200420056a3602582003410036024820034200370340200341d0006a200341c0006a10411a200341106a41086a2204200328025836020020032003290350370310200341e0006a41086a2205200428020036020020032003290310370360200341f0006a41086a20052802002204360200200341386a20043602002003200037032020032001370328200320032903602200370330200320003703702003410036020820034200370300200328024420032802406b220441306d2105024002402004450d00200541d6aad52a4f0d01200341086a200410202204200541306c6a36020020032004360200200320043602042003280244200328024022026b22054101480d0020042002200510061a20032003280204200541306e41306c6a3602040b200341206a20031038024020032802002204450d0020032004360204200410220b024020032802402204450d0020032004360244200410220b20034180016a24000f0b20031028000bc60301067f0240024002400240024020002802082202200028020422036b41306d20014f0d002003200028020022046b41306d220520016a220641d6aad52a4f0d0241d5aad52a21030240200220046b41306d220241a9d5aa154b0d0020062002410174220320032006491b2203450d020b200341306c102021040c030b200041046a21020340200341086a2200420037030020034200370300200341286a4200370300200341206a4200370300200341186a4200370300200341106a4200370300200041003602002002200228020041306a22033602002001417f6a22010d000c040b0b41002103410021040c010b20001028000b2004200341306c6a21072004200541306c6a220521030340200341086a2202420037030020034200370300200341286a4200370300200341206a4200370300200341186a4200370300200341106a420037030020024100360200200341306a21032001417f6a22010d000b2004200641306c6a21042005200041046a2206280200200028020022036b220141506d41306c6a2102024020014101480d0020022003200110061a200028020021030b2000200236020020062004360200200041086a20073602002003450d00200310220f0b0b8a0101037f230041e0006b2202210320022400024002400240024010042204450d002004418004490d012004101921020c020b410021020c020b20022004410f6a4170716b220224000b2002200410051a0b20032002360254200320023602502003200220046a360258200341d0006a200341086a10421a20001007200341086a1029200341e0006a24000b950101047f230041106b22022103200224000240024002400240024010042204450d002004418004490d012004101921020c020b2003420037030841002102200341086a21050c020b20022004410f6a4170716b220224000b2002200410051a20034200370308200341086a2105200441074b0d010b41004185c10010020b20052002410810061a20032903081007200341106a24000bd70303047f027e017f230041f0006b2202210320022400024002400240024010042204450d002004418004490d012004101921050c020b410021050c020b20022004410f6a4170716b220524000b2005200410051a0b42002106200341286a420037030041102102200341106a41106a4200370300200342003703182003420037031002402004411f4b0d0041004185c10010020b200341d0006a2005412010061a200341306a2105410021044200210702400340200341d0006a20046a2108024020024102490d002007420886200620083100008422064238888421072002417f6a210220064208862106200441016a22044120470d010c020b024020024101460d00410041ffc20010020b200520073703082005200620083100008437030041102102200541106a21054200210642002107200441016a22044120470d000b0b024020024110460d00024020024102490d00200320062007200241037441786a1011200341086a2903002107200329030021060b20052006370300200520073703080b200341106a41186a200341306a41186a290300370300200341106a41106a200341306a41106a290300370300200320032903383703182003200329033037031020001007200341106a102c200341f0006a24000be00303047f027e017f230041f0006b2202210320022400024002400240024010042204450d002004418004490d012004101921050c020b410021050c020b20022004410f6a4170716b220524000b2005200410051a0b42002106200341286a420037030041102102200341106a41106a4200370300200342003703182003420037031002402004411f4b0d0041004185c10010020b200341d0006a2005412010061a200341306a2105410021044200210702400340200341d0006a20046a2108024020024102490d002007420886200620083100008422064238888421072002417f6a210220064208862106200441016a22044120470d010c020b024020024101460d00410041ffc20010020b200520073703082005200620083100008437030041102102200541106a21054200210642002107200441016a22044120470d000b0b024020024110460d00024020024102490d00200320062007200241037441786a1011200341086a2903002107200329030021060b20052006370300200520073703080b200341106a41186a200341306a41186a290300370300200341106a41106a200341306a41106a29030037030020032003290338370318200320032903303703100240200341106a102b0d00410041d9c20010020b200341f0006a24000beb0201037f23004180016b2202210320022400024002400240024010042204450d002004418004490d012004101921020c020b410021020c020b20022004410f6a4170716b220224000b2002200410051a0b20032002360254200320023602502003200220046a360258200342003703480240200441074b0d0041004185c1001002200328025421020b200341c8006a2002410810061a2003200241086a3602542003410036024020034200370338200341d0006a200341386a10431a200341086a41086a2202200341d0006a41086a28020036020020032003290350370308200341e0006a41086a2204200228020036020020032003290308370360200341f0006a41086a20042802002202360200200341306a2002360200200320003703182003200137032020032003290360220037032820032000370370200341186a2003290348200341386a103d024020032802382202450d002003200236023c200210220b20034180016a24000bbc0102037f017e230041306b22032400200020013602302000420037030020002002280204220428020029030037030020022802002101200428020422042802002205200428020420056b200041106a2204101520032000410810061a20034108722004412010061a2000200129030842808080809aecb4ee31200228020829030020002903002206200341281016360234024020062001290310540d00200141106a427e200642017c2006427d561b3703000b200341306a240020000baa0301057f024002402000280204200028020022046b41186d220541016a220641abd5aad5004f0d0041aad5aad500210702400240200028020820046b41186d220441d4aad52a4b0d0020062004410174220720072006491b2207450d010b200741186c102021040c020b41002107410021040c010b20001028000b20012802002106200141003602002004200541186c22086a2201200636020020012002290300370308200120032802003602102004200741186c6a2105200141186a210602400240200041046a280200220220002802002207460d00200420086a41686a21010340200241686a220428020021032004410036020020012003360200200141106a200241786a280200360200200141086a200241706a290300370300200141686a21012004210220072004470d000b200141186a2101200041046a2802002107200028020021020c010b200721020b20002001360200200041046a2006360200200041086a2005360200024020072002460d000340200741686a220728020021012007410036020002402001450d00200110220b20022007470d000b0b02402002450d00200210220b0b0bdf030b00419cc0000b4c6661696c656420746f20616c6c6f63617465207061676573006f626a6563742070617373656420746f206974657261746f725f746f206973206e6f7420696e206d756c74695f696e646578000041e8c0000b1d7772697465006572726f722072656164696e67206974657261746f7200004185c1000b05726561640000418ac1000b3363616e6e6f7420637265617465206f626a6563747320696e207461626c65206f6620616e6f7468657220636f6e7472616374000041bdc1000b2e6f626a6563742070617373656420746f206d6f64696679206973206e6f7420696e206d756c74695f696e646578000041ebc1000b3363616e6e6f74206d6f64696679206f626a6563747320696e207461626c65206f6620616e6f7468657220636f6e74726163740000419ec2000b3b757064617465722063616e6e6f74206368616e6765207072696d617279206b6579207768656e206d6f64696679696e6720616e206f626a656374000041d9c2000b2270726f746f636f6c2066656174757265206973206e6f7420616374697661746564000041fbc2000b04676574000041ffc2000b2c756e6578706563746564206572726f7220696e2066697865645f627974657320636f6e7374727563746f72000041000b04b02100000000000000000000000003917c562680b415b93db73416ff29230dfbe7ab1ba4d208b46029d01333cd3a03000000023b3d4b01000000034097ed362ec2a0eecb45779129e26e7b0c11ee9149a27c43f4e71bf1010000000000ea30556ab602000000000000000000000000 DMLOG CREATION_OP ROOT 0 DMLOG RAM_OP 0 eosio abi update setabi eosio 180538 44 DMLOG RAM_OP 0 eosio:eosio:abihash table add create_table eosio 180650 112 @@ -46,90 +46,98 @@ DMLOG TBL_OP INS 0 eosio eosio abihash eosio DMLOG RAM_OP 0 eosio:eosio:abihash:eosio table_row add primary_index_add eosio 180802 152 DMLOG DB_OP INS 0 eosio eosio eosio abihash eosio 0000000000ea3055d7abd75d188060de8a01ab2672d1cc2cd768fddc56203181b43685cc11f5ce46 DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304002,"value_ex":41298,"consumed":7136},"cpu_usage":{"last_ordinal":1262304002,"value_ex":24307,"consumed":4101},"ram_usage":180802} -DMLOG APPLIED_TRANSACTION 3 78216184577675cf681592f18c754116fdf63576c1fa05b7566dd6ae6fe2ed8003000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190100d00700008101000000000000000008040000000000000001010000010000000000ea3055e7de58a9939c6e694d3235202685f51b7fab8e82b1f9f96a637dafd9be0998a204000000000000000400000000000000010000000000ea3055040000000000000001010000000000ea30550000000000ea305500000000b863b2c2010000000000ea305500000000a8ed32328a110000000000ea305580110e656f73696f3a3a6162692f312e310019086162695f686173680002056f776e6572046e616d6504686173680b636865636b73756d32353608616374697661746500010e666561747572655f6469676573740b636865636b73756d32353609617574686f726974790004097468726573686f6c640675696e743332046b6579730c6b65795f7765696768745b5d086163636f756e7473197065726d697373696f6e5f6c6576656c5f7765696768745b5d0577616974730d776169745f7765696768745b5d15626c6f636b636861696e5f706172616d65746572730011136d61785f626c6f636b5f6e65745f75736167650675696e7436341a7461726765745f626c6f636b5f6e65745f75736167655f7063740675696e743332196d61785f7472616e73616374696f6e5f6e65745f75736167650675696e7433321e626173655f7065725f7472616e73616374696f6e5f6e65745f75736167650675696e743332106e65745f75736167655f6c65657761790675696e74333223636f6e746578745f667265655f646973636f756e745f6e65745f75736167655f6e756d0675696e74333223636f6e746578745f667265655f646973636f756e745f6e65745f75736167655f64656e0675696e743332136d61785f626c6f636b5f6370755f75736167650675696e7433321a7461726765745f626c6f636b5f6370755f75736167655f7063740675696e743332196d61785f7472616e73616374696f6e5f6370755f75736167650675696e743332196d696e5f7472616e73616374696f6e5f6370755f75736167650675696e743332186d61785f7472616e73616374696f6e5f6c69666574696d650675696e7433321e64656665727265645f7472785f65787069726174696f6e5f77696e646f770675696e743332156d61785f7472616e73616374696f6e5f64656c61790675696e743332166d61785f696e6c696e655f616374696f6e5f73697a650675696e743332176d61785f696e6c696e655f616374696f6e5f64657074680675696e743136136d61785f617574686f726974795f64657074680675696e7431360b63616e63656c64656c617900020e63616e63656c696e675f61757468107065726d697373696f6e5f6c6576656c067472785f69640b636865636b73756d3235360a64656c657465617574680002076163636f756e74046e616d650a7065726d697373696f6e046e616d650a6b65795f7765696768740002036b65790a7075626c69635f6b6579067765696768740675696e743136086c696e6b617574680004076163636f756e74046e616d6504636f6465046e616d650474797065046e616d650b726571756972656d656e74046e616d650a6e65776163636f756e7400040763726561746f72046e616d65046e616d65046e616d65056f776e657209617574686f726974790661637469766509617574686f72697479076f6e6572726f7200020973656e6465725f69640775696e743132380873656e745f747278056279746573107065726d697373696f6e5f6c6576656c0002056163746f72046e616d650a7065726d697373696f6e046e616d65177065726d697373696f6e5f6c6576656c5f77656967687400020a7065726d697373696f6e107065726d697373696f6e5f6c6576656c067765696768740675696e7431360c70726f64756365725f6b657900020d70726f64756365725f6e616d65046e616d6511626c6f636b5f7369676e696e675f6b65790a7075626c69635f6b65790c72657161637469766174656400010e666561747572655f6469676573740b636865636b73756d323536077265716175746800010466726f6d046e616d65067365746162690002076163636f756e74046e616d65036162690562797465730a736574616c696d6974730004076163636f756e74046e616d650972616d5f627974657305696e7436340a6e65745f77656967687405696e7436340a6370755f77656967687405696e74363407736574636f64650004076163636f756e74046e616d6506766d747970650575696e743809766d76657273696f6e0575696e743804636f64650562797465730a736574676c696d69747300030372616d0675696e743634036e65740675696e743634036370750675696e74363409736574706172616d73000106706172616d7315626c6f636b636861696e5f706172616d657465727307736574707269760002076163636f756e74046e616d650769735f707269760575696e74380873657470726f64730001087363686564756c650e70726f64756365725f6b65795b5d0a756e6c696e6b617574680003076163636f756e74046e616d6504636f6465046e616d650474797065046e616d650a757064617465617574680004076163636f756e74046e616d650a7065726d697373696f6e046e616d6506706172656e74046e616d65046175746809617574686f726974790b776169745f776569676874000208776169745f7365630675696e743332067765696768740675696e743136110000002a9bed32320861637469766174650000bc892a4585a6410b63616e63656c64656c6179000040cbdaa8aca24a0a64656c65746561757468000000002d6b03a78b086c696e6b617574680000409e9a2264b89a0a6e65776163636f756e7400000000e0d27bd5a4076f6e6572726f7200905436db6564acba0c72657161637469766174656400000000a0656dacba07726571617574680000000000b863b2c206736574616269000000ce4eba68b2c20a736574616c696d6974730000000040258ab2c207736574636f6465000000ce4ebac8b2c20a736574676c696d697473000000c0d25c53b3c209736574706172616d730000000060bb5bb3c207736574707269760000000038d15bb3c20873657470726f6473000040cbdac0e9e2d40a756e6c696e6b61757468000040cbdaa86c52d50a757064617465617574680001000000a061d3dc31036936340000086162695f6861736800000000000000000000000000000078216184577675cf681592f18c754116fdf63576c1fa05b7566dd6ae6fe2ed8003000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df719010000000000ea3055340100000000000000000000000000 +DMLOG APPLIED_TRANSACTION 3 78216184577675cf681592f18c754116fdf63576c1fa05b7566dd6ae6fe2ed8003000000023b3d4b01000000034097ed362ec2a0eecb45779129e26e7b0c11ee9149a27c43f4e71bf10100d00700008101000000000000000008040000000000000001010000010000000000ea3055e7de58a9939c6e694d3235202685f51b7fab8e82b1f9f96a637dafd9be0998a204000000000000000400000000000000010000000000ea3055040000000000000001010000000000ea30550000000000ea305500000000b863b2c2010000000000ea305500000000a8ed32328a110000000000ea305580110e656f73696f3a3a6162692f312e310019086162695f686173680002056f776e6572046e616d6504686173680b636865636b73756d32353608616374697661746500010e666561747572655f6469676573740b636865636b73756d32353609617574686f726974790004097468726573686f6c640675696e743332046b6579730c6b65795f7765696768745b5d086163636f756e7473197065726d697373696f6e5f6c6576656c5f7765696768745b5d0577616974730d776169745f7765696768745b5d15626c6f636b636861696e5f706172616d65746572730011136d61785f626c6f636b5f6e65745f75736167650675696e7436341a7461726765745f626c6f636b5f6e65745f75736167655f7063740675696e743332196d61785f7472616e73616374696f6e5f6e65745f75736167650675696e7433321e626173655f7065725f7472616e73616374696f6e5f6e65745f75736167650675696e743332106e65745f75736167655f6c65657761790675696e74333223636f6e746578745f667265655f646973636f756e745f6e65745f75736167655f6e756d0675696e74333223636f6e746578745f667265655f646973636f756e745f6e65745f75736167655f64656e0675696e743332136d61785f626c6f636b5f6370755f75736167650675696e7433321a7461726765745f626c6f636b5f6370755f75736167655f7063740675696e743332196d61785f7472616e73616374696f6e5f6370755f75736167650675696e743332196d696e5f7472616e73616374696f6e5f6370755f75736167650675696e743332186d61785f7472616e73616374696f6e5f6c69666574696d650675696e7433321e64656665727265645f7472785f65787069726174696f6e5f77696e646f770675696e743332156d61785f7472616e73616374696f6e5f64656c61790675696e743332166d61785f696e6c696e655f616374696f6e5f73697a650675696e743332176d61785f696e6c696e655f616374696f6e5f64657074680675696e743136136d61785f617574686f726974795f64657074680675696e7431360b63616e63656c64656c617900020e63616e63656c696e675f61757468107065726d697373696f6e5f6c6576656c067472785f69640b636865636b73756d3235360a64656c657465617574680002076163636f756e74046e616d650a7065726d697373696f6e046e616d650a6b65795f7765696768740002036b65790a7075626c69635f6b6579067765696768740675696e743136086c696e6b617574680004076163636f756e74046e616d6504636f6465046e616d650474797065046e616d650b726571756972656d656e74046e616d650a6e65776163636f756e7400040763726561746f72046e616d65046e616d65046e616d65056f776e657209617574686f726974790661637469766509617574686f72697479076f6e6572726f7200020973656e6465725f69640775696e743132380873656e745f747278056279746573107065726d697373696f6e5f6c6576656c0002056163746f72046e616d650a7065726d697373696f6e046e616d65177065726d697373696f6e5f6c6576656c5f77656967687400020a7065726d697373696f6e107065726d697373696f6e5f6c6576656c067765696768740675696e7431360c70726f64756365725f6b657900020d70726f64756365725f6e616d65046e616d6511626c6f636b5f7369676e696e675f6b65790a7075626c69635f6b65790c72657161637469766174656400010e666561747572655f6469676573740b636865636b73756d323536077265716175746800010466726f6d046e616d65067365746162690002076163636f756e74046e616d65036162690562797465730a736574616c696d6974730004076163636f756e74046e616d650972616d5f627974657305696e7436340a6e65745f77656967687405696e7436340a6370755f77656967687405696e74363407736574636f64650004076163636f756e74046e616d6506766d747970650575696e743809766d76657273696f6e0575696e743804636f64650562797465730a736574676c696d69747300030372616d0675696e743634036e65740675696e743634036370750675696e74363409736574706172616d73000106706172616d7315626c6f636b636861696e5f706172616d657465727307736574707269760002076163636f756e74046e616d650769735f707269760575696e74380873657470726f64730001087363686564756c650e70726f64756365725f6b65795b5d0a756e6c696e6b617574680003076163636f756e74046e616d6504636f6465046e616d650474797065046e616d650a757064617465617574680004076163636f756e74046e616d650a7065726d697373696f6e046e616d6506706172656e74046e616d65046175746809617574686f726974790b776169745f776569676874000208776169745f7365630675696e743332067765696768740675696e743136110000002a9bed32320861637469766174650000bc892a4585a6410b63616e63656c64656c6179000040cbdaa8aca24a0a64656c65746561757468000000002d6b03a78b086c696e6b617574680000409e9a2264b89a0a6e65776163636f756e7400000000e0d27bd5a4076f6e6572726f7200905436db6564acba0c72657161637469766174656400000000a0656dacba07726571617574680000000000b863b2c206736574616269000000ce4eba68b2c20a736574616c696d6974730000000040258ab2c207736574636f6465000000ce4ebac8b2c20a736574676c696d697473000000c0d25c53b3c209736574706172616d730000000060bb5bb3c207736574707269760000000038d15bb3c20873657470726f6473000040cbdac0e9e2d40a756e6c696e6b61757468000040cbdaa86c52d50a757064617465617574680001000000a061d3dc31036936340000086162695f6861736800000000000000000000000000000078216184577675cf681592f18c754116fdf63576c1fa05b7566dd6ae6fe2ed8003000000023b3d4b01000000034097ed362ec2a0eecb45779129e26e7b0c11ee9149a27c43f4e71bf1010000000000ea3055340100000000000000000000000000 DMLOG CREATION_OP ROOT 0 DMLOG FEATURE_OP PRE_ACTIVATE 0 1a99a59d87e06e09ec5b028a9cbb7749b4a5ad8819004365d02dc4379a8b7241 {"feature_digest":"1a99a59d87e06e09ec5b028a9cbb7749b4a5ad8819004365d02dc4379a8b7241","subjective_restrictions":{"enabled":true,"preactivation_required":true,"earliest_allowed_activation_time":"1970-01-01T00:00:00.000"},"description_digest":"f3c3d91c4603cde2397268bfed4e662465293aab10cd9416db0d442b8cec2949","dependencies":[],"protocol_feature_type":"builtin","specification":[{"name":"builtin_feature_codename","value":"ONLY_LINK_TO_EXISTING_PERMISSION"}]} DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304002,"value_ex":42039,"consumed":7264},"cpu_usage":{"last_ordinal":1262304002,"value_ex":35882,"consumed":6101},"ram_usage":180802} -DMLOG APPLIED_TRANSACTION 3 aa30bc93a59737ce708fd4d691b61d7858bfb309c4cf883e77a6a161b5a4abe503000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190100d007000010000000000000000080000000000000000001010000010000000000ea3055218268a92acd1b24eeaeff3b51b569de14ee151eea2132d748be984aa9535d1405000000000000000500000000000000010000000000ea3055050000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232201a99a59d87e06e09ec5b028a9cbb7749b4a5ad8819004365d02dc4379a8b724100000000000000000000aa30bc93a59737ce708fd4d691b61d7858bfb309c4cf883e77a6a161b5a4abe503000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190000000000000000 +DMLOG APPLIED_TRANSACTION 3 aa30bc93a59737ce708fd4d691b61d7858bfb309c4cf883e77a6a161b5a4abe503000000023b3d4b01000000034097ed362ec2a0eecb45779129e26e7b0c11ee9149a27c43f4e71bf10100d007000010000000000000000080000000000000000001010000010000000000ea3055218268a92acd1b24eeaeff3b51b569de14ee151eea2132d748be984aa9535d1405000000000000000500000000000000010000000000ea3055050000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232201a99a59d87e06e09ec5b028a9cbb7749b4a5ad8819004365d02dc4379a8b724100000000000000000000aa30bc93a59737ce708fd4d691b61d7858bfb309c4cf883e77a6a161b5a4abe503000000023b3d4b01000000034097ed362ec2a0eecb45779129e26e7b0c11ee9149a27c43f4e71bf10000000000000000 DMLOG CREATION_OP ROOT 0 DMLOG FEATURE_OP PRE_ACTIVATE 0 ef43112c6543b88db2283a2e077278c315ae2c84719a8b25f25cc88565fbea99 {"feature_digest":"ef43112c6543b88db2283a2e077278c315ae2c84719a8b25f25cc88565fbea99","subjective_restrictions":{"enabled":true,"preactivation_required":true,"earliest_allowed_activation_time":"1970-01-01T00:00:00.000"},"description_digest":"9908b3f8413c8474ab2a6be149d3f4f6d0421d37886033f27d4759c47a26d944","dependencies":[],"protocol_feature_type":"builtin","specification":[{"name":"builtin_feature_codename","value":"REPLACE_DEFERRED"}]} DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304002,"value_ex":42780,"consumed":7392},"cpu_usage":{"last_ordinal":1262304002,"value_ex":47457,"consumed":8101},"ram_usage":180802} -DMLOG APPLIED_TRANSACTION 3 3f12eecaafb41ec5142c6c6d69df767fb8f5183e1e5468aa418bef38a2bdf2bb03000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190100d007000010000000000000000080000000000000000001010000010000000000ea305513ab6d113ba5b180d6f68e1b67bdea99847550d673a1785e40dfe4faee8ec7c706000000000000000600000000000000010000000000ea3055060000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220ef43112c6543b88db2283a2e077278c315ae2c84719a8b25f25cc88565fbea99000000000000000000003f12eecaafb41ec5142c6c6d69df767fb8f5183e1e5468aa418bef38a2bdf2bb03000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190000000000000000 +DMLOG APPLIED_TRANSACTION 3 3f12eecaafb41ec5142c6c6d69df767fb8f5183e1e5468aa418bef38a2bdf2bb03000000023b3d4b01000000034097ed362ec2a0eecb45779129e26e7b0c11ee9149a27c43f4e71bf10100d007000010000000000000000080000000000000000001010000010000000000ea305513ab6d113ba5b180d6f68e1b67bdea99847550d673a1785e40dfe4faee8ec7c706000000000000000600000000000000010000000000ea3055060000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220ef43112c6543b88db2283a2e077278c315ae2c84719a8b25f25cc88565fbea99000000000000000000003f12eecaafb41ec5142c6c6d69df767fb8f5183e1e5468aa418bef38a2bdf2bb03000000023b3d4b01000000034097ed362ec2a0eecb45779129e26e7b0c11ee9149a27c43f4e71bf10000000000000000 DMLOG CREATION_OP ROOT 0 DMLOG FEATURE_OP PRE_ACTIVATE 0 4a90c00d55454dc5b059055ca213579c6ea856967712a56017487886a4d4cc0f {"feature_digest":"4a90c00d55454dc5b059055ca213579c6ea856967712a56017487886a4d4cc0f","subjective_restrictions":{"enabled":true,"preactivation_required":true,"earliest_allowed_activation_time":"1970-01-01T00:00:00.000"},"description_digest":"45967387ee92da70171efd9fefd1ca8061b5efe6f124d269cd2468b47f1575a0","dependencies":["ef43112c6543b88db2283a2e077278c315ae2c84719a8b25f25cc88565fbea99"],"protocol_feature_type":"builtin","specification":[{"name":"builtin_feature_codename","value":"NO_DUPLICATE_DEFERRED_ID"}]} DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304002,"value_ex":43521,"consumed":7520},"cpu_usage":{"last_ordinal":1262304002,"value_ex":59032,"consumed":10101},"ram_usage":180802} -DMLOG APPLIED_TRANSACTION 3 39ec55367e4e4d0d6063a5e5aa2aa15d4a1aa1fbe0abe42c9081713ee04e55b103000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190100d007000010000000000000000080000000000000000001010000010000000000ea30552267bc3ee69f217c4f0bdbff84c23074f1780839b8adfb17537db55da4a0dc7607000000000000000700000000000000010000000000ea3055070000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232204a90c00d55454dc5b059055ca213579c6ea856967712a56017487886a4d4cc0f0000000000000000000039ec55367e4e4d0d6063a5e5aa2aa15d4a1aa1fbe0abe42c9081713ee04e55b103000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190000000000000000 +DMLOG APPLIED_TRANSACTION 3 39ec55367e4e4d0d6063a5e5aa2aa15d4a1aa1fbe0abe42c9081713ee04e55b103000000023b3d4b01000000034097ed362ec2a0eecb45779129e26e7b0c11ee9149a27c43f4e71bf10100d007000010000000000000000080000000000000000001010000010000000000ea30552267bc3ee69f217c4f0bdbff84c23074f1780839b8adfb17537db55da4a0dc7607000000000000000700000000000000010000000000ea3055070000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232204a90c00d55454dc5b059055ca213579c6ea856967712a56017487886a4d4cc0f0000000000000000000039ec55367e4e4d0d6063a5e5aa2aa15d4a1aa1fbe0abe42c9081713ee04e55b103000000023b3d4b01000000034097ed362ec2a0eecb45779129e26e7b0c11ee9149a27c43f4e71bf10000000000000000 DMLOG CREATION_OP ROOT 0 DMLOG FEATURE_OP PRE_ACTIVATE 0 e0fb64b1085cc5538970158d05a009c24e276fb94e1a0bf6a528b48fbc4ff526 {"feature_digest":"e0fb64b1085cc5538970158d05a009c24e276fb94e1a0bf6a528b48fbc4ff526","subjective_restrictions":{"enabled":true,"preactivation_required":true,"earliest_allowed_activation_time":"1970-01-01T00:00:00.000"},"description_digest":"a98241c83511dc86c857221b9372b4aa7cea3aaebc567a48604e1d3db3557050","dependencies":[],"protocol_feature_type":"builtin","specification":[{"name":"builtin_feature_codename","value":"FIX_LINKAUTH_RESTRICTION"}]} DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304002,"value_ex":44262,"consumed":7648},"cpu_usage":{"last_ordinal":1262304002,"value_ex":70607,"consumed":12101},"ram_usage":180802} -DMLOG APPLIED_TRANSACTION 3 72c5e78f690d5d20ec8c8e12ace2a3b34929099b93f621a8671ae43df821bc5b03000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190100d007000010000000000000000080000000000000000001010000010000000000ea30550f86c0418ffb919c58d37997594e446d2d98fd38b1ff3849da2c5da410aa331a08000000000000000800000000000000010000000000ea3055080000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220e0fb64b1085cc5538970158d05a009c24e276fb94e1a0bf6a528b48fbc4ff5260000000000000000000072c5e78f690d5d20ec8c8e12ace2a3b34929099b93f621a8671ae43df821bc5b03000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190000000000000000 +DMLOG APPLIED_TRANSACTION 3 72c5e78f690d5d20ec8c8e12ace2a3b34929099b93f621a8671ae43df821bc5b03000000023b3d4b01000000034097ed362ec2a0eecb45779129e26e7b0c11ee9149a27c43f4e71bf10100d007000010000000000000000080000000000000000001010000010000000000ea30550f86c0418ffb919c58d37997594e446d2d98fd38b1ff3849da2c5da410aa331a08000000000000000800000000000000010000000000ea3055080000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220e0fb64b1085cc5538970158d05a009c24e276fb94e1a0bf6a528b48fbc4ff5260000000000000000000072c5e78f690d5d20ec8c8e12ace2a3b34929099b93f621a8671ae43df821bc5b03000000023b3d4b01000000034097ed362ec2a0eecb45779129e26e7b0c11ee9149a27c43f4e71bf10000000000000000 DMLOG CREATION_OP ROOT 0 DMLOG FEATURE_OP PRE_ACTIVATE 0 68dcaa34c0517d19666e6b33add67351d8c5f69e999ca1e37931bc410a297428 {"feature_digest":"68dcaa34c0517d19666e6b33add67351d8c5f69e999ca1e37931bc410a297428","subjective_restrictions":{"enabled":true,"preactivation_required":true,"earliest_allowed_activation_time":"1970-01-01T00:00:00.000"},"description_digest":"2853617cec3eabd41881eb48882e6fc5e81a0db917d375057864b3befbe29acd","dependencies":[],"protocol_feature_type":"builtin","specification":[{"name":"builtin_feature_codename","value":"DISALLOW_EMPTY_PRODUCER_SCHEDULE"}]} DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304002,"value_ex":45003,"consumed":7776},"cpu_usage":{"last_ordinal":1262304002,"value_ex":82182,"consumed":14101},"ram_usage":180802} -DMLOG APPLIED_TRANSACTION 3 e358ede0d30a5ac5fa03a484a5142b0a38f658e0fb57644adb5b60c94206f9e003000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190100d007000010000000000000000080000000000000000001010000010000000000ea3055659dd999c0cb81c2eea85d3eda39898997e4a9bd57bcebcac06cc25db35e000b09000000000000000900000000000000010000000000ea3055090000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed32322068dcaa34c0517d19666e6b33add67351d8c5f69e999ca1e37931bc410a29742800000000000000000000e358ede0d30a5ac5fa03a484a5142b0a38f658e0fb57644adb5b60c94206f9e003000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190000000000000000 +DMLOG APPLIED_TRANSACTION 3 e358ede0d30a5ac5fa03a484a5142b0a38f658e0fb57644adb5b60c94206f9e003000000023b3d4b01000000034097ed362ec2a0eecb45779129e26e7b0c11ee9149a27c43f4e71bf10100d007000010000000000000000080000000000000000001010000010000000000ea3055659dd999c0cb81c2eea85d3eda39898997e4a9bd57bcebcac06cc25db35e000b09000000000000000900000000000000010000000000ea3055090000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed32322068dcaa34c0517d19666e6b33add67351d8c5f69e999ca1e37931bc410a29742800000000000000000000e358ede0d30a5ac5fa03a484a5142b0a38f658e0fb57644adb5b60c94206f9e003000000023b3d4b01000000034097ed362ec2a0eecb45779129e26e7b0c11ee9149a27c43f4e71bf10000000000000000 DMLOG CREATION_OP ROOT 0 DMLOG FEATURE_OP PRE_ACTIVATE 0 ad9e3d8f650687709fd68f4b90b41f7d825a365b02c23a636cef88ac2ac00c43 {"feature_digest":"ad9e3d8f650687709fd68f4b90b41f7d825a365b02c23a636cef88ac2ac00c43","subjective_restrictions":{"enabled":true,"preactivation_required":true,"earliest_allowed_activation_time":"1970-01-01T00:00:00.000"},"description_digest":"e71b6712188391994c78d8c722c1d42c477cf091e5601b5cf1befd05721a57f3","dependencies":[],"protocol_feature_type":"builtin","specification":[{"name":"builtin_feature_codename","value":"RESTRICT_ACTION_TO_SELF"}]} DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304002,"value_ex":45744,"consumed":7904},"cpu_usage":{"last_ordinal":1262304002,"value_ex":93757,"consumed":16101},"ram_usage":180802} -DMLOG APPLIED_TRANSACTION 3 60b8a605178774eed85eb65b3ae743e5f3dc9b11d4672e1d00be33a0d21c8dae03000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190100d007000010000000000000000080000000000000000001010000010000000000ea3055d209fd21b66b7e1f62b25302fd208120700fb20e0a9a0151d3909e1ca7a98f460a000000000000000a00000000000000010000000000ea30550a0000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220ad9e3d8f650687709fd68f4b90b41f7d825a365b02c23a636cef88ac2ac00c430000000000000000000060b8a605178774eed85eb65b3ae743e5f3dc9b11d4672e1d00be33a0d21c8dae03000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190000000000000000 +DMLOG APPLIED_TRANSACTION 3 60b8a605178774eed85eb65b3ae743e5f3dc9b11d4672e1d00be33a0d21c8dae03000000023b3d4b01000000034097ed362ec2a0eecb45779129e26e7b0c11ee9149a27c43f4e71bf10100d007000010000000000000000080000000000000000001010000010000000000ea3055d209fd21b66b7e1f62b25302fd208120700fb20e0a9a0151d3909e1ca7a98f460a000000000000000a00000000000000010000000000ea30550a0000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220ad9e3d8f650687709fd68f4b90b41f7d825a365b02c23a636cef88ac2ac00c430000000000000000000060b8a605178774eed85eb65b3ae743e5f3dc9b11d4672e1d00be33a0d21c8dae03000000023b3d4b01000000034097ed362ec2a0eecb45779129e26e7b0c11ee9149a27c43f4e71bf10000000000000000 DMLOG CREATION_OP ROOT 0 DMLOG FEATURE_OP PRE_ACTIVATE 0 8ba52fe7a3956c5cd3a656a3174b931d3bb2abb45578befc59f283ecd816a405 {"feature_digest":"8ba52fe7a3956c5cd3a656a3174b931d3bb2abb45578befc59f283ecd816a405","subjective_restrictions":{"enabled":true,"preactivation_required":true,"earliest_allowed_activation_time":"1970-01-01T00:00:00.000"},"description_digest":"2f1f13e291c79da5a2bbad259ed7c1f2d34f697ea460b14b565ac33b063b73e2","dependencies":[],"protocol_feature_type":"builtin","specification":[{"name":"builtin_feature_codename","value":"ONLY_BILL_FIRST_AUTHORIZER"}]} DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304002,"value_ex":46485,"consumed":8032},"cpu_usage":{"last_ordinal":1262304002,"value_ex":105332,"consumed":18101},"ram_usage":180802} -DMLOG APPLIED_TRANSACTION 3 689db7ff0751fd6025dbc997d9a7ca1fe4e525ee48e55e5fb2aee8403077dd3e03000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190100d007000010000000000000000080000000000000000001010000010000000000ea3055fd71f42952743b790fcaa82dabd6a843676b9bd5b91c891fc050f9c41374a35e0b000000000000000b00000000000000010000000000ea30550b0000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232208ba52fe7a3956c5cd3a656a3174b931d3bb2abb45578befc59f283ecd816a40500000000000000000000689db7ff0751fd6025dbc997d9a7ca1fe4e525ee48e55e5fb2aee8403077dd3e03000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190000000000000000 +DMLOG APPLIED_TRANSACTION 3 689db7ff0751fd6025dbc997d9a7ca1fe4e525ee48e55e5fb2aee8403077dd3e03000000023b3d4b01000000034097ed362ec2a0eecb45779129e26e7b0c11ee9149a27c43f4e71bf10100d007000010000000000000000080000000000000000001010000010000000000ea3055fd71f42952743b790fcaa82dabd6a843676b9bd5b91c891fc050f9c41374a35e0b000000000000000b00000000000000010000000000ea30550b0000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232208ba52fe7a3956c5cd3a656a3174b931d3bb2abb45578befc59f283ecd816a40500000000000000000000689db7ff0751fd6025dbc997d9a7ca1fe4e525ee48e55e5fb2aee8403077dd3e03000000023b3d4b01000000034097ed362ec2a0eecb45779129e26e7b0c11ee9149a27c43f4e71bf10000000000000000 DMLOG CREATION_OP ROOT 0 DMLOG FEATURE_OP PRE_ACTIVATE 0 2652f5f96006294109b3dd0bbde63693f55324af452b799ee137a81a905eed25 {"feature_digest":"2652f5f96006294109b3dd0bbde63693f55324af452b799ee137a81a905eed25","subjective_restrictions":{"enabled":true,"preactivation_required":true,"earliest_allowed_activation_time":"1970-01-01T00:00:00.000"},"description_digest":"898082c59f921d0042e581f00a59d5ceb8be6f1d9c7a45b6f07c0e26eaee0222","dependencies":[],"protocol_feature_type":"builtin","specification":[{"name":"builtin_feature_codename","value":"FORWARD_SETCODE"}]} DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304002,"value_ex":47226,"consumed":8160},"cpu_usage":{"last_ordinal":1262304002,"value_ex":116907,"consumed":20101},"ram_usage":180802} -DMLOG APPLIED_TRANSACTION 3 48ed94d5a6fa7dd478278b29bbff0a72bd9d9a5431423ed3f0b1ce393643108303000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190100d007000010000000000000000080000000000000000001010000010000000000ea305512250767854476ab3904c7f604b0322bfa91821d01ddb20ecfaaff1beef8e04b0c000000000000000c00000000000000010000000000ea30550c0000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232202652f5f96006294109b3dd0bbde63693f55324af452b799ee137a81a905eed250000000000000000000048ed94d5a6fa7dd478278b29bbff0a72bd9d9a5431423ed3f0b1ce393643108303000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190000000000000000 +DMLOG APPLIED_TRANSACTION 3 48ed94d5a6fa7dd478278b29bbff0a72bd9d9a5431423ed3f0b1ce393643108303000000023b3d4b01000000034097ed362ec2a0eecb45779129e26e7b0c11ee9149a27c43f4e71bf10100d007000010000000000000000080000000000000000001010000010000000000ea305512250767854476ab3904c7f604b0322bfa91821d01ddb20ecfaaff1beef8e04b0c000000000000000c00000000000000010000000000ea30550c0000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232202652f5f96006294109b3dd0bbde63693f55324af452b799ee137a81a905eed250000000000000000000048ed94d5a6fa7dd478278b29bbff0a72bd9d9a5431423ed3f0b1ce393643108303000000023b3d4b01000000034097ed362ec2a0eecb45779129e26e7b0c11ee9149a27c43f4e71bf10000000000000000 DMLOG CREATION_OP ROOT 0 DMLOG FEATURE_OP PRE_ACTIVATE 0 f0af56d2c5a48d60a4a5b5c903edfb7db3a736a94ed589d0b797df33ff9d3e1d {"feature_digest":"f0af56d2c5a48d60a4a5b5c903edfb7db3a736a94ed589d0b797df33ff9d3e1d","subjective_restrictions":{"enabled":true,"preactivation_required":true,"earliest_allowed_activation_time":"1970-01-01T00:00:00.000"},"description_digest":"1eab748b95a2e6f4d7cb42065bdee5566af8efddf01a55a0a8d831b823f8828a","dependencies":[],"protocol_feature_type":"builtin","specification":[{"name":"builtin_feature_codename","value":"GET_SENDER"}]} DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304002,"value_ex":47967,"consumed":8288},"cpu_usage":{"last_ordinal":1262304002,"value_ex":128482,"consumed":22101},"ram_usage":180802} -DMLOG APPLIED_TRANSACTION 3 aa192243a78a9d8954a3af3f044207536068d3ad3f7ffb3b7de53b959de190b003000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190100d007000010000000000000000080000000000000000001010000010000000000ea3055063f8bf038af0888c33fcfdd66c2f91fd6b060df73aaa32a1e905b143ceb9ac00d000000000000000d00000000000000010000000000ea30550d0000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220f0af56d2c5a48d60a4a5b5c903edfb7db3a736a94ed589d0b797df33ff9d3e1d00000000000000000000aa192243a78a9d8954a3af3f044207536068d3ad3f7ffb3b7de53b959de190b003000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190000000000000000 +DMLOG APPLIED_TRANSACTION 3 aa192243a78a9d8954a3af3f044207536068d3ad3f7ffb3b7de53b959de190b003000000023b3d4b01000000034097ed362ec2a0eecb45779129e26e7b0c11ee9149a27c43f4e71bf10100d007000010000000000000000080000000000000000001010000010000000000ea3055063f8bf038af0888c33fcfdd66c2f91fd6b060df73aaa32a1e905b143ceb9ac00d000000000000000d00000000000000010000000000ea30550d0000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220f0af56d2c5a48d60a4a5b5c903edfb7db3a736a94ed589d0b797df33ff9d3e1d00000000000000000000aa192243a78a9d8954a3af3f044207536068d3ad3f7ffb3b7de53b959de190b003000000023b3d4b01000000034097ed362ec2a0eecb45779129e26e7b0c11ee9149a27c43f4e71bf10000000000000000 DMLOG CREATION_OP ROOT 0 DMLOG FEATURE_OP PRE_ACTIVATE 0 4e7bf348da00a945489b2a681749eb56f5de00b900014e137ddae39f48f69d67 {"feature_digest":"4e7bf348da00a945489b2a681749eb56f5de00b900014e137ddae39f48f69d67","subjective_restrictions":{"enabled":true,"preactivation_required":true,"earliest_allowed_activation_time":"1970-01-01T00:00:00.000"},"description_digest":"1812fdb5096fd854a4958eb9d53b43219d114de0e858ce00255bd46569ad2c68","dependencies":[],"protocol_feature_type":"builtin","specification":[{"name":"builtin_feature_codename","value":"RAM_RESTRICTIONS"}]} DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304002,"value_ex":48708,"consumed":8416},"cpu_usage":{"last_ordinal":1262304002,"value_ex":140057,"consumed":24101},"ram_usage":180802} -DMLOG APPLIED_TRANSACTION 3 a9e581a81302c707c14f5985458d2ef53faf24afacb03115f5cbc17271d7504803000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190100d007000010000000000000000080000000000000000001010000010000000000ea3055f279231a0740adb280f58749e984c932e17897073e9aedc1c33a102df52498430e000000000000000e00000000000000010000000000ea30550e0000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232204e7bf348da00a945489b2a681749eb56f5de00b900014e137ddae39f48f69d6700000000000000000000a9e581a81302c707c14f5985458d2ef53faf24afacb03115f5cbc17271d7504803000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190000000000000000 +DMLOG APPLIED_TRANSACTION 3 a9e581a81302c707c14f5985458d2ef53faf24afacb03115f5cbc17271d7504803000000023b3d4b01000000034097ed362ec2a0eecb45779129e26e7b0c11ee9149a27c43f4e71bf10100d007000010000000000000000080000000000000000001010000010000000000ea3055f279231a0740adb280f58749e984c932e17897073e9aedc1c33a102df52498430e000000000000000e00000000000000010000000000ea30550e0000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232204e7bf348da00a945489b2a681749eb56f5de00b900014e137ddae39f48f69d6700000000000000000000a9e581a81302c707c14f5985458d2ef53faf24afacb03115f5cbc17271d7504803000000023b3d4b01000000034097ed362ec2a0eecb45779129e26e7b0c11ee9149a27c43f4e71bf10000000000000000 DMLOG CREATION_OP ROOT 0 DMLOG FEATURE_OP PRE_ACTIVATE 0 4fca8bd82bbd181e714e283f83e1b45d95ca5af40fb89ad3977b653c448f78c2 {"feature_digest":"4fca8bd82bbd181e714e283f83e1b45d95ca5af40fb89ad3977b653c448f78c2","subjective_restrictions":{"enabled":true,"preactivation_required":true,"earliest_allowed_activation_time":"1970-01-01T00:00:00.000"},"description_digest":"927fdf78c51e77a899f2db938249fb1f8bb38f4e43d9c1f75b190492080cbc34","dependencies":[],"protocol_feature_type":"builtin","specification":[{"name":"builtin_feature_codename","value":"WEBAUTHN_KEY"}]} DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304002,"value_ex":49449,"consumed":8544},"cpu_usage":{"last_ordinal":1262304002,"value_ex":151632,"consumed":26101},"ram_usage":180802} -DMLOG APPLIED_TRANSACTION 3 4185b6265a360d2bf774af7d82bd837333cfb6b976390dac78c284207b6bbce103000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190100d007000010000000000000000080000000000000000001010000010000000000ea305578e423734b3bacaadd9c1864e7a7c612255a9c0d9fcdeba49708ee6b147e13170f000000000000000f00000000000000010000000000ea30550f0000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232204fca8bd82bbd181e714e283f83e1b45d95ca5af40fb89ad3977b653c448f78c2000000000000000000004185b6265a360d2bf774af7d82bd837333cfb6b976390dac78c284207b6bbce103000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190000000000000000 +DMLOG APPLIED_TRANSACTION 3 4185b6265a360d2bf774af7d82bd837333cfb6b976390dac78c284207b6bbce103000000023b3d4b01000000034097ed362ec2a0eecb45779129e26e7b0c11ee9149a27c43f4e71bf10100d007000010000000000000000080000000000000000001010000010000000000ea305578e423734b3bacaadd9c1864e7a7c612255a9c0d9fcdeba49708ee6b147e13170f000000000000000f00000000000000010000000000ea30550f0000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232204fca8bd82bbd181e714e283f83e1b45d95ca5af40fb89ad3977b653c448f78c2000000000000000000004185b6265a360d2bf774af7d82bd837333cfb6b976390dac78c284207b6bbce103000000023b3d4b01000000034097ed362ec2a0eecb45779129e26e7b0c11ee9149a27c43f4e71bf10000000000000000 DMLOG CREATION_OP ROOT 0 DMLOG FEATURE_OP PRE_ACTIVATE 0 299dcb6af692324b899b39f16d5a530a33062804e41f09dc97e9f156b4476707 {"feature_digest":"299dcb6af692324b899b39f16d5a530a33062804e41f09dc97e9f156b4476707","subjective_restrictions":{"enabled":true,"preactivation_required":true,"earliest_allowed_activation_time":"1970-01-01T00:00:00.000"},"description_digest":"ab76031cad7a457f4fd5f5fca97a3f03b8a635278e0416f77dcc91eb99a48e10","dependencies":[],"protocol_feature_type":"builtin","specification":[{"name":"builtin_feature_codename","value":"WTMSIG_BLOCK_SIGNATURES"}]} DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304002,"value_ex":50190,"consumed":8672},"cpu_usage":{"last_ordinal":1262304002,"value_ex":163207,"consumed":28101},"ram_usage":180802} -DMLOG APPLIED_TRANSACTION 3 f6025d888ddcfb8fdfeee18204122f8b7a71908a96ac4e52bf9542ff398b0d4403000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190100d007000010000000000000000080000000000000000001010000010000000000ea3055368a5df8e81472fb54f3424401fba4956a6e0737806b4f642b2d7014cf66fc2c10000000000000001000000000000000010000000000ea3055100000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220299dcb6af692324b899b39f16d5a530a33062804e41f09dc97e9f156b447670700000000000000000000f6025d888ddcfb8fdfeee18204122f8b7a71908a96ac4e52bf9542ff398b0d4403000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190000000000000000 +DMLOG APPLIED_TRANSACTION 3 f6025d888ddcfb8fdfeee18204122f8b7a71908a96ac4e52bf9542ff398b0d4403000000023b3d4b01000000034097ed362ec2a0eecb45779129e26e7b0c11ee9149a27c43f4e71bf10100d007000010000000000000000080000000000000000001010000010000000000ea3055368a5df8e81472fb54f3424401fba4956a6e0737806b4f642b2d7014cf66fc2c10000000000000001000000000000000010000000000ea3055100000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220299dcb6af692324b899b39f16d5a530a33062804e41f09dc97e9f156b447670700000000000000000000f6025d888ddcfb8fdfeee18204122f8b7a71908a96ac4e52bf9542ff398b0d4403000000023b3d4b01000000034097ed362ec2a0eecb45779129e26e7b0c11ee9149a27c43f4e71bf10000000000000000 DMLOG CREATION_OP ROOT 0 DMLOG FEATURE_OP PRE_ACTIVATE 0 c3a6138c5061cf291310887c0b5c71fcaffeab90d5deb50d3b9e687cead45071 {"feature_digest":"c3a6138c5061cf291310887c0b5c71fcaffeab90d5deb50d3b9e687cead45071","subjective_restrictions":{"enabled":true,"preactivation_required":true,"earliest_allowed_activation_time":"1970-01-01T00:00:00.000"},"description_digest":"69b064c5178e2738e144ed6caa9349a3995370d78db29e494b3126ebd9111966","dependencies":[],"protocol_feature_type":"builtin","specification":[{"name":"builtin_feature_codename","value":"ACTION_RETURN_VALUE"}]} DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304002,"value_ex":50931,"consumed":8800},"cpu_usage":{"last_ordinal":1262304002,"value_ex":174782,"consumed":30101},"ram_usage":180802} -DMLOG APPLIED_TRANSACTION 3 116b232e8995b25d7bab8c5134bc993bcd84e72bc35d0b27fe723d7d25e98ac703000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190100d007000010000000000000000080000000000000000001010000010000000000ea30552acd5ab1218225e0cc0a013d8e86b58cfc4d998058708fb1eb0116c1124f7c7f11000000000000001100000000000000010000000000ea3055110000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220c3a6138c5061cf291310887c0b5c71fcaffeab90d5deb50d3b9e687cead4507100000000000000000000116b232e8995b25d7bab8c5134bc993bcd84e72bc35d0b27fe723d7d25e98ac703000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190000000000000000 +DMLOG APPLIED_TRANSACTION 3 116b232e8995b25d7bab8c5134bc993bcd84e72bc35d0b27fe723d7d25e98ac703000000023b3d4b01000000034097ed362ec2a0eecb45779129e26e7b0c11ee9149a27c43f4e71bf10100d007000010000000000000000080000000000000000001010000010000000000ea30552acd5ab1218225e0cc0a013d8e86b58cfc4d998058708fb1eb0116c1124f7c7f11000000000000001100000000000000010000000000ea3055110000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220c3a6138c5061cf291310887c0b5c71fcaffeab90d5deb50d3b9e687cead4507100000000000000000000116b232e8995b25d7bab8c5134bc993bcd84e72bc35d0b27fe723d7d25e98ac703000000023b3d4b01000000034097ed362ec2a0eecb45779129e26e7b0c11ee9149a27c43f4e71bf10000000000000000 DMLOG CREATION_OP ROOT 0 DMLOG FEATURE_OP PRE_ACTIVATE 0 5443fcf88330c586bc0e5f3dee10e7f63c76c00249c87fe4fbf7f38c082006b4 {"feature_digest":"5443fcf88330c586bc0e5f3dee10e7f63c76c00249c87fe4fbf7f38c082006b4","subjective_restrictions":{"enabled":true,"preactivation_required":true,"earliest_allowed_activation_time":"1970-01-01T00:00:00.000"},"description_digest":"70787548dcea1a2c52c913a37f74ce99e6caae79110d7ca7b859936a0075b314","dependencies":[],"protocol_feature_type":"builtin","specification":[{"name":"builtin_feature_codename","value":"BLOCKCHAIN_PARAMETERS"}]} DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304002,"value_ex":51672,"consumed":8928},"cpu_usage":{"last_ordinal":1262304002,"value_ex":186357,"consumed":32101},"ram_usage":180802} -DMLOG APPLIED_TRANSACTION 3 11a09bc0cc023daf656af6dadf37577a9d4c0cea8020c1d007a2c3d6dc1e52c103000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190100d007000010000000000000000080000000000000000001010000010000000000ea3055db17f5e8a451e3814885ec6d61c420ac422f1e0de77043c9024e592b64f8bd1412000000000000001200000000000000010000000000ea3055120000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232205443fcf88330c586bc0e5f3dee10e7f63c76c00249c87fe4fbf7f38c082006b40000000000000000000011a09bc0cc023daf656af6dadf37577a9d4c0cea8020c1d007a2c3d6dc1e52c103000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190000000000000000 +DMLOG APPLIED_TRANSACTION 3 11a09bc0cc023daf656af6dadf37577a9d4c0cea8020c1d007a2c3d6dc1e52c103000000023b3d4b01000000034097ed362ec2a0eecb45779129e26e7b0c11ee9149a27c43f4e71bf10100d007000010000000000000000080000000000000000001010000010000000000ea3055db17f5e8a451e3814885ec6d61c420ac422f1e0de77043c9024e592b64f8bd1412000000000000001200000000000000010000000000ea3055120000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232205443fcf88330c586bc0e5f3dee10e7f63c76c00249c87fe4fbf7f38c082006b40000000000000000000011a09bc0cc023daf656af6dadf37577a9d4c0cea8020c1d007a2c3d6dc1e52c103000000023b3d4b01000000034097ed362ec2a0eecb45779129e26e7b0c11ee9149a27c43f4e71bf10000000000000000 DMLOG CREATION_OP ROOT 0 DMLOG FEATURE_OP PRE_ACTIVATE 0 bcd2a26394b36614fd4894241d3c451ab0f6fd110958c3423073621a70826e99 {"feature_digest":"bcd2a26394b36614fd4894241d3c451ab0f6fd110958c3423073621a70826e99","subjective_restrictions":{"enabled":true,"preactivation_required":true,"earliest_allowed_activation_time":"1970-01-01T00:00:00.000"},"description_digest":"d2596697fed14a0840013647b99045022ae6a885089f35a7e78da7a43ad76ed4","dependencies":[],"protocol_feature_type":"builtin","specification":[{"name":"builtin_feature_codename","value":"GET_CODE_HASH"}]} DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304002,"value_ex":52413,"consumed":9056},"cpu_usage":{"last_ordinal":1262304002,"value_ex":197932,"consumed":34101},"ram_usage":180802} -DMLOG APPLIED_TRANSACTION 3 76bcbbd871a26403befd2ebf5491d6b84ded9f29cb95bfd54ca6ec46b1dfad5903000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190100d007000010000000000000000080000000000000000001010000010000000000ea3055693240e7063adb7478594592f8a6e6cb76e33cabc605272575b687e3a0fa5f5e13000000000000001300000000000000010000000000ea3055130000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220bcd2a26394b36614fd4894241d3c451ab0f6fd110958c3423073621a70826e990000000000000000000076bcbbd871a26403befd2ebf5491d6b84ded9f29cb95bfd54ca6ec46b1dfad5903000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190000000000000000 +DMLOG APPLIED_TRANSACTION 3 76bcbbd871a26403befd2ebf5491d6b84ded9f29cb95bfd54ca6ec46b1dfad5903000000023b3d4b01000000034097ed362ec2a0eecb45779129e26e7b0c11ee9149a27c43f4e71bf10100d007000010000000000000000080000000000000000001010000010000000000ea3055693240e7063adb7478594592f8a6e6cb76e33cabc605272575b687e3a0fa5f5e13000000000000001300000000000000010000000000ea3055130000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220bcd2a26394b36614fd4894241d3c451ab0f6fd110958c3423073621a70826e990000000000000000000076bcbbd871a26403befd2ebf5491d6b84ded9f29cb95bfd54ca6ec46b1dfad5903000000023b3d4b01000000034097ed362ec2a0eecb45779129e26e7b0c11ee9149a27c43f4e71bf10000000000000000 DMLOG CREATION_OP ROOT 0 DMLOG FEATURE_OP PRE_ACTIVATE 0 d528b9f6e9693f45ed277af93474fd473ce7d831dae2180cca35d907bd10cb40 {"feature_digest":"d528b9f6e9693f45ed277af93474fd473ce7d831dae2180cca35d907bd10cb40","subjective_restrictions":{"enabled":true,"preactivation_required":true,"earliest_allowed_activation_time":"1970-01-01T00:00:00.000"},"description_digest":"8139e99247b87f18ef7eae99f07f00ea3adf39ed53f4d2da3f44e6aa0bfd7c62","dependencies":[],"protocol_feature_type":"builtin","specification":[{"name":"builtin_feature_codename","value":"CONFIGURABLE_WASM_LIMITS2"}]} DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304002,"value_ex":53154,"consumed":9184},"cpu_usage":{"last_ordinal":1262304002,"value_ex":209507,"consumed":36101},"ram_usage":180802} -DMLOG APPLIED_TRANSACTION 3 1948411767455fe23b05b44fe5fb737422ce3831a41f2c68064990fd6f52fdaf03000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190100d007000010000000000000000080000000000000000001010000010000000000ea3055a40aa97866a6e0814065142f7d1038aaccb2e8a73661f6554c415c331ab8ec8b14000000000000001400000000000000010000000000ea3055140000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220d528b9f6e9693f45ed277af93474fd473ce7d831dae2180cca35d907bd10cb40000000000000000000001948411767455fe23b05b44fe5fb737422ce3831a41f2c68064990fd6f52fdaf03000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190000000000000000 +DMLOG APPLIED_TRANSACTION 3 1948411767455fe23b05b44fe5fb737422ce3831a41f2c68064990fd6f52fdaf03000000023b3d4b01000000034097ed362ec2a0eecb45779129e26e7b0c11ee9149a27c43f4e71bf10100d007000010000000000000000080000000000000000001010000010000000000ea3055a40aa97866a6e0814065142f7d1038aaccb2e8a73661f6554c415c331ab8ec8b14000000000000001400000000000000010000000000ea3055140000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220d528b9f6e9693f45ed277af93474fd473ce7d831dae2180cca35d907bd10cb40000000000000000000001948411767455fe23b05b44fe5fb737422ce3831a41f2c68064990fd6f52fdaf03000000023b3d4b01000000034097ed362ec2a0eecb45779129e26e7b0c11ee9149a27c43f4e71bf10000000000000000 DMLOG CREATION_OP ROOT 0 DMLOG FEATURE_OP PRE_ACTIVATE 0 6bcb40a24e49c26d0a60513b6aeb8551d264e4717f306b81a37a5afb3b47cedc {"feature_digest":"6bcb40a24e49c26d0a60513b6aeb8551d264e4717f306b81a37a5afb3b47cedc","subjective_restrictions":{"enabled":true,"preactivation_required":true,"earliest_allowed_activation_time":"1970-01-01T00:00:00.000"},"description_digest":"68d6405cb8df3de95bd834ebb408196578500a9f818ff62ccc68f60b932f7d82","dependencies":[],"protocol_feature_type":"builtin","specification":[{"name":"builtin_feature_codename","value":"CRYPTO_PRIMITIVES"}]} DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304002,"value_ex":53895,"consumed":9312},"cpu_usage":{"last_ordinal":1262304002,"value_ex":221082,"consumed":38101},"ram_usage":180802} -DMLOG APPLIED_TRANSACTION 3 3cea935e0deaa090b14d4ee01f3fee31a1c426779f1c32840aefaa99cb83ec5f03000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190100d007000010000000000000000080000000000000000001010000010000000000ea30555705a61c2ae1877963ee8e857abb78d2975071d25ce32f1235b4d4803967a9fa15000000000000001500000000000000010000000000ea3055150000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232206bcb40a24e49c26d0a60513b6aeb8551d264e4717f306b81a37a5afb3b47cedc000000000000000000003cea935e0deaa090b14d4ee01f3fee31a1c426779f1c32840aefaa99cb83ec5f03000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190000000000000000 +DMLOG APPLIED_TRANSACTION 3 3cea935e0deaa090b14d4ee01f3fee31a1c426779f1c32840aefaa99cb83ec5f03000000023b3d4b01000000034097ed362ec2a0eecb45779129e26e7b0c11ee9149a27c43f4e71bf10100d007000010000000000000000080000000000000000001010000010000000000ea30555705a61c2ae1877963ee8e857abb78d2975071d25ce32f1235b4d4803967a9fa15000000000000001500000000000000010000000000ea3055150000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232206bcb40a24e49c26d0a60513b6aeb8551d264e4717f306b81a37a5afb3b47cedc000000000000000000003cea935e0deaa090b14d4ee01f3fee31a1c426779f1c32840aefaa99cb83ec5f03000000023b3d4b01000000034097ed362ec2a0eecb45779129e26e7b0c11ee9149a27c43f4e71bf10000000000000000 DMLOG CREATION_OP ROOT 0 DMLOG FEATURE_OP PRE_ACTIVATE 0 35c2186cc36f7bb4aeaf4487b36e57039ccf45a9136aa856a5d569ecca55ef2b {"feature_digest":"35c2186cc36f7bb4aeaf4487b36e57039ccf45a9136aa856a5d569ecca55ef2b","subjective_restrictions":{"enabled":true,"preactivation_required":true,"earliest_allowed_activation_time":"1970-01-01T00:00:00.000"},"description_digest":"e5d7992006e628a38c5e6c28dd55ff5e57ea682079bf41fef9b3cced0f46b491","dependencies":[],"protocol_feature_type":"builtin","specification":[{"name":"builtin_feature_codename","value":"GET_BLOCK_NUM"}]} DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304002,"value_ex":54636,"consumed":9440},"cpu_usage":{"last_ordinal":1262304002,"value_ex":232657,"consumed":40101},"ram_usage":180802} -DMLOG APPLIED_TRANSACTION 3 04ba316cf9ddd86690833edc0f4548f8c07f0d66c09dca029b0a1fb96f16c62803000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190100d007000010000000000000000080000000000000000001010000010000000000ea3055302a2f1713925c939a997367c967b457bfc2c580304f9686b1de22fc5946e40616000000000000001600000000000000010000000000ea3055160000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed32322035c2186cc36f7bb4aeaf4487b36e57039ccf45a9136aa856a5d569ecca55ef2b0000000000000000000004ba316cf9ddd86690833edc0f4548f8c07f0d66c09dca029b0a1fb96f16c62803000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190000000000000000 +DMLOG APPLIED_TRANSACTION 3 04ba316cf9ddd86690833edc0f4548f8c07f0d66c09dca029b0a1fb96f16c62803000000023b3d4b01000000034097ed362ec2a0eecb45779129e26e7b0c11ee9149a27c43f4e71bf10100d007000010000000000000000080000000000000000001010000010000000000ea3055302a2f1713925c939a997367c967b457bfc2c580304f9686b1de22fc5946e40616000000000000001600000000000000010000000000ea3055160000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed32322035c2186cc36f7bb4aeaf4487b36e57039ccf45a9136aa856a5d569ecca55ef2b0000000000000000000004ba316cf9ddd86690833edc0f4548f8c07f0d66c09dca029b0a1fb96f16c62803000000023b3d4b01000000034097ed362ec2a0eecb45779129e26e7b0c11ee9149a27c43f4e71bf10000000000000000 DMLOG CREATION_OP ROOT 0 DMLOG FEATURE_OP PRE_ACTIVATE 0 98c4175db53ed27e7911a1b5adf0e7db0fc96c2cae172cf594dfa9a742ca9e88 {"feature_digest":"98c4175db53ed27e7911a1b5adf0e7db0fc96c2cae172cf594dfa9a742ca9e88","subjective_restrictions":{"enabled":true,"preactivation_required":true,"earliest_allowed_activation_time":"1970-01-01T00:00:00.000"},"description_digest":"01969c44de35999b924095ae7f50081a7f274409fdbccb9fc54fa7836c76089c","dependencies":[],"protocol_feature_type":"builtin","specification":[{"name":"builtin_feature_codename","value":"BLS_PRIMITIVES"}]} DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304002,"value_ex":55377,"consumed":9568},"cpu_usage":{"last_ordinal":1262304002,"value_ex":244232,"consumed":42101},"ram_usage":180802} -DMLOG APPLIED_TRANSACTION 3 793b276fb55f2f81cbdcfcaf882555ea5dde340f80c16e5dc652ffad52eea87c03000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190100d007000010000000000000000080000000000000000001010000010000000000ea30553a97dc6254ea785e8c6ee5994044fae975bfc8ef1916a24b476a984724cc5cf017000000000000001700000000000000010000000000ea3055170000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed32322098c4175db53ed27e7911a1b5adf0e7db0fc96c2cae172cf594dfa9a742ca9e8800000000000000000000793b276fb55f2f81cbdcfcaf882555ea5dde340f80c16e5dc652ffad52eea87c03000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190000000000000000 +DMLOG APPLIED_TRANSACTION 3 793b276fb55f2f81cbdcfcaf882555ea5dde340f80c16e5dc652ffad52eea87c03000000023b3d4b01000000034097ed362ec2a0eecb45779129e26e7b0c11ee9149a27c43f4e71bf10100d007000010000000000000000080000000000000000001010000010000000000ea30553a97dc6254ea785e8c6ee5994044fae975bfc8ef1916a24b476a984724cc5cf017000000000000001700000000000000010000000000ea3055170000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed32322098c4175db53ed27e7911a1b5adf0e7db0fc96c2cae172cf594dfa9a742ca9e8800000000000000000000793b276fb55f2f81cbdcfcaf882555ea5dde340f80c16e5dc652ffad52eea87c03000000023b3d4b01000000034097ed362ec2a0eecb45779129e26e7b0c11ee9149a27c43f4e71bf10000000000000000 DMLOG CREATION_OP ROOT 0 -DMLOG FEATURE_OP PRE_ACTIVATE 0 a9cb566f982145ebccca8dcb6d2fe89b91dbd445c32ecef873cdc5d594279fcc {"feature_digest":"a9cb566f982145ebccca8dcb6d2fe89b91dbd445c32ecef873cdc5d594279fcc","subjective_restrictions":{"enabled":true,"preactivation_required":true,"earliest_allowed_activation_time":"1970-01-01T00:00:00.000"},"description_digest":"bc726a24928ea2d71ba294b70c5c9efc515c1542139bcf9e42f8bc174f2e72ff","dependencies":[],"protocol_feature_type":"builtin","specification":[{"name":"builtin_feature_codename","value":"INSTANT_FINALITY"}]} +DMLOG FEATURE_OP PRE_ACTIVATE 0 fce57d2331667353a0eac6b4209b67b843a7262a848af0a49a6e2fa9f6584eb4 {"feature_digest":"fce57d2331667353a0eac6b4209b67b843a7262a848af0a49a6e2fa9f6584eb4","subjective_restrictions":{"enabled":true,"preactivation_required":true,"earliest_allowed_activation_time":"1970-01-01T00:00:00.000"},"description_digest":"440c3efaaab212c387ce967c574dc813851cf8332d041beb418dfaf55facd5a9","dependencies":[],"protocol_feature_type":"builtin","specification":[{"name":"builtin_feature_codename","value":"DISABLE_DEFERRED_TRXS_STAGE_1"}]} DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304002,"value_ex":56118,"consumed":9696},"cpu_usage":{"last_ordinal":1262304002,"value_ex":255807,"consumed":44101},"ram_usage":180802} -DMLOG APPLIED_TRANSACTION 3 dd3c62c2bccdf1a4ca01464e03c6deba265089df27e9ca08b3ec671f424a4e7e03000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190100d007000010000000000000000080000000000000000001010000010000000000ea3055ac6be432e6c9fa887fb2ef020e979c440cb9a3f3458375d7dafa7e510aded96f18000000000000001800000000000000010000000000ea3055180000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220a9cb566f982145ebccca8dcb6d2fe89b91dbd445c32ecef873cdc5d594279fcc00000000000000000000dd3c62c2bccdf1a4ca01464e03c6deba265089df27e9ca08b3ec671f424a4e7e03000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190000000000000000 -DMLOG RLIMIT_OP STATE UPD {"average_block_net_usage":{"last_ordinal":2,"value_ex":0,"consumed":0},"average_block_cpu_usage":{"last_ordinal":2,"value_ex":833334,"consumed":100},"pending_net_usage":9696,"pending_cpu_usage":44100,"total_net_weight":0,"total_cpu_weight":0,"total_ram_bytes":0,"virtual_net_limit":1049625,"virtual_cpu_limit":200200} -DMLOG RLIMIT_OP STATE UPD {"average_block_net_usage":{"last_ordinal":3,"value_ex":80800000,"consumed":9696},"average_block_cpu_usage":{"last_ordinal":3,"value_ex":368326389,"consumed":44101},"pending_net_usage":0,"pending_cpu_usage":0,"total_net_weight":0,"total_cpu_weight":0,"total_ram_bytes":0,"virtual_net_limit":1050675,"virtual_cpu_limit":200400} -DMLOG ACCEPTED_BLOCK 3 03000000030000000200000000000000010000000000ea3055000100000001000240e54a7b27e042b80a810153bec1dd166eef95fa69f6c9886ae283363bc2add8010000000000012d5b1b639d6ae94fcdd0536b224644931573d1ccb2a0c548613cd1feea18888b0200000000000000010000000000ea305503000000010000000000ea305502000000000100000001000240e54a7b27e042b80a810153bec1dd166eef95fa69f6c9886ae283363bc2add801000000000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df719023b3d4b0000000000ea305500000000000213588be25132b4167ced6df22b5439e376d5a20284190bb94a43e3e815c39c909387122a322a319e68e2a400273172919552ac6944509ba2ec812d1fde4254975a4ef4af4d3829f170281c6011578a9828a798eeaab84e11450c712e000000000000001f20041c84dfa3dc10503182e60706eeae02db7fbda81f47ea43d623f3dfd84c7b5e063a2ee30ba7f62984f4e87938e34e291f4425f7180ae676c8a02083f489970000000029807708239aa7de914d3ed61e9009ab2280bfbc50f1d9769f27f8341ef26198000000000001010ec7e080177b2c02b278d5088611686b49d739925a92d9bfcacd7fc6b74053bd0001023b3d4b0000000000ea305500000000000213588be25132b4167ced6df22b5439e376d5a20284190bb94a43e3e815c39c909387122a322a319e68e2a400273172919552ac6944509ba2ec812d1fde4254975a4ef4af4d3829f170281c6011578a9828a798eeaab84e11450c712e000000000000001f20041c84dfa3dc10503182e60706eeae02db7fbda81f47ea43d623f3dfd84c7b5e063a2ee30ba7f62984f4e87938e34e291f4425f7180ae676c8a02083f489971600d0070000fb05010100203b7de491b51d3d74624078bc2c5dc4420985f0350afb6923a5585b5621750c9f126d7cff0efeade2068c7b618fc754b2abb5bff8cdb9bd0ecb4432b72ae1ed380100a82f78daed5c7b8c5ce755ff1ef7357b67e3ebc6d94c3609f9e662d0b8a4659bb8eb2575dbbddbc476694b9cca2dfea3b0bbd99d647776bdbb9e1da70e0adead081045158a7894b6405524a4d21424545aa8cacb0d0815a94891fa20414284ff2a025511a245ad54737ee77cf7ceeccb71f09a87545b9e7be77b9cef7ce79cef3cbf71f44fe94f1bf5d03d9f1951f447e343fdf3d87be873f2879efef473830dea77fff59e7bbef7f440d3bfd197d9f57368d1bfa54767949ab11b9736d48cd9b8840f7a0b372ed11f35136cf0436fe80dfac0b80dbc2afa67f84d6306e6063201ad97a8ff9234d00880f033d54c84469e48cd68b03c8b3ea54dd0909531c1fc52d0b0ed95c70e2dae4f3fd29eed5de8b6a767e77a8b8fcdf6daf32a42d7cd6bdd76d9548e51317aeaedd5f5c5d5e9d9f5f576b7a72c9aa273ed73ebed9e4af025c3b4d595e9f9d9deecf4fae2cfb4558d9b09defcf4409f1a2aa7cead3d2e53ebddf6f90b8b40e6426f41a568ba89e04eaf75171f5b5c6e3f4ac8d519393476dbebab17ba73ede9e5c5738bbd75358c9e70f6e155c24ae17d44a6aeaeadaeb7e7f1327f61aedd5d5737a1d3a1f3e1e5d5b9a5b985d9c595e9b5d9eeecb9768ffae9756e8956e29db9475f6918efa23e77a1db6daff4a67b8be7daea00d316339982ed81b579743afff0f4238b2bf3d38be347558696da34d17361b9b778af3a88ef0707693c3db73adf56868958aed36dcfb5097257d61a2280580ef09890d1fac2ec3d6f1c57af61e4a877bdb74a6445ffcd681aa6a60b6bf3e02dda0ed993275414abb8369444511c0f0d594b9f517c8b1e31237624a07ff4371cd123d60e51efd0adb7da86ff63ab8f46725b10ea353d34145aad7434623774b17959a51baaf8d45f568fb8a6c3d9b5b5e5c7d5eb6a07b42a745a7bfdd83d47c727ee7bd39b87fe66539f0854767bbaa9b5dd3093f2d7a9078655417f5be683f4a5c81ecb752737e3f44d5a9f9cccad539d22ee1417cfe76a9c1a9c29b29e53ef1ad64e4faa62e3c4b0a9dbb45007e81ff5e90e663b4d2fe83d39aca9bdf8cdcb2a33ce1e489d4d8d4ac7b5def8415a6e29a755c64d9d66d262f59651832ba175dc6cd2f3ad0a40313352c533b4f3ffd03ada2854d3601718b7043ccf3b757258611fef0076d96d07d2ecce62649cc0127ae5968b8d4e1e38ddc96ecbb17da75c405b74f67c6e4ed034553cd1c92da19207457c3ed70f0c1b0c21ac685a71b19387d4d78c9c75da192c1c776901daf9131d02648088f62d173b2e62184ec68434c5f29bca465367881c84970c54f4d1c22c80549d0a2430a126fe9ede4b742b469a9637a28be0ed843e6191fd00d024d49de6bd366d0a5a6777d2dc74429b0dde36f5df9e6bec7a5859225a9339fce1c9dc60ae39a894d39e26292146a426345d7a93f272c2484b6b9e2e1154e1a0398c01a6a8778011febd839629d7b3d95d34d54c62415e4c31a2584ca6381a31acea26051d200bf4245168a23feb1ca6d5d2043cd2d9e1eda8f8f61f4e43950da9f42744a85e22fae9c3a08b2e5e0021137ecde82da8ded0adb2d78ef257a75be822622d65756a7949d1bae92fd774c0846b1104fa0872b354c43fcee7e5eb2cceaa08c0b2a62194695a9245a3dc961b6c411509c9112f456fcd80799088f838bb54d8415018cf5c23410b00c783082a10f50e84dded3abb44840118013088481f4a76fd881cda17441ad78fc81dfb8288bb7e440eef0b22adeb47e4ee7d4164ecfa1139ba2f884c5c3f22c7f70591cb6a174cf45e9898014c4c05e33982a10750d17ba2a2050223a0592d1118361ae9778cd51be612eb3957aa3975c4aadc4cb9a78eab14d660aa456f43fc36466f357e9ba03728426c01e32d8f870db33cdef01bc66b7ec378b62d9fc883fbd4017a0b8ae4b1fbd44dfc96d1db30bf35e8ad8e193c2eaec645d5b8b01a17f0fa0d5edf1c57b70aee99c7e5f60a97d10a97db2a5c1abc0b8cbbb9dae36baa3d1eacf69809ce8a9118e10581c42db234bd1d1264d57dea2e2107b5fd4035eece6adc1d6459c844b286602bf4adefd3fe7f92f6da533efd522076fd194daed5619535e0fa38f56e78155bff121a57aefcf1b77ee7d73ffde2d44f929380af57ae7cf6db5fc35720b9b9b9f9fca7fff04f3e72cf43c356be5efe95ef50ef43c3817cddfc230c7ef770e22c7c910f12ba05b9544fd1d3d923f6297dccb263414ecb8f8ed693d42f71e55b1f7e71ea3dbcc4339f7cf1c57ff8e047bef6f98d3ed0bfffbddfa0efef1e8e05ea3c3dc8c59e119833c76c4b409205c8de305a8f539ef639d94705e5437ffbf257805a244096e9419a6541802c1cb3ce03719decded17a94fab537bffde13e10c0fc28808402e4494c08c8c5f6fbdba4fd251e4ed2c9de385a0f531979861ee1b8392de34e1fb3137ed844273b365a0ffcb01e3da271b326c3d68ed9861fd6e8643f365ab77ed83be9118f9b5332ecd4313be98791a20538e3c73d013cc6cd451977f198cdfcb8ac931d1fad6b3fec7df4a88d9bb332ecec313be6878d75b2b78c52f891dd415f9ed190a6d7283eb3194e0bf99b27b324fdb2d131046c8ce4ab19389231e8eea0198a568f24ccc8823c7e4064cec5c507d8f58eb3db9a86d1a0a6039d62ed3cbbc37007e32c240f3f2848d65b2e98526010b5769ab010ae038f30f1b0e277b025f8f92fc012a09310635fd260540df077b6d2bce4647f5eea12572b34fae9bc53d4007b414c1f3719351cc2e45a47da98c714f14094031716fa8220d5eabc4ea926751db1ae09479bbacec3d7e6082462fb1461abca25c5157dde4507b51a2086c978c36344650a3d2378e671fa73468757a36d79743d753d30ed296b52d09ec5612f0283b22d4fd91dd44c795b25e102f218997a4c0750d45614c9842289d0ac0145dae9d3e6886dbd0245a283666f5a0cf7652e3b927edb50e84a24f9b8b911f2f6450ad6157d667654f6725c1e13781095c6095c40a756866653a3bc550e555cd032934211daf1045303a7069d09efb9ea4c8ed96760595ee05e97205a1662d29e4bb22a1c7fa6ae9359cfe89cb9c55d2f6881ee71268c99452f700b562d5b1a1523aec20199181db4bb70e1e346d870f3e0d1c79cac96feaa3511197562c7a6be91227a4a1e93f2382d8fb3c29aa3f218ab38045e819050a478bb8c2816e738036dbe496c7b2b734d58365171658c8f34c2d75d5846ebcdc8eced1c6b0d722c138e3564d24cae847bf4581304060ec559728fe871baa9f138454a891e93cda1abf069c8c125c2790976e1d4a6de7960ee4ebf6775c207e6867108142639236748b4227fcf8884fefb560ebe02cf66fa3cdbd4b229614a764ab856bb1ad78840bb706d53ced910b85613ae65c0d8d5ae81718cc54bb2c31a2ca4eaaf98418892b289d978cc2ec8db647f6dac54cd430309821d9c450e083949b2b45f31bbb673bbb9f7b9f5d2f05e4e35e586844ea48239adfc6095dd46019b2246227596a5a3900f24d5c897ec33dbed18927e2e14b3ff4db5b71e8e2b5d9c94ba38f1eb267d5d9c6c93aaa4b4fd7071f6949a44a4060a93c5252b46af76aa9f17f9a8ed38d5a72be161d1b986537d7a40386604cfb395626a99fbd91010518ab173cd9a77ad2db8572bbef6ec575ffbe030ab7ea44c3397c7d43ab6ec7d8b182e223fcef421e535c0d2a77032e9f85b56ebe8815339b682d93966a4d726348cef82e03b431009d0e9a53c06b221840833428f28fca9af13a231231a6e4174461ef38209a000d1b08f682888f2bc15993a2f324be42e6596e6cd88d6f1d0e22c4fa5fdf440fb99b23d19907119c6f957efacdd4fed792a6a1ab27f2015ce672d957a25426f3763619dfd083b3a2f3e074727ad952a33fd4598347de34ddae92d7af1ecdede06fb1ba52dfb22f46243ccbad8b2c957f040763767c99ee6ec2a0ec8cc80ffb1b6c5b5d8d59c5d456f95562cbc8a15bb8c8481bec479f2cb8a83576477103b2134297833766a03e859f16345c3e5014e2ce144f8fbe347e87338f7d17ff9cc37de40bccf5038390595c4d11069b50772d522cd826f2758303e7b993d600b7e247ed49492c8ee0436d4cac3615d2f87d4113d31a3127ecb3a651878d20f7e6058a7a20b8abb3b790492d3493b816202e9da850e1020c1715cd2e19ac0034c1412e8900b3329c7b818a4a038c326b5442e947a482ee11feb6eff967ecc4af4b0a93df57212ab2306e25629e6b054cca1e742d857cce136e90dbd62862e15511a70ca4eeda2a343d6d1c66ba3ad815acb1c45be8e75370825dac2727c717440afb364676ff3ca3de21e7a1b14e6ad2e40eca2bd1db718648f2a151f5d9be326fa1af179c04a964f23407ad373ff00fdbc66e20a9868a6e24b34d070054ab45329e15f30da6e38613b54129f42944b2cca25c1d2568a599fe40cc08a40086639cbca8bf9c04cb15c21c6dd3f90287bec23b44687a34186a6010df5a3dc6e83a6fb395d55ca871ec8e932b4f4dff50d2261b00709d51e2095b84c7b8084d0ecdfa6bf6e593346bcf1a069a6147c3bae9271dabb19d2f18e2ca7f470d0d4db7989efc2d471029d4b6e48579071e69a73cee2097b75459d7711f21379d4fbfd27096e54c49d664487980c1249ee79d2435ea9f20e12d9526d891c083a7af613b97950aaaa2e5ecadeeb7bcb8de5c949d699d0facebc0b03a983cc81613726c1eee85b728274a564f0835229d2eeb4f5cbd2495adaa14e7857b52a5bc14dd007466aba21a8e469a2b7d124d84a934068120dd224649a18a189014d42170dd0049ed95b0cb248f5bedcb868a9703bd0447291c8da1c40b3e93940be207c54a4a6b886bc7b117510e2401155977b7f1545d441506511065af8da8aa8bb2162b13bfbaa8ba8af0e9143fb8248e3fa11b9635f1071d78fc8e17d41a475fd88dcbd2f888c5d3f2247f7059189eb47e4f8be20b27b11752f4caeb188ba072aba84b05b11f5b7c52f0ff7d1fa243badcfa0a68d5cb2cdfa88ed89c5ba180a3b617822313ce4122f650f55db492aa32ac3c5b925e55d591f52c61c4103346f04d4499660a128307e701712259ca6a0686e2bb738620389fe53f74397cc27502417c677740825f24bab6b48755e104ec1521e88c7b8f1ce61d6e6e46052e81dba402e3489b3cf8fa03f5130266727d7127d87f065450042870b65e4efa896783641cea40b386e534211cd496d89d4789ce65d6a7642602ea55261d877e1a00417a5b0469efa6b46c81821b6fe0b6b62899edd12a79ce47a13416de4108f3b1855443db8d34456556e6d69dc1c433585c2a0f0a4bfcf147074c48d4027e4ea1c9132aceea269dcb2cb0ee54c30d0ed0301b22bf0edfa910ba49183f2e21b12d20588700a0d3bcc63b343a374ba98ce0a914bc8ac629a6cad8684a5810d61c3622925253cf062a7b86bcbd8d82585e3b1a0d551445308dce98108b526112af5d4ab6b75779010321fe9dd61c70f725aa32665158d143697eb10a2b01cc41c82e32d92405471e94a3e90612401c97eca45083c25b8268fb4d1d41e0ce8076632174bd2a67fa5ad2106a2649c079c11d2888b9504c57fc69b03ba4896dcfc1037be2c3b66998e24f0e18f983d667203d9e6e771760b4d8c789c4cfcd873c20fe2dfe94e19df97c5a6b314ac09050981a3ac1d5bd9ad0c0195f7337251b13375c94553fa09faf8d9f7de4e6c232e51b0fa5d4d7e93d4cd82c39c1c3a46b84cf2da25da4ffb1217d21d874a0a071c1712754422ac5c05e864ef1b958188092d5f02909091a01ecd43cf46f60724b28fd9aa7b26c6583e41264cea100a706249b344b44b6622b49296b48eeb94c50a30904f218e9b5c4f844a75c8b130982d4c948a59fa211b0a0b858d14ae8b0ae228c9ee0c4228a4b96bb72004210dc270e5d930600b1c3026c54f683635ab00d6fa688af860cb443a244c1583c0389a4a7e01d9bc3728f5641e4c4d3cf524498b2e363ad80cf5b1f9206340d0ab2081149a08de95e7fc098c40c9b084430c670cf840c2c30f80c1001c72a3194cc61aa744850e3d04b1b03d3ab8d9413ec822bd068f000b0550d7b21ea77848e6d0820405be34e44ba3c3bb979b21d294f9a6ac6c324898105f3eef85321bd08c03a944affa37399518f854a264b612a46b78e9665837e93605c7df919d97b17e9c682fbe3dbc5d7dd9d216f910179773b795c36d3596d57b7a3f85d95244a87095c41ae3ab3cbe7a2fd4522e197c1fc80d02f26553a9bb6d92b5975c9529ea3da1226175581e8e9d003afca4be5a223c8d1dd6b1ca4d86d089879b7c07a5515d1e6079e220f730fc4f674e6e99ea7c4a6fcbec5b315b97b3f59eb3ab0923db26f00ea026b3fed1701dc9cabe6d5492748924e97c0ed7882d6435fae7b86830703b4af160f1a12cd9b407799af2ae171cad3c821f620a5c698a59f511d988b0c5f7a8016e3f291dc2ab0777d1456fbf1dd503b80a996be23700e23d231d6c71ef05b7b3011d3bf7fefb062960728e82342d8b6b900cc5e50dbec311c38292e1586a4afa350f91f328e15902d5b4151ce636bcf6509cd8a85526bf902f5e62d5e00b4f7cc58ebdddca313462bd02c9e921b5ca387a6374204d9fd7261057f07f5de10d68ba6d6a8ec28b4a668ed804fecbeb540c5394c5d81d5f712a95e0a70ced28d8eedc5edb8e1a7e478d6bd851c38f7ba51d855e77e73bb7c585403f322b4766db062503831a25811a7bd801efdd8148311e194556f468346b4cab1ae221176535ef4aa65ff6d6eed590ea1a69b4cfc4317b11a74ca76571b9a9bfb6b2295454fcae08e7607b2565b3aaa404a2baab4a4a807d04be9262717acec8035703032e989c159d754a640147f079ae90f81a37d0872a65dff3ac04ce72a710f181af81841c78579d196a20b6ac8184acb2b8936f32c9302e78707dade56f56a20632263d6b825352ba0e16c569cb65eec0578e41c4c1dab154bf387e0dfaa5635b2e17c0a3adc0700c2faa861597e8700e1ffad5e320f5fa3b9b280b2c81e86e0616488598c1f5dbefe7769ac8451714c7a02d898f57d1edb4a36dea1dc96dafe17d65bcf82a3dd99b868e47bf293ef9d5676f19d0f2b401d6f296b53c59956552f441a5e80df39698a53c4dfd83ec68f9e6aab746f596f937291396399eb1dd6d848574f66d44c0587438c5cd2ca9ec036cf37f0b0de3ebb0c8d80d9a1672b079a95dac8b45a2e2f439ee36e2e48b8db192b550550564771bc377292cdb98a735bb4ffca3a5fdf47ccec8e3b4f77ce450ca314cf8d69fe8047a3f22878e20fcdaff19f79e7434a3c746ebefac0dca7bf7dfbc36328542a6edb820b046600432719855c908c5604614532916a51dc32363fdba353d22d40c25b264e141fc88e82de6f851fa0349af1889da620490914b38808c3880440e860248c3c16513f65ae35786fd00d2ec08206309203d9c12f92a808ca6b80254c19100d29401a447c5226ea72f6500697d00197b3be92355e5d713a3238999b16dc1a2646ac606e245d6be134c3ebc8d41b32bcfd0ec6ed1e3c48a97becfd8ffff8cf51750b65c46aa38fcb211ed36e06ddc30edc657387689ea5ae68c04575f54db8239f95583c21d259e3d51a9c80984574c3ab62bd2debfb351fa2b49df5f09d88a559dc9167f25e0247f69659ca9fc9586f82b6ec05f69f5fd9506dfb13c25f8bc593c83898168ef7819edb16790fea93656c29531b92dc3e9b631e7adb35c01e3727499d6e15008d849b3385d64ef9638319907d92dcef6af04245d64f6d8be210d990cdc472248b8432a9797f8f46523e3e668992de55ca7de35d729a1aa53e9b3b8ea53ba3241e5b634cec1ad82dbf229f257908c2c9ec50b0e635956966141f1157268c47b09e0bdc470e7254625ff212e1ae2bd9832f41c702bb4fca25bfb4b4174e61acb79826461243f15364c32fc34462ea121730a88b0635c868d7c0e5c2e0918c13f3ec1ee2049d102d7fe49ea16fc85002be94fc0ae8acafc3b702f455adcf7b5f2e46906e10294915cc077a9785d5d9574627f8904bb8a21f13edb8a7ed9063b20a15ccd22152117b762a0148b24c4e5c5ad7e469696ab344d799b2b4dffd1a6fc93fef49d8fcc2e2eb7e75d6fd5cd2e2fafcecdf6da6e6df6d1f6ba5a7db8d39eebd197f575e95fecb5bbb3bdd5ee34ded7ddca6acf2daeb87317967b8bd38b2bf3ed8b8a7f0c99def9fe2e0d55ed6e77b5ebf07f5b2cae3c5a4d567cacd310ed8a33e0e9bd73b32b0036476db4baacbb0ed8bdd98797a9e111374bfd0bedae9b5b5de97567e77a8aeb00e9eb77e0786e757ef191c7f744efe581e5fcd06b5cee63cfa9f44df21f4350bb47786176e551225777f1dc6cf771b7d47edcbd7fa1bde22163d7b32b1ebe62cd9ae66bddd5deeadceab2f3ff71488969ffff18e132651a3cdac61cb22ce9dd1756da17d70806ed50684aa83eb278b13d3ffdf0e3bdf63ab05cef752fcc097569ee1f349552ff05ee7357f400d00700008101010100204b21f3cba072cc493e70861540df4677b498b0505a8b8e2a346b85a0c2dd2fc4263c4a7d8629026c4eb594ad96fac2bfe5f8ffebb9c841c353920b7b8ec11abc0100d90778da8d563b8f1c4510eedbf7e37cf209d9e60808402496c0dcdaac4e8ece01090112afe83043ef74ed4e6b677a86ee9edd5b3b2121b049888d842c84c0c1456702eb20b036424242c2e00408800c24fe03d53db3f33a58e860b6bbeaebeaeaaaafaab7f55bff9d1a796df0e5798263c37cc89f2fbe657e1eb8c7cb92e0de5f83c1eded95e4fded2d08150faf5ea5237e69f7855db2d3c199e351e5915a339c0b900d4103681849dff5c09daa3818bc34ec5057f319d54036b6c640752cc1617c024a17515d1a6b2f945c2f48a3ab3d09ca0b7dd68ab9d097078d292cd4267e9c39f089a70faea351378c85563b11c8802bf44c383eccc0cf20cd39e55a9d31df4c766ee487eed4f528174e4425baab412ab2fd44400f1dab73046827567402f6ece195a73495139455b44ee4ead4bb1db3594b2a94b929fa51367179f0f4882adc00722dea6c6edb0798d3452a7fd60d858643ed8c2598c8297bf18227220efe2f948148a1851bbb515c72a47ce34cbbeec655133b0106781de0c9aa059f8f41f3200b19833148090c41870e1c465c528b9b73c1c2798a3a57b5c2c0cfe276de28b9f0b90027552b7e6375c085d35a0691f6ac7a7768c39351b2a4eabb54b8e0dba3486d2b597131b1f0b3553ab68cff9c15a9dec3adc83b0327b5764a645b3bbd7c77b2ce294f6a755cf4a278e473d7c1692b91a74e75d083a9b5d828596cb8218364a6175132eb4b782fe61202581d2b906ec926dcee4a2cd2302de6ec9354785ea52d5bd5900bda21ea652849adab4030243b676debdc60af83126d32d91c2d34a85341c20682e6d233ab41b8f02f154e6a05e4e9b897c2b319c990c52e3a859123b533d932bbdf76c276c527c2e4b21ceb4d8cd8aa8bb1b56dac6d90260d1b8db10c036bbaa54063abace4ba8ea2241c3da3f77980ddaa92bd2e7628c7629ab617f54c2527174b05a6ae8a8236da3229af186acd0293fea689c65e7716ccb0eb61a892b5e548eeca2475a55ec7d3d32658c78357533c329d62a2b5eda28a6cb492c93f3758e35524f9ac128236578e11276e742c286468aca330a42cf661ab98b783ebbd58643cafff27cf7b71c4685a678db575669c5f1543c3e0735af70bef07a975ec4a819b769132cbcc6379f1637c36f3278f7c7debe2cb1f7c7eadd434c8feb73fdd3bfaf4956223c0f1fcb4fec587792193fd4fee3cc31edc2956278e5f1fdd7cfc59566c1fbd39fc19d8d14999a138ee42707492b171f5c0afa848c877af9e78c7cb22f570ec3f77fb789951c882be4940930cf4f0d1db6fdc5f16528fe3ddaf0eee2fb324e3d8fb1e057942cd851ffef1fb8fc5fcd920f8af3f2e66c9fcffb84b7ff865b7ce875708c9ff60d8f137aa5a1fa900d00700001001010020742877c36a520b152b1337ea1ecd37b0c98ad07289c32fec392e7eebab9f0ac71f7bc8c718cfa75317b2e15702372a9222c4616783ee7b3f0ec6358f8c328eea00005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232201a99a59d87e06e09ec5b028a9cbb7749b4a5ad8819004365d02dc4379a8b72410000d00700001001010020058e23368b919493d6ac61d27f66b829a53893e88ddde857d3b82d913960960d22fa36f397752b98c295e3b31927f740127c0a99e76f8bfeea88f44466b8fbfd00005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220ef43112c6543b88db2283a2e077278c315ae2c84719a8b25f25cc88565fbea990000d0070000100101001f43fe868e263d8134cf705aa85e26ce78ebb058edd558865fa3d240f5cb9e50c2389e9c8276eac800b7233a552045b2e79124c97e5156a0649849cc7f5d09eee600005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232204a90c00d55454dc5b059055ca213579c6ea856967712a56017487886a4d4cc0f0000d0070000100101001f29e82b08ccf15e2187f29fea11ee3f4974f41b51e45b19f353348d8848b86fb71cadd88630456b7a1c60803c7b402487d41fbf18f0b0a13b4cca1f740447938300005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220e0fb64b1085cc5538970158d05a009c24e276fb94e1a0bf6a528b48fbc4ff5260000d0070000100101002047a8b784c3765b5c63ac52e3d8461b80bc2d3e3f62434f8accb277d9f2487cfd3c0728fcd26b5119a11288e5db46bc5b547877e220971609d1cef8cba443340800005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed32322068dcaa34c0517d19666e6b33add67351d8c5f69e999ca1e37931bc410a2974280000d007000010010100203e701fbafd4149bc95b55a6bfc3b78246f5c2668ccc05ed4059a36ceb38f140b31e3b69e15f2579571e5bde39e034947271599c200e540b3949112bef163074c00005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220ad9e3d8f650687709fd68f4b90b41f7d825a365b02c23a636cef88ac2ac00c430000d0070000100101001f0cc7352e60f4f8476783d6d1b48766a111c56fee2c1a552e76a75c92bc17de172f994ffc854c09717c904054819ca7a17379ddecaf531c439b35337ba099b81300005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232208ba52fe7a3956c5cd3a656a3174b931d3bb2abb45578befc59f283ecd816a4050000d0070000100101002040965063a83be2d53b36c8d7e0775f503c2caa1407e586314562aace52c272fe60659e196413a6c9db4168470bcabb9a5851121c10c7b665f363f6cd4d1e4bda00005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232202652f5f96006294109b3dd0bbde63693f55324af452b799ee137a81a905eed250000d0070000100101002074ea7468b2a031c4cd53bf10ec3ac66b0c4b5c8779e045f1ef8d9c7b116be649217ff340107d0163397b99918ee2ce822b66cd6fce7b385af97a04671136e2ee00005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220f0af56d2c5a48d60a4a5b5c903edfb7db3a736a94ed589d0b797df33ff9d3e1d0000d007000010010100204dfb21ca5140582379bc026792c16b4cf97827143a4a9cd99ae70b3e6016cd6316bcbb9f1cb1233f12a0bbcd9debafa64724d0459b5c8d3cb67ceddfb2e3962500005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232204e7bf348da00a945489b2a681749eb56f5de00b900014e137ddae39f48f69d670000d0070000100101002033446a3a94ade71dff3edb786259679487ab701bbc147490b1d4159fecf545fa22fee0698db16bf616465e5cebb985bfc4d9ed1ec4a55e38997dd4b4bbc427eb00005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232204fca8bd82bbd181e714e283f83e1b45d95ca5af40fb89ad3977b653c448f78c20000d0070000100101001f3f67edd35bf731a07f40c638e8812112cd7d1baa39ec7dac4a1b2f0c83ac8bd53689b56dba69a7386e3860a6f8976695ac0bc2b5dacae91080f1d54df2dac0c000005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220299dcb6af692324b899b39f16d5a530a33062804e41f09dc97e9f156b44767070000d0070000100101001f1e030564013603d54f9e983b63cd940f8ff09ae038b14813f4021bb0c09ebb640d90cb4f8d57be2809f492a51737b671a5f549d4efa8e7efdaeaa9663c09d1ad00005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220c3a6138c5061cf291310887c0b5c71fcaffeab90d5deb50d3b9e687cead450710000d007000010010100205cea642eecf05568ce8c5564e63349eea3b816108914ba2ab5efffbb8ea467265f0b6d474f03ed02a3bf529fd6e55a595cbf8dd1adf4311cb9c51e862f8a535400005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232205443fcf88330c586bc0e5f3dee10e7f63c76c00249c87fe4fbf7f38c082006b40000d0070000100101001f4556076cc86e0840bf69664f1ef8fcd4d91abda313d08e7840d24ba45cb429cf12b7d3a1f64250c19d1b975e7b107853beff70ebfc4c27c44f825dc05cdc9cd600005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220bcd2a26394b36614fd4894241d3c451ab0f6fd110958c3423073621a70826e990000d0070000100101001f354d903ad0f2c6cc9d9a377d681ffaa00475d1e559e48074b4c8cce3111d5c172903b2f179ad4d736dda4e7d1b6a859baeab9dde5e5e495ce09733ec4650634400005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220d528b9f6e9693f45ed277af93474fd473ce7d831dae2180cca35d907bd10cb400000d0070000100101001f1766fa716a828da244c9ce52919b7a19acb38dbd110d1bb0039bb2477c17e4465dceecb8330ed5ee9de1330930dfcfa1a5e8149ce8536a82c0093642adf7328200005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232206bcb40a24e49c26d0a60513b6aeb8551d264e4717f306b81a37a5afb3b47cedc0000d00700001001010020488923db1c78fa430a3a9eab75f4ee467c7b9a3d3b4eb3bd08e183c82ef79b9102a4d2a7d1ec79c96b404911ae1b10f579bd82a660011c1ca2b872b30ef7dcac00005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed32322035c2186cc36f7bb4aeaf4487b36e57039ccf45a9136aa856a5d569ecca55ef2b0000d0070000100101002031ca6aeda725c01ed6aa6199dd2767930803051d3bc2897956bc9f97f8db5abf3bf243b775b4020f0c96d8ad197d591d11f8a51760c19fdc81134eff06a1941f00005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed32322098c4175db53ed27e7911a1b5adf0e7db0fc96c2cae172cf594dfa9a742ca9e880000d0070000100101001f03670020103e7843695b5c83b87d3183f9c0b21ee28f46ce80c061311835f436600f684f91df8e1e4a21233f1f97505a789189b4272a0d8bc2666891f93298e000005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220a9cb566f982145ebccca8dcb6d2fe89b91dbd445c32ecef873cdc5d594279fcc000001 +DMLOG APPLIED_TRANSACTION 3 163cea51d12265063bf77437db57c2e9c1ef93dcb7205808665ab4cfc9bc7be103000000023b3d4b01000000034097ed362ec2a0eecb45779129e26e7b0c11ee9149a27c43f4e71bf10100d007000010000000000000000080000000000000000001010000010000000000ea30559ce3cf675d2f9ecbf427930685680d9117ba72ed64d5d7474fb50c8768a921d218000000000000001800000000000000010000000000ea3055180000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220fce57d2331667353a0eac6b4209b67b843a7262a848af0a49a6e2fa9f6584eb400000000000000000000163cea51d12265063bf77437db57c2e9c1ef93dcb7205808665ab4cfc9bc7be103000000023b3d4b01000000034097ed362ec2a0eecb45779129e26e7b0c11ee9149a27c43f4e71bf10000000000000000 +DMLOG CREATION_OP ROOT 0 +DMLOG FEATURE_OP PRE_ACTIVATE 0 09e86cb0accf8d81c9e85d34bea4b925ae936626d00c984e4691186891f5bc16 {"feature_digest":"09e86cb0accf8d81c9e85d34bea4b925ae936626d00c984e4691186891f5bc16","subjective_restrictions":{"enabled":true,"preactivation_required":true,"earliest_allowed_activation_time":"1970-01-01T00:00:00.000"},"description_digest":"a857eeb932774c511a40efb30346ec01bfb7796916b54c3c69fe7e5fb70d5cba","dependencies":["fce57d2331667353a0eac6b4209b67b843a7262a848af0a49a6e2fa9f6584eb4"],"protocol_feature_type":"builtin","specification":[{"name":"builtin_feature_codename","value":"DISABLE_DEFERRED_TRXS_STAGE_2"}]} +DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304002,"value_ex":56859,"consumed":9824},"cpu_usage":{"last_ordinal":1262304002,"value_ex":267382,"consumed":46101},"ram_usage":180802} +DMLOG APPLIED_TRANSACTION 3 0ba60f7118b04f4981554d97fcd15865c4ad6633f4e78f216d034a9ef6394e7f03000000023b3d4b01000000034097ed362ec2a0eecb45779129e26e7b0c11ee9149a27c43f4e71bf10100d007000010000000000000000080000000000000000001010000010000000000ea3055b76acc0a0bc58aae737e94451f7f38e72ff2e66e45b1838f558f7266783bf69719000000000000001900000000000000010000000000ea3055190000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed32322009e86cb0accf8d81c9e85d34bea4b925ae936626d00c984e4691186891f5bc16000000000000000000000ba60f7118b04f4981554d97fcd15865c4ad6633f4e78f216d034a9ef6394e7f03000000023b3d4b01000000034097ed362ec2a0eecb45779129e26e7b0c11ee9149a27c43f4e71bf10000000000000000 +DMLOG CREATION_OP ROOT 0 +DMLOG FEATURE_OP PRE_ACTIVATE 0 8cb6dd1e5607208331eb5983141e159c75a597413887e80e8a9a4b715a507eb7 {"feature_digest":"8cb6dd1e5607208331eb5983141e159c75a597413887e80e8a9a4b715a507eb7","subjective_restrictions":{"enabled":true,"preactivation_required":true,"earliest_allowed_activation_time":"1970-01-01T00:00:00.000"},"description_digest":"bc726a24928ea2d71ba294b70c5c9efc515c1542139bcf9e42f8bc174f2e72ff","dependencies":[],"protocol_feature_type":"builtin","specification":[{"name":"builtin_feature_codename","value":"INSTANT_FINALITY"}]} +DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304002,"value_ex":57600,"consumed":9952},"cpu_usage":{"last_ordinal":1262304002,"value_ex":278957,"consumed":48101},"ram_usage":180802} +DMLOG APPLIED_TRANSACTION 3 4b44a1f39c39048a1fa53c7070cea6a57f0afbb982370bcaa03d4d735797778c03000000023b3d4b01000000034097ed362ec2a0eecb45779129e26e7b0c11ee9149a27c43f4e71bf10100d007000010000000000000000080000000000000000001010000010000000000ea30551b7179e66f67158e50d547f27fb19f7660419a39880b1e596665bf44d4ce7fe21a000000000000001a00000000000000010000000000ea30551a0000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232208cb6dd1e5607208331eb5983141e159c75a597413887e80e8a9a4b715a507eb7000000000000000000004b44a1f39c39048a1fa53c7070cea6a57f0afbb982370bcaa03d4d735797778c03000000023b3d4b01000000034097ed362ec2a0eecb45779129e26e7b0c11ee9149a27c43f4e71bf10000000000000000 +DMLOG RLIMIT_OP STATE UPD {"average_block_net_usage":{"last_ordinal":2,"value_ex":0,"consumed":0},"average_block_cpu_usage":{"last_ordinal":2,"value_ex":833334,"consumed":100},"pending_net_usage":9952,"pending_cpu_usage":48100,"total_net_weight":0,"total_cpu_weight":0,"total_ram_bytes":0,"virtual_net_limit":1049625,"virtual_cpu_limit":200200} +DMLOG RLIMIT_OP STATE UPD {"average_block_net_usage":{"last_ordinal":3,"value_ex":82933334,"consumed":9952},"average_block_cpu_usage":{"last_ordinal":3,"value_ex":401659723,"consumed":48101},"pending_net_usage":0,"pending_cpu_usage":0,"total_net_weight":0,"total_cpu_weight":0,"total_ram_bytes":0,"virtual_net_limit":1050675,"virtual_cpu_limit":200400} +DMLOG ACCEPTED_BLOCK 3 03000000030000000200000000000000010000000000ea3055000100000001000240e54a7b27e042b80a810153bec1dd166eef95fa69f6c9886ae283363bc2add8010000000000012d5b1b639d6ae94fcdd0536b224644931573d1ccb2a0c548613cd1feea18888b0200000000000000010000000000ea305503000000010000000000ea305502000000000100000001000240e54a7b27e042b80a810153bec1dd166eef95fa69f6c9886ae283363bc2add8010000000000034097ed362ec2a0eecb45779129e26e7b0c11ee9149a27c43f4e71bf1023b3d4b0000000000ea305500000000000213588be25132b4167ced6df22b5439e376d5a20284190bb94a43e3e8c771cad6c14e7b03f51048ccf8f52fa1b54ba7880c11722d0aa93f5b9c4bb66b95d4808edc7d96ceeb3a19d03945d89f369abb41036038cd59ea2f711ba52b48000000000000002006b85ad39d5019e1cd871ba7f9d4dbdec7256c7c2c0e027d595e1654c8a50c1765e994e897703222fa1971c76f2b578b4fb12f8e28f6b03e61bbecdba00d592f0000000029807708239aa7de914d3ed61e9009ab2280bfbc50f1d9769f27f8341ef26198000000000001010ec7e080177b2c02b278d5088611686b49d739925a92d9bfcacd7fc6b74053bd0001023b3d4b0000000000ea305500000000000213588be25132b4167ced6df22b5439e376d5a20284190bb94a43e3e8c771cad6c14e7b03f51048ccf8f52fa1b54ba7880c11722d0aa93f5b9c4bb66b95d4808edc7d96ceeb3a19d03945d89f369abb41036038cd59ea2f711ba52b48000000000000002006b85ad39d5019e1cd871ba7f9d4dbdec7256c7c2c0e027d595e1654c8a50c1765e994e897703222fa1971c76f2b578b4fb12f8e28f6b03e61bbecdba00d592f1800d0070000fb05010100203b7de491b51d3d74624078bc2c5dc4420985f0350afb6923a5585b5621750c9f126d7cff0efeade2068c7b618fc754b2abb5bff8cdb9bd0ecb4432b72ae1ed380100a82f78daed5c7b8c5ce755ff1ef7357b67e3ebc6d94c3609f9e662d0b8a4659bb8eb2575dbbddbc476694b9cca2dfea3b0bbd99d647776bdbb9e1da70e0adead081045158a7894b6405524a4d21424545aa8cacb0d0815a94891fa20414284ff2a025511a245ad54737ee77cf7ceeccb71f09a87545b9e7be77b9cef7ce79cef3cbf71f44fe94f1bf5d03d9f1951f447e343fdf3d87be873f2879efef473830dea77fff59e7bbef7f440d3bfd197d9f57368d1bfa54767949ab11b9736d48cd9b8840f7a0b372ed11f35136cf0436fe80dfac0b80dbc2afa67f84d6306e6063201ad97a8ff9234d00880f033d54c84469e48cd68b03c8b3ea54dd0909531c1fc52d0b0ed95c70e2dae4f3fd29eed5de8b6a767e77a8b8fcdf6daf32a42d7cd6bdd76d9548e51317aeaedd5f5c5d5e9d9f5f576b7a72c9aa273ed73ebed9e4af025c3b4d595e9f9d9deecf4fae2cfb4558d9b09defcf4409f1a2aa7cead3d2e53ebddf6f90b8b40e6426f41a568ba89e04eaf75171f5b5c6e3f4ac8d519393476dbebab17ba73ede9e5c5738bbd75358c9e70f6e155c24ae17d44a6aeaeadaeb7e7f1327f61aedd5d5737a1d3a1f3e1e5d5b9a5b985d9c595e9b5d9eeecb9768ffae9756e8956e29db9475f6918efa23e77a1db6daff4a67b8be7daea00d316339982ed81b579743afff0f4238b2bf3d38be347558696da34d17361b9b778af3a88ef0707693c3db73adf56868958aed36dcfb5097257d61a2280580ef09890d1fac2ec3d6f1c57af61e4a877bdb74a6445ffcd681aa6a60b6bf3e02dda0ed993275414abb8369444511c0f0d594b9f517c8b1e31237624a07ff4371cd123d60e51efd0adb7da86ff63ab8f46725b10ea353d34145aad7434623774b17959a51baaf8d45f568fb8a6c3d9b5b5e5c7d5eb6a07b42a745a7bfdd83d47c727ee7bd39b87fe66539f0854767bbaa9b5dd3093f2d7a9078655417f5be683f4a5c81ecb752737e3f44d5a9f9cccad539d22ee1417cfe76a9c1a9c29b29e53ef1ad64e4faa62e3c4b0a9dbb45007e81ff5e90e663b4d2fe83d39aca9bdf8cdcb2a33ce1e489d4d8d4ac7b5def8415a6e29a755c64d9d66d262f59651832ba175dc6cd2f3ad0a40313352c533b4f3ffd03ada2854d3601718b7043ccf3b757258611fef0076d96d07d2ecce62649cc0127ae5968b8d4e1e38ddc96ecbb17da75c405b74f67c6e4ed034553cd1c92da19207457c3ed70f0c1b0c21ac685a71b19387d4d78c9c75da192c1c776901daf9131d02648088f62d173b2e62184ec68434c5f29bca465367881c84970c54f4d1c22c80549d0a2430a126fe9ede4b742b469a9637a28be0ed843e6191fd00d024d49de6bd366d0a5a6777d2dc74429b0dde36f5df9e6bec7a5859225a9339fce1c9dc60ae39a894d39e26292146a426345d7a93f272c2484b6b9e2e1154e1a0398c01a6a8778011febd839629d7b3d95d34d54c62415e4c31a2584ca6381a31acea26051d200bf4245168a23feb1ca6d5d2043cd2d9e1eda8f8f61f4e43950da9f42744a85e22fae9c3a08b2e5e0021137ecde82da8ded0adb2d78ef257a75be822622d65756a7949d1bae92fd774c0846b1104fa0872b354c43fcee7e5eb2cceaa08c0b2a62194695a9245a3dc961b6c411509c9112f456fcd80799088f838bb54d8415018cf5c23410b00c783082a10f50e84dded3abb44840118013088481f4a76fd881cda17441ad78fc81dfb8288bb7e440eef0b22adeb47e4ee7d4164ecfa1139ba2f884c5c3f22c7f70591cb6a174cf45e9898014c4c05e33982a10750d17ba2a2050223a0592d1118361ae9778cd51be612eb3957aa3975c4aadc4cb9a78eab14d660aa456f43fc36466f357e9ba03728426c01e32d8f870db33cdef01bc66b7ec378b62d9fc883fbd4017a0b8ae4b1fbd44dfc96d1db30bf35e8ad8e193c2eaec645d5b8b01a17f0fa0d5edf1c57b70aee99c7e5f60a97d10a97db2a5c1abc0b8cbbb9dae36baa3d1eacf69809ce8a9118e10581c42db234bd1d1264d57dea2e2107b5fd4035eece6adc1d6459c844b286602bf4adefd3fe7f92f6da533efd522076fd194daed5619535e0fa38f56e78155bff121a57aefcf1b77ee7d73ffde2d44f929380af57ae7cf6db5fc35720b9b9b9f9fca7fff04f3e72cf43c356be5efe95ef50ef43c3817cddfc230c7ef770e22c7c910f12ba05b9544fd1d3d923f6297dccb263414ecb8f8ed693d42f71e55b1f7e71ea3dbcc4339f7cf1c57ff8e047bef6f98d3ed0bfffbddfa0efef1e8e05ea3c3dc8c59e119833c76c4b409205c8de305a8f539ef639d94705e5437ffbf257805a244096e9419a6541802c1cb3ce03719decded17a94fab537bffde13e10c0fc28808402e4494c08c8c5f6fbdba4fd251e4ed2c9de385a0f531979861ee1b8392de34e1fb3137ed844273b365a0ffcb01e3da271b326c3d68ed9861fd6e8643f365ab77ed83be9118f9b5332ecd4313be98791a20538e3c73d013cc6cd451977f198cdfcb8ac931d1fad6b3fec7df4a88d9bb332ecec313be6878d75b2b78c52f891dd415f9ed190a6d7283eb3194e0bf99b27b324fdb2d131046c8ce4ab19389231e8eea0198a568f24ccc8823c7e4064cec5c507d8f58eb3db9a86d1a0a6039d62ed3cbbc37007e32c240f3f2848d65b2e98526010b5769ab010ae038f30f1b0e277b025f8f92fc012a09310635fd260540df077b6d2bce4647f5eea12572b34fae9bc53d4007b414c1f3719351cc2e45a47da98c714f14094031716fa8220d5eabc4ea926751db1ae09479bbacec3d7e6082462fb1461abca25c5157dde4507b51a2086c978c36344650a3d2378e671fa73468757a36d79743d753d30ed296b52d09ec5612f0283b22d4fd91dd44c795b25e102f218997a4c0750d45614c9842289d0ac0145dae9d3e6886dbd0245a283666f5a0cf7652e3b927edb50e84a24f9b8b911f2f6450ad6157d667654f6725c1e13781095c6095c40a756866653a3bc550e555cd032934211daf1045303a7069d09efb9ea4c8ed96760595ee05e97205a1662d29e4bb22a1c7fa6ae9359cfe89cb9c55d2f6881ee71268c99452f700b562d5b1a1523aec20199181db4bb70e1e346d870f3e0d1c79cac96feaa3511197562c7a6be91227a4a1e93f2382d8fb3c29aa3f218ab38045e819050a478bb8c2816e738036dbe496c7b2b734d58365171658c8f34c2d75d5846ebcdc8eced1c6b0d722c138e3564d24cae847bf4581304060ec559728fe871baa9f138454a891e93cda1abf069c8c125c2790976e1d4a6de7960ee4ebf6775c207e6867108142639236748b4227fcf8884fefb560ebe02cf66fa3cdbd4b229614a764ab856bb1ad78840bb706d53ced910b85613ae65c0d8d5ae81718cc54bb2c31a2ca4eaaf98418892b289d978cc2ec8db647f6dac54cd430309821d9c450e083949b2b45f31bbb673bbb9f7b9f5d2f05e4e35e586844ea48239adfc6095dd46019b2246227596a5a3900f24d5c897ec33dbed18927e2e14b3ff4db5b71e8e2b5d9c94ba38f1eb267d5d9c6c93aaa4b4fd7071f6949a44a4060a93c5252b46af76aa9f17f9a8ed38d5a72be161d1b986537d7a40386604cfb395626a99fbd91010518ab173cd9a77ad2db8572bbef6ec575ffbe030ab7ea44c3397c7d43ab6ec7d8b182e223fcef421e535c0d2a77032e9f85b56ebe8815339b682d93966a4d726348cef82e03b431009d0e9a53c06b221840833428f28fca9af13a231231a6e4174461ef38209a000d1b08f682888f2bc15993a2f324be42e6596e6cd88d6f1d0e22c4fa5fdf440fb99b23d19907119c6f957efacdd4fed792a6a1ab27f2015ce672d957a25426f3763619dfd083b3a2f3e074727ad952a33fd4598347de34ddae92d7af1ecdede06fb1ba52dfb22f46243ccbad8b2c957f040763767c99ee6ec2a0ec8cc80ffb1b6c5b5d8d59c5d456f95562cbc8a15bb8c8481bec479f2cb8a83576477103b2134297833766a03e859f16345c3e5014e2ce144f8fbe347e87338f7d17ff9cc37de40bccf5038390595c4d11069b50772d522cd826f2758303e7b993d600b7e247ed49492c8ee0436d4cac3615d2f87d4113d31a3127ecb3a651878d20f7e6058a7a20b8abb3b790492d3493b816202e9da850e1020c1715cd2e19ac0034c1412e8900b3329c7b818a4a038c326b5442e947a482ee11feb6eff967ecc4af4b0a93df57212ab2306e25629e6b054cca1e742d857cce136e90dbd62862e15511a70ca4eeda2a343d6d1c66ba3ad815acb1c45be8e75370825dac2727c717440afb364676ff3ca3de21e7a1b14e6ad2e40eca2bd1db718648f2a151f5d9be326fa1af179c04a964f23407ad373ff00fdbc66e20a9868a6e24b34d070054ab45329e15f30da6e38613b54129f42944b2cca25c1d2568a599fe40cc08a40086639cbca8bf9c04cb15c21c6dd3f90287bec23b44687a34186a6010df5a3dc6e83a6fb395d55ca871ec8e932b4f4dff50d2261b00709d51e2095b84c7b8084d0ecdfa6bf6e593346bcf1a069a6147c3bae9271dabb19d2f18e2ca7f470d0d4db7989efc2d471029d4b6e48579071e69a73cee2097b75459d7711f21379d4fbfd27096e54c49d664487980c1249ee79d2435ea9f20e12d9526d891c083a7af613b97950aaaa2e5ecadeeb7bcb8de5c949d699d0facebc0b03a983cc81613726c1eee85b728274a564f0835229d2eeb4f5cbd2495adaa14e7857b52a5bc14dd007466aba21a8e469a2b7d124d84a934068120dd224649a18a189014d42170dd0049ed95b0cb248f5bedcb868a9703bd0447291c8da1c40b3e93940be207c54a4a6b886bc7b117510e2401155977b7f1545d441506511065af8da8aa8bb2162b13bfbaa8ba8af0e9143fb8248e3fa11b9635f1071d78fc8e17d41a475fd88dcbd2f888c5d3f2247f7059189eb47e4f8be20b27b11752f4caeb188ba072aba84b05b11f5b7c52f0ff7d1fa243badcfa0a68d5cb2cdfa88ed89c5ba180a3b617822313ce4122f650f55db492aa32ac3c5b925e55d591f52c61c4103346f04d4499660a128307e701712259ca6a0686e2bb738620389fe53f74397cc27502417c677740825f24bab6b48755e104ec1521e88c7b8f1ce61d6e6e46052e81dba402e3489b3cf8fa03f5130266727d7127d87f065450042870b65e4efa896783641cea40b386e534211cd496d89d4789ce65d6a7642602ea55261d877e1a00417a5b0469efa6b46c81821b6fe0b6b62899edd12a79ce47a13416de4108f3b1855443db8d34456556e6d69dc1c433585c2a0f0a4bfcf147074c48d4027e4ea1c9132aceea269dcb2cb0ee54c30d0ed0301b22bf0edfa910ba49183f2e21b12d20588700a0d3bcc63b343a374ba98ce0a914bc8ac629a6cad8684a5810d61c3622925253cf062a7b86bcbd8d82585e3b1a0d551445308dce98108b526112af5d4ab6b75779010321fe9dd61c70f725aa32665158d143697eb10a2b01cc41c82e32d92405471e94a3e90612401c97eca45083c25b8268fb4d1d41e0ce8076632174bd2a67fa5ad2106a2649c079c11d2888b9504c57fc69b03ba4896dcfc1037be2c3b66998e24f0e18f983d667203d9e6e771760b4d8c789c4cfcd873c20fe2dfe94e19df97c5a6b314ac09050981a3ac1d5bd9ad0c0195f7337251b13375c94553fa09faf8d9f7de4e6c232e51b0fa5d4d7e93d4cd82c39c1c3a46b84cf2da25da4ffb1217d21d874a0a071c1712754422ac5c05e864ef1b958188092d5f02909091a01ecd43cf46f60724b28fd9aa7b26c6583e41264cea100a706249b344b44b6622b49296b48eeb94c50a30904f218e9b5c4f844a75c8b130982d4c948a59fa211b0a0b858d14ae8b0ae228c9ee0c4228a4b96bb72004210dc270e5d930600b1c3026c54f683635ab00d6fa688af860cb443a244c1583c0389a4a7e01d9bc3728f5641e4c4d3cf524498b2e363ad80cf5b1f9206340d0ab2081149a08de95e7fc098c40c9b084430c670cf840c2c30f80c1001c72a3194cc61aa744850e3d04b1b03d3ab8d9413ec822bd068f000b0550d7b21ea77848e6d0820405be34e44ba3c3bb979b21d294f9a6ac6c324898105f3eef85321bd08c03a944affa37399518f854a264b612a46b78e9665837e93605c7df919d97b17e9c682fbe3dbc5d7dd9d216f910179773b795c36d3596d57b7a3f85d95244a87095c41ae3ab3cbe7a2fd4522e197c1fc80d02f26553a9bb6d92b5975c9529ea3da1226175581e8e9d003afca4be5a223c8d1dd6b1ca4d86d089879b7c07a5515d1e6079e220f730fc4f674e6e99ea7c4a6fcbec5b315b97b3f59eb3ab0923db26f00ea026b3fed1701dc9cabe6d5492748924e97c0ed7882d6435fae7b86830703b4af160f1a12cd9b407799af2ae171cad3c821f620a5c698a59f511d988b0c5f7a8016e3f291dc2ab0777d1456fbf1dd503b80a996be23700e23d231d6c71ef05b7b3011d3bf7fefb062960728e82342d8b6b900cc5e50dbec311c38292e1586a4afa350f91f328e15902d5b4151ce636bcf6509cd8a85526bf902f5e62d5e00b4f7cc58ebdddca313462bd02c9e921b5ca387a6374204d9fd7261057f07f5de10d68ba6d6a8ec28b4a668ed804fecbeb540c5394c5d81d5f712a95e0a70ced28d8eedc5edb8e1a7e478d6bd851c38f7ba51d855e77e73bb7c585403f322b4766db062503831a25811a7bd801efdd8148311e194556f468346b4cab1ae221176535ef4aa65ff6d6eed590ea1a69b4cfc4317b11a74ca76571b9a9bfb6b2295454fcae08e7607b2565b3aaa404a2baab4a4a807d04be9262717acec8035703032e989c159d754a640147f079ae90f81a37d0872a65dff3ac04ce72a710f181af81841c78579d196a20b6ac8184acb2b8936f32c9302e78707dade56f56a20632263d6b825352ba0e16c569cb65eec0578e41c4c1dab154bf387e0dfaa5635b2e17c0a3adc0700c2faa861597e8700e1ffad5e320f5fa3b9b280b2c81e86e0616488598c1f5dbefe7769ac8451714c7a02d898f57d1edb4a36dea1dc96dafe17d65bcf82a3dd99b868e47bf293ef9d5676f19d0f2b401d6f296b53c59956552f441a5e80df39698a53c4dfd83ec68f9e6aab746f596f937291396399eb1dd6d848574f66d44c0587438c5cd2ca9ec036cf37f0b0de3ebb0c8d80d9a1672b079a95dac8b45a2e2f439ee36e2e48b8db192b550550564771bc377292cdb98a735bb4ffca3a5fdf47ccec8e3b4f77ce450ca314cf8d69fe8047a3f22878e20fcdaff19f79e7434a3c746ebefac0dca7bf7dfbc36328542a6edb820b046600432719855c908c5604614532916a51dc32363fdba353d22d40c25b264e141fc88e82de6f851fa0349af1889da620490914b38808c3880440e860248c3c16513f65ae35786fd00d2ec08206309203d9c12f92a808ca6b80254c19100d29401a447c5226ea72f6500697d00197b3be92355e5d713a3238999b16dc1a2646ac606e245d6be134c3ebc8d41b32bcfd0ec6ed1e3c48a97becfd8ffff8cf51750b65c46aa38fcb211ed36e06ddc30edc657387689ea5ae68c04575f54db8239f95583c21d259e3d51a9c80984574c3ab62bd2debfb351fa2b49df5f09d88a559dc9167f25e0247f69659ca9fc9586f82b6ec05f69f5fd9506dfb13c25f8bc593c83898168ef7819edb16790fea93656c29531b92dc3e9b631e7adb35c01e3727499d6e15008d849b3385d64ef9638319907d92dcef6af04245d64f6d8be210d990cdc472248b8432a9797f8f46523e3e668992de55ca7de35d729a1aa53e9b3b8ea53ba3241e5b634cec1ad82dbf229f257908c2c9ec50b0e635956966141f1157268c47b09e0bdc470e7254625ff212e1ae2bd9832f41c702bb4fca25bfb4b4174e61acb79826461243f15364c32fc34462ea121730a88b0635c868d7c0e5c2e0918c13f3ec1ee2049d102d7fe49ea16fc85002be94fc0ae8acafc3b702f455adcf7b5f2e46906e10294915cc077a9785d5d9574627f8904bb8a21f13edb8a7ed9063b20a15ccd22152117b762a0148b24c4e5c5ad7e469696ab344d799b2b4dffd1a6fc93fef49d8fcc2e2eb7e75d6fd5cd2e2fafcecdf6da6e6df6d1f6ba5a7db8d39eebd197f575e95fecb5bbb3bdd5ee34ded7ddca6acf2daeb87317967b8bd38b2bf3ed8b8a7f0c99def9fe2e0d55ed6e77b5ebf07f5b2cae3c5a4d567cacd310ed8a33e0e9bd73b32b0036476db4baacbb0ed8bdd98797a9e111374bfd0bedae9b5b5de97567e77a8aeb00e9eb77e0786e757ef191c7f744efe581e5fcd06b5cee63cfa9f44df21f4350bb47786176e551225777f1dc6cf771b7d47edcbd7fa1bde22163d7b32b1ebe62cd9ae66bddd5deeadceab2f3ff71488969ffff18e132651a3cdac61cb22ce9dd1756da17d70806ed50684aa83eb278b13d3ffdf0e3bdf63ab05cef752fcc097569ee1f349552ff05ee7357f400d00700008101010100204b21f3cba072cc493e70861540df4677b498b0505a8b8e2a346b85a0c2dd2fc4263c4a7d8629026c4eb594ad96fac2bfe5f8ffebb9c841c353920b7b8ec11abc0100d90778da8d563b8f1c4510eedbf7e37cf209d9e60808402496c0dcdaac4e8ece01090112afe83043ef74ed4e6b677a86ee9edd5b3b2121b049888d842c84c0c1456702eb20b036424242c2e00408800c24fe03d53db3f33a58e860b6bbeaebeaeaaaafaab7f55bff9d1a796df0e5798263c37cc89f2fbe657e1eb8c7cb92e0de5f83c1eded95e4fded2d08150faf5ea5237e69f7855db2d3c199e351e5915a339c0b900d4103681849dff5c09daa3818bc34ec5057f319d54036b6c640752cc1617c024a17515d1a6b2f945c2f48a3ab3d09ca0b7dd68ab9d097078d292cd4267e9c39f089a70faea351378c85563b11c8802bf44c383eccc0cf20cd39e55a9d31df4c766ee487eed4f528174e4425baab412ab2fd44400f1dab73046827567402f6ece195a73495139455b44ee4ead4bb1db3594b2a94b929fa51367179f0f4882adc00722dea6c6edb0798d3452a7fd60d858643ed8c2598c8297bf18227220efe2f948148a1851bbb515c72a47ce34cbbeec655133b0106781de0c9aa059f8f41f3200b19833148090c41870e1c465c528b9b73c1c2798a3a57b5c2c0cfe276de28b9f0b90027552b7e6375c085d35a0691f6ac7a7768c39351b2a4eabb54b8e0dba3486d2b597131b1f0b3553ab68cff9c15a9dec3adc83b0327b5764a645b3bbd7c77b2ce294f6a755cf4a278e473d7c1692b91a74e75d083a9b5d828596cb8218364a6175132eb4b782fe61202581d2b906ec926dcee4a2cd2302de6ec9354785ea52d5bd5900bda21ea652849adab4030243b676debdc60af83126d32d91c2d34a85341c20682e6d233ab41b8f02f154e6a05e4e9b897c2b319c990c52e3a859123b533d932bbdf76c276c527c2e4b21ceb4d8cd8aa8bb1b56dac6d90260d1b8db10c036bbaa54063abace4ba8ea2241c3da3f77980ddaa92bd2e7628c7629ab617f54c2527174b05a6ae8a8236da3229af186acd0293fea689c65e7716ccb0eb61a892b5e548eeca2475a55ec7d3d32658c78357533c329d62a2b5eda28a6cb492c93f3758e35524f9ac128236578e11276e742c286468aca330a42cf661ab98b783ebbd58643cafff27cf7b71c4685a678db575669c5f1543c3e0735af70bef07a975ec4a819b769132cbcc6379f1637c36f3278f7c7debe2cb1f7c7eadd434c8feb73fdd3bfaf4956223c0f1fcb4fec587792193fd4fee3cc31edc2956278e5f1fdd7cfc59566c1fbd39fc19d8d14999a138ee42707492b171f5c0afa848c877af9e78c7cb22f570ec3f77fb789951c882be4940930cf4f0d1db6fdc5f16528fe3ddaf0eee2fb324e3d8fb1e057942cd851ffef1fb8fc5fcd920f8af3f2e66c9fcffb84b7ff865b7ce875708c9ff60d8f137aa5a1fa900d00700001001010020742877c36a520b152b1337ea1ecd37b0c98ad07289c32fec392e7eebab9f0ac71f7bc8c718cfa75317b2e15702372a9222c4616783ee7b3f0ec6358f8c328eea00005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232201a99a59d87e06e09ec5b028a9cbb7749b4a5ad8819004365d02dc4379a8b72410000d00700001001010020058e23368b919493d6ac61d27f66b829a53893e88ddde857d3b82d913960960d22fa36f397752b98c295e3b31927f740127c0a99e76f8bfeea88f44466b8fbfd00005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220ef43112c6543b88db2283a2e077278c315ae2c84719a8b25f25cc88565fbea990000d0070000100101001f43fe868e263d8134cf705aa85e26ce78ebb058edd558865fa3d240f5cb9e50c2389e9c8276eac800b7233a552045b2e79124c97e5156a0649849cc7f5d09eee600005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232204a90c00d55454dc5b059055ca213579c6ea856967712a56017487886a4d4cc0f0000d0070000100101001f29e82b08ccf15e2187f29fea11ee3f4974f41b51e45b19f353348d8848b86fb71cadd88630456b7a1c60803c7b402487d41fbf18f0b0a13b4cca1f740447938300005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220e0fb64b1085cc5538970158d05a009c24e276fb94e1a0bf6a528b48fbc4ff5260000d0070000100101002047a8b784c3765b5c63ac52e3d8461b80bc2d3e3f62434f8accb277d9f2487cfd3c0728fcd26b5119a11288e5db46bc5b547877e220971609d1cef8cba443340800005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed32322068dcaa34c0517d19666e6b33add67351d8c5f69e999ca1e37931bc410a2974280000d007000010010100203e701fbafd4149bc95b55a6bfc3b78246f5c2668ccc05ed4059a36ceb38f140b31e3b69e15f2579571e5bde39e034947271599c200e540b3949112bef163074c00005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220ad9e3d8f650687709fd68f4b90b41f7d825a365b02c23a636cef88ac2ac00c430000d0070000100101001f0cc7352e60f4f8476783d6d1b48766a111c56fee2c1a552e76a75c92bc17de172f994ffc854c09717c904054819ca7a17379ddecaf531c439b35337ba099b81300005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232208ba52fe7a3956c5cd3a656a3174b931d3bb2abb45578befc59f283ecd816a4050000d0070000100101002040965063a83be2d53b36c8d7e0775f503c2caa1407e586314562aace52c272fe60659e196413a6c9db4168470bcabb9a5851121c10c7b665f363f6cd4d1e4bda00005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232202652f5f96006294109b3dd0bbde63693f55324af452b799ee137a81a905eed250000d0070000100101002074ea7468b2a031c4cd53bf10ec3ac66b0c4b5c8779e045f1ef8d9c7b116be649217ff340107d0163397b99918ee2ce822b66cd6fce7b385af97a04671136e2ee00005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220f0af56d2c5a48d60a4a5b5c903edfb7db3a736a94ed589d0b797df33ff9d3e1d0000d007000010010100204dfb21ca5140582379bc026792c16b4cf97827143a4a9cd99ae70b3e6016cd6316bcbb9f1cb1233f12a0bbcd9debafa64724d0459b5c8d3cb67ceddfb2e3962500005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232204e7bf348da00a945489b2a681749eb56f5de00b900014e137ddae39f48f69d670000d0070000100101002033446a3a94ade71dff3edb786259679487ab701bbc147490b1d4159fecf545fa22fee0698db16bf616465e5cebb985bfc4d9ed1ec4a55e38997dd4b4bbc427eb00005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232204fca8bd82bbd181e714e283f83e1b45d95ca5af40fb89ad3977b653c448f78c20000d0070000100101001f3f67edd35bf731a07f40c638e8812112cd7d1baa39ec7dac4a1b2f0c83ac8bd53689b56dba69a7386e3860a6f8976695ac0bc2b5dacae91080f1d54df2dac0c000005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220299dcb6af692324b899b39f16d5a530a33062804e41f09dc97e9f156b44767070000d0070000100101001f1e030564013603d54f9e983b63cd940f8ff09ae038b14813f4021bb0c09ebb640d90cb4f8d57be2809f492a51737b671a5f549d4efa8e7efdaeaa9663c09d1ad00005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220c3a6138c5061cf291310887c0b5c71fcaffeab90d5deb50d3b9e687cead450710000d007000010010100205cea642eecf05568ce8c5564e63349eea3b816108914ba2ab5efffbb8ea467265f0b6d474f03ed02a3bf529fd6e55a595cbf8dd1adf4311cb9c51e862f8a535400005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232205443fcf88330c586bc0e5f3dee10e7f63c76c00249c87fe4fbf7f38c082006b40000d0070000100101001f4556076cc86e0840bf69664f1ef8fcd4d91abda313d08e7840d24ba45cb429cf12b7d3a1f64250c19d1b975e7b107853beff70ebfc4c27c44f825dc05cdc9cd600005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220bcd2a26394b36614fd4894241d3c451ab0f6fd110958c3423073621a70826e990000d0070000100101001f354d903ad0f2c6cc9d9a377d681ffaa00475d1e559e48074b4c8cce3111d5c172903b2f179ad4d736dda4e7d1b6a859baeab9dde5e5e495ce09733ec4650634400005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220d528b9f6e9693f45ed277af93474fd473ce7d831dae2180cca35d907bd10cb400000d0070000100101001f1766fa716a828da244c9ce52919b7a19acb38dbd110d1bb0039bb2477c17e4465dceecb8330ed5ee9de1330930dfcfa1a5e8149ce8536a82c0093642adf7328200005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232206bcb40a24e49c26d0a60513b6aeb8551d264e4717f306b81a37a5afb3b47cedc0000d00700001001010020488923db1c78fa430a3a9eab75f4ee467c7b9a3d3b4eb3bd08e183c82ef79b9102a4d2a7d1ec79c96b404911ae1b10f579bd82a660011c1ca2b872b30ef7dcac00005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed32322035c2186cc36f7bb4aeaf4487b36e57039ccf45a9136aa856a5d569ecca55ef2b0000d0070000100101002031ca6aeda725c01ed6aa6199dd2767930803051d3bc2897956bc9f97f8db5abf3bf243b775b4020f0c96d8ad197d591d11f8a51760c19fdc81134eff06a1941f00005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed32322098c4175db53ed27e7911a1b5adf0e7db0fc96c2cae172cf594dfa9a742ca9e880000d0070000100101001f184aad2b65730f7485957642fa1688c66e8ece7827ee2e8e01f8bc904cedd8ec5462c12a1e3c6cd41f4a15a350ec8575bb05e9597f4316ff73a4e1066aeab3d500005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220fce57d2331667353a0eac6b4209b67b843a7262a848af0a49a6e2fa9f6584eb40000d0070000100101002041c996b52c4bdbbc4fbdaf707dd01e74c46c51ce2c8e10e174e12502cb6be3f23e2d44e8e8802e970bc5ccfc4d056e400c92a56667183c37e0f79fbe77540a0000005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed32322009e86cb0accf8d81c9e85d34bea4b925ae936626d00c984e4691186891f5bc160000d0070000100101002064bee652fda3828128a5e42da08c65127b9e247662507ed6b46d8d18ecf73afd3313c096184a70a88fad68232faa6438a23eb399cfeeb9b18e044f94ffa6049f00005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232208cb6dd1e5607208331eb5983141e159c75a597413887e80e8a9a4b715a507eb7000001 DMLOG START_BLOCK 4 DMLOG FEATURE_OP ACTIVATE 1a99a59d87e06e09ec5b028a9cbb7749b4a5ad8819004365d02dc4379a8b7241 {"feature_digest":"1a99a59d87e06e09ec5b028a9cbb7749b4a5ad8819004365d02dc4379a8b7241","subjective_restrictions":{"enabled":true,"preactivation_required":true,"earliest_allowed_activation_time":"1970-01-01T00:00:00.000"},"description_digest":"f3c3d91c4603cde2397268bfed4e662465293aab10cd9416db0d442b8cec2949","dependencies":[],"protocol_feature_type":"builtin","specification":[{"name":"builtin_feature_codename","value":"ONLY_LINK_TO_EXISTING_PERMISSION"}]} DMLOG FEATURE_OP ACTIVATE ef43112c6543b88db2283a2e077278c315ae2c84719a8b25f25cc88565fbea99 {"feature_digest":"ef43112c6543b88db2283a2e077278c315ae2c84719a8b25f25cc88565fbea99","subjective_restrictions":{"enabled":true,"preactivation_required":true,"earliest_allowed_activation_time":"1970-01-01T00:00:00.000"},"description_digest":"9908b3f8413c8474ab2a6be149d3f4f6d0421d37886033f27d4759c47a26d944","dependencies":[],"protocol_feature_type":"builtin","specification":[{"name":"builtin_feature_codename","value":"REPLACE_DEFERRED"}]} @@ -150,41 +158,43 @@ DMLOG FEATURE_OP ACTIVATE d528b9f6e9693f45ed277af93474fd473ce7d831dae2180cca35d9 DMLOG FEATURE_OP ACTIVATE 6bcb40a24e49c26d0a60513b6aeb8551d264e4717f306b81a37a5afb3b47cedc {"feature_digest":"6bcb40a24e49c26d0a60513b6aeb8551d264e4717f306b81a37a5afb3b47cedc","subjective_restrictions":{"enabled":true,"preactivation_required":true,"earliest_allowed_activation_time":"1970-01-01T00:00:00.000"},"description_digest":"68d6405cb8df3de95bd834ebb408196578500a9f818ff62ccc68f60b932f7d82","dependencies":[],"protocol_feature_type":"builtin","specification":[{"name":"builtin_feature_codename","value":"CRYPTO_PRIMITIVES"}]} DMLOG FEATURE_OP ACTIVATE 35c2186cc36f7bb4aeaf4487b36e57039ccf45a9136aa856a5d569ecca55ef2b {"feature_digest":"35c2186cc36f7bb4aeaf4487b36e57039ccf45a9136aa856a5d569ecca55ef2b","subjective_restrictions":{"enabled":true,"preactivation_required":true,"earliest_allowed_activation_time":"1970-01-01T00:00:00.000"},"description_digest":"e5d7992006e628a38c5e6c28dd55ff5e57ea682079bf41fef9b3cced0f46b491","dependencies":[],"protocol_feature_type":"builtin","specification":[{"name":"builtin_feature_codename","value":"GET_BLOCK_NUM"}]} DMLOG FEATURE_OP ACTIVATE 98c4175db53ed27e7911a1b5adf0e7db0fc96c2cae172cf594dfa9a742ca9e88 {"feature_digest":"98c4175db53ed27e7911a1b5adf0e7db0fc96c2cae172cf594dfa9a742ca9e88","subjective_restrictions":{"enabled":true,"preactivation_required":true,"earliest_allowed_activation_time":"1970-01-01T00:00:00.000"},"description_digest":"01969c44de35999b924095ae7f50081a7f274409fdbccb9fc54fa7836c76089c","dependencies":[],"protocol_feature_type":"builtin","specification":[{"name":"builtin_feature_codename","value":"BLS_PRIMITIVES"}]} -DMLOG FEATURE_OP ACTIVATE a9cb566f982145ebccca8dcb6d2fe89b91dbd445c32ecef873cdc5d594279fcc {"feature_digest":"a9cb566f982145ebccca8dcb6d2fe89b91dbd445c32ecef873cdc5d594279fcc","subjective_restrictions":{"enabled":true,"preactivation_required":true,"earliest_allowed_activation_time":"1970-01-01T00:00:00.000"},"description_digest":"bc726a24928ea2d71ba294b70c5c9efc515c1542139bcf9e42f8bc174f2e72ff","dependencies":[],"protocol_feature_type":"builtin","specification":[{"name":"builtin_feature_codename","value":"INSTANT_FINALITY"}]} +DMLOG FEATURE_OP ACTIVATE fce57d2331667353a0eac6b4209b67b843a7262a848af0a49a6e2fa9f6584eb4 {"feature_digest":"fce57d2331667353a0eac6b4209b67b843a7262a848af0a49a6e2fa9f6584eb4","subjective_restrictions":{"enabled":true,"preactivation_required":true,"earliest_allowed_activation_time":"1970-01-01T00:00:00.000"},"description_digest":"440c3efaaab212c387ce967c574dc813851cf8332d041beb418dfaf55facd5a9","dependencies":[],"protocol_feature_type":"builtin","specification":[{"name":"builtin_feature_codename","value":"DISABLE_DEFERRED_TRXS_STAGE_1"}]} +DMLOG FEATURE_OP ACTIVATE 09e86cb0accf8d81c9e85d34bea4b925ae936626d00c984e4691186891f5bc16 {"feature_digest":"09e86cb0accf8d81c9e85d34bea4b925ae936626d00c984e4691186891f5bc16","subjective_restrictions":{"enabled":true,"preactivation_required":true,"earliest_allowed_activation_time":"1970-01-01T00:00:00.000"},"description_digest":"a857eeb932774c511a40efb30346ec01bfb7796916b54c3c69fe7e5fb70d5cba","dependencies":["fce57d2331667353a0eac6b4209b67b843a7262a848af0a49a6e2fa9f6584eb4"],"protocol_feature_type":"builtin","specification":[{"name":"builtin_feature_codename","value":"DISABLE_DEFERRED_TRXS_STAGE_2"}]} +DMLOG FEATURE_OP ACTIVATE 8cb6dd1e5607208331eb5983141e159c75a597413887e80e8a9a4b715a507eb7 {"feature_digest":"8cb6dd1e5607208331eb5983141e159c75a597413887e80e8a9a4b715a507eb7","subjective_restrictions":{"enabled":true,"preactivation_required":true,"earliest_allowed_activation_time":"1970-01-01T00:00:00.000"},"description_digest":"bc726a24928ea2d71ba294b70c5c9efc515c1542139bcf9e42f8bc174f2e72ff","dependencies":[],"protocol_feature_type":"builtin","specification":[{"name":"builtin_feature_codename","value":"INSTANT_FINALITY"}]} DMLOG CREATION_OP ROOT 0 -DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304003,"value_ex":56117,"consumed":1},"cpu_usage":{"last_ordinal":1262304003,"value_ex":256384,"consumed":101},"ram_usage":180802} -DMLOG TRX_OP CREATE onblock 4d5e4d90e4202f63d5763bb7dca7fcd081b155306a82f20a9acce09df0e5c2d8 0000000000000000000000000000010000000000ea305500000000221acfa4010000000000ea305500000000a8ed323274023b3d4b0000000000ea305500000000000213588be25132b4167ced6df22b5439e376d5a20284190bb94a43e3e815c39c909387122a322a319e68e2a400273172919552ac6944509ba2ec812d1fde4254975a4ef4af4d3829f170281c6011578a9828a798eeaab84e11450c712e000000000000000000 -DMLOG APPLIED_TRANSACTION 4 4d5e4d90e4202f63d5763bb7dca7fcd081b155306a82f20a9acce09df0e5c2d804000000033b3d4b0100000004f5b1c8962f98b2d6155f6d21977938d545d83ef187d93aaf83e483e501006400000000000000000000000000000000000000000001010000010000000000ea30551f4b48aa5b23f57381aca9e958853d170378813437993dbb6599a35510d8c8d119000000000000001900000000000000010000000000ea3055190000000000000001010000000000ea30550000000000ea305500000000221acfa4010000000000ea305500000000a8ed323274023b3d4b0000000000ea305500000000000213588be25132b4167ced6df22b5439e376d5a20284190bb94a43e3e815c39c909387122a322a319e68e2a400273172919552ac6944509ba2ec812d1fde4254975a4ef4af4d3829f170281c6011578a9828a798eeaab84e11450c712e000000000000000000000000000000004d5e4d90e4202f63d5763bb7dca7fcd081b155306a82f20a9acce09df0e5c2d804000000033b3d4b0100000004f5b1c8962f98b2d6155f6d21977938d545d83ef187d93aaf83e483e50000000000000000 +DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304003,"value_ex":57599,"consumed":1},"cpu_usage":{"last_ordinal":1262304003,"value_ex":279534,"consumed":101},"ram_usage":180802} +DMLOG TRX_OP CREATE onblock 2194e185d9b96978f1f64e0b6d85c143f8ce43d0a01e84f21c14fcdaf84f8a6b 0000000000000000000000000000010000000000ea305500000000221acfa4010000000000ea305500000000a8ed323274023b3d4b0000000000ea305500000000000213588be25132b4167ced6df22b5439e376d5a20284190bb94a43e3e8c771cad6c14e7b03f51048ccf8f52fa1b54ba7880c11722d0aa93f5b9c4bb66b95d4808edc7d96ceeb3a19d03945d89f369abb41036038cd59ea2f711ba52b48000000000000000000 +DMLOG APPLIED_TRANSACTION 4 2194e185d9b96978f1f64e0b6d85c143f8ce43d0a01e84f21c14fcdaf84f8a6b04000000033b3d4b010000000422c55bcc9df846ced4de43e8b8da9ad8057bcd95e32e31cac7e7546801006400000000000000000000000000000000000000000001010000010000000000ea3055454334eab0d5e354660b8a20073ee85c6da78a0a4cf7c2e7d1930d5af6f807cb1b000000000000001b00000000000000010000000000ea30551b0000000000000001010000000000ea30550000000000ea305500000000221acfa4010000000000ea305500000000a8ed323274023b3d4b0000000000ea305500000000000213588be25132b4167ced6df22b5439e376d5a20284190bb94a43e3e8c771cad6c14e7b03f51048ccf8f52fa1b54ba7880c11722d0aa93f5b9c4bb66b95d4808edc7d96ceeb3a19d03945d89f369abb41036038cd59ea2f711ba52b48000000000000000000000000000000002194e185d9b96978f1f64e0b6d85c143f8ce43d0a01e84f21c14fcdaf84f8a6b04000000033b3d4b010000000422c55bcc9df846ced4de43e8b8da9ad8057bcd95e32e31cac7e754680000000000000000 DMLOG CREATION_OP ROOT 0 DMLOG RAM_OP 0 eosio code update setcode eosio 199492 18690 -DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304003,"value_ex":95932,"consumed":6881},"cpu_usage":{"last_ordinal":1262304003,"value_ex":267959,"consumed":2101},"ram_usage":199492} -DMLOG APPLIED_TRANSACTION 4 f6e310259a2df1180a080592a90630cfdbffbd90a5144d2fb46801bbaff3aaec04000000033b3d4b0100000004f5b1c8962f98b2d6155f6d21977938d545d83ef187d93aaf83e483e50100d0070000dc060000000000000000e01a0000000000000001010000010000000000ea3055378d583c2888f3564b4db37bfb52d74d038e54fcc63aeb57cf27b03c001e97a51a000000000000001a00000000000000010000000000ea30551a0000000000000002010000000000ea30550000000000ea305500000040258ab2c2010000000000ea305500000000a8ed3232cb99010000000000ea30550000be99010061736d010000000198011960000060027f7f0060037f7f7f0060047e7e7e7e017f6000017e60047f7e7e7f0060057f7f7f7f7f017f60037f7f7f017f60027f7f017f60027f7f017e60057f7f7f7f7f0060067e7e7e7e7f7f017f60017e0060027e7f0060047e7e7e7e0060037e7f7f017e60017f0060017f017f6000017f60027f7e0060047f7e7f7f0060037e7e7e0060037f7e7f0060047f7f7f7f0060027e7e0002f0052403656e760b64625f66696e645f693634000303656e760c656f73696f5f617373657274000103656e761063757272656e745f7265636569766572000403656e760561626f7274000003656e760d6173736572745f736861323536000203656e760b6173736572745f73686131000203656e760d6173736572745f736861353132000203656e76106173736572745f726970656d64313630000203656e7606736861323536000203656e76095f5f6173686c746933000503656e760473686131000203656e7606736861353132000203656e7609726970656d64313630000203656e760b7265636f7665725f6b6579000603656e76207365745f626c6f636b636861696e5f706172616d65746572735f7061636b6564000103656e76066d656d637079000703656e76206765745f626c6f636b636861696e5f706172616d65746572735f7061636b6564000803656e76167365745f70726f706f7365645f70726f647563657273000903656e760c63757272656e745f74696d65000403656e76146765745f6163746976655f70726f647563657273000803656e76087072696e74735f6c000103656e76126173736572745f7265636f7665725f6b6579000a03656e760c64625f73746f72655f693634000b03656e760c726571756972655f61757468000c03656e760e7365745f70726976696c65676564000d03656e76137365745f7265736f757263655f6c696d697473000e03656e76197365745f70726f706f7365645f70726f6475636572735f6578000f03656e761370726561637469766174655f66656174757265001003656e76067072696e7473001003656e761469735f666561747572655f616374697661746564001103656e7610616374696f6e5f646174615f73697a65001203656e7610726561645f616374696f6e5f64617461000803656e7611656f73696f5f6173736572745f636f6465001303656e760a64625f6765745f693634000703656e760d64625f7570646174655f693634001403656e76087072696e7468657800010346450015111000111010100c100802101608020817010110011818181818181808011818181818080101180818181808000808010101080101010801010102080108020202020804050170010d0d05030100010616037f014180c0000b7f0041e2c5000b7f0041e2c5000b070901056170706c7900250912010041010b0c555657595a5b5d5e5f6465660aab8b0145040010280bdd03002000102d102420002001510440428080f9d4a98499dc9a7f200251044020002001103b05428080add68d959ba955200251044020002001103c05428080add68d95abd1ca00200251044020002001103d0542808080e8b2edc0d38b7f200251044020002001103e05428080add68db8baf154200251044020002001103f054280f8a6d4d2a8a1d3c1002002510440200020011040054280808080d4c4a2d942200251044020002001104105428080808080f798d9422002510440200020011044054280808080aefadeeaa47f2002510440200020011045054280808080b6f7d6d942200251044020002001104605428080b8f6a4979ad94220025104402000200110470542808080c093fad6d9422002510440200020011048054280808096cdebd4d942200251044020002001104c054280808080daac9bd6ba7f200251044020002001104e0542808080d0b2b3bb9932200251044020002001104f054290a9d9d9dd8c99d6ba7f2002510440200020011050052000428080808080c0ba98d500520440410042808080d9d3b3ed82ef0010200b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b05428080808080c0ba98d50020015104404280808080aefadeeaa47f2002510440410042818080d9d3b3ed82ef0010200b0b0b410010310b7201037f024020000d0041000f0b4100410028028c40200041107622016a220236028c404100410028028440220320006a410f6a4170712200360284400240200241107420004b0d004100200241016a36028c40200141016a21010b024020014000417f470d0041004190c00010010b20030b02000b3601017f230041106b2200410036020c4100200028020c280200410f6a417071220036028040410020003602844041003f0036028c400b3301027f2000410120001b2101024003402001102622000d01410021004100280284412202450d0120021100000c000b0b20000b0600200010270b05001003000b05001003000b0a0041002000370388410b4e01017f230041e0006b220124002001200141d8006a3602082001200141106a3602042001200141106a36020020012000102f1a200141106a200128020420012802006b100e200141e0006a24000ba20801027f02402000280208200028020422026b41074a0d0041004190c1001001200028020421020b200220014108100f1a2000200028020441086a2202360204200141086a21030240200028020820026b41034a0d0041004190c1001001200028020421020b200220034104100f1a2000200028020441046a22023602042001410c6a21030240200028020820026b41034a0d0041004190c1001001200028020421020b200220034104100f1a2000200028020441046a2202360204200141106a21030240200028020820026b41034a0d0041004190c1001001200028020421020b200220034104100f1a2000200028020441046a2202360204200141146a21030240200028020820026b41034a0d0041004190c1001001200028020421020b200220034104100f1a2000200028020441046a2202360204200141186a21030240200028020820026b41034a0d0041004190c1001001200028020421020b200220034104100f1a2000200028020441046a22023602042001411c6a21030240200028020820026b41034a0d0041004190c1001001200028020421020b200220034104100f1a2000200028020441046a2202360204200141206a21030240200028020820026b41034a0d0041004190c1001001200028020421020b200220034104100f1a2000200028020441046a2202360204200141246a21030240200028020820026b41034a0d0041004190c1001001200028020421020b200220034104100f1a2000200028020441046a2202360204200141286a21030240200028020820026b41034a0d0041004190c1001001200028020421020b200220034104100f1a2000200028020441046a22023602042001412c6a21030240200028020820026b41034a0d0041004190c1001001200028020421020b200220034104100f1a2000200028020441046a2202360204200141306a21030240200028020820026b41034a0d0041004190c1001001200028020421020b200220034104100f1a2000200028020441046a2202360204200141346a21030240200028020820026b41034a0d0041004190c1001001200028020421020b200220034104100f1a2000200028020441046a2202360204200141386a21030240200028020820026b41034a0d0041004190c1001001200028020421020b200220034104100f1a2000200028020441046a22023602042001413c6a21030240200028020820026b41034a0d0041004190c1001001200028020421020b200220034104100f1a2000200028020441046a2202360204200141c0006a21030240200028020820026b41014a0d0041004190c1001001200028020421020b200220034102100f1a2000200028020441026a2202360204200141c2006a21010240200028020820026b41014a0d0041004190c1001001200028020421020b200220014102100f1a2000200028020441026a36020420000bfa0103017f027e017f230041306b2203240020012002200341106a1008420021044110210141002102420021050340200341106a20026a21060240024020014102490d002005420886200420063100008422044238888421052001417f6a2101200442088621040c010b024020014101460d00410041a9c00010010b200020053703082000200420063100008437030041102101200041106a210042002104420021050b200241016a22024120470d000b024020014110460d00024020014102490d00200320042005200141037441786a1009200341086a2903002105200329030021040b20002004370300200020053703080b200341306a24000b02000b970503017f017e047f230041f0006b22032400200341206a4100360200200342003703182003427f37031020032000290300220437030820032004370300024002402004200442808080809aecb4ee312001100022004100480d00024020032000103322002802302003460d00410041c0c20010010b2003200236023020032000200341306a10340c010b024020041002510d004100418ac30010010b41c000102922004200370310200041286a22054200370300200041206a22064200370300200041186a220742003703002000200336023020002001370300200341306a20022802002208200228020420086b10302005200341306a41186a2903003703002006200341306a41106a29030037030020072003290338370300200020032903303703102003200341306a41286a3602682003200341306a360260200341306a20004108100f1a2003200341306a410872360264200341e0006a200041106a10351a2000200329030842808080809aecb4ee31200120002903002204200341306a412810162205360234024020042003290310540d002003427e200442017c2004427d561b3703100b200320003602602003200029030022043703302003200536022c02400240200328021c220220032802204f0d00200220053602102002200437030820034100360260200220003602002003200241186a36021c0c010b200341186a200341e0006a200341306a2003412c6a10360b20032802602100200341003602602000450d002000102a0b024020032802182205450d0002400240200328021c22002005470d00200521000c010b0340200041686a220028020021022000410036020002402002450d002002102a0b20052000470d000b200328021821000b2003200536021c2000102a0b200341f0006a24000b840603097f027e017f230041e0006b220221032002240002400240200028021822042000411c6a2802002205460d0002400340200541786a2802002001460d012004200541686a2205470d000c020b0b20042005460d00200541686a28020021060c010b024002400240024020014100410010212205417f4a0d00410041f3c20010010c010b2005418104490d010b200510262107410121080c010b20022005410f6a4170716b22072400410021080b20012007200510211a41c0001029220642003703102006420037030020062000360230200641186a4200370300200641206a4200370300200641286a42003703000240200541074b0d00410041d9c40010010b200620074108100f1a200741086a21040240200541786a411f4b0d00410041d9c40010010b200041186a2109200641106a210a200341c0006a20044120100f1a4200210b41102105200341206a2102410021044200210c0340200341c0006a20046a210d0240024020054102490d00200c420886200b200d31000084220b42388884210c2005417f6a2105200b420886210b0c010b024020054101460d00410041b6c50010010b2002200c3703082002200b200d3100008437030041102105200241106a21024200210b4200210c0b200441016a22044120470d000b024020054110460d00024020054102490d00200341086a200b200c200541037441786a1009200341106a290300210c2003290308210b0b2002200b3703002002200c3703080b200a2003290320370300200a41086a2003290328370300200a41186a200341206a41186a290300370300200a41106a200341206a41106a290300370300200620013602342003200636022020032006290300220b3703402003200136021c02400240200028021c2205200041206a2802004f0d00200520013602102005200b37030820034100360220200520063602002000200541186a36021c0c010b2009200341206a200341c0006a2003411c6a10360b02402008450d00200710270b20032802202105200341003602202005450d002005102a0b200341e0006a240020060b980203027f017e017f230041206b2203210420032400024020012802302000460d00410041bdc30010010b024010022000290300510d00410041ebc30010010b200129030021052004200228020022022802002206200228020420066b1030200141286a200441186a290300370300200141206a200441106a290300370300200141186a200429030837030020012004290300370310200141106a2102024020052001290300510d004100419ec40010010b200341506a220324002004200341286a36020820042003360200200320014108100f1a2004200341086a3602042004200210351a20012802344200200341281022024020052000290310540d002000427e200542017c2005427d561b3703100b200441206a24000bd20303017f027e017f230041206b220224002002200141186a29030022033c00172002200141086a29030022044220883c0003200220044228883c0002200220044230883c0001200220044238883c0000200220034220883c001320022003a722054108763a0016200220054110763a0015200220054118763a001420022004a722053a0007200220054108763a0006200220054110763a0005200220054118763a0004200220012903002204423886200442288642808080808080c0ff0083842004421886428080808080e03f8320044208864280808080f01f838484200442088842808080f80f832004421888428080fc07838420044228884280fe03832004423888848484370308200220012903102204423886200442288642808080808080c0ff0083842004421886428080808080e03f8320044208864280808080f01f838484200442088842808080f80f832004421888428080fc07838420044228884280fe03832004423888848484370318200220034230883c0011200220034228883c0012200220034238883c001002402000280208200028020422016b411f4a0d0041004188c2001001200028020421010b200120024120100f1a2000200028020441206a360204200241206a240020000b9a0301057f0240024002402000280204200028020022046b41186d220541016a220641abd5aad5004f0d0041aad5aad500210702400240200028020820046b41186d220441d4aad52a4b0d0020062004410174220720072006491b22070d0041002107410021040c010b200741186c102921040b20012802002106200141003602002004200541186c22086a2201200328020036021020012002290300370308200120063602002004200741186c6a2105200141186a21062000280204220220002802002207460d01200420086a41686a21010340200241686a220428020021032004410036020020012003360200200141086a200241706a2202290300370300200141106a200241086a280200360200200141686a21012004210220072004470d000b200141186a210120002802042107200028020021040c020b2000102c000b200721040b200020053602082000200636020420002001360200024020072004460d000340200741686a220728020021012007410036020002402001450d002001102a0b20042007470d000b0b02402004450d002004102a0b0bd00203047f017e017f230041106b220224004100210320004100360208200042003702002002410036020020012802042204200128020022056b410575ad21060340200341016a2103200642078822064200520d000b2002200336020002400240024020052004460d0003402002200341086a3602002003410c6a2103200541186a2802002207ad21060340200341016a2103200642078822064200520d000b20022003417c6a3602002007417f460d022002200336020020022005410c6a10511a20022802002103200541206a22052004470d000b20002802002105200028020421070c020b41002105410021070c010b1052000b024002402003200720056b22074d0d002000200320076b1043200028020021050c010b200320074f0d002000200520036a3602040b2002200536020420022005360200200220002802043602082002200110531a200241106a24000baf0302017f027e230041206b22022400200029030010172002200141186a29030022033c00172002200141086a29030022044220883c0003200220044228883c0002200220044230883c0001200220044238883c0000200220034220883c001320022003a722004108763a0016200220004110763a0015200220004118763a001420022004a722003a0007200220004108763a0006200220004110763a0005200220004118763a0004200220012903002204423886200442288642808080808080c0ff0083842004421886428080808080e03f8320044208864280808080f01f838484200442088842808080f80f832004421888428080fc07838420044228884280fe03832004423888848484370308200220012903102204423886200442288642808080808080c0ff0083842004421886428080808080e03f8320044208864280808080f01f838484200442088842808080f80f832004421888428080fc07838420044228884280fe03832004423888848484370318200220034230883c0011200220034228883c0012200220034238883c00102002101b41bdc100101c2001103941bbc100101c200241206a24000b9c0303017f027e017f230041206b220124002001200041186a29030022023c00172001200041086a29030022034220883c0003200120034228883c0002200120034230883c0001200120034238883c0000200120024220883c001320012002a722044108763a0016200120044110763a0015200120044118763a001420012003a722043a0007200120044108763a0006200120044110763a0005200120044118763a0004200120002903002203423886200342288642808080808080c0ff0083842003421886428080808080e03f8320034208864280808080f01f838484200342088842808080f80f832003421888428080fc07838420034228884280fe03832003423888848484370308200120002903102203423886200342288642808080808080c0ff0083842003421886428080808080e03f8320034208864280808080f01f838484200342088842808080f80f832003421888428080fc07838420034228884280fe03832003423888848484370318200120024230883c0011200120024228883c0012200120024238883c0010200141201023200141206a24000ba70303017f027e017f230041206b220224002002200141186a29030022033c00172002200141086a29030022044220883c0003200220044228883c0002200220044230883c0001200220044238883c0000200220034220883c001320022003a722054108763a0016200220054110763a0015200220054118763a001420022004a722053a0007200220054108763a0006200220054110763a0005200220054118763a0004200220012903002204423886200442288642808080808080c0ff0083842004421886428080808080e03f8320044208864280808080f01f838484200442088842808080f80f832004421888428080fc07838420044228884280fe03832004423888848484370308200220012903102204423886200442288642808080808080c0ff0083842004421886428080808080e03f8320044208864280808080f01f838484200442088842808080f80f832004421888428080fc07838420044228884280fe03832004423888848484370318200220034230883c0011200220034228883c0012200220034238883c001002402002101d0d00410041d8c10010010b200241206a24000bb90101047f230041106b2202210320022400024002400240101e22040d002003420037030841002102200341086a21050c010b024002402004418004490d002004102621020c010b20022004410f6a4170716b220224000b20022004101f1a20034200370308200341086a2105200441074b0d010b410041d9c40010010b200520024108100f1a20034200370300200241086a2102024020044178714108470d00410041d9c40010010b200320024108100f1a200341106a24000b4401037f2300220221030240101e2204450d00024002402004418004490d002004102621020c010b20022004410f6a4170716b220224000b20022004101f1a0b200324000b4401037f2300220221030240101e2204450d00024002402004418004490d002004102621020c010b20022004410f6a4170716b220224000b20022004101f1a0b200324000b4401037f2300220221030240101e2204450d00024002402004418004490d002004102621020c010b20022004410f6a4170716b220224000b20022004101f1a0b200324000b4401037f2300220221030240101e2204450d00024002402004418004490d002004102621020c010b20022004410f6a4170716b220224000b20022004101f1a0b200324000b4401037f2300220221030240101e2204450d00024002402004418004490d002004102621020c010b20022004410f6a4170716b220224000b20022004101f1a0b200324000bc90201047f230041306b220221032002240002400240101e22040d00410021020c010b024002402004418004490d002004102621020c010b20022004410f6a4170716b220224000b20022004101f1a0b20032002360224200320023602202003200220046a2205360228200342003703180240200441074b0d00410041d9c400100120032802282105200328022421020b200341186a20024108100f1a2003200241086a2202360224024020052002470d00410041d9c400100120032802282105200328022421020b200341176a20024101100f1a2003200241016a2202360224024020052002470d00410041d9c4001001200328022421020b200341166a20024101100f1a2003200241016a3602242003410036021020034200370308200341206a200341086a10421a024020032802082202450d002003200236020c2002102a0b200341306a24000bff0103017f017e047f2000280204210242002103410021040340024020022000280208490d0041004183c5001001200028020421020b20022d000021052000200241016a22063602042003200541ff0071200441ff0171220274ad842103200241076a2104200621022005418001710d000b0240024020012802042205200128020022026b22072003a722044f0d002001200420076b10432000280204210620012802042105200128020021020c010b200720044d0d002001200220046a22053602040b0240200028020820066b200520026b22054f0d00410041d9c4001001200028020421060b200220062005100f1a2000200028020420056a36020420000b980201057f02400240024020002802082202200028020422036b2001490d000340200341003a00002000200028020441016a22033602042001417f6a22010d000c020b0b2003200028020022046b220520016a2206417f4c0d0141ffffffff07210302400240200220046b220241feffffff034b0d0020062002410174220320032006491b22030d0041002103410021020c010b2003102921020b200220036a2106200220056a220421030340200341003a0000200341016a21032001417f6a22010d000b20042000280204200028020022016b22026b2104024020024101480d00200420012002100f1a200028020021010b2000200636020820002003360204200020043602002001450d002001102a0b0f0b2000102c000bb20202037f017e23004180016b220221032002240002400240101e22040d00410021020c010b024002402004418004490d002004102621020c010b20022004410f6a4170716b220224000b20022004101f1a0b20032002360254200320023602502003200220046a360258200342003703480240200441074b0d00410041d9c4001001200328025421020b200341c8006a20024108100f1a2003200241086a3602542003410036024020034200370338200341d0006a200341386a10421a200341086a41086a200341d0006a41086a2802002202360200200341306a2002360200200320032903502205370308200320013703202003200037031820032005370328200341186a2003290348200341386a1032024020032802382202450d002003200236023c2002102a0b20034180016a24000b4c01037f2300220221030240101e2204450d00024002402004418004490d002004102621020c010b20022004410f6a4170716b220224000b20022004101f1a0b410041d5c0001001200324000bcf0102047f017e230041106b2202210320022400024002400240101e22040d002003420037030841002102200341086a21050c010b024002402004418004490d002004102621020c010b20022004410f6a4170716b220224000b20022004101f1a20034200370308200341086a2105200441074b0d010b410041d9c40010010b200520024108100f1a200241086a2102024020044108470d00410041d9c40010010b200341076a20024101100f1a2003290308210620032d0007210420001017200620044100471018200341106a24000baa0202047f047e230041206b2202210320022400024002400240101e22040d002003420037031841002102200341186a21050c010b024002402004418004490d002004102621020c010b20022004410f6a4170716b220224000b20022004101f1a20034200370318200341186a2105200441074b0d010b410041d9c40010010b200520024108100f1a200241086a21050240200441787122044108470d00410041d9c40010010b200341106a20054108100f1a200241106a2105024020044110470d00410041d9c40010010b200341086a20054108100f1a200241186a2102024020044118470d00410041d9c40010010b200320024108100f1a200329030021062003290308210720032903102108200329031821092000101720092008200720061019200341206a24000ba103010b7f230041306b2202210320022400410021040240101e2205450d00024002402005418004490d002005102621040c010b20022005410f6a4170716b220424000b20042005101f1a0b20032004360214200320043602102003200420056a3602182003410036020820034200370300200341106a200310491a20001017200341206a20031037420120032802202204200328022420046b101a1a024020032802202204450d00200320043602242004102a0b024020032802002206450d0002400240200328020422072006470d00200621040c010b03402007220441606a21070240200441786a2208280200417f460d002004416c6a2209280200220a450d00200a21050240200441706a220b2802002204200a460d000340200441486a21050240200441786a2202280200220c417f460d00200341206a200441486a200c4102744188c5006a2802001101000b2002417f36020020052104200a2005470d000b200928020021050b200b200a3602002005102a0b2008417f36020020072006470d000b200328020021040b200320063602042004102a0b200341306a24000bcc0303027f017e097f230041206b220224002000280204210342002104410021050340024020032000280208490d0041004183c5001001200028020421030b20032d000021062000200341016a22033602042004200641ff0071200541ff0171220574ad842104200541076a2105200321032006418001710d000b0240024020012802042207200128020022056b41057522062004a722034f0d002001200320066b104a200128020421070c010b200620034d0d000240200520034105746a22082007460d0003402007220341606a21070240200341786a2209280200417f460d002003416c6a220a280200220b450d00200b21060240200341706a220c2802002203200b460d000340200341486a21060240200341786a2205280200220d417f460d00200241186a200341486a200d4102744188c5006a2802001101000b2005417f36020020062103200b2006470d000b200a28020021060b200c200b3602002006102a0b2009417f36020020072008470d000b0b20012008360204200821070b0240200128020022032007460d00034020022000360208200220033602102002200341086a360214200241106a200241086a104b200341206a22032007470d000b0b200241206a240020000b9f06030a7f017e037f230041106b220224000240024020002802082203200028020422046b4105752001490d000340200441186a2203420037030020044200370300200441106a4200370300200441086a4200370300200341003602002000200028020441206a22043602042001417f6a22010d000c020b0b02400240024002402004200028020022056b410575220620016a220741808080c0004f0d0041ffffff3f210402400240200320056b220341057541feffff1f4b0d00024020072003410475220420042007491b22040d0041002104410021030c020b200441808080c0004f0d030b2004410574102921030b200320044105746a2108200320064105746a22092104034020044200370300200441186a4200370300200441106a4200370300200441086a4200370300200441206a21042001417f6a22010d000b2000280204220a20002802002206460d022006200a6b210b410021050340200920056a220141786a2206417f360200200a20056a220341606a290300210c200141686a220741003a0000200141606a200c3703000240200341786a280200220d417f460d00200141706a220e42003702002001416c6a220f4100360200200e200341706a280200360200200f2003416c6a220e280200360200200141746a200341746a22012802003602002007200341686a2802003602002006200d36020020014100360200200e42003702000b200b200541606a2205470d000b200920056a2109200028020421062000280200210d0c030b2000102c000b1003000b2006210d0b20002008360208200020043602042000200936020002402006200d460d0003402006220441606a21060240200441786a2207280200417f460d002004416c6a220e2802002200450d00200021010240200441706a220f28020022042000460d000340200441486a21010240200441786a22032802002205417f460d00200241086a200441486a20054102744188c5006a2802001101000b2003417f3602002001210420002001470d000b200e28020021010b200f20003602002001102a0b2007417f3602002006200d470d000b0b200d450d00200d102a0b200241106a24000bca0102037f017e20002802002102024020012802002203280208200328020422046b41074b0d00410041d9c4001001200328020421040b200220044108100f1a2003200328020441086a3602042000280204210220012802002201280204210342002105410021040340024020032001280208490d0041004183c5001001200128020421030b20032d000021002001200341016a22033602042005200041ff0071200441ff0171220474ad842105200441076a2104200321032000418001710d000b200120022005a710600b890101037f230041e0006b220221032002240002400240101e22040d00410021020c010b024002402004418004490d002004102621020c010b20022004410f6a4170716b220224000b20022004101f1a0b20032002360254200320023602502003200220046a360258200341d0006a200341086a104d1a20001017200341086a102e200341e0006a24000ba20801027f02402000280208200028020422026b41074b0d00410041d9c4001001200028020421020b200120024108100f1a2000200028020441086a2202360204200141086a21030240200028020820026b41034b0d00410041d9c4001001200028020421020b200320024104100f1a2000200028020441046a22023602042001410c6a21030240200028020820026b41034b0d00410041d9c4001001200028020421020b200320024104100f1a2000200028020441046a2202360204200141106a21030240200028020820026b41034b0d00410041d9c4001001200028020421020b200320024104100f1a2000200028020441046a2202360204200141146a21030240200028020820026b41034b0d00410041d9c4001001200028020421020b200320024104100f1a2000200028020441046a2202360204200141186a21030240200028020820026b41034b0d00410041d9c4001001200028020421020b200320024104100f1a2000200028020441046a22023602042001411c6a21030240200028020820026b41034b0d00410041d9c4001001200028020421020b200320024104100f1a2000200028020441046a2202360204200141206a21030240200028020820026b41034b0d00410041d9c4001001200028020421020b200320024104100f1a2000200028020441046a2202360204200141246a21030240200028020820026b41034b0d00410041d9c4001001200028020421020b200320024104100f1a2000200028020441046a2202360204200141286a21030240200028020820026b41034b0d00410041d9c4001001200028020421020b200320024104100f1a2000200028020441046a22023602042001412c6a21030240200028020820026b41034b0d00410041d9c4001001200028020421020b200320024104100f1a2000200028020441046a2202360204200141306a21030240200028020820026b41034b0d00410041d9c4001001200028020421020b200320024104100f1a2000200028020441046a2202360204200141346a21030240200028020820026b41034b0d00410041d9c4001001200028020421020b200320024104100f1a2000200028020441046a2202360204200141386a21030240200028020820026b41034b0d00410041d9c4001001200028020421020b200320024104100f1a2000200028020441046a22023602042001413c6a21030240200028020820026b41034b0d00410041d9c4001001200028020421020b200320024104100f1a2000200028020441046a2202360204200141c0006a21030240200028020820026b41014b0d00410041d9c4001001200028020421020b200320024102100f1a2000200028020441026a2202360204200141c2006a21010240200028020820026b41014b0d00410041d9c4001001200028020421020b200120024102100f1a2000200028020441026a36020420000b940101047f230041106b2202210320022400024002400240101e22040d002003420037030841002102200341086a21050c010b024002402004418004490d002004102621020c010b20022004410f6a4170716b220224000b20022004101f1a20034200370308200341086a2105200441074b0d010b410041d9c40010010b200520024108100f1a20032903081017200341106a24000b8c0405047f017e037f017e017f230041f0006b220221032002240002400240101e22040d00410021050c010b024002402004418004490d002004102621050c010b20022004410f6a4170716b220524000b20052004101f1a0b42002106200341286a420037030041102102200341106a41106a4200370300200342003703182003420037031002402004411f4b0d00410041d9c40010010b200520046a2107200341d0006a20054120100f1a200541206a2108200341306a2109410021044200210a0340200341d0006a20046a210b0240024020024102490d00200a4208862006200b31000084220642388884210a2002417f6a2102200642088621060c010b024020024101460d00410041b6c50010010b2009200a37030820092006200b3100008437030041102102200941106a2109420021064200210a0b200441016a22044120470d000b024020024110460d00024020024102490d0020032006200a200241037441786a1009200341086a290300210a200329030021060b200920063703002009200a3703080b200341106a41186a200341306a41186a290300370300200341106a41106a200341306a41106a2903003703002003200329033837031820032003290330370310200341d0006a41186a2007360200200341e4006a2008360200200320053602602003200137035820032000370350200341d0006a200341106a1038200341f0006a24000bc80303047f027e017f230041f0006b220221032002240002400240101e22040d00410021050c010b024002402004418004490d002004102621050c010b20022004410f6a4170716b220524000b20052004101f1a0b42002106200341286a420037030041102102200341106a41106a4200370300200342003703182003420037031002402004411f4b0d00410041d9c40010010b200341d0006a20054120100f1a200341306a210541002104420021070340200341d0006a20046a21080240024020024102490d002007420886200620083100008422064238888421072002417f6a2102200642088621060c010b024020024101460d00410041b6c50010010b200520073703082005200620083100008437030041102102200541106a210542002106420021070b200441016a22044120470d000b024020024110460d00024020024102490d00200320062007200241037441786a1009200341086a2903002107200329030021060b20052006370300200520073703080b200341106a41186a200341306a41186a290300370300200341106a41106a200341306a41106a29030037030020032003290338370318200320032903303703102002200341106a103a200341f0006a24000bd50103037f017e017f230041106b2202240020012802042203200128020022046b41386dad2105200028020021010340200141016a2101200542078822054200520d000b200020013602000240024020042003460d00034020042802302206ad21050340200141016a2101200542078822054200520d000b20002001360200200220003602002006417f460d0220022002360208200241086a2004200641027441fcc1006a2802001101002000200028020041026a2201360200200441386a22042003470d000b0b200241106a240020000f0b1052000b05001003000bfe0103017f017e037f230041106b22022400200128020420012802006b410575ad21032000280204210403402003a721052002200342078822034200522206410774200541ff0071723a000f0240200028020820046b41004a0d0041004188c2001001200028020421040b20042002410f6a4101100f1a2000200028020441016a220436020420060d000b02402001280200220520012802042206460d0003400240200028020820046b41074a0d0041004188c2001001200028020421040b200420054108100f1a2000200028020441086a3602042000200541086a10541a200541206a22052006460d01200028020421040c000b0b200241106a240020000bdd0103027f017e027f230041106b22022400200028020421032001350210210403402004a721052002200442078822044200522206410774200541ff0071723a000f0240200028020820036b41004a0d0041004188c2001001200028020421030b20032002410f6a4101100f1a2000200028020441016a220336020420060d000b02402001280210417f460d00200141046a21050240200028020820036b41034a0d0041004188c2001001200028020421030b200320014104100f1a2000200028020441046a3602042000200510581a200241106a240020000f0b1052000b170020002802002802002200200028020041216a3602000b170020002802002802002200200028020041216a3602000b7602017f017e20002802002802002202200228020041226a2200360200200141286a350200420020012d00244101711b21030340200041016a2100200342078822034200520d000b200220003602000240200128022820012d0024220141017620014101711b2201450d002002200120006a3602000b0b990303017f017e047f230041106b22022400200128020420012802006b41386dad21032000280204210403402003a721052002200342078822034200522206410774200541ff0071723a000f0240200028020820046b41004a0d0041004188c2001001200028020421040b20042002410f6a4101100f1a2000200028020441016a220436020420060d000b024002402001280200220720012802042201460d0003402007350230210303402003a721052002200342078822034200522206410774200541ff0071723a000e0240200028020820046b41004a0d0041004188c2001001200028020421040b20042002410e6a4101100f1a2000200028020441016a220436020420060d000b2002200036020020072802302204417f460d0220022002360208200241086a2007200441027441b4c2006a280200110100200741346a210502402000280208200028020422046b41014a0d0041004188c2001001200028020421040b200420054102100f1a2000200028020441026a2204360204200741386a22072001470d000b0b200241106a240020000f0b1052000b6401037f200028020028020022002802042102410021030340200120036a21040240200028020820026b41004a0d0041004188c2001001200028020421020b200220044101100f1a2000200028020441016a2202360204200341016a22034121470d000b0b6401037f200028020028020022002802042102410021030340200120036a21040240200028020820026b41004a0d0041004188c2001001200028020421020b200220044101100f1a2000200028020441016a2202360204200341016a22034121470d000b0baa0101037f200028020028020022002802042102410021030340200120036a21040240200028020820026b41004a0d0041004188c2001001200028020421020b200220044101100f1a2000200028020441016a2202360204200341016a22034121470d000b200141216a21030240200028020820026b41004a0d0041004188c2001001200028020421020b200220034101100f1a2000200028020441016a3602042000200141246a105c1a0bfd0103027f017e027f230041106b22022400200128020420012d0000220341017620034101711bad21042000280204210303402004a721052002200442078822044200522206410774200541ff0071723a000f0240200028020820036b41004a0d0041004188c2001001200028020421030b20032002410f6a4101100f1a2000200028020441016a220336020420060d000b0240200128020420012d00002205410176200541017122061b2205450d002001280208200141016a20061b21060240200028020820036b20054e0d0041004188c2001001200028020421030b200320062005100f1a2000200028020420056a3602040b200241106a240020000b02000b02000b1a00024020012d0024410171450d002001412c6a280200102a0b0bae0201047f230041206b220324000240024020020d00200341146a41003602002003420037020c200341086a410472210402402000280208200028020422026b41034b0d00410041d9c4001001200028020421020b200341086a20024104100f1a2000200028020441046a3602042000200410611a02402001280210417f460d0020012802042205450d00200521020240200141086a28020022002005460d000340200041486a21020240200041786a22042802002206417f460d00200341186a200041486a20064102744188c5006a2802001101000b2004417f3602002002210020052002470d000b200128020421020b200120053602082002102a0b2001200329030837020020014100360210200141086a20032903103702000c010b410041a0c50010010b200341206a24000b870303027f017e047f230041106b220224002000280204210342002104410021050340024020032000280208490d0041004183c5001001200028020421030b20032d000021062000200341016a22033602042004200641ff0071200541ff0171220574ad842104200541076a2105200321032006418001710d000b0240024020012802042205200128020022076b41386d22062004a722034f0d002001200320066b1062200128020421050c010b200620034d0d0002402007200341386c6a22082005460d000340200541486a21030240200541786a22062802002207417f460d00200241086a200541486a20074102744188c5006a2802001101000b2006417f3602002003210520082003470d000b0b20012008360204200821050b0240200128020022032005460d0003402000200310631a02402000280208200028020422066b41014b0d00410041d9c4001001200028020421060b200341346a20064102100f1a2000200028020441026a360204200341386a22032005470d000b0b200241106a240020000ba105010c7f230041106b2202240002400240024020002802082203200028020422046b41386d2001490d000340200441306a2203420037020020044200370200200441286a4200370200200441186a4200370200200441106a4200370200200441086a4200370200200441206a4200370200200341003602002000200028020441386a22043602042001417f6a22010d000c020b0b2004200028020022056b41386d220620016a220741a592c9244f0d0141a492c924210402400240200320056b41386d22034191c9a4124b0d0020072003410174220420042007491b22040d0041002104410021030c010b200441386c102921030b2003200441386c6a21082003200641386c6a22092104034020044200370200200441286a4200370200200441186a4200370200200441106a4200370200200441086a4200370200200441206a4200370200200441306a4200370200200441386a21042001417f6a22010d000b024002402000280204220a20002802002205470d002000200836020820002004360204200020093602000c010b2005200a6b210b410021010340200920016a220341786a2206417f360200200341486a220741003a00000240200a20016a220541786a220c280200220d417f460d00200241086a2007200541486a200d4102744194c5006a2802001102002006200c2802003602000b2003417c6a2005417c6a2f01003b0100200b200141486a2201470d000b200020083602082000280204210320002004360204200028020021052000200920016a36020020032005460d000340200341486a21040240200341786a22012802002200417f460d002002200341486a20004102744188c5006a2802001101000b2001417f3602002004210320052004470d000b0b2005450d002005102a0b200241106a24000f0b2000102c000bdf0203027f017e037f230041306b220224002000280204210342002104410021050340024020032000280208490d0041004183c5001001200028020421030b20032d000021062000200341016a22073602042004200641ff0071200541ff0171220374ad842104200341076a2105200721032006418001710d000b024002402004a722030d00410021030340200220036a2106024020002802082007470d00410041d9c4001001200028020421070b200620074101100f1a2000200028020441016a2207360204200341016a22034121470d000b024020012802302203417f460d00200241286a200120034102744188c5006a2802001101000b2001200229030037000020014100360230200141206a200241206a2d00003a0000200141186a200241186a290300370000200141106a200241106a290300370000200141086a200241086a2903003700000c010b20002001200310670b200241306a240020000b4c0020012002290000370000200141206a200241206a2d00003a0000200141186a200241186a290000370000200141106a200241106a290000370000200141086a200241086a2900003700000b4c0020012002290000370000200141206a200241206a2d00003a0000200141186a200241186a290000370000200141106a200241106a290000370000200141086a200241086a2900003700000b7801017f20012002290200370200200141206a200241206a2f01003b0100200141186a200241186a290200370200200141106a200241106a290200370200200141086a200241086a2902003702002001412c6a2002412c6a22032802003602002001200229022437022420024200370224200341003602000be70401037f230041c0006b22032400024002402002417f6a220241014b0d000240024020020e020001000b20002802042102410021040340200341086a20046a2105024020002802082002470d00410041d9c4001001200028020421020b200520024101100f1a2000200028020441016a2202360204200441016a22044121470d000b024020012802302200417f460d00200341386a200120004102744188c5006a2802001101000b2001200329030837000020014101360230200141206a200341086a41206a2d00003a0000200141186a200341086a41186a290300370000200141106a200341086a41106a290300370000200141086a200341086a41086a2903003700000c020b200341346a41003602002003420037022c20002802042102410021040340200341086a20046a2105024020002802082002470d00410041d9c4001001200028020421020b200520024101100f1a2000200028020441016a2202360204200441016a22044121470d000b200341296a2104024020002802082002470d00410041d9c4001001200028020421020b200420024101100f1a2000200028020441016a36020420002003412c6a220210681a024020012802302200417f460d00200341386a200120004102744188c5006a2802001101000b200120032903083702002001410236023020012002290200370224200141206a200341086a41206a2f01003b0100200141186a200341086a41186a290300370200200141106a200341086a41106a290300370200200141086a200341086a41086a2903003702002001412c6a200241086a2802003602000c010b410041a0c50010010b200341c0006a24000ba00301057f230041206b2202240020024100360218200242003703102000200241106a10421a0240024002402002280214200228021022036b2204450d00200241086a410036020020024200370300200441704f0d02024002402004410a4b0d00200220044101743a0000200241017221050c010b200441106a4170712206102921052002200436020420022006410172360200200220053602080b0340200520032d00003a0000200541016a2105200341016a21032004417f6a22040d000b200541003a00000240024020012d00004101710d00200141003b01000c010b200128020841003a00002001410036020420012d0000410171450d002001280208102a200141003602000b20012002290300370200200141086a200241086a2802003602000c010b0240024020012d00004101710d00200141003b01000c010b200128020841003a00002001410036020420012d0000410171450d002001280208102a200141003602000b20014100360208200142003702000b024020022802102205450d00200220053602142005102a0b200241206a240020000f0b2002102b000b0beb0503004190c0000b796661696c656420746f20616c6c6f6361746520706167657300756e6578706563746564206572726f7220696e2066697865645f627974657320636f6e7374727563746f7200746865206f6e6572726f7220616374696f6e2063616e6e6f742062652063616c6c6564206469726563746c790000000000000000004189c1000bd904000000000000006461746173747265616d20617474656d7074656420746f20777269746520706173742074686520656e64000a006665617475726520646967657374206163746976617465643a200070726f746f636f6c2066656174757265206973206e6f74206163746976617465640000000100000002000000030000006461746173747265616d20617474656d7074656420746f20777269746520706173742074686520656e6400000400000005000000060000006f626a6563742070617373656420746f206974657261746f725f746f206973206e6f7420696e206d756c74695f696e646578006572726f722072656164696e67206974657261746f720063616e6e6f7420637265617465206f626a6563747320696e207461626c65206f6620616e6f7468657220636f6e7472616374006f626a6563742070617373656420746f206d6f64696679206973206e6f7420696e206d756c74695f696e6465780063616e6e6f74206d6f64696679206f626a6563747320696e207461626c65206f6620616e6f7468657220636f6e747261637400757064617465722063616e6e6f74206368616e6765207072696d617279206b6579207768656e206d6f64696679696e6720616e206f626a656374006461746173747265616d20617474656d7074656420746f207265616420706173742074686520656e640067657400000700000008000000090000000a0000000b0000000c000000696e76616c69642076617269616e7420696e64657800756e6578706563746564206572726f7220696e2066697865645f627974657320636f6e7374727563746f72000041000b04e822000000000000000000000000f6e310259a2df1180a080592a90630cfdbffbd90a5144d2fb46801bbaff3aaec04000000033b3d4b0100000004f5b1c8962f98b2d6155f6d21977938d545d83ef187d93aaf83e483e5010000000000ea3055024900000000000000000000000000 +DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304003,"value_ex":97414,"consumed":6881},"cpu_usage":{"last_ordinal":1262304003,"value_ex":291109,"consumed":2101},"ram_usage":199492} +DMLOG APPLIED_TRANSACTION 4 81292a0b46e645c14534988939f33d632cb0263615d92cbbf1612b473443947404000000033b3d4b010000000422c55bcc9df846ced4de43e8b8da9ad8057bcd95e32e31cac7e754680100d0070000dc060000000000000000e01a0000000000000001010000010000000000ea3055378d583c2888f3564b4db37bfb52d74d038e54fcc63aeb57cf27b03c001e97a51c000000000000001c00000000000000010000000000ea30551c0000000000000002010000000000ea30550000000000ea305500000040258ab2c2010000000000ea305500000000a8ed3232cb99010000000000ea30550000be99010061736d010000000198011960000060027f7f0060037f7f7f0060047e7e7e7e017f6000017e60047f7e7e7f0060057f7f7f7f7f017f60037f7f7f017f60027f7f017f60027f7f017e60057f7f7f7f7f0060067e7e7e7e7f7f017f60017e0060027e7f0060047e7e7e7e0060037e7f7f017e60017f0060017f017f6000017f60027f7e0060047f7e7f7f0060037e7e7e0060037f7e7f0060047f7f7f7f0060027e7e0002f0052403656e760b64625f66696e645f693634000303656e760c656f73696f5f617373657274000103656e761063757272656e745f7265636569766572000403656e760561626f7274000003656e760d6173736572745f736861323536000203656e760b6173736572745f73686131000203656e760d6173736572745f736861353132000203656e76106173736572745f726970656d64313630000203656e7606736861323536000203656e76095f5f6173686c746933000503656e760473686131000203656e7606736861353132000203656e7609726970656d64313630000203656e760b7265636f7665725f6b6579000603656e76207365745f626c6f636b636861696e5f706172616d65746572735f7061636b6564000103656e76066d656d637079000703656e76206765745f626c6f636b636861696e5f706172616d65746572735f7061636b6564000803656e76167365745f70726f706f7365645f70726f647563657273000903656e760c63757272656e745f74696d65000403656e76146765745f6163746976655f70726f647563657273000803656e76087072696e74735f6c000103656e76126173736572745f7265636f7665725f6b6579000a03656e760c64625f73746f72655f693634000b03656e760c726571756972655f61757468000c03656e760e7365745f70726976696c65676564000d03656e76137365745f7265736f757263655f6c696d697473000e03656e76197365745f70726f706f7365645f70726f6475636572735f6578000f03656e761370726561637469766174655f66656174757265001003656e76067072696e7473001003656e761469735f666561747572655f616374697661746564001103656e7610616374696f6e5f646174615f73697a65001203656e7610726561645f616374696f6e5f64617461000803656e7611656f73696f5f6173736572745f636f6465001303656e760a64625f6765745f693634000703656e760d64625f7570646174655f693634001403656e76087072696e7468657800010346450015111000111010100c100802101608020817010110011818181818181808011818181818080101180818181808000808010101080101010801010102080108020202020804050170010d0d05030100010616037f014180c0000b7f0041e2c5000b7f0041e2c5000b070901056170706c7900250912010041010b0c555657595a5b5d5e5f6465660aab8b0145040010280bdd03002000102d102420002001510440428080f9d4a98499dc9a7f200251044020002001103b05428080add68d959ba955200251044020002001103c05428080add68d95abd1ca00200251044020002001103d0542808080e8b2edc0d38b7f200251044020002001103e05428080add68db8baf154200251044020002001103f054280f8a6d4d2a8a1d3c1002002510440200020011040054280808080d4c4a2d942200251044020002001104105428080808080f798d9422002510440200020011044054280808080aefadeeaa47f2002510440200020011045054280808080b6f7d6d942200251044020002001104605428080b8f6a4979ad94220025104402000200110470542808080c093fad6d9422002510440200020011048054280808096cdebd4d942200251044020002001104c054280808080daac9bd6ba7f200251044020002001104e0542808080d0b2b3bb9932200251044020002001104f054290a9d9d9dd8c99d6ba7f2002510440200020011050052000428080808080c0ba98d500520440410042808080d9d3b3ed82ef0010200b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b05428080808080c0ba98d50020015104404280808080aefadeeaa47f2002510440410042818080d9d3b3ed82ef0010200b0b0b410010310b7201037f024020000d0041000f0b4100410028028c40200041107622016a220236028c404100410028028440220320006a410f6a4170712200360284400240200241107420004b0d004100200241016a36028c40200141016a21010b024020014000417f470d0041004190c00010010b20030b02000b3601017f230041106b2200410036020c4100200028020c280200410f6a417071220036028040410020003602844041003f0036028c400b3301027f2000410120001b2101024003402001102622000d01410021004100280284412202450d0120021100000c000b0b20000b0600200010270b05001003000b05001003000b0a0041002000370388410b4e01017f230041e0006b220124002001200141d8006a3602082001200141106a3602042001200141106a36020020012000102f1a200141106a200128020420012802006b100e200141e0006a24000ba20801027f02402000280208200028020422026b41074a0d0041004190c1001001200028020421020b200220014108100f1a2000200028020441086a2202360204200141086a21030240200028020820026b41034a0d0041004190c1001001200028020421020b200220034104100f1a2000200028020441046a22023602042001410c6a21030240200028020820026b41034a0d0041004190c1001001200028020421020b200220034104100f1a2000200028020441046a2202360204200141106a21030240200028020820026b41034a0d0041004190c1001001200028020421020b200220034104100f1a2000200028020441046a2202360204200141146a21030240200028020820026b41034a0d0041004190c1001001200028020421020b200220034104100f1a2000200028020441046a2202360204200141186a21030240200028020820026b41034a0d0041004190c1001001200028020421020b200220034104100f1a2000200028020441046a22023602042001411c6a21030240200028020820026b41034a0d0041004190c1001001200028020421020b200220034104100f1a2000200028020441046a2202360204200141206a21030240200028020820026b41034a0d0041004190c1001001200028020421020b200220034104100f1a2000200028020441046a2202360204200141246a21030240200028020820026b41034a0d0041004190c1001001200028020421020b200220034104100f1a2000200028020441046a2202360204200141286a21030240200028020820026b41034a0d0041004190c1001001200028020421020b200220034104100f1a2000200028020441046a22023602042001412c6a21030240200028020820026b41034a0d0041004190c1001001200028020421020b200220034104100f1a2000200028020441046a2202360204200141306a21030240200028020820026b41034a0d0041004190c1001001200028020421020b200220034104100f1a2000200028020441046a2202360204200141346a21030240200028020820026b41034a0d0041004190c1001001200028020421020b200220034104100f1a2000200028020441046a2202360204200141386a21030240200028020820026b41034a0d0041004190c1001001200028020421020b200220034104100f1a2000200028020441046a22023602042001413c6a21030240200028020820026b41034a0d0041004190c1001001200028020421020b200220034104100f1a2000200028020441046a2202360204200141c0006a21030240200028020820026b41014a0d0041004190c1001001200028020421020b200220034102100f1a2000200028020441026a2202360204200141c2006a21010240200028020820026b41014a0d0041004190c1001001200028020421020b200220014102100f1a2000200028020441026a36020420000bfa0103017f027e017f230041306b2203240020012002200341106a1008420021044110210141002102420021050340200341106a20026a21060240024020014102490d002005420886200420063100008422044238888421052001417f6a2101200442088621040c010b024020014101460d00410041a9c00010010b200020053703082000200420063100008437030041102101200041106a210042002104420021050b200241016a22024120470d000b024020014110460d00024020014102490d00200320042005200141037441786a1009200341086a2903002105200329030021040b20002004370300200020053703080b200341306a24000b02000b970503017f017e047f230041f0006b22032400200341206a4100360200200342003703182003427f37031020032000290300220437030820032004370300024002402004200442808080809aecb4ee312001100022004100480d00024020032000103322002802302003460d00410041c0c20010010b2003200236023020032000200341306a10340c010b024020041002510d004100418ac30010010b41c000102922004200370310200041286a22054200370300200041206a22064200370300200041186a220742003703002000200336023020002001370300200341306a20022802002208200228020420086b10302005200341306a41186a2903003703002006200341306a41106a29030037030020072003290338370300200020032903303703102003200341306a41286a3602682003200341306a360260200341306a20004108100f1a2003200341306a410872360264200341e0006a200041106a10351a2000200329030842808080809aecb4ee31200120002903002204200341306a412810162205360234024020042003290310540d002003427e200442017c2004427d561b3703100b200320003602602003200029030022043703302003200536022c02400240200328021c220220032802204f0d00200220053602102002200437030820034100360260200220003602002003200241186a36021c0c010b200341186a200341e0006a200341306a2003412c6a10360b20032802602100200341003602602000450d002000102a0b024020032802182205450d0002400240200328021c22002005470d00200521000c010b0340200041686a220028020021022000410036020002402002450d002002102a0b20052000470d000b200328021821000b2003200536021c2000102a0b200341f0006a24000b840603097f027e017f230041e0006b220221032002240002400240200028021822042000411c6a2802002205460d0002400340200541786a2802002001460d012004200541686a2205470d000c020b0b20042005460d00200541686a28020021060c010b024002400240024020014100410010212205417f4a0d00410041f3c20010010c010b2005418104490d010b200510262107410121080c010b20022005410f6a4170716b22072400410021080b20012007200510211a41c0001029220642003703102006420037030020062000360230200641186a4200370300200641206a4200370300200641286a42003703000240200541074b0d00410041d9c40010010b200620074108100f1a200741086a21040240200541786a411f4b0d00410041d9c40010010b200041186a2109200641106a210a200341c0006a20044120100f1a4200210b41102105200341206a2102410021044200210c0340200341c0006a20046a210d0240024020054102490d00200c420886200b200d31000084220b42388884210c2005417f6a2105200b420886210b0c010b024020054101460d00410041b6c50010010b2002200c3703082002200b200d3100008437030041102105200241106a21024200210b4200210c0b200441016a22044120470d000b024020054110460d00024020054102490d00200341086a200b200c200541037441786a1009200341106a290300210c2003290308210b0b2002200b3703002002200c3703080b200a2003290320370300200a41086a2003290328370300200a41186a200341206a41186a290300370300200a41106a200341206a41106a290300370300200620013602342003200636022020032006290300220b3703402003200136021c02400240200028021c2205200041206a2802004f0d00200520013602102005200b37030820034100360220200520063602002000200541186a36021c0c010b2009200341206a200341c0006a2003411c6a10360b02402008450d00200710270b20032802202105200341003602202005450d002005102a0b200341e0006a240020060b980203027f017e017f230041206b2203210420032400024020012802302000460d00410041bdc30010010b024010022000290300510d00410041ebc30010010b200129030021052004200228020022022802002206200228020420066b1030200141286a200441186a290300370300200141206a200441106a290300370300200141186a200429030837030020012004290300370310200141106a2102024020052001290300510d004100419ec40010010b200341506a220324002004200341286a36020820042003360200200320014108100f1a2004200341086a3602042004200210351a20012802344200200341281022024020052000290310540d002000427e200542017c2005427d561b3703100b200441206a24000bd20303017f027e017f230041206b220224002002200141186a29030022033c00172002200141086a29030022044220883c0003200220044228883c0002200220044230883c0001200220044238883c0000200220034220883c001320022003a722054108763a0016200220054110763a0015200220054118763a001420022004a722053a0007200220054108763a0006200220054110763a0005200220054118763a0004200220012903002204423886200442288642808080808080c0ff0083842004421886428080808080e03f8320044208864280808080f01f838484200442088842808080f80f832004421888428080fc07838420044228884280fe03832004423888848484370308200220012903102204423886200442288642808080808080c0ff0083842004421886428080808080e03f8320044208864280808080f01f838484200442088842808080f80f832004421888428080fc07838420044228884280fe03832004423888848484370318200220034230883c0011200220034228883c0012200220034238883c001002402000280208200028020422016b411f4a0d0041004188c2001001200028020421010b200120024120100f1a2000200028020441206a360204200241206a240020000b9a0301057f0240024002402000280204200028020022046b41186d220541016a220641abd5aad5004f0d0041aad5aad500210702400240200028020820046b41186d220441d4aad52a4b0d0020062004410174220720072006491b22070d0041002107410021040c010b200741186c102921040b20012802002106200141003602002004200541186c22086a2201200328020036021020012002290300370308200120063602002004200741186c6a2105200141186a21062000280204220220002802002207460d01200420086a41686a21010340200241686a220428020021032004410036020020012003360200200141086a200241706a2202290300370300200141106a200241086a280200360200200141686a21012004210220072004470d000b200141186a210120002802042107200028020021040c020b2000102c000b200721040b200020053602082000200636020420002001360200024020072004460d000340200741686a220728020021012007410036020002402001450d002001102a0b20042007470d000b0b02402004450d002004102a0b0bd00203047f017e017f230041106b220224004100210320004100360208200042003702002002410036020020012802042204200128020022056b410575ad21060340200341016a2103200642078822064200520d000b2002200336020002400240024020052004460d0003402002200341086a3602002003410c6a2103200541186a2802002207ad21060340200341016a2103200642078822064200520d000b20022003417c6a3602002007417f460d022002200336020020022005410c6a10511a20022802002103200541206a22052004470d000b20002802002105200028020421070c020b41002105410021070c010b1052000b024002402003200720056b22074d0d002000200320076b1043200028020021050c010b200320074f0d002000200520036a3602040b2002200536020420022005360200200220002802043602082002200110531a200241106a24000baf0302017f027e230041206b22022400200029030010172002200141186a29030022033c00172002200141086a29030022044220883c0003200220044228883c0002200220044230883c0001200220044238883c0000200220034220883c001320022003a722004108763a0016200220004110763a0015200220004118763a001420022004a722003a0007200220004108763a0006200220004110763a0005200220004118763a0004200220012903002204423886200442288642808080808080c0ff0083842004421886428080808080e03f8320044208864280808080f01f838484200442088842808080f80f832004421888428080fc07838420044228884280fe03832004423888848484370308200220012903102204423886200442288642808080808080c0ff0083842004421886428080808080e03f8320044208864280808080f01f838484200442088842808080f80f832004421888428080fc07838420044228884280fe03832004423888848484370318200220034230883c0011200220034228883c0012200220034238883c00102002101b41bdc100101c2001103941bbc100101c200241206a24000b9c0303017f027e017f230041206b220124002001200041186a29030022023c00172001200041086a29030022034220883c0003200120034228883c0002200120034230883c0001200120034238883c0000200120024220883c001320012002a722044108763a0016200120044110763a0015200120044118763a001420012003a722043a0007200120044108763a0006200120044110763a0005200120044118763a0004200120002903002203423886200342288642808080808080c0ff0083842003421886428080808080e03f8320034208864280808080f01f838484200342088842808080f80f832003421888428080fc07838420034228884280fe03832003423888848484370308200120002903102203423886200342288642808080808080c0ff0083842003421886428080808080e03f8320034208864280808080f01f838484200342088842808080f80f832003421888428080fc07838420034228884280fe03832003423888848484370318200120024230883c0011200120024228883c0012200120024238883c0010200141201023200141206a24000ba70303017f027e017f230041206b220224002002200141186a29030022033c00172002200141086a29030022044220883c0003200220044228883c0002200220044230883c0001200220044238883c0000200220034220883c001320022003a722054108763a0016200220054110763a0015200220054118763a001420022004a722053a0007200220054108763a0006200220054110763a0005200220054118763a0004200220012903002204423886200442288642808080808080c0ff0083842004421886428080808080e03f8320044208864280808080f01f838484200442088842808080f80f832004421888428080fc07838420044228884280fe03832004423888848484370308200220012903102204423886200442288642808080808080c0ff0083842004421886428080808080e03f8320044208864280808080f01f838484200442088842808080f80f832004421888428080fc07838420044228884280fe03832004423888848484370318200220034230883c0011200220034228883c0012200220034238883c001002402002101d0d00410041d8c10010010b200241206a24000bb90101047f230041106b2202210320022400024002400240101e22040d002003420037030841002102200341086a21050c010b024002402004418004490d002004102621020c010b20022004410f6a4170716b220224000b20022004101f1a20034200370308200341086a2105200441074b0d010b410041d9c40010010b200520024108100f1a20034200370300200241086a2102024020044178714108470d00410041d9c40010010b200320024108100f1a200341106a24000b4401037f2300220221030240101e2204450d00024002402004418004490d002004102621020c010b20022004410f6a4170716b220224000b20022004101f1a0b200324000b4401037f2300220221030240101e2204450d00024002402004418004490d002004102621020c010b20022004410f6a4170716b220224000b20022004101f1a0b200324000b4401037f2300220221030240101e2204450d00024002402004418004490d002004102621020c010b20022004410f6a4170716b220224000b20022004101f1a0b200324000b4401037f2300220221030240101e2204450d00024002402004418004490d002004102621020c010b20022004410f6a4170716b220224000b20022004101f1a0b200324000b4401037f2300220221030240101e2204450d00024002402004418004490d002004102621020c010b20022004410f6a4170716b220224000b20022004101f1a0b200324000bc90201047f230041306b220221032002240002400240101e22040d00410021020c010b024002402004418004490d002004102621020c010b20022004410f6a4170716b220224000b20022004101f1a0b20032002360224200320023602202003200220046a2205360228200342003703180240200441074b0d00410041d9c400100120032802282105200328022421020b200341186a20024108100f1a2003200241086a2202360224024020052002470d00410041d9c400100120032802282105200328022421020b200341176a20024101100f1a2003200241016a2202360224024020052002470d00410041d9c4001001200328022421020b200341166a20024101100f1a2003200241016a3602242003410036021020034200370308200341206a200341086a10421a024020032802082202450d002003200236020c2002102a0b200341306a24000bff0103017f017e047f2000280204210242002103410021040340024020022000280208490d0041004183c5001001200028020421020b20022d000021052000200241016a22063602042003200541ff0071200441ff0171220274ad842103200241076a2104200621022005418001710d000b0240024020012802042205200128020022026b22072003a722044f0d002001200420076b10432000280204210620012802042105200128020021020c010b200720044d0d002001200220046a22053602040b0240200028020820066b200520026b22054f0d00410041d9c4001001200028020421060b200220062005100f1a2000200028020420056a36020420000b980201057f02400240024020002802082202200028020422036b2001490d000340200341003a00002000200028020441016a22033602042001417f6a22010d000c020b0b2003200028020022046b220520016a2206417f4c0d0141ffffffff07210302400240200220046b220241feffffff034b0d0020062002410174220320032006491b22030d0041002103410021020c010b2003102921020b200220036a2106200220056a220421030340200341003a0000200341016a21032001417f6a22010d000b20042000280204200028020022016b22026b2104024020024101480d00200420012002100f1a200028020021010b2000200636020820002003360204200020043602002001450d002001102a0b0f0b2000102c000bb20202037f017e23004180016b220221032002240002400240101e22040d00410021020c010b024002402004418004490d002004102621020c010b20022004410f6a4170716b220224000b20022004101f1a0b20032002360254200320023602502003200220046a360258200342003703480240200441074b0d00410041d9c4001001200328025421020b200341c8006a20024108100f1a2003200241086a3602542003410036024020034200370338200341d0006a200341386a10421a200341086a41086a200341d0006a41086a2802002202360200200341306a2002360200200320032903502205370308200320013703202003200037031820032005370328200341186a2003290348200341386a1032024020032802382202450d002003200236023c2002102a0b20034180016a24000b4c01037f2300220221030240101e2204450d00024002402004418004490d002004102621020c010b20022004410f6a4170716b220224000b20022004101f1a0b410041d5c0001001200324000bcf0102047f017e230041106b2202210320022400024002400240101e22040d002003420037030841002102200341086a21050c010b024002402004418004490d002004102621020c010b20022004410f6a4170716b220224000b20022004101f1a20034200370308200341086a2105200441074b0d010b410041d9c40010010b200520024108100f1a200241086a2102024020044108470d00410041d9c40010010b200341076a20024101100f1a2003290308210620032d0007210420001017200620044100471018200341106a24000baa0202047f047e230041206b2202210320022400024002400240101e22040d002003420037031841002102200341186a21050c010b024002402004418004490d002004102621020c010b20022004410f6a4170716b220224000b20022004101f1a20034200370318200341186a2105200441074b0d010b410041d9c40010010b200520024108100f1a200241086a21050240200441787122044108470d00410041d9c40010010b200341106a20054108100f1a200241106a2105024020044110470d00410041d9c40010010b200341086a20054108100f1a200241186a2102024020044118470d00410041d9c40010010b200320024108100f1a200329030021062003290308210720032903102108200329031821092000101720092008200720061019200341206a24000ba103010b7f230041306b2202210320022400410021040240101e2205450d00024002402005418004490d002005102621040c010b20022005410f6a4170716b220424000b20042005101f1a0b20032004360214200320043602102003200420056a3602182003410036020820034200370300200341106a200310491a20001017200341206a20031037420120032802202204200328022420046b101a1a024020032802202204450d00200320043602242004102a0b024020032802002206450d0002400240200328020422072006470d00200621040c010b03402007220441606a21070240200441786a2208280200417f460d002004416c6a2209280200220a450d00200a21050240200441706a220b2802002204200a460d000340200441486a21050240200441786a2202280200220c417f460d00200341206a200441486a200c4102744188c5006a2802001101000b2002417f36020020052104200a2005470d000b200928020021050b200b200a3602002005102a0b2008417f36020020072006470d000b200328020021040b200320063602042004102a0b200341306a24000bcc0303027f017e097f230041206b220224002000280204210342002104410021050340024020032000280208490d0041004183c5001001200028020421030b20032d000021062000200341016a22033602042004200641ff0071200541ff0171220574ad842104200541076a2105200321032006418001710d000b0240024020012802042207200128020022056b41057522062004a722034f0d002001200320066b104a200128020421070c010b200620034d0d000240200520034105746a22082007460d0003402007220341606a21070240200341786a2209280200417f460d002003416c6a220a280200220b450d00200b21060240200341706a220c2802002203200b460d000340200341486a21060240200341786a2205280200220d417f460d00200241186a200341486a200d4102744188c5006a2802001101000b2005417f36020020062103200b2006470d000b200a28020021060b200c200b3602002006102a0b2009417f36020020072008470d000b0b20012008360204200821070b0240200128020022032007460d00034020022000360208200220033602102002200341086a360214200241106a200241086a104b200341206a22032007470d000b0b200241206a240020000b9f06030a7f017e037f230041106b220224000240024020002802082203200028020422046b4105752001490d000340200441186a2203420037030020044200370300200441106a4200370300200441086a4200370300200341003602002000200028020441206a22043602042001417f6a22010d000c020b0b02400240024002402004200028020022056b410575220620016a220741808080c0004f0d0041ffffff3f210402400240200320056b220341057541feffff1f4b0d00024020072003410475220420042007491b22040d0041002104410021030c020b200441808080c0004f0d030b2004410574102921030b200320044105746a2108200320064105746a22092104034020044200370300200441186a4200370300200441106a4200370300200441086a4200370300200441206a21042001417f6a22010d000b2000280204220a20002802002206460d022006200a6b210b410021050340200920056a220141786a2206417f360200200a20056a220341606a290300210c200141686a220741003a0000200141606a200c3703000240200341786a280200220d417f460d00200141706a220e42003702002001416c6a220f4100360200200e200341706a280200360200200f2003416c6a220e280200360200200141746a200341746a22012802003602002007200341686a2802003602002006200d36020020014100360200200e42003702000b200b200541606a2205470d000b200920056a2109200028020421062000280200210d0c030b2000102c000b1003000b2006210d0b20002008360208200020043602042000200936020002402006200d460d0003402006220441606a21060240200441786a2207280200417f460d002004416c6a220e2802002200450d00200021010240200441706a220f28020022042000460d000340200441486a21010240200441786a22032802002205417f460d00200241086a200441486a20054102744188c5006a2802001101000b2003417f3602002001210420002001470d000b200e28020021010b200f20003602002001102a0b2007417f3602002006200d470d000b0b200d450d00200d102a0b200241106a24000bca0102037f017e20002802002102024020012802002203280208200328020422046b41074b0d00410041d9c4001001200328020421040b200220044108100f1a2003200328020441086a3602042000280204210220012802002201280204210342002105410021040340024020032001280208490d0041004183c5001001200128020421030b20032d000021002001200341016a22033602042005200041ff0071200441ff0171220474ad842105200441076a2104200321032000418001710d000b200120022005a710600b890101037f230041e0006b220221032002240002400240101e22040d00410021020c010b024002402004418004490d002004102621020c010b20022004410f6a4170716b220224000b20022004101f1a0b20032002360254200320023602502003200220046a360258200341d0006a200341086a104d1a20001017200341086a102e200341e0006a24000ba20801027f02402000280208200028020422026b41074b0d00410041d9c4001001200028020421020b200120024108100f1a2000200028020441086a2202360204200141086a21030240200028020820026b41034b0d00410041d9c4001001200028020421020b200320024104100f1a2000200028020441046a22023602042001410c6a21030240200028020820026b41034b0d00410041d9c4001001200028020421020b200320024104100f1a2000200028020441046a2202360204200141106a21030240200028020820026b41034b0d00410041d9c4001001200028020421020b200320024104100f1a2000200028020441046a2202360204200141146a21030240200028020820026b41034b0d00410041d9c4001001200028020421020b200320024104100f1a2000200028020441046a2202360204200141186a21030240200028020820026b41034b0d00410041d9c4001001200028020421020b200320024104100f1a2000200028020441046a22023602042001411c6a21030240200028020820026b41034b0d00410041d9c4001001200028020421020b200320024104100f1a2000200028020441046a2202360204200141206a21030240200028020820026b41034b0d00410041d9c4001001200028020421020b200320024104100f1a2000200028020441046a2202360204200141246a21030240200028020820026b41034b0d00410041d9c4001001200028020421020b200320024104100f1a2000200028020441046a2202360204200141286a21030240200028020820026b41034b0d00410041d9c4001001200028020421020b200320024104100f1a2000200028020441046a22023602042001412c6a21030240200028020820026b41034b0d00410041d9c4001001200028020421020b200320024104100f1a2000200028020441046a2202360204200141306a21030240200028020820026b41034b0d00410041d9c4001001200028020421020b200320024104100f1a2000200028020441046a2202360204200141346a21030240200028020820026b41034b0d00410041d9c4001001200028020421020b200320024104100f1a2000200028020441046a2202360204200141386a21030240200028020820026b41034b0d00410041d9c4001001200028020421020b200320024104100f1a2000200028020441046a22023602042001413c6a21030240200028020820026b41034b0d00410041d9c4001001200028020421020b200320024104100f1a2000200028020441046a2202360204200141c0006a21030240200028020820026b41014b0d00410041d9c4001001200028020421020b200320024102100f1a2000200028020441026a2202360204200141c2006a21010240200028020820026b41014b0d00410041d9c4001001200028020421020b200120024102100f1a2000200028020441026a36020420000b940101047f230041106b2202210320022400024002400240101e22040d002003420037030841002102200341086a21050c010b024002402004418004490d002004102621020c010b20022004410f6a4170716b220224000b20022004101f1a20034200370308200341086a2105200441074b0d010b410041d9c40010010b200520024108100f1a20032903081017200341106a24000b8c0405047f017e037f017e017f230041f0006b220221032002240002400240101e22040d00410021050c010b024002402004418004490d002004102621050c010b20022004410f6a4170716b220524000b20052004101f1a0b42002106200341286a420037030041102102200341106a41106a4200370300200342003703182003420037031002402004411f4b0d00410041d9c40010010b200520046a2107200341d0006a20054120100f1a200541206a2108200341306a2109410021044200210a0340200341d0006a20046a210b0240024020024102490d00200a4208862006200b31000084220642388884210a2002417f6a2102200642088621060c010b024020024101460d00410041b6c50010010b2009200a37030820092006200b3100008437030041102102200941106a2109420021064200210a0b200441016a22044120470d000b024020024110460d00024020024102490d0020032006200a200241037441786a1009200341086a290300210a200329030021060b200920063703002009200a3703080b200341106a41186a200341306a41186a290300370300200341106a41106a200341306a41106a2903003703002003200329033837031820032003290330370310200341d0006a41186a2007360200200341e4006a2008360200200320053602602003200137035820032000370350200341d0006a200341106a1038200341f0006a24000bc80303047f027e017f230041f0006b220221032002240002400240101e22040d00410021050c010b024002402004418004490d002004102621050c010b20022004410f6a4170716b220524000b20052004101f1a0b42002106200341286a420037030041102102200341106a41106a4200370300200342003703182003420037031002402004411f4b0d00410041d9c40010010b200341d0006a20054120100f1a200341306a210541002104420021070340200341d0006a20046a21080240024020024102490d002007420886200620083100008422064238888421072002417f6a2102200642088621060c010b024020024101460d00410041b6c50010010b200520073703082005200620083100008437030041102102200541106a210542002106420021070b200441016a22044120470d000b024020024110460d00024020024102490d00200320062007200241037441786a1009200341086a2903002107200329030021060b20052006370300200520073703080b200341106a41186a200341306a41186a290300370300200341106a41106a200341306a41106a29030037030020032003290338370318200320032903303703102002200341106a103a200341f0006a24000bd50103037f017e017f230041106b2202240020012802042203200128020022046b41386dad2105200028020021010340200141016a2101200542078822054200520d000b200020013602000240024020042003460d00034020042802302206ad21050340200141016a2101200542078822054200520d000b20002001360200200220003602002006417f460d0220022002360208200241086a2004200641027441fcc1006a2802001101002000200028020041026a2201360200200441386a22042003470d000b0b200241106a240020000f0b1052000b05001003000bfe0103017f017e037f230041106b22022400200128020420012802006b410575ad21032000280204210403402003a721052002200342078822034200522206410774200541ff0071723a000f0240200028020820046b41004a0d0041004188c2001001200028020421040b20042002410f6a4101100f1a2000200028020441016a220436020420060d000b02402001280200220520012802042206460d0003400240200028020820046b41074a0d0041004188c2001001200028020421040b200420054108100f1a2000200028020441086a3602042000200541086a10541a200541206a22052006460d01200028020421040c000b0b200241106a240020000bdd0103027f017e027f230041106b22022400200028020421032001350210210403402004a721052002200442078822044200522206410774200541ff0071723a000f0240200028020820036b41004a0d0041004188c2001001200028020421030b20032002410f6a4101100f1a2000200028020441016a220336020420060d000b02402001280210417f460d00200141046a21050240200028020820036b41034a0d0041004188c2001001200028020421030b200320014104100f1a2000200028020441046a3602042000200510581a200241106a240020000f0b1052000b170020002802002802002200200028020041216a3602000b170020002802002802002200200028020041216a3602000b7602017f017e20002802002802002202200228020041226a2200360200200141286a350200420020012d00244101711b21030340200041016a2100200342078822034200520d000b200220003602000240200128022820012d0024220141017620014101711b2201450d002002200120006a3602000b0b990303017f017e047f230041106b22022400200128020420012802006b41386dad21032000280204210403402003a721052002200342078822034200522206410774200541ff0071723a000f0240200028020820046b41004a0d0041004188c2001001200028020421040b20042002410f6a4101100f1a2000200028020441016a220436020420060d000b024002402001280200220720012802042201460d0003402007350230210303402003a721052002200342078822034200522206410774200541ff0071723a000e0240200028020820046b41004a0d0041004188c2001001200028020421040b20042002410e6a4101100f1a2000200028020441016a220436020420060d000b2002200036020020072802302204417f460d0220022002360208200241086a2007200441027441b4c2006a280200110100200741346a210502402000280208200028020422046b41014a0d0041004188c2001001200028020421040b200420054102100f1a2000200028020441026a2204360204200741386a22072001470d000b0b200241106a240020000f0b1052000b6401037f200028020028020022002802042102410021030340200120036a21040240200028020820026b41004a0d0041004188c2001001200028020421020b200220044101100f1a2000200028020441016a2202360204200341016a22034121470d000b0b6401037f200028020028020022002802042102410021030340200120036a21040240200028020820026b41004a0d0041004188c2001001200028020421020b200220044101100f1a2000200028020441016a2202360204200341016a22034121470d000b0baa0101037f200028020028020022002802042102410021030340200120036a21040240200028020820026b41004a0d0041004188c2001001200028020421020b200220044101100f1a2000200028020441016a2202360204200341016a22034121470d000b200141216a21030240200028020820026b41004a0d0041004188c2001001200028020421020b200220034101100f1a2000200028020441016a3602042000200141246a105c1a0bfd0103027f017e027f230041106b22022400200128020420012d0000220341017620034101711bad21042000280204210303402004a721052002200442078822044200522206410774200541ff0071723a000f0240200028020820036b41004a0d0041004188c2001001200028020421030b20032002410f6a4101100f1a2000200028020441016a220336020420060d000b0240200128020420012d00002205410176200541017122061b2205450d002001280208200141016a20061b21060240200028020820036b20054e0d0041004188c2001001200028020421030b200320062005100f1a2000200028020420056a3602040b200241106a240020000b02000b02000b1a00024020012d0024410171450d002001412c6a280200102a0b0bae0201047f230041206b220324000240024020020d00200341146a41003602002003420037020c200341086a410472210402402000280208200028020422026b41034b0d00410041d9c4001001200028020421020b200341086a20024104100f1a2000200028020441046a3602042000200410611a02402001280210417f460d0020012802042205450d00200521020240200141086a28020022002005460d000340200041486a21020240200041786a22042802002206417f460d00200341186a200041486a20064102744188c5006a2802001101000b2004417f3602002002210020052002470d000b200128020421020b200120053602082002102a0b2001200329030837020020014100360210200141086a20032903103702000c010b410041a0c50010010b200341206a24000b870303027f017e047f230041106b220224002000280204210342002104410021050340024020032000280208490d0041004183c5001001200028020421030b20032d000021062000200341016a22033602042004200641ff0071200541ff0171220574ad842104200541076a2105200321032006418001710d000b0240024020012802042205200128020022076b41386d22062004a722034f0d002001200320066b1062200128020421050c010b200620034d0d0002402007200341386c6a22082005460d000340200541486a21030240200541786a22062802002207417f460d00200241086a200541486a20074102744188c5006a2802001101000b2006417f3602002003210520082003470d000b0b20012008360204200821050b0240200128020022032005460d0003402000200310631a02402000280208200028020422066b41014b0d00410041d9c4001001200028020421060b200341346a20064102100f1a2000200028020441026a360204200341386a22032005470d000b0b200241106a240020000ba105010c7f230041106b2202240002400240024020002802082203200028020422046b41386d2001490d000340200441306a2203420037020020044200370200200441286a4200370200200441186a4200370200200441106a4200370200200441086a4200370200200441206a4200370200200341003602002000200028020441386a22043602042001417f6a22010d000c020b0b2004200028020022056b41386d220620016a220741a592c9244f0d0141a492c924210402400240200320056b41386d22034191c9a4124b0d0020072003410174220420042007491b22040d0041002104410021030c010b200441386c102921030b2003200441386c6a21082003200641386c6a22092104034020044200370200200441286a4200370200200441186a4200370200200441106a4200370200200441086a4200370200200441206a4200370200200441306a4200370200200441386a21042001417f6a22010d000b024002402000280204220a20002802002205470d002000200836020820002004360204200020093602000c010b2005200a6b210b410021010340200920016a220341786a2206417f360200200341486a220741003a00000240200a20016a220541786a220c280200220d417f460d00200241086a2007200541486a200d4102744194c5006a2802001102002006200c2802003602000b2003417c6a2005417c6a2f01003b0100200b200141486a2201470d000b200020083602082000280204210320002004360204200028020021052000200920016a36020020032005460d000340200341486a21040240200341786a22012802002200417f460d002002200341486a20004102744188c5006a2802001101000b2001417f3602002004210320052004470d000b0b2005450d002005102a0b200241106a24000f0b2000102c000bdf0203027f017e037f230041306b220224002000280204210342002104410021050340024020032000280208490d0041004183c5001001200028020421030b20032d000021062000200341016a22073602042004200641ff0071200541ff0171220374ad842104200341076a2105200721032006418001710d000b024002402004a722030d00410021030340200220036a2106024020002802082007470d00410041d9c4001001200028020421070b200620074101100f1a2000200028020441016a2207360204200341016a22034121470d000b024020012802302203417f460d00200241286a200120034102744188c5006a2802001101000b2001200229030037000020014100360230200141206a200241206a2d00003a0000200141186a200241186a290300370000200141106a200241106a290300370000200141086a200241086a2903003700000c010b20002001200310670b200241306a240020000b4c0020012002290000370000200141206a200241206a2d00003a0000200141186a200241186a290000370000200141106a200241106a290000370000200141086a200241086a2900003700000b4c0020012002290000370000200141206a200241206a2d00003a0000200141186a200241186a290000370000200141106a200241106a290000370000200141086a200241086a2900003700000b7801017f20012002290200370200200141206a200241206a2f01003b0100200141186a200241186a290200370200200141106a200241106a290200370200200141086a200241086a2902003702002001412c6a2002412c6a22032802003602002001200229022437022420024200370224200341003602000be70401037f230041c0006b22032400024002402002417f6a220241014b0d000240024020020e020001000b20002802042102410021040340200341086a20046a2105024020002802082002470d00410041d9c4001001200028020421020b200520024101100f1a2000200028020441016a2202360204200441016a22044121470d000b024020012802302200417f460d00200341386a200120004102744188c5006a2802001101000b2001200329030837000020014101360230200141206a200341086a41206a2d00003a0000200141186a200341086a41186a290300370000200141106a200341086a41106a290300370000200141086a200341086a41086a2903003700000c020b200341346a41003602002003420037022c20002802042102410021040340200341086a20046a2105024020002802082002470d00410041d9c4001001200028020421020b200520024101100f1a2000200028020441016a2202360204200441016a22044121470d000b200341296a2104024020002802082002470d00410041d9c4001001200028020421020b200420024101100f1a2000200028020441016a36020420002003412c6a220210681a024020012802302200417f460d00200341386a200120004102744188c5006a2802001101000b200120032903083702002001410236023020012002290200370224200141206a200341086a41206a2f01003b0100200141186a200341086a41186a290300370200200141106a200341086a41106a290300370200200141086a200341086a41086a2903003702002001412c6a200241086a2802003602000c010b410041a0c50010010b200341c0006a24000ba00301057f230041206b2202240020024100360218200242003703102000200241106a10421a0240024002402002280214200228021022036b2204450d00200241086a410036020020024200370300200441704f0d02024002402004410a4b0d00200220044101743a0000200241017221050c010b200441106a4170712206102921052002200436020420022006410172360200200220053602080b0340200520032d00003a0000200541016a2105200341016a21032004417f6a22040d000b200541003a00000240024020012d00004101710d00200141003b01000c010b200128020841003a00002001410036020420012d0000410171450d002001280208102a200141003602000b20012002290300370200200141086a200241086a2802003602000c010b0240024020012d00004101710d00200141003b01000c010b200128020841003a00002001410036020420012d0000410171450d002001280208102a200141003602000b20014100360208200142003702000b024020022802102205450d00200220053602142005102a0b200241206a240020000f0b2002102b000b0beb0503004190c0000b796661696c656420746f20616c6c6f6361746520706167657300756e6578706563746564206572726f7220696e2066697865645f627974657320636f6e7374727563746f7200746865206f6e6572726f7220616374696f6e2063616e6e6f742062652063616c6c6564206469726563746c790000000000000000004189c1000bd904000000000000006461746173747265616d20617474656d7074656420746f20777269746520706173742074686520656e64000a006665617475726520646967657374206163746976617465643a200070726f746f636f6c2066656174757265206973206e6f74206163746976617465640000000100000002000000030000006461746173747265616d20617474656d7074656420746f20777269746520706173742074686520656e6400000400000005000000060000006f626a6563742070617373656420746f206974657261746f725f746f206973206e6f7420696e206d756c74695f696e646578006572726f722072656164696e67206974657261746f720063616e6e6f7420637265617465206f626a6563747320696e207461626c65206f6620616e6f7468657220636f6e7472616374006f626a6563742070617373656420746f206d6f64696679206973206e6f7420696e206d756c74695f696e6465780063616e6e6f74206d6f64696679206f626a6563747320696e207461626c65206f6620616e6f7468657220636f6e747261637400757064617465722063616e6e6f74206368616e6765207072696d617279206b6579207768656e206d6f64696679696e6720616e206f626a656374006461746173747265616d20617474656d7074656420746f207265616420706173742074686520656e640067657400000700000008000000090000000a0000000b0000000c000000696e76616c69642076617269616e7420696e64657800756e6578706563746564206572726f7220696e2066697865645f627974657320636f6e7374727563746f72000041000b04e82200000000000000000000000081292a0b46e645c14534988939f33d632cb0263615d92cbbf1612b473443947404000000033b3d4b010000000422c55bcc9df846ced4de43e8b8da9ad8057bcd95e32e31cac7e75468010000000000ea3055024900000000000000000000000000 DMLOG CREATION_OP ROOT 0 DMLOG RAM_OP 0 eosio abi update setabi eosio 199629 137 DMLOG DB_OP UPD 0 eosio:eosio eosio eosio abihash eosio 0000000000ea3055d7abd75d188060de8a01ab2672d1cc2cd768fddc56203181b43685cc11f5ce46:0000000000ea3055fc470c7761cfe2530d91ab199fc6326b456e254a57fcc882544eb4c0e488fd39 -DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304003,"value_ex":101997,"consumed":7929},"cpu_usage":{"last_ordinal":1262304003,"value_ex":279534,"consumed":4101},"ram_usage":199629} -DMLOG APPLIED_TRANSACTION 4 5ade57480d2e64fb49dd5d8303b08ecff6499745f854b8e70dff5f00cc1c060b04000000033b3d4b0100000004f5b1c8962f98b2d6155f6d21977938d545d83ef187d93aaf83e483e50100d00700008301000000000000000018040000000000000001010000010000000000ea30552deb8b0eef2f2bfd027d20727a96e4b30eb6ccdc27488670d57bf488395c48fc1b000000000000001b00000000000000010000000000ea30551b0000000000000002020000000000ea30550000000000ea305500000000b863b2c2010000000000ea305500000000a8ed323293120000000000ea305589120e656f73696f3a3a6162692f312e320117626c6f636b5f7369676e696e675f617574686f726974792276617269616e745f626c6f636b5f7369676e696e675f617574686f726974795f763019086162695f686173680002056f776e6572046e616d6504686173680b636865636b73756d32353608616374697661746500010e666561747572655f6469676573740b636865636b73756d32353609617574686f726974790004097468726573686f6c640675696e743332046b6579730c6b65795f7765696768745b5d086163636f756e7473197065726d697373696f6e5f6c6576656c5f7765696768745b5d0577616974730d776169745f7765696768745b5d1a626c6f636b5f7369676e696e675f617574686f726974795f76300002097468726573686f6c640675696e743332046b6579730c6b65795f7765696768745b5d15626c6f636b636861696e5f706172616d65746572730011136d61785f626c6f636b5f6e65745f75736167650675696e7436341a7461726765745f626c6f636b5f6e65745f75736167655f7063740675696e743332196d61785f7472616e73616374696f6e5f6e65745f75736167650675696e7433321e626173655f7065725f7472616e73616374696f6e5f6e65745f75736167650675696e743332106e65745f75736167655f6c65657761790675696e74333223636f6e746578745f667265655f646973636f756e745f6e65745f75736167655f6e756d0675696e74333223636f6e746578745f667265655f646973636f756e745f6e65745f75736167655f64656e0675696e743332136d61785f626c6f636b5f6370755f75736167650675696e7433321a7461726765745f626c6f636b5f6370755f75736167655f7063740675696e743332196d61785f7472616e73616374696f6e5f6370755f75736167650675696e743332196d696e5f7472616e73616374696f6e5f6370755f75736167650675696e743332186d61785f7472616e73616374696f6e5f6c69666574696d650675696e7433321e64656665727265645f7472785f65787069726174696f6e5f77696e646f770675696e743332156d61785f7472616e73616374696f6e5f64656c61790675696e743332166d61785f696e6c696e655f616374696f6e5f73697a650675696e743332176d61785f696e6c696e655f616374696f6e5f64657074680675696e743136136d61785f617574686f726974795f64657074680675696e7431360b63616e63656c64656c617900020e63616e63656c696e675f61757468107065726d697373696f6e5f6c6576656c067472785f69640b636865636b73756d3235360a64656c657465617574680002076163636f756e74046e616d650a7065726d697373696f6e046e616d650a6b65795f7765696768740002036b65790a7075626c69635f6b6579067765696768740675696e743136086c696e6b617574680004076163636f756e74046e616d6504636f6465046e616d650474797065046e616d650b726571756972656d656e74046e616d650a6e65776163636f756e7400040763726561746f72046e616d65046e616d65046e616d65056f776e657209617574686f726974790661637469766509617574686f72697479076f6e6572726f7200020973656e6465725f69640775696e743132380873656e745f747278056279746573107065726d697373696f6e5f6c6576656c0002056163746f72046e616d650a7065726d697373696f6e046e616d65177065726d697373696f6e5f6c6576656c5f77656967687400020a7065726d697373696f6e107065726d697373696f6e5f6c6576656c067765696768740675696e7431361270726f64756365725f617574686f7269747900020d70726f64756365725f6e616d65046e616d6509617574686f7269747917626c6f636b5f7369676e696e675f617574686f726974790c72657161637469766174656400010e666561747572655f6469676573740b636865636b73756d323536077265716175746800010466726f6d046e616d65067365746162690002076163636f756e74046e616d65036162690562797465730a736574616c696d6974730004076163636f756e74046e616d650972616d5f627974657305696e7436340a6e65745f77656967687405696e7436340a6370755f77656967687405696e74363407736574636f64650004076163636f756e74046e616d6506766d747970650575696e743809766d76657273696f6e0575696e743804636f646505627974657309736574706172616d73000106706172616d7315626c6f636b636861696e5f706172616d657465727307736574707269760002076163636f756e74046e616d650769735f707269760575696e74380873657470726f64730001087363686564756c651470726f64756365725f617574686f726974795b5d0a756e6c696e6b617574680003076163636f756e74046e616d6504636f6465046e616d650474797065046e616d650a757064617465617574680004076163636f756e74046e616d650a7065726d697373696f6e046e616d6506706172656e74046e616d65046175746809617574686f726974790b776169745f776569676874000208776169745f7365630675696e743332067765696768740675696e743136100000002a9bed32320861637469766174650000bc892a4585a6410b63616e63656c64656c6179000040cbdaa8aca24a0a64656c65746561757468000000002d6b03a78b086c696e6b617574680000409e9a2264b89a0a6e65776163636f756e7400000000e0d27bd5a4076f6e6572726f7200905436db6564acba0c72657161637469766174656400000000a0656dacba07726571617574680000000000b863b2c206736574616269000000ce4eba68b2c20a736574616c696d6974730000000040258ab2c207736574636f6465000000c0d25c53b3c209736574706172616d730000000060bb5bb3c207736574707269760000000038d15bb3c20873657470726f6473000040cbdac0e9e2d40a756e6c696e6b61757468000040cbdaa86c52d50a757064617465617574680001000000a061d3dc31036936340000086162695f68617368000000012276617269616e745f626c6f636b5f7369676e696e675f617574686f726974795f7630011a626c6f636b5f7369676e696e675f617574686f726974795f763000000000000000000000005ade57480d2e64fb49dd5d8303b08ecff6499745f854b8e70dff5f00cc1c060b04000000033b3d4b0100000004f5b1c8962f98b2d6155f6d21977938d545d83ef187d93aaf83e483e5010000000000ea3055890000000000000000000000000000 -DMLOG RLIMIT_OP STATE UPD {"average_block_net_usage":{"last_ordinal":3,"value_ex":80800000,"consumed":9696},"average_block_cpu_usage":{"last_ordinal":3,"value_ex":368326389,"consumed":44101},"pending_net_usage":7928,"pending_cpu_usage":4100,"total_net_weight":0,"total_cpu_weight":0,"total_ram_bytes":0,"virtual_net_limit":1050675,"virtual_cpu_limit":200400} -DMLOG RLIMIT_OP STATE UPD {"average_block_net_usage":{"last_ordinal":4,"value_ex":146193333,"consumed":8009},"average_block_cpu_usage":{"last_ordinal":4,"value_ex":399423669,"consumed":4466},"pending_net_usage":0,"pending_cpu_usage":0,"total_net_weight":0,"total_cpu_weight":0,"total_ram_bytes":0,"virtual_net_limit":1051726,"virtual_cpu_limit":200600} -DMLOG ACCEPTED_BLOCK 4 04000000040000000300000000000000010000000000ea3055000100000001000240e54a7b27e042b80a810153bec1dd166eef95fa69f6c9886ae283363bc2add80100000000000300000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7192d5b1b639d6ae94fcdd0536b224644931573d1ccb2a0c548613cd1feea18888b5a5902476311cae3e60a34f4b68b4336275d05d6835128c04ba783367af61f050300000000000000010000000000ea305504000000010000000000ea305503000000000100000001000240e54a7b27e042b80a810153bec1dd166eef95fa69f6c9886ae283363bc2add801000000000004f5b1c8962f98b2d6155f6d21977938d545d83ef187d93aaf83e483e5033b3d4b0000000000ea3055000000000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7196b5bdb9f6b98a1a4629cfddea5210c8afcc2c3b5364a9e9906716f0e72dba9e90d2ddd212cdd265a1ec5551fc1187ed73259766adad832e3a0e143676db9055d00000000000100008105141a99a59d87e06e09ec5b028a9cbb7749b4a5ad8819004365d02dc4379a8b7241ef43112c6543b88db2283a2e077278c315ae2c84719a8b25f25cc88565fbea994a90c00d55454dc5b059055ca213579c6ea856967712a56017487886a4d4cc0fe0fb64b1085cc5538970158d05a009c24e276fb94e1a0bf6a528b48fbc4ff52668dcaa34c0517d19666e6b33add67351d8c5f69e999ca1e37931bc410a297428ad9e3d8f650687709fd68f4b90b41f7d825a365b02c23a636cef88ac2ac00c438ba52fe7a3956c5cd3a656a3174b931d3bb2abb45578befc59f283ecd816a4052652f5f96006294109b3dd0bbde63693f55324af452b799ee137a81a905eed25f0af56d2c5a48d60a4a5b5c903edfb7db3a736a94ed589d0b797df33ff9d3e1d4e7bf348da00a945489b2a681749eb56f5de00b900014e137ddae39f48f69d674fca8bd82bbd181e714e283f83e1b45d95ca5af40fb89ad3977b653c448f78c2299dcb6af692324b899b39f16d5a530a33062804e41f09dc97e9f156b4476707c3a6138c5061cf291310887c0b5c71fcaffeab90d5deb50d3b9e687cead450715443fcf88330c586bc0e5f3dee10e7f63c76c00249c87fe4fbf7f38c082006b4bcd2a26394b36614fd4894241d3c451ab0f6fd110958c3423073621a70826e99d528b9f6e9693f45ed277af93474fd473ce7d831dae2180cca35d907bd10cb406bcb40a24e49c26d0a60513b6aeb8551d264e4717f306b81a37a5afb3b47cedc35c2186cc36f7bb4aeaf4487b36e57039ccf45a9136aa856a5d569ecca55ef2b98c4175db53ed27e7911a1b5adf0e7db0fc96c2cae172cf594dfa9a742ca9e88a9cb566f982145ebccca8dcb6d2fe89b91dbd445c32ecef873cdc5d594279fcc002011cfaa913847cc0153220aaca619114879a97d55942af073d83a71fd044ede7257cda33f044c154d10a137e48e9862e00bf114268cc46b3eef3a622c7fd6c3a20000000029807708239aa7de914d3ed61e9009ab2280bfbc50f1d9769f27f8341ef26198000000000001150ec7e080177b2c02b278d5088611686b49d739925a92d9bfcacd7fc6b74053bd1a99a59d87e06e09ec5b028a9cbb7749b4a5ad8819004365d02dc4379a8b72412652f5f96006294109b3dd0bbde63693f55324af452b799ee137a81a905eed25299dcb6af692324b899b39f16d5a530a33062804e41f09dc97e9f156b447670735c2186cc36f7bb4aeaf4487b36e57039ccf45a9136aa856a5d569ecca55ef2b4a90c00d55454dc5b059055ca213579c6ea856967712a56017487886a4d4cc0f4e7bf348da00a945489b2a681749eb56f5de00b900014e137ddae39f48f69d674fca8bd82bbd181e714e283f83e1b45d95ca5af40fb89ad3977b653c448f78c25443fcf88330c586bc0e5f3dee10e7f63c76c00249c87fe4fbf7f38c082006b468dcaa34c0517d19666e6b33add67351d8c5f69e999ca1e37931bc410a2974286bcb40a24e49c26d0a60513b6aeb8551d264e4717f306b81a37a5afb3b47cedc8ba52fe7a3956c5cd3a656a3174b931d3bb2abb45578befc59f283ecd816a40598c4175db53ed27e7911a1b5adf0e7db0fc96c2cae172cf594dfa9a742ca9e88a9cb566f982145ebccca8dcb6d2fe89b91dbd445c32ecef873cdc5d594279fccad9e3d8f650687709fd68f4b90b41f7d825a365b02c23a636cef88ac2ac00c43bcd2a26394b36614fd4894241d3c451ab0f6fd110958c3423073621a70826e99c3a6138c5061cf291310887c0b5c71fcaffeab90d5deb50d3b9e687cead45071d528b9f6e9693f45ed277af93474fd473ce7d831dae2180cca35d907bd10cb40e0fb64b1085cc5538970158d05a009c24e276fb94e1a0bf6a528b48fbc4ff526ef43112c6543b88db2283a2e077278c315ae2c84719a8b25f25cc88565fbea99f0af56d2c5a48d60a4a5b5c903edfb7db3a736a94ed589d0b797df33ff9d3e1d0001033b3d4b0000000000ea3055000000000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7196b5bdb9f6b98a1a4629cfddea5210c8afcc2c3b5364a9e9906716f0e72dba9e90d2ddd212cdd265a1ec5551fc1187ed73259766adad832e3a0e143676db9055d00000000000100008105141a99a59d87e06e09ec5b028a9cbb7749b4a5ad8819004365d02dc4379a8b7241ef43112c6543b88db2283a2e077278c315ae2c84719a8b25f25cc88565fbea994a90c00d55454dc5b059055ca213579c6ea856967712a56017487886a4d4cc0fe0fb64b1085cc5538970158d05a009c24e276fb94e1a0bf6a528b48fbc4ff52668dcaa34c0517d19666e6b33add67351d8c5f69e999ca1e37931bc410a297428ad9e3d8f650687709fd68f4b90b41f7d825a365b02c23a636cef88ac2ac00c438ba52fe7a3956c5cd3a656a3174b931d3bb2abb45578befc59f283ecd816a4052652f5f96006294109b3dd0bbde63693f55324af452b799ee137a81a905eed25f0af56d2c5a48d60a4a5b5c903edfb7db3a736a94ed589d0b797df33ff9d3e1d4e7bf348da00a945489b2a681749eb56f5de00b900014e137ddae39f48f69d674fca8bd82bbd181e714e283f83e1b45d95ca5af40fb89ad3977b653c448f78c2299dcb6af692324b899b39f16d5a530a33062804e41f09dc97e9f156b4476707c3a6138c5061cf291310887c0b5c71fcaffeab90d5deb50d3b9e687cead450715443fcf88330c586bc0e5f3dee10e7f63c76c00249c87fe4fbf7f38c082006b4bcd2a26394b36614fd4894241d3c451ab0f6fd110958c3423073621a70826e99d528b9f6e9693f45ed277af93474fd473ce7d831dae2180cca35d907bd10cb406bcb40a24e49c26d0a60513b6aeb8551d264e4717f306b81a37a5afb3b47cedc35c2186cc36f7bb4aeaf4487b36e57039ccf45a9136aa856a5d569ecca55ef2b98c4175db53ed27e7911a1b5adf0e7db0fc96c2cae172cf594dfa9a742ca9e88a9cb566f982145ebccca8dcb6d2fe89b91dbd445c32ecef873cdc5d594279fcc002011cfaa913847cc0153220aaca619114879a97d55942af073d83a71fd044ede7257cda33f044c154d10a137e48e9862e00bf114268cc46b3eef3a622c7fd6c3a20200d0070000dc060101001f00e74c5607ebe92350dc791bb2cb65c8ceb52fe6623104137f710805b93a84e23a3530fea5cea3743b77736669d4962f0be8dbe1bede210eb1c2460924b505a60100af3578daed3c0b8c5c5775f7f33eb3f366ece7609261ed36771e4b3aa64ed90467bd3569e3b725fe902f69a0f4c77abc3bf6ceecd7b3b3c6aea8c734566a3e95684b4b12aa1650da90d05029204441544e4a24a0544d2141a42a2dad2a15416953552a1451d2f3b9f7cd9bd9dde03049402a9b78e7befbee39f7def33fe7ded9f09fa2376a717edfe73e21e047e22ff1b5f1d7c1effd2f7bdb438fe43bc407be71f5d57f7577aeeb2fe0a1beba883df22ef99223421c51ddae38a2bbf8db3b033fb27b44c83347bcee9933d0e577f107fa347fa8ecf719fb4e1c09108cfae519c077c66102b46768a0841ed925c4080b2f003b4dcba3ba04c2c814f4a8a7fc31dd583a19cd1e9d3ed65c9a9d6e4eec111a7b4a8de5d5e6f2747d75b5d1ee08895df1cc5abbdd58ea4cb71b338de6c9465b78d8edd78f2ec31081ed328f9f5e9dab5f7dcd845084bbd77715f7e4465d73d5d5dc17dbbe7673a5b1387bd5c4387707794c23d3b09eb9854ef395c2c767af8732c8e31a194012c1829761bdd3f38dd322c01eb3dae84c1f5d589e999f99ab3797a657eaedfa62a3d368af427366be31cb3b0e161b8b332ba7454830c7bf174c01875d8aa857dacb2bcbab8d596cccaecdc0183142547524ec34171b4cbeed88b63ed30182e64613aac24abbb9d4599d5ee0d55ce24894db4d91b002f7563bcbed06b12fa2ae76e3c45a137aea6b9d3951c2ae2dbcb0e6c9e642e338acb68c9d2fc2ce76637579ad3dd3985e682e363bab620bbe79c9c6fb986e9c125b0972a5dda065d73b8de9638d7a67addd1031518d97cd0fdb9babeeedb41b3e2bb631cbe17979697ab6dea94faf367fad212ea16ec03b3b9d7bc7c4d89617c8e999e5d9867811f61761f34842dc3af1a90c1d6b2bb3b82cecdbdea3e41cac5dea03d78b176f8bc5b6388e4b7141c5971654e132296359e19f82b41fb252c04f5180a674ff54411614fc143c5faec872d9d752c8e052dd95e9d90b22ea8af49f1fcd3ec211e9d75756164e8b978d5c22452aa3d2eb5eff0bbff84bbffcab6f9c9e6d1c2b7ef0edf27a4fc4b5e8cb5a18115f198f1961e46bbdfd5367cffecfe3f79fbbfbefefe91a05cfd81dbfca87ee07bff85bbff79efb5fd7ebbdd6f57ef06f3f2b7add3f83dd67bffad0372e7ce1ed391c3f6b477fece3ff797baff73ae8fdd69f3cfef90fbcef0b0fe770ec271c671fffd4fb9f9ceaf5a6dc7bf69b77e57b5fcdbd1ffaf63f7ceddedc7cd773f747bff9c5fce003d8fbb1ffbef7ddf7e47b0fd2d80bbffbedbeb187a8f7f7fffaeb8fe77b6f64bc7ff7a7eff9e2c773d3dd4cdd8f3df4e14fdc7d75aff7167fea9df73ff9e497df7177dfe05b7d23782b173e7ed713e2366f7f4acf4f7ee1c3dff88dff10b189067ffcdc70c7a7be3d0382b7f42348457c55d496baab60d2b248c556e84a454dbd039ed3f864225b899a8027ee3db73fd146b4d2adad74e5442226a00300551a778cb801c1a12d5b38de4868546504afe57e91760fe2dbf49d17442c23a32325a20929bb2f8539e6137833a14a000c33946a4af4d09fdd8fbd384d2aae1388377aa5545d589a34624755aafd1af0c75724a22c5351e535a689babe2c8dda2644494491115180e2fb13910f3a2fecef222e56ecd5e7d3e8665ec857c47c22c78070b0f42f09d844819a31b4bcac85af45fc8a517a34b286af60c5f3f116e8f98a688d89e8fd05582192b30618e09797a8f9347c0defff61d83f7556556414c014e2ada38676eea505a2b587bdadaa7628005a6f0cad532f07ed65d0a5a1a0e3a1a0b70f055d190a7ae750d06628e8b1a1a06b4341ef1e0a7a7c28e83d43414f0e057ded50d017443fb8dc0c5ce5c05506fe0880cbef0d2e07c0115844df965a76d519b23be3f38926b38373c5adb83025aa5e1a57d1a02968fb60e2f08551ad6aa0d0de02cec36561fca9c29dc633c155429c4bbca9c9f3e7aa3ebcebc2ba8c07efaa5e89ed6f2a0fd0daee67eb0b907b35982607bb570b9c0eed7dab2a70769c3522539ea8d480e9663431a0e94daf011ee7d39df4542b1e8135165abb34401a8d1f1e4ee4edc5c881e603ab0fa206f6114cffbb212c817cc0c3ed3f2578ff1a1410fd00b4a6c02e57e0a3bb57c7308d007489874bd6849068e0c116d1bbddf36f1ff9f7abc00508f42287687d0011bf32017a8f1bcd1bbff008bb1d03bc1bc7f7b496780fd3c78bd56b69d8dbfe12878160c4bb12818b888126b556e2631bf6012b4c02d7aeb492d0b68d46b4c0427c42cc46814f480af8e199c27c3c0e84c27e0082bde0a8809f63f71c22d1262db65d7a9c774e636a203373f661421de109043b0e3ba4d09e50b3d00407445c8caf19653c853c8d2c212dd6f8d2c49f507b88943032be1d593a7506c82adf0cbf7efdf53b600d48334193665c40fa01e06ee282aea99d89c20f730bc02b7c13c307732b25506598ab204f15d8c0ce1272029a76bdb41d0d362c9e8810d191aa7090e2fa323aee97473c5325f1af2f8bdebc205707510daa02506a8c57e65ac876501b4321050a83421c0a70000b044a3261aae2272e7627e187099f22df7d2ed0234e2f311e505558f618cf297005a0bce06690bb3e29034ceb83f8d7303038004107a804ae02175652107bc0f3015c2374e2c2029238fe0f5407561957133fedb2edf82f1453248f9fbec53b5cc6467c45354c65b580bd405d8e8ce693700cc65741a724488e1f5747596803165a2ba301127edc04406bdb0102ec5a356e295c7f48a15bfae4a7484b0213b270851886788a77985ede3708e5bf3a0278c06414817c604c8d971a0003db118139f149a1ab2a657352222346a35ad5326ddf673352422b16993259b188ac5809de8115f34d84562c622df59d15fbe8a3b402654a2864cac1b215f331186d91dd8c705ae0005a312fb362beb362767ab45a8002a7ec1932524b58066a5035c2b922a41a4f199922be30d853446878a8f10309b5c9a97911ed3675c53dcd97a076207dc18432f8817a05e8d16ec19b9d4ed676263e591c101b542d1f5fc6f01165aa65e02940d542f9ca546b84e6b3c4d620aca05780b1807a1042104cca4aec6114d8efb30e50fc6a82e82ea5159867d20203d6b90a16628c2c3fda54c16cf824194bb53f56641ad8827e9d3a8d643fe0b11da45f011bc3008d21c63bc0978c4a187bc173dc7b06427a407b7ac016893585a60a594713f08c7fc8f2a8d35b5be446d0bcd52878f7d02ca3ddb141b647bc46ff0beb420b09bbd9338512508b13c22aac191460067d34837e66064180d03e7c5ef7fc3650064c03b978da49a2af1597714c4f8fde94397fadd0680da76ad052d41a8796a4d624b4105cd3b81761eb3eb0058593fbc4a5a4eb31b45e4cad0ab4b623100cd82742eac3714136cecfc679b8049e7ff24e9cfa4ece0acf5e785adc710e3a2ab6e32bd7dd4161023d3d75f91de7f065e13c3e7e6b2bbeaa60fb3b2101d5a0fd5d7d072dfbdcb973ac79304dfc3c4f53210221d1b6510b097909b5907c715f9a25e7d3cbd9909e7f240bc2501ac126985c1066480814711462b17bb4f4bbd624e37bfc05d49b4f2b8bc00e301e41fac1271e7802b5307d001bd5d08d0521a3615efaf8034fbc1c0c246837d89b4e1282590e0eef48425c0e587041b11858d4ca42bc0b432349de005d00ca287a8dca4202f99f44f514a8e9b06a927bcc42031e84e02d8af1c0f80636b7e4e586ec7c0a2d703455a931270737e4e12c1034f12c921502e5135eaf406c97e91b4697d04d53e3f31cc590e04743e391d3a4292d49439a12760401ae8877c3db90a33d1fd54ee06a3d8c86d80103063018b0a21057142224382de79e259a1f89e607b687335140869d1e74468f29ed394b1493bea5b821f2ee3015b8308525075e359283d3f1c49f4ffdb507ab01791d09713ef8c4f03cfac7db70378a286179eebb052a6b20d024600a4d569588fb8c98d237134c98760f9495454dda586ac5af1d251348b82078f42d35897ebea526901136e5a39c808cc4b78988431cf4ece0e96f2a534c68c2f9f8e72c20455026bc85de802547798e38f8f2f8031780d8914aa0a7f1cf8f925f040bf6675aa105ebd92f34def165cfb11913991913991913793326d88c89cc8c89cc8c89ff7f660cfcd18ef4939039ee045efd74fa096ab1818afea0dfe570854a585e29e4153e32afb4e595b453286a31afa49d8c324dcb2b68dd07c68b7925d10513afb0c5bc92c84c0f79857dcc2b37cecfc6792eb7d048443d4844dd4744dd4f449d23a2ce11516744d43d5ed134f1f33c4d8508c4bcc216f30a5bcc2b8856e29752cc02dcb9ef4701c10f5b40a0e21fa320e04b0f739ec08cfa73293de7457a491d84af3f9e78655b732860c5859c00d958ae33a467bdc3e48eaea82acec23c978501127a8e2f1fb5082c300c819c4a46bd7c09f312ced83901436f4bb1ac979e3a91160ee6732b9d8d6593fd6aa961e5b86c5eae4b822f72691106ef3f42b20192cf289689f13e9960894051789632600b4c63fc81b91df4b7b0ca52b3352dc295cfb631daab6132565363582fa4ba88e33e0909961bc7284a51079f09ee3284930e4e3e039c05b8740080169e52e899c932e59185563c35ca35974242e514da5f89ab2ab6a8f7b4b4153d5bfa84dc5b63d4abe97c8862e5c3b48c3b1eedab8f5e292810e22553e088a1d2d3e20410ea697922519d07cf216bd2b00559685045a376569e28db2089623e9f633e05c112b92b8c8b30187611938781367ef040662184a53795b9eaca3cf22217d307f348b5f9c4bf254738c683ac0e205dce9209e3db8aee5daa2f8b287060ee257adec8c3145e023df609e19210d8aee6427217a27e5b2dd22ef7c03d61e2d1bdb12cd3a7e12744412752c24b957e17ba34e71b0af30d8d8504c8373409aeb6c26b34241b5cc4c67c016807294155f7d662235ab7060cc27b19908489e6a9fe03531c42f1476ad1d629888f38d42f70fd13237e8fc27017d16fb5d9c1434a69100dd0b3b3f23955b4dbf9e356ab6813ea0d2cb9873654b3db59ec3f2d06148cf0a0dcef67e849787a8c4a279328f8a40054e5c15ece9150b75ca1974b0c7a97be35f1b9442df76ad47dae6163e9bb66cb9dbbf421c67a356bd3644e9bae75da7456a23add38a479838d3f7181360e9d7f2395c70cf8413bbf9cd71b7079a0df9939c2a25b60f49502d24a83b90926d5e2605c710ef101051bf25c0eb3d9862a764395ef7743150bfcbd36e45b379eacdf15e4d5be1b19bb91f1c0a0426e50c5d1a7b249488095b5806944670671b5801f95ea08916ac414b0f410bf84ac37ece87d5a46fd3e0ecd32512aaba6fb962a586df6062acdde189905dfaa1da8f876fe88f90008f4a7c2fa5370b10d6d5bc787476945ec45e2bd53a48506cf1fc00781198b47ad573124df8c758cf27eee174990abf77b60dd03acf707b4462c2800c18fb4b01a83e46f2505bc3ad0c572bb972eb49211c45044cc454bf8955612917d3545cef8bdf450c6be16d7294b8c417349f250cb9452d549cf3f2a50f1b7491491b48b4aef837016e9042232239496472632457a85aa5ce061bc68aabad29998e6f28897f39d9fd3546e1dc9e510e46d341d04d201209f6a6de44475849a8232c1e69cbd0ab84a72a23e39511f9d28d6984294668d358c754e34cc154e9200130bcd7e5463cdf635ec40b1408147573771051d26f43b407713da0a4fa21d433412742463884686147182081912e14126740243f0be07b8afe880f591875af61dc0fbf8aecc181417d78121e54186f84ce900f615596a17a9bc8665fd885e21b5471c430a546782ad159054a047111301d711ba5290e0d289e6f32c2e0c6d272d26a58f6f20114108c6969513ff28d045e0a6ee95ac7a3181e698c04322bbb000ebe089d51ccf7ec02cae556839a5125ceab725ccc41b8c1eb27325ebbf1d2b4126c214f330aa6042e0701dea3f49943f0f1cf3d7309cc0e31daad6e9d45b4b5082428827d83fa3106aacf6790e8fc6b6df81f042935540394043048285123182815f6f3795d6e6fbc2bd54bd5c0842142af21602aca805a6385f8d580fc0be410c235138026667113b50ecf8c446529191a31b09bd786223ac3ce5a449a2e86de1f2a144d9dccae4dd424269cba05b596cb76455d10e4a206c4fda1e24d69c1b1d98328f6244841b2d820fab48ac9980b5a29de69094a2a87249db30092f25810c9731ac2a7058e5715835c2a5529880853360bb1738bb15f6db3d5c6fc247a7744181ecde56b67b2267f7a4832753eb3b352b58bbe70faa996682cb2a157769435b6c20b8958f78a98e1b5a6d3465568c32aea48c6f6c05f2b392e241debfca540f236f6db5633076f3aa1ebb6a77e8cdb7a5263854c53a35e190ce6afa59eaa1f14d9fd59479ab49062eb39a78e0d64b3d3cb49ae4fc514035959dd96a52d6e0df171f89de2a29501b3c2b7e3e225b1b9482e9b9c9395668ff943bb6dbe4dad90d83298ce2f3908bbb76b6113486221777edecd941c743416f1f0aba3214f4cea1a0cd50d0634341d78682de3d14f4f850d07b86829e1c0afadaa1a0d75d3bdb0cfc22af9d6da6e11b5d3b7bd70f4b1114d217b260e410dee1f91e454cf6a0efa94d8ce986cbf10796e3e3727c36a653942ab9ab2e695ce51b765914925d34c3eb0584b7ff928b8f9755426b7a7d3e43c6733c8c74507e47ece5962245ae8ff1e5165ea2e2db2545bcdc1298882eb70474b9a5880904647926c0cb2d7c210853dfbecb2d23a688841c71b06ef923682647705f38edbacb2dca5d6e51ee8a1e044ff0307845af68f3489c28404af07c9cb172a09dbfac66893670654ddb2b6b156ef195352a920082902b24ff0234297089c4e76b6472af7e0357476ecd7c5adc8a27b32b589fd6da73272a3f3492d02702c47bdff23eccf3be90e77dc8bc2fe4781f5e0cef7d1322ef7d07eb16ec5305c1f23ebc28de871bf03ecc78ef33ef79bee1796fafafeecb38f984d4bafff09e534dcdd11ac479938b0ff231b8a03b0bfc9501e3e301bb6f0fd8dd3d02bea768c3d79a1a4f82072921d81cc65d3c0cdcc1bca2948e025ce884e8f63b0fbbe8960da5403b4ba01eb808ac54b8dc2ea6dc6e2b9dcef3f707becb056f3db039fe36005d3ee0648f32217d1f5e4c03f18245828cdd06c94bd8e13a777b9fd89abb4c22d65d60f1b0fca250a865cea24b9b0006f66e2e85f04cde808894c3196e8cd31f080239d9f031aabc7dd4dd5708f05e09c394f2a488be2ca968a172fbe77a8491d7a898f33fdeb587bbf636dfb5de68d79a7de0fa5debfe5dc72e9ff3b890e330ea8d31ca01a76cf71cbf617480c997b140502ac5a251c55b1e9bf69f54d2e5345420a66b1f69d24a6cea586b5da3c414b4ae1463a93cb183aaf0026557f4c4822f94b89b313555a3e190eeca9328e7277624545cc7537d41b34677ebde45eaf55288eaf5024aa193c390e550daa2d0356a9ccf1c9e71fa2d1733fd96cda777da1ea26df0d6ab7c083a0d2aff914732950f3188f4fb32262fbbc6bf5e5906c2319a3844331172323c6826662133ecc90a05665846419385c7315e2e865bbf5fc59e6c60b3140272ba9a5669ce17649207e40b300b0878b53f30de04951e40652f9b412614ffca68f4bfebcd122b0464fb3015289246457ab06a2b07fa05b25376053eae007e9d48821d547fa7f204393113eca0928e9dcbf8376f38d706a78f39abace8ff51b21f6c69680e48d5807578a1ee43f6c8dbd0972e385ca1faecf6dc972f54894fbdbc768fb7aea2b071b6c3570a37b2ad5e5c1fed37d574644bb78eb9fa63cfd404dd9427ab78880f410416a73caa03ba2a72a545afd97de78b531e579d5455d813ef880b3d940cd1bd443a5f93947aec7575ba982f43e2310af495285779efa336e2a3e393dfe4dabcb7cecdbd90b5797bc01da2455f5f9b3f6a0fb7fb6af398b54c2e606dde52d547aa6a7b993f09085faee487afc19c0d50d5d65835acace082a1ac6ceee7cae68e7546c733a37d22136c94a20648df3dc4c675592a9e9022c67e9b1abdcf97a5fe92fafaa2fae462afa83ece4575c545750ae928fa5759415a6505699515a41517a4b9d55f729fdca0e49e2bb51367a8d4fec7bff399b15bca32bd173e7395761ca1d3dffeccbd97e0b93df2477636acb34b94e6c9855e6d1df8686bebc8d15e6dfdfbda1452c6b526fb2aefd90568577da76fd76c548ca6afa8b8aabca4aa3c19f25e551e0f6a6c191e9016f135c95da9ef4487dcb29f9de9bccb4a1e558f4b5c568fe87e2d0c7a73eb1552bc0adc367a0a40ce0568b73a8e3cdd22eded5a5a964d3e73c74b9e3b5e22d9b59573c5674b62500324ef07b1dbcbbb51ee2b132c9deea2c33ff2d726b43b6e1dce5684eb6d85665ba1d9568483b602ed02dfffe0cbccad9e3f090f0eaa60c85ff419f05ae1a05bb65ffa8047cbb35a8b4ae68364e2cbeac2dad571fe4a079e89c19ef82c862e36715a29b22be771efb9c0076bfc5ca2db2530517c1ca93cce36e046baafb34b5888cd66100333888119e8f9b945764aca2ea153f648c9a2b332db43e7de3b74eed9a173cfbbf179379fcdf0dd7dc03db6578d1985da6baf6a89e85f3d3e80b820720e1d355a91d9e5e72d4a487bb2c65fc822552850c9220b80d5c10d1cbbef2e650c446eb6f6d02722d951ef648bae24af131172bd443c998908c519fd64a7ae7e41a1ae7e59b1d772acb8287628b91066f7f3b55d40b52b1ff36e84c75b87878d277ecd3151f1dce8b3a31949047d75d589d8581ff5f25296a39e5a4f3db59e7a3d7173dfff1888832e5031e7bdf82d99dc25672475858411bf254bc24cd70459e26a78560e215fa2e7f972076267ee2877eebb724b59d9225ef10632c1f8d5191403205e9be319f465f8a72002f08614a3f3371c021860bf6501e61fef82f8643d1118bfb2435f6fa3ab6d1eea8257a65b02ec8d383486d4fb0445c648399c09e370776c2c266cbceee2677817bfdc1eed66c62eafb719e19e13fc7c9b46f211329333e6909936bcdd391f63d34d886d7f121cd3d77d4d7f61233a7dacde5c68cc9aceb2a92f2c2ccfd43b0db3523fde58156b4b8d532b8d990ebc6cb4dbcb6dd35c32c79aa71ab3d3474f771aab66667969b5d35e9be92cb74567ae6196977818ffb91b33535f5a5aee98a30d682de00cb3cd36605b382ddc4ffad68745f4a4679ff0cfe300be467dd1d43b9dc6e24a8757f5a6769396b4da31384b6369561485fd333c801356da31d95fe3d967c44a7bb9b33cb3bc60dc98e6aac185f4fe620fff012c05fff4b39b57e05a7df817c0bfe5a32dd80e0e58650018deae0331a6b1cd7302c516d7163acde9e6d26ce39460fae0df046a2e1dcfc60b4ba91978013332de5584edd48f2e40c7315387f7738d3692bcd3868dac9f7c7179b679ecf426f3da09ec988b9a80ffea50db717166aebe741ca8d16e2ed6dba7cd7ce3b479d35c63c9a2c4ddd4972ce24d098afbeea7e7f1464788106859807f23f0af08ff22817f8a4588e6d2c9fa4273d69cacb79bf525dc136ee5d90825d8dac8fb6a02b8fe0f216a74d100d00700008301010100203d33cead0d8cb33323616dbe9a5ffbc9ba05f2b727d2be15c3832fa53e9260492fc88e9db27ca1cb7eb80ea3dcb514f23d4253ec80d5ed34b02b43a922ac95730100e70778da8d56bd8f1b45141f7f9cedb393d3e5201c97822288265220e704eb74d551d05050f0511d6119ef3c7b47de9dddccccda67a891083448744142114290e2aa4b135d2822b7202402698002e840e27fe0cdec7a77bdc7999b623fde7bf366de7bbff79b69fed179b7463edafdfe21c151310ff2f7b5b7cdeb817b345b10dcfba7dbfd6c632eb9bdb106a1e2e1ee2eedf397b65fec5636fb7ee88e1cc587828ba14363ed8592ebe9e531959c0aed9ca277c6d7b65ae8c4f1a8f24875259c0890754103a81b49c7f5c01da938e8bedc6b5157f331d5402a6b03a03a96e0303e04a58b56ab996b525fd59e04e5853e6bc45ce8ebddfa08a6ea1c3e9c09f0a1a7f76fa253378c85565b11c8802b0c4a383e8cc1cf4c5626946b75de3c33d9a5d3c321d5332c7bd1ce773dca85135189e16a908a5c782aa00769aa046827567408d649efc6254de5107459eb44ae4e97d93293b5a442994c611c8b2eae779feb538513402eb55acf7dfb00133a4de5cfbba1d070a09d81049379651357d8898883b39a3210a9692162378a1736b21871a65d1671d9c55680095e66f06cd983cf07a07990a58cc100a4048646070e1c445c526b37e1828593d4ea62d90b033fcbdb3346c985cf0538a95af1f7e70b6c9ed43288b467d5db3d9b9e1c5e4555c7a5c205df2e45aa6bc9df1c8deb653837ccfe392bb64a1ba722ee8c39a936d346b0bdd7ce6727ff397649b5863fed28eefbdc75f0b391c8d34db5700723ebb1bee0b1ee860c922f3d8d92af8e845b319710c07c5981704b26e174576293872919648f8421f22e6f5856805cd00c512f43897da84030043b674dbbb9ee4e0b25da5472a53fd5a04e24090908dda56b9693b0790a43906ac1f264de17d2b311c990c52e6e2aa7a9eaf94c98459987731ab19ec3e4cd09912d65c4a6b13415a9d407320cacff86028dac5b2a7b0d454966da46eff30089af54c855242bc7daac585a6a9ba64e624c05a6c58a8226fa32d52f396a8c0383841593989dd571304602c4ac25ff162ec956b08ada52a4229546f2f1dfec69d689241f97826a72e51871e2b8658d4286ce5a0a93c4621f9e3e5994fd9bed586450aefd2f94db71c468da4af5a5ad644298e3bd6eecf352770a470ca9b6ec9f0237258a4520ade3417ce5733c94f353917c7bfbcaab1f7efdca022f90bdef7eb977f8e56bc55ec7717554fbe693bc57c9de17772eb307778a0d88e3f7c71f3cf92aeba74fdfeafd0aecf078117938ee4270789ca16c7e7d98438c901f5e3ff68e664548e1d87be1e3a359060d421e3d7ee7cdfbb342b171bcf770fffe2c2b2b8e9d1f519097d004f7e8af3f7f2ed6ca06ecbff1a458117393b94b7ffa6dbbc67b3708c9ef1b78eb39c305a5b2ecb427ff024faa597d0001 +DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304003,"value_ex":103433,"consumed":7921},"cpu_usage":{"last_ordinal":1262304003,"value_ex":302684,"consumed":4101},"ram_usage":199629} +DMLOG APPLIED_TRANSACTION 4 78abc3b1ae22aa2722807ad0acf95f43e21cecd8fc44ef7fb92a3ef3199f229004000000033b3d4b010000000422c55bcc9df846ced4de43e8b8da9ad8057bcd95e32e31cac7e754680100d00700008201000000000000000010040000000000000001010000010000000000ea30552deb8b0eef2f2bfd027d20727a96e4b30eb6ccdc27488670d57bf488395c48fc1d000000000000001d00000000000000010000000000ea30551d0000000000000002020000000000ea30550000000000ea305500000000b863b2c2010000000000ea305500000000a8ed323293120000000000ea305589120e656f73696f3a3a6162692f312e320117626c6f636b5f7369676e696e675f617574686f726974792276617269616e745f626c6f636b5f7369676e696e675f617574686f726974795f763019086162695f686173680002056f776e6572046e616d6504686173680b636865636b73756d32353608616374697661746500010e666561747572655f6469676573740b636865636b73756d32353609617574686f726974790004097468726573686f6c640675696e743332046b6579730c6b65795f7765696768745b5d086163636f756e7473197065726d697373696f6e5f6c6576656c5f7765696768745b5d0577616974730d776169745f7765696768745b5d1a626c6f636b5f7369676e696e675f617574686f726974795f76300002097468726573686f6c640675696e743332046b6579730c6b65795f7765696768745b5d15626c6f636b636861696e5f706172616d65746572730011136d61785f626c6f636b5f6e65745f75736167650675696e7436341a7461726765745f626c6f636b5f6e65745f75736167655f7063740675696e743332196d61785f7472616e73616374696f6e5f6e65745f75736167650675696e7433321e626173655f7065725f7472616e73616374696f6e5f6e65745f75736167650675696e743332106e65745f75736167655f6c65657761790675696e74333223636f6e746578745f667265655f646973636f756e745f6e65745f75736167655f6e756d0675696e74333223636f6e746578745f667265655f646973636f756e745f6e65745f75736167655f64656e0675696e743332136d61785f626c6f636b5f6370755f75736167650675696e7433321a7461726765745f626c6f636b5f6370755f75736167655f7063740675696e743332196d61785f7472616e73616374696f6e5f6370755f75736167650675696e743332196d696e5f7472616e73616374696f6e5f6370755f75736167650675696e743332186d61785f7472616e73616374696f6e5f6c69666574696d650675696e7433321e64656665727265645f7472785f65787069726174696f6e5f77696e646f770675696e743332156d61785f7472616e73616374696f6e5f64656c61790675696e743332166d61785f696e6c696e655f616374696f6e5f73697a650675696e743332176d61785f696e6c696e655f616374696f6e5f64657074680675696e743136136d61785f617574686f726974795f64657074680675696e7431360b63616e63656c64656c617900020e63616e63656c696e675f61757468107065726d697373696f6e5f6c6576656c067472785f69640b636865636b73756d3235360a64656c657465617574680002076163636f756e74046e616d650a7065726d697373696f6e046e616d650a6b65795f7765696768740002036b65790a7075626c69635f6b6579067765696768740675696e743136086c696e6b617574680004076163636f756e74046e616d6504636f6465046e616d650474797065046e616d650b726571756972656d656e74046e616d650a6e65776163636f756e7400040763726561746f72046e616d65046e616d65046e616d65056f776e657209617574686f726974790661637469766509617574686f72697479076f6e6572726f7200020973656e6465725f69640775696e743132380873656e745f747278056279746573107065726d697373696f6e5f6c6576656c0002056163746f72046e616d650a7065726d697373696f6e046e616d65177065726d697373696f6e5f6c6576656c5f77656967687400020a7065726d697373696f6e107065726d697373696f6e5f6c6576656c067765696768740675696e7431361270726f64756365725f617574686f7269747900020d70726f64756365725f6e616d65046e616d6509617574686f7269747917626c6f636b5f7369676e696e675f617574686f726974790c72657161637469766174656400010e666561747572655f6469676573740b636865636b73756d323536077265716175746800010466726f6d046e616d65067365746162690002076163636f756e74046e616d65036162690562797465730a736574616c696d6974730004076163636f756e74046e616d650972616d5f627974657305696e7436340a6e65745f77656967687405696e7436340a6370755f77656967687405696e74363407736574636f64650004076163636f756e74046e616d6506766d747970650575696e743809766d76657273696f6e0575696e743804636f646505627974657309736574706172616d73000106706172616d7315626c6f636b636861696e5f706172616d657465727307736574707269760002076163636f756e74046e616d650769735f707269760575696e74380873657470726f64730001087363686564756c651470726f64756365725f617574686f726974795b5d0a756e6c696e6b617574680003076163636f756e74046e616d6504636f6465046e616d650474797065046e616d650a757064617465617574680004076163636f756e74046e616d650a7065726d697373696f6e046e616d6506706172656e74046e616d65046175746809617574686f726974790b776169745f776569676874000208776169745f7365630675696e743332067765696768740675696e743136100000002a9bed32320861637469766174650000bc892a4585a6410b63616e63656c64656c6179000040cbdaa8aca24a0a64656c65746561757468000000002d6b03a78b086c696e6b617574680000409e9a2264b89a0a6e65776163636f756e7400000000e0d27bd5a4076f6e6572726f7200905436db6564acba0c72657161637469766174656400000000a0656dacba07726571617574680000000000b863b2c206736574616269000000ce4eba68b2c20a736574616c696d6974730000000040258ab2c207736574636f6465000000c0d25c53b3c209736574706172616d730000000060bb5bb3c207736574707269760000000038d15bb3c20873657470726f6473000040cbdac0e9e2d40a756e6c696e6b61757468000040cbdaa86c52d50a757064617465617574680001000000a061d3dc31036936340000086162695f68617368000000012276617269616e745f626c6f636b5f7369676e696e675f617574686f726974795f7630011a626c6f636b5f7369676e696e675f617574686f726974795f7630000000000000000000000078abc3b1ae22aa2722807ad0acf95f43e21cecd8fc44ef7fb92a3ef3199f229004000000033b3d4b010000000422c55bcc9df846ced4de43e8b8da9ad8057bcd95e32e31cac7e75468010000000000ea3055890000000000000000000000000000 +DMLOG RLIMIT_OP STATE UPD {"average_block_net_usage":{"last_ordinal":3,"value_ex":82933334,"consumed":9952},"average_block_cpu_usage":{"last_ordinal":3,"value_ex":401659723,"consumed":48101},"pending_net_usage":7920,"pending_cpu_usage":4100,"total_net_weight":0,"total_cpu_weight":0,"total_ram_bytes":0,"virtual_net_limit":1050675,"virtual_cpu_limit":200400} +DMLOG RLIMIT_OP STATE UPD {"average_block_net_usage":{"last_ordinal":4,"value_ex":148242222,"consumed":8003},"average_block_cpu_usage":{"last_ordinal":4,"value_ex":432479225,"consumed":4499},"pending_net_usage":0,"pending_cpu_usage":0,"total_net_weight":0,"total_cpu_weight":0,"total_ram_bytes":0,"virtual_net_limit":1051726,"virtual_cpu_limit":200600} +DMLOG ACCEPTED_BLOCK 4 04000000040000000300000000000000010000000000ea3055000100000001000240e54a7b27e042b80a810153bec1dd166eef95fa69f6c9886ae283363bc2add801000000000003000000034097ed362ec2a0eecb45779129e26e7b0c11ee9149a27c43f4e71bf12d5b1b639d6ae94fcdd0536b224644931573d1ccb2a0c548613cd1feea18888be03e3647461734768c46c32b8795974eb830455e9c28467caefd7af2321c85310300000000000000010000000000ea305504000000010000000000ea305503000000000100000001000240e54a7b27e042b80a810153bec1dd166eef95fa69f6c9886ae283363bc2add80100000000000422c55bcc9df846ced4de43e8b8da9ad8057bcd95e32e31cac7e75468033b3d4b0000000000ea30550000000000034097ed362ec2a0eecb45779129e26e7b0c11ee9149a27c43f4e71bf1e2f75da256c76c91c8bdeb576ae84924a3056daad0655741ff3b92a1471bdc10503460f43afc0d7510bceac7fceeb31b013cfbb389502cdaf7c9689ef1768b780000000000010000c105161a99a59d87e06e09ec5b028a9cbb7749b4a5ad8819004365d02dc4379a8b7241ef43112c6543b88db2283a2e077278c315ae2c84719a8b25f25cc88565fbea994a90c00d55454dc5b059055ca213579c6ea856967712a56017487886a4d4cc0fe0fb64b1085cc5538970158d05a009c24e276fb94e1a0bf6a528b48fbc4ff52668dcaa34c0517d19666e6b33add67351d8c5f69e999ca1e37931bc410a297428ad9e3d8f650687709fd68f4b90b41f7d825a365b02c23a636cef88ac2ac00c438ba52fe7a3956c5cd3a656a3174b931d3bb2abb45578befc59f283ecd816a4052652f5f96006294109b3dd0bbde63693f55324af452b799ee137a81a905eed25f0af56d2c5a48d60a4a5b5c903edfb7db3a736a94ed589d0b797df33ff9d3e1d4e7bf348da00a945489b2a681749eb56f5de00b900014e137ddae39f48f69d674fca8bd82bbd181e714e283f83e1b45d95ca5af40fb89ad3977b653c448f78c2299dcb6af692324b899b39f16d5a530a33062804e41f09dc97e9f156b4476707c3a6138c5061cf291310887c0b5c71fcaffeab90d5deb50d3b9e687cead450715443fcf88330c586bc0e5f3dee10e7f63c76c00249c87fe4fbf7f38c082006b4bcd2a26394b36614fd4894241d3c451ab0f6fd110958c3423073621a70826e99d528b9f6e9693f45ed277af93474fd473ce7d831dae2180cca35d907bd10cb406bcb40a24e49c26d0a60513b6aeb8551d264e4717f306b81a37a5afb3b47cedc35c2186cc36f7bb4aeaf4487b36e57039ccf45a9136aa856a5d569ecca55ef2b98c4175db53ed27e7911a1b5adf0e7db0fc96c2cae172cf594dfa9a742ca9e88fce57d2331667353a0eac6b4209b67b843a7262a848af0a49a6e2fa9f6584eb409e86cb0accf8d81c9e85d34bea4b925ae936626d00c984e4691186891f5bc168cb6dd1e5607208331eb5983141e159c75a597413887e80e8a9a4b715a507eb7001f75c9082683116464b13203c9930faeae94dd8a6d797b04012a28fbfe78ae9b9f0f2a807c01a445a6f109c49a8c1a833c119a5b5b5d64a2948726b169a7d309d40000000029807708239aa7de914d3ed61e9009ab2280bfbc50f1d9769f27f8341ef261980000000000011709e86cb0accf8d81c9e85d34bea4b925ae936626d00c984e4691186891f5bc160ec7e080177b2c02b278d5088611686b49d739925a92d9bfcacd7fc6b74053bd1a99a59d87e06e09ec5b028a9cbb7749b4a5ad8819004365d02dc4379a8b72412652f5f96006294109b3dd0bbde63693f55324af452b799ee137a81a905eed25299dcb6af692324b899b39f16d5a530a33062804e41f09dc97e9f156b447670735c2186cc36f7bb4aeaf4487b36e57039ccf45a9136aa856a5d569ecca55ef2b4a90c00d55454dc5b059055ca213579c6ea856967712a56017487886a4d4cc0f4e7bf348da00a945489b2a681749eb56f5de00b900014e137ddae39f48f69d674fca8bd82bbd181e714e283f83e1b45d95ca5af40fb89ad3977b653c448f78c25443fcf88330c586bc0e5f3dee10e7f63c76c00249c87fe4fbf7f38c082006b468dcaa34c0517d19666e6b33add67351d8c5f69e999ca1e37931bc410a2974286bcb40a24e49c26d0a60513b6aeb8551d264e4717f306b81a37a5afb3b47cedc8ba52fe7a3956c5cd3a656a3174b931d3bb2abb45578befc59f283ecd816a4058cb6dd1e5607208331eb5983141e159c75a597413887e80e8a9a4b715a507eb798c4175db53ed27e7911a1b5adf0e7db0fc96c2cae172cf594dfa9a742ca9e88ad9e3d8f650687709fd68f4b90b41f7d825a365b02c23a636cef88ac2ac00c43bcd2a26394b36614fd4894241d3c451ab0f6fd110958c3423073621a70826e99c3a6138c5061cf291310887c0b5c71fcaffeab90d5deb50d3b9e687cead45071d528b9f6e9693f45ed277af93474fd473ce7d831dae2180cca35d907bd10cb40e0fb64b1085cc5538970158d05a009c24e276fb94e1a0bf6a528b48fbc4ff526ef43112c6543b88db2283a2e077278c315ae2c84719a8b25f25cc88565fbea99f0af56d2c5a48d60a4a5b5c903edfb7db3a736a94ed589d0b797df33ff9d3e1dfce57d2331667353a0eac6b4209b67b843a7262a848af0a49a6e2fa9f6584eb40001033b3d4b0000000000ea30550000000000034097ed362ec2a0eecb45779129e26e7b0c11ee9149a27c43f4e71bf1e2f75da256c76c91c8bdeb576ae84924a3056daad0655741ff3b92a1471bdc10503460f43afc0d7510bceac7fceeb31b013cfbb389502cdaf7c9689ef1768b780000000000010000c105161a99a59d87e06e09ec5b028a9cbb7749b4a5ad8819004365d02dc4379a8b7241ef43112c6543b88db2283a2e077278c315ae2c84719a8b25f25cc88565fbea994a90c00d55454dc5b059055ca213579c6ea856967712a56017487886a4d4cc0fe0fb64b1085cc5538970158d05a009c24e276fb94e1a0bf6a528b48fbc4ff52668dcaa34c0517d19666e6b33add67351d8c5f69e999ca1e37931bc410a297428ad9e3d8f650687709fd68f4b90b41f7d825a365b02c23a636cef88ac2ac00c438ba52fe7a3956c5cd3a656a3174b931d3bb2abb45578befc59f283ecd816a4052652f5f96006294109b3dd0bbde63693f55324af452b799ee137a81a905eed25f0af56d2c5a48d60a4a5b5c903edfb7db3a736a94ed589d0b797df33ff9d3e1d4e7bf348da00a945489b2a681749eb56f5de00b900014e137ddae39f48f69d674fca8bd82bbd181e714e283f83e1b45d95ca5af40fb89ad3977b653c448f78c2299dcb6af692324b899b39f16d5a530a33062804e41f09dc97e9f156b4476707c3a6138c5061cf291310887c0b5c71fcaffeab90d5deb50d3b9e687cead450715443fcf88330c586bc0e5f3dee10e7f63c76c00249c87fe4fbf7f38c082006b4bcd2a26394b36614fd4894241d3c451ab0f6fd110958c3423073621a70826e99d528b9f6e9693f45ed277af93474fd473ce7d831dae2180cca35d907bd10cb406bcb40a24e49c26d0a60513b6aeb8551d264e4717f306b81a37a5afb3b47cedc35c2186cc36f7bb4aeaf4487b36e57039ccf45a9136aa856a5d569ecca55ef2b98c4175db53ed27e7911a1b5adf0e7db0fc96c2cae172cf594dfa9a742ca9e88fce57d2331667353a0eac6b4209b67b843a7262a848af0a49a6e2fa9f6584eb409e86cb0accf8d81c9e85d34bea4b925ae936626d00c984e4691186891f5bc168cb6dd1e5607208331eb5983141e159c75a597413887e80e8a9a4b715a507eb7001f75c9082683116464b13203c9930faeae94dd8a6d797b04012a28fbfe78ae9b9f0f2a807c01a445a6f109c49a8c1a833c119a5b5b5d64a2948726b169a7d309d40200d0070000dc060101001f2b7b7553347499474b85540932b7f1ae60a0029b1e613d792ec72e9f86c4713332bde3a5ca84f5dd84783ae1bb2d6bd8735599161e48800a7cb133d5f107ac090100b13578daed3c0b8c5c5775f7f33eb3f366ece7609261ed36771e0b1d530736c1596f43daf86d893f2421210d34fdb11eef8ebd33fbf5ecacb12bea318d959a4f25dad29284aa0594362434540a08d1202a272512a1ad9a920491aab4b4aa540485a6aa5428a2a4e773ef9b37b3bbc1619214a96ce29dfbeebbe7dc7bcfff9c7b67c37f8adeaac5ab1ffee03705fc48fc25be36fe66f8bdef15ef7ae0e17c87f8c837aeb8e22fefcc75fd393cd45717b147de215f765888c3aadb158775177f7ba7e147760f0b79fab0d73d7d1abafc2efe409fe60f95fd3e6ddf89c3018251bf3c0df84e3b4c80f6340d94d023bb841861e10560a769795497401899821ef5b43fa61b4b27a2d923d3479b4bb3d3cd893d42634fa9b1bcda5c9eaeafae36da1d21b12b9e596bb71b4b9de97663a6d13cd1680b0fbbfdfa91651822b05de6f1d3ab73f52bae9c108a70f7fa2ee79edca82b2fbf82fb62dbd76eae3416672f9f18e7ee208f69641ad633b7d069be56f8f8ecf55006795c2303482258f032ac777abe714a04d863561b9de9230bcb33f33373f5e6d2f44abd5d5f6c741aed5568cecc376679c7c162637166e5940809e6d8f78329e0b08b11f54a7b796579b5318b8dd9b51918234688aa8e849de66283c9b71dd1d6673a40d0dc684255586937973aabd30bbc9a8b1c8972bb291256e0de6a67b9dd20f645d4d56e1c5f6b424f7dad33274ad8b58517d63cd15c681c83d596b1f325d8d96eac2eafb5671ad30bcdc56667556cc1372fdb781fd38d93622b41aeb41bb4ec7aa7317db451efacb51b2226aaf1b2f9617b73d5bd9d76c367c53666393c2f2f4dcfd63bf5e9d5e6af36c445d40d7867a773ef9818dbf202393db33cdb102fc1fe226c1e49885b273e95a1636d651697857ddb7b949c83b54bbdff5af1d26db1d816c771292ea8f8e2822a5c22652c2bfc5390f643560af8290ad094ee9f2ac882829f82e7cb15592efb5a0a195cacbb323d735e445d91fef323d9473822fdfacacac229f18a918ba44865547af35b7efe177ef1977ee5add3b38da3c58fbe5b5eeb89b8167d590b23e2cbe231238c7c93b76feacc99ff7ee2deb377fefd5d5da3e019bbe3d7f9d07dff177ff3773f70ef9b7bbd57bbde8ffeede745affba7b1fbcc571ff8c6f9c7df9dc3f13376f4a71efc8f5b7abdd740efb7fff8892f7ce4438f3f94c3b18f709c79e2b31f7e6aaad79b72ef996fdd91ef7d3df77eec3bfff0b5bb73f35dcbdd9ffcd617f383f763efa7feebeef7df95ef3d4063cfffce77fac61ea4dedffbebaf3f91efbd9ef1fedd9f7ce08b0fe6a67b23753ff6c0c73f7de715bdde1bfda9f7defbd4535f7ecf9d7d836ff28de0ad9c7ff08e27c5cddebe949e9f7afce3dff8f57f17b189067ffcdc70c7a7be3d038277f42348457c79d496baab60d2b248c556e84a454dbd079ed3f844225b899a8027ee3dbb2fd146b4d2adad74e5782226a00300551a778cb80ec1a12d5b38de4868546504afe53e91760fe0dbf4bde7452c23a32325a20929bb2f8739e6137833a14a000c33946a4af4d09fd987bd384d2aae1188377aad545d589a34624755aa7d1af0c7af4c4459a6a2ca6b4c13756d591ab54d8892882223a200c5f727221f745ed8df455cacd8abcfa5d11b79215f11f3891c03c2c1d2bf246013056ac6d0f2b216be16f16b46e9d1c81abe8215cfc75ba0e72ba23526a20f17608548ce1a60805f5ea2e6d3f00dbcff8760ffd459559151005388b78e1adab9971688d61ef6b6aadaa10068bd31b44ebd1cb497419786828e8782de3e14746528e89d43419ba1a0c78682ae0d05bd7b28e8f1a1a0f70c053d3914f4d543419f17fde072337095035719f8c3002ebf3fb81c004760117d476ad955a7c9ee8ccf279acc0ece15b7e2c294a87a695c4583a6a0ed8389c31746b5aa81427b0b380f9585f1a70ab71bcf04970b7136f1a626cf9dadfaf0ae0beb321ebcab7a25b6bfa9dc4f6bbb97ad2f40eed5609a1cec5e2d703ab4f7adaac0d971d6884c79a25203a69bd1c480a637bd06789c4f77d293ad7804d65868edd20069347e783891b71723079a0fac3e881ad84730fdef87b004f2010fb7ffb4e0fd6b5040f403d09a02bb5c818fee5e1dc33402d0251e2e591342a281075b44ef76d7bf7de29b97830b10e8450ed2fa00227e6d02f41e379a377efe61763b0678378eef692df11ea68f17ab37d1b077fd050e03c1887725021711034d6aadc4c736ec03569804ae5d6925a16d1b8d688185f884988d029f9014f0c33385f9781c0885fd00047bc151013fc7ee3944a24d5a6cbbf438ef9cc6d44066e6ecc3843acc1308761c7648a13da166a1090e88b8185f39ca780a791a59425aacf1c5893fa1f6102961647c0bb274ea349055be1d7efdda5b76c01a90668226cdb880f403c0ddc4055d533b13851fe6468057f826860fe6564aa0ca3057419e2ab0819d25e40434ed7a693b1a6c583c1121a2c355e120c5b56574dcaf8a78a64ae25f5b16bd7941ae0ea01a5405a0d418afccb590eda03686420a1406853814e00016089464c254c54f5cec4ec20f133e4dbefb6ca0479c5e623ca0aab0ec319e53e00a4079c1cd20777d520698d607f1af6160b01f820e50095c052eaca420f680e7fdb846e8c485052471fc1fa80eac32ae267eda65dbf19f28a6481e3f7d8777a88c8df895d53095d502f6027539329a4fc231185f059d9220397e5c1d65a10d5868ad8c0648f8711300ad6d0708b06bd5b8a570fd21856ee9539f252d094cc8c2156218e229de617a69df2094ffea08e001935104f28131355e6a000c6c4704e6c42785aeaa94cd49898c188d6a55cbb47d9fcd4809ad5864ca64c522b26225780756cc37115ab188b5d47756ec938fd00a9429a1902907cb56ccc760b4457633c269810368c5bccc8af9ce8ad9e9d16a010a9cb267c8482d6119a841d508e78a906a3c65648af8c2604f11a1e1a1c60f24d426a7e645b4dbd415f7345f82da81f40513cae007ea15a047bb056f763a59db99f86471406c50b57c7c19c34794a99681a700550be52b53ad119acf125b83b0825e01c602ea41084130292bb1875160bfcf3a40f1ab09a23b9456609e490b0c58e72a588831b2fc685305b3e133642cd5be589169600bfa75ea3492fd80c776907e056c0c03348618ef005f322a61ec05cf71ef1908e901ede9015b24d6149a2a641d4dc033fe01cba34e6f6a911b41f356a3e0dd43b38c76c706d91ef11afd2fac0b2d24ec66cf144a402d4e08abb066508019f4d10cfa9919040142fbf005ddf3db4019300de4e2692789be5a5cc2313d3d7a53e6dcd542a3359caa414b516b1c5a925a93d042704de35e82ad7bc016144e5c252e265d8fa1f5526a55a0b51d8160c05522a43e1c1764e3fc6c9c874be0f9276fc7a96fe7acf0ccf967c46d67a1a3623bbe72cd6d1426d0d3d397de76165f16cee1e3b7b7e2ab0ab6bf1b12500ddadfd3b7d1b2cf9e3dcb9a07d3c42ff034152210126d1bb5909017510bc917f7a559723ebd940de9b987b3200ca5116c82c9056186844011472116bb4b4bbf6b4d32bec75f40bdf9b4b208ec00e311a41f7df2be27510bd3fbb0510ddd5810321ae6a54fdcf7e4abc040827683bde9242198e5e0d08e24c4e5800517148b8145ad2cc4bb303492e40dd005a08ca2d7a82c2490ff49544f819a0eab26b9c72c34e04108dea2180f8c6f60734b5e6ec8cea7d0024753951a737270431ece024113cf225921503ee1f50ac47699be617409dd34353ecf510c097e34341e394d9ad29234a429614710e08a7837bc0d39daf351ed04aed6c368881d30600083012b0a7145214282d372ee59a2f991687e607b38130564d8e94167f498d29eb34431e95b8a1b22ef0e53810b535872e0552339381d4ffcf9d45fbbbf1a90d79110e7834f0ccfa17fbc1977a3881296e7be5ba0b206024d02a6d0645589b8cf8a297d3bc18469777f5959d4a48da556fca6513281840b8247df5293e8e75b6a021961533eca09c8487cb38838c441cf0e9efe8632c584269c8f7fd602520465c21be90d587294e788832f8f3f7001881da9047a1affdc28f945b0607faa155ab09efd42e31d5ff23c9b3191993191993191376382cd98c8cc98c8cc98f8ff67c6c01fed483f0399e34ee0d54fa59fa6161ba8e8f7fb5d0e57a884e595425ee123f34a5b5e493b85a216f34adac928d3b4bc82d63d60bc9857125d30f10a5bcc2b89ccf49057d8c7bc72e3fc6c9ce7720b8d44d48344d47d44d4fd44d43922ea1c11754644dde3154d13bfc0d3548840cc2b6c31afb0c5bc8268257e39c52cc09d7b7e1410fcb005042afe310a02bef410e709cca83f93d2735ea497d441f8fae38957b6358702565cc809908de53a437ac63b44eee89555c55998e7b2304042cff1a5a316810586219053c9a8972f615ec2193b2760e86d2996f5d293c7d3c2817c6ea5b3b16cb25f2f35ac1c97cdcb7549f0052e2dc2e0fd47483640f2a8629918ef930996081485e72803b6c034c61f98db417f0bab2c355bd3225cf96c1ba3bd1a2663353586f542aa8b38ee939060b9718ca21475e0d9e02e4138e9e0e4b3c059808b070068e129859e992c531e5968c553a35c732924544ea1fd95b8aa628b7acf485bd1b3a54fc8bd3546bd9ace8728563e44cbb8ed91befae8658202215e32058e182a3d238e03a19e91c713d5b9ff2cb2260d5b90850655346a67e4f1b20d9228e6f339e653102c91bbc2b80883611731791868e3070f641642587a4399abaecc232f72317d308f549b4ffc1b7384633cc8ea00d2e52c9930beade8dea1fab2880207e65ea2e78d3c44e125d0e32a215c1202dbd55c48ee42d46fab45dae51eb8274c3cbad79765fa0cfc8428e8444a78a9d2ef4197e67c4361bea1b19000f98626c1d556788d8664838bd8982f00ed2025a8eade5a6c44ebd68041782f039230d13cd57f608a8328fe482dda3a05f11187fa05ae7f62c4ef5118ee22faad363b7840290da2017a76463eaf8a760b7fdc64156d42ddca927b704335bb85c5fe736240c1080fcafd3e869e84a7c7a8743289824f0a40551eece51c0975cb157ab9c4a077e99b129f4bd472af46dde71a3696be6bb6dcb94b1f64ac57b0364de6b4e96aa74d6724aad3f5439a37d8f893e769e3d0f9375279cc80ff6be797f37a032e0ff43b334758740b8cbe4c405a693037c1a45a1c882bce21dea760439ecb6136db50c56ea8f2836ea86281bfdf867cebc693f5bb82bcda77236337321e1854c80daa38fa54360909b0b216308de8cc20ae16f0a3521d21528d9802961ee29791f5861d7d48cba8dfc7a159264a65d574df5205abcdde40a5d91b23b3e05bb50315dfce1f311f0081fe54587f0a2eb6a16debf8d028ad88bd48bc778ab4d0e0f903f8203063f1a8f52a86e49bb18e51decffd220972f57e0fac7b80f5fe80d688050520f8e116566390fcada4805707ba586ef7d285563282188a88b96809bfd24a22b2afa6c819bf971eccd8d7e23a658931682e491e6c9952aa3ae9b947042afe368922927651e97d10ce229d40446684d2f2c844a648af50950b3c8c174d55573a13d35c1ef172bef3af34955b47723904791b4d07817400c8a75a1b39511da1a6a04cb03967af02ae929ca84f4ed447278a35a610a559630d639d130d73859324c0c442b31fd558b37d033b502c50e0d1d50d5c418709fd0ed0dd84b6c29368c7108d041dc918a29121459c204286447890099dc010bcef01ee2bda6f7de4c1967d07f03ebe2b3306c5c57560487990213e533a807d4596da452aaf61593fa25748ed11c79002d599606b052415e851c444c07584ae1424b874a2f93c8b0b43db498b49e9e3eb48441082b165e5c43f0c7411b8a97b25ab5e4ca03926f090c82e2cc03a786235c7b31f308b6b155a4ea90497fa6d0933f106a387ec5cc9fa6fc74a908930c53c8c2a9810385c83fa4f12e5cf03c7fc350c27f07887aa753af5d61294a010e209f6cf28841aab7d9ec3a3b1ed7720bcd06415500ed0108160a1448c60e0d7db4da5b5f9be702f552f178210858abc85002b6a8129ce5723d603b06f10c348148e80d959c40e143b3eb1915464e4e846422f9ed8082b4f396992287a5bb87c285136b73279b79050da32e85616db2d5955b4831208db93b6078935e74607a6cca31811e1468be0c32a126b2660ad68a73924a528aa5cd2364cc24b4920c3650cab0a1c56791c568d70a9142660e10cd8ee05ce6e85fd760fd79bf0d1295d5020bbb795ed9ec8d93de9e0c9d4fa4ecd0ad6eef9836aa699e0b24ac55ddad0161b086ee5235eaae386561b4d9915a38c2b29e31b5b81fcbca47890f7af32d5c3c85b5bed188cddbcaac7aeda1d7af36da9090e55b14e4d38a4b39a7e967a687cd3673565de6a9281cbac261eb8f5520f0fad26397f14504d6567b69a9435f8f7c487a3774a0ad406cf8a5f88c8d606a5607a6e708e15daaf76c7769b5c3bbb6e3085517c1e7261d7ce3682c650e4c2ae9d3d37e87828e8ed4341578682de3914b4190a7a6c28e8da50d0bb87821e1f0a7acf50d09343415f3d14f4ba6b679b815fe0b5b3cd347ca36b67effb61298242fa42168c1cc27b3cdfa388c91ef43dbd8931dd7039fec0727c5c8ecfc6748a522577d5258dab7cc32e8b42b28b6678bd80f0f65f72f1f1b24a684dafcf67c8788e87910ecaef88bddc52a4c8f531bedcc24b547cbba488975b0213d1e596802eb7143181802ccf0478b9852f0461eadb77b965c4149190230ed62d7f04cde408ee0ba75d77b945b9cb2dca5dd183e0091e06afe8156d1e89130548099e8f33560eb4f397d52cd106aeac697b65adc22dbeb246451240107285e45f8026052e91f87c8d4ceed5b77275e4a6cca7c5ad7832bb82f539ad3d77a2f24323097d2240bcf72defc33cef0b79de87ccfb428ef7e185f0de3721f2de77b06ec13e55102cefc30be27db801efc38cf73ef39ee71b9ef7f6faea5519279f945af71fde73aaa9395a83386f72f17e3e0617746781bf32607c3c60f7ed01bbbb47c0f7146df85a53e349703f25049bc3b88b87813b985794d251800b9d10dd7ef72117ddb2a114686709d4031781950a97dbc594db6da5d379fefec0f7b8e0ad0736c7df06a0cb079cec5126a4efc18b69205eb04890b19b2179093b5ce76e5f25b6e62e93887517583c2cbf28146a99b3e8d2268081bd9b4b213c93372022e570861be3f40782404e367c8c2a6f1975f71502bc57c230a53c29a22f4b2a5aa8dcfeb91e61e4952ae6fc8f77ede1aebdcd77ad37dab5661fb87ed7ba7fd7b1cbe73c2ee4388c7a638c72c029db3dc7b78e0e30f91216084aa55834aa78cb63d3fe134aba9c860ac474ed234d5a894d1d6bad2b959882d665622c95c77750155ea0ec8a9e58f085127733a6a66a341cd25d7902e5fcf88e848aeb78aa2f68d6e84eddbb48bd5e0a51bd5e4429747218b21c4a5b14ba528df399c3b34ebfe542a6dfb2f9f44edb43b40dde7a950f41a741e53ff170a6f22106917e5fc6e465d7f8d72bcb40384613876826424e8607cdc42c64863d59a1c00ccb2868b2f038c6cbc570ebf7abd8930d6c9642404e57d32acdf9a24c729f7c11660101aff607c69ba0d203a8ec6533c884e25f1e8dfe67bd596285806c1fa60245d2a848f7576de540bf4876caaec0c715c0afe349b083eaef549e202766821d54d2b17319ff8d1bceb5c1e963ce2a2bfa7f94ec075b1a9a035235601d5ea8fb983df236f4a50b0e57a83ebb3df7e50b55e2532fafdde3adab286c9cedf095c28d6cab17d747fb4d351dd9d2ad63aefed833354137e5c92a1ee4431081c5298fea80ae8a5c69d16b76dff9e294c755275515f6c43be2420f2543742f91ced724a51e7b5d9d2ee6cb90788c027d25ca553ef8888df8e8f8e437b836efad73732f666dde1e708768d1d7d7e68fd8c3edbeda3c662d930b589bb754f591aada5ee64f02c2972bf9e16b30670354b535560d2b2bb860282b9bfbb9b2b9639dd1f1cc689fc8041ba5a801d2770fb1715d968a27a488b1dfa6461ff265a9bfa4bebea83eb9d82baa8f73515d71519d423a8afe5556905659415a650569c505696ef597dc273728b9e74aedc4192ab5ffd16f3f3a766359a677c367aed28e2374fa5b8fde7d119edb237f6467c33abb44699e5ce8d5d6818fb6b68e1cedd5d67fa04d21655c6bb2aff29e5d8076d577fa76cd46c568fa8a8aabca4baaca9321ef55e5f1a0c696e10169115f93dc95fa4e74c82dfbd999cefbace451f5b8c465f588eed7c2a0b7b75e23c5ebc06da3a700e45c8076abe3c8d32dd2deaea565d9e43377bce4b9e325925d5b39577cb624063540f27e10bbbdbc1be5be32c1d2e92e3afc237f6d42bbe3d6e16c45b8de5668b6159a6d4538682bd02ef0fd0fbeccdceaf993f0c0a00a86fc459f01af150eba65fba50f78b43cabb5a8643e4826beac2eac5d1de7af74e09918ec89cf62e86213a79522bb721ef79e0b7cb0c6cf25ba5d0213c5c790cae36c03aea7fb3abb8485d86c063130831898819e9f5f6427a5ec123a658f942c3a2bb33d74eebd43e79e1d3af7bc1b9f77f3d90cdfdd07dc637bd59851a8bdf6aa9688fed5e30388f322e7d051a315995d7edea284b4276bfc852c528502952cb200581dd8c0b1fbee52c640e4666b0f7d22921df54eb6e84af23a1121d74bc4939988509cd14f76eaea1714eaea97157b2dc78a8b6287920b6176bf50db0554bbf231ef4678bc7578d878e2d71c1315cf8d3e379a9144d057579d888df5512f2f6539eaa9f5d453eba9d71337f7fd8f8138e83c15733e88df92c95d724652574818f15bb224cc744d9025ae8667e510f2257a9e2f772076e68e72e7be2b3796952de215af23138c5f9d413100e2b5399e415f867f0a22006f48313a7fc3218001f65b1660fef12e884fd61381f12b3bf4f536badae6a12e7865ba25c0de88436348bd8f53648c94c399300e77c7c662c2c6eb2e7e8677f1abecd16e66ecf27a9b11ee79c1cfb769241f213339630e9969c3db9df33136dd84d8f627c1317dddd7f41736a25347ebcd85c6ace92c9bfac2c2f24cbdd3302bf5638d55b1b6d438b9d298e9c0cb46bbbddc36cd2573b479b2313b7de454a7b16a669697563bedb599ce725b74e61a66798987f19fbb3133f5a5a5e58e39d280d602ce30db6c03b68553c2fda4ef7c48444f79f609ff3c0ee06bd4174dbdd3692cae7478556f6b376949ab1d83b33496664551d83fc3033861a51d93fd359eab8c58692f77966796178c1bd35c35b890de5fece13f80a5e09f7e6ef30a5cab0fff02f8b77ca405dbc101ab0c00c3db7520c634b6794ea0d8e2da42a739dd5c9a6d9c144c1ffc9b40cda563d978612935032f6046c6bb8ab09dfa9105e8386aeaf07eaed1469277dab091f5932f2ecf368f9eda645e3b811d734113f05f1d6a3b2ececcd5978e0135dacdc57afb94996f9c326f9b6b2c5994b89bfa9245bc294171dffdf43cd6e80811022d0bf06f04fe15e15f24f04fb108d15c3a515f68ce9a13f576b3be847bc2ad3c17a1045b1b795f4d00d7ff02111e750600d0070000820101010020735c8eb6c526ee4338408c004f978bd8918237e963af39a06196c3b6e21c10f67b11b412999f839d4fdbc74295d7c626b77d05003dfd2be574d9e258ce9e896e0100e40778da8d56bd6f1c45149ffb3edf25963104e3141441349108f1259cac54a6a0a1a0e0a3326199db79773bbaddd96566f6ce073545a041a20b12b2108214ae9c263214d1b5484804d20005d081047f036f66f776f7d6f8f014fbf1de9b37f3defbbddf4cebf7ee3b35726d7ef80fc151310ff2d7f5b7cceb817b3c5f12dcfbbbd7fb747321b9b3b90ea1e2e1ad5b74c05fdcb9d6ab6c0dfcd01d3b8a8f04172387c6da0b25d7b32b132a3915da3943ef4cae6fb7d189e351e5916a239c0a90754103a81b49d7f5c01dab38e8bdd46f5357f309d5402aeb43a03a96e0303e02a58b566b996b525fd39e04e5853e6bc65ce81bbdfa1866ea023e9c29f091a7f76fa353378c8556db11c8802b0c4a383e4cc0cf4c1a53cab5ba689e99ecf2d9e190ea3996bd64e7bb1ee5c289a8c4703548459e7832a00769aa046827567404d649ffe6654de5087459eb44ae4e97d93693b5a442994c611ccb2e6ef49e1d50851340aeb4dac87dfb00533a4be5cfb9a1d070a09da1049379651357d8898883f39a3210a9692162378a9736b21c71a65d1571d9c57680095e65f04cd983cf87a07990a58cc110a4048646070e1c445c526b37e58285d3d4ea52d90b033fcbdbd346c985cf0538a95af1f7170b6c9dd63288b467d53b7d9b9e1c5e4555d7a5c205df2e45aaebc9df028d1b653837cdfe392bb64a07a722ee8c39a9b6d246b0bdd7c96727ff397649b5863f9d281ef8dc75f0b399c8d34db5710763ebb1bee4b1ee860c922f3d8b92afae84f7622e2180c5b202e1964cc2e9aec4260f5332c81e0943e45ddeb4ac00b9a015a25e8612fb5081600876ce5a7673bddd364ab4a9646330d3a04e25090908dda56b9693b0750643906ac1f274de97d2b319c990c52e6e2aa7a9eac54c984599877316b15ec0e42d0891ad64c496b13415a9d487320cacffa6028dac5b2a7b0d4549663a46eff30089af54c835242bc7da342c2d754c532731a602d36245410b7d99ea971c3527814142c32466776d124c9000316bc9bf854bb215aca2b614a948a5997cfc377b9a7522c927a5a05a5c39469c386e5ba390a1b3b6c224b1d887a74e1765ff76271619946bff0be54e1c319ab6527d652b99101678af1bfbbcd4ddc21143aa6dfba7c04d896219481b78105ffd0c0fe5fc5424dfdeb9faca875fbdbcc40b64efbb9fef1d7df16ab1d771bc30ae7dfd71deab64eff3bb57d883bbc506c4f1dba30f1e7f99f5d3276ff67f017674b28c3c1c87101c9d64285b5c1f161023e4fbd74ebce379115238f69effe8789e418390878fde7ee3febc506c1cef7eb37f7f9e9515c7ee0f28c84b68827bf8e71f3f156b6503f65f7f5cac88b9c91cd21f7fdda9f1fe4d42f2fb06de7ace7141a9ac3aedc9bf393f59b20001 DMLOG START_BLOCK 5 DMLOG CREATION_OP ROOT 0 -DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304004,"value_ex":101996,"consumed":1},"cpu_usage":{"last_ordinal":1262304004,"value_ex":280111,"consumed":101},"ram_usage":199629} -DMLOG TRX_OP CREATE onblock 3a7e599683d2c0c0bd72111e3b4545288bedea9d59017f5aab92a95fc346d521 0000000000000000000000000000010000000000ea305500000000221acfa4010000000000ea305500000000a8ed3232f905033b3d4b0000000000ea3055000000000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7196b5bdb9f6b98a1a4629cfddea5210c8afcc2c3b5364a9e9906716f0e72dba9e90d2ddd212cdd265a1ec5551fc1187ed73259766adad832e3a0e143676db9055d00000000000100008105141a99a59d87e06e09ec5b028a9cbb7749b4a5ad8819004365d02dc4379a8b7241ef43112c6543b88db2283a2e077278c315ae2c84719a8b25f25cc88565fbea994a90c00d55454dc5b059055ca213579c6ea856967712a56017487886a4d4cc0fe0fb64b1085cc5538970158d05a009c24e276fb94e1a0bf6a528b48fbc4ff52668dcaa34c0517d19666e6b33add67351d8c5f69e999ca1e37931bc410a297428ad9e3d8f650687709fd68f4b90b41f7d825a365b02c23a636cef88ac2ac00c438ba52fe7a3956c5cd3a656a3174b931d3bb2abb45578befc59f283ecd816a4052652f5f96006294109b3dd0bbde63693f55324af452b799ee137a81a905eed25f0af56d2c5a48d60a4a5b5c903edfb7db3a736a94ed589d0b797df33ff9d3e1d4e7bf348da00a945489b2a681749eb56f5de00b900014e137ddae39f48f69d674fca8bd82bbd181e714e283f83e1b45d95ca5af40fb89ad3977b653c448f78c2299dcb6af692324b899b39f16d5a530a33062804e41f09dc97e9f156b4476707c3a6138c5061cf291310887c0b5c71fcaffeab90d5deb50d3b9e687cead450715443fcf88330c586bc0e5f3dee10e7f63c76c00249c87fe4fbf7f38c082006b4bcd2a26394b36614fd4894241d3c451ab0f6fd110958c3423073621a70826e99d528b9f6e9693f45ed277af93474fd473ce7d831dae2180cca35d907bd10cb406bcb40a24e49c26d0a60513b6aeb8551d264e4717f306b81a37a5afb3b47cedc35c2186cc36f7bb4aeaf4487b36e57039ccf45a9136aa856a5d569ecca55ef2b98c4175db53ed27e7911a1b5adf0e7db0fc96c2cae172cf594dfa9a742ca9e88a9cb566f982145ebccca8dcb6d2fe89b91dbd445c32ecef873cdc5d594279fcc000000 -DMLOG APPLIED_TRANSACTION 5 3a7e599683d2c0c0bd72111e3b4545288bedea9d59017f5aab92a95fc346d52105000000043b3d4b010000000561f8cbc8bd40df6d1ad8514946e23c3fa752ea31c29ed774509e0d3201006400000000000000000000000000000000000000000001010000010000000000ea3055cf335d2018f12502cd38d1e00cdd86f5e0c7d69c417d27f48a89d18ce8220d5a1c000000000000001c00000000000000010000000000ea30551c0000000000000002020000000000ea30550000000000ea305500000000221acfa4010000000000ea305500000000a8ed3232f905033b3d4b0000000000ea3055000000000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7196b5bdb9f6b98a1a4629cfddea5210c8afcc2c3b5364a9e9906716f0e72dba9e90d2ddd212cdd265a1ec5551fc1187ed73259766adad832e3a0e143676db9055d00000000000100008105141a99a59d87e06e09ec5b028a9cbb7749b4a5ad8819004365d02dc4379a8b7241ef43112c6543b88db2283a2e077278c315ae2c84719a8b25f25cc88565fbea994a90c00d55454dc5b059055ca213579c6ea856967712a56017487886a4d4cc0fe0fb64b1085cc5538970158d05a009c24e276fb94e1a0bf6a528b48fbc4ff52668dcaa34c0517d19666e6b33add67351d8c5f69e999ca1e37931bc410a297428ad9e3d8f650687709fd68f4b90b41f7d825a365b02c23a636cef88ac2ac00c438ba52fe7a3956c5cd3a656a3174b931d3bb2abb45578befc59f283ecd816a4052652f5f96006294109b3dd0bbde63693f55324af452b799ee137a81a905eed25f0af56d2c5a48d60a4a5b5c903edfb7db3a736a94ed589d0b797df33ff9d3e1d4e7bf348da00a945489b2a681749eb56f5de00b900014e137ddae39f48f69d674fca8bd82bbd181e714e283f83e1b45d95ca5af40fb89ad3977b653c448f78c2299dcb6af692324b899b39f16d5a530a33062804e41f09dc97e9f156b4476707c3a6138c5061cf291310887c0b5c71fcaffeab90d5deb50d3b9e687cead450715443fcf88330c586bc0e5f3dee10e7f63c76c00249c87fe4fbf7f38c082006b4bcd2a26394b36614fd4894241d3c451ab0f6fd110958c3423073621a70826e99d528b9f6e9693f45ed277af93474fd473ce7d831dae2180cca35d907bd10cb406bcb40a24e49c26d0a60513b6aeb8551d264e4717f306b81a37a5afb3b47cedc35c2186cc36f7bb4aeaf4487b36e57039ccf45a9136aa856a5d569ecca55ef2b98c4175db53ed27e7911a1b5adf0e7db0fc96c2cae172cf594dfa9a742ca9e88a9cb566f982145ebccca8dcb6d2fe89b91dbd445c32ecef873cdc5d594279fcc000000000000000000003a7e599683d2c0c0bd72111e3b4545288bedea9d59017f5aab92a95fc346d52105000000043b3d4b010000000561f8cbc8bd40df6d1ad8514946e23c3fa752ea31c29ed774509e0d320000000000000000 +DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304004,"value_ex":103432,"consumed":1},"cpu_usage":{"last_ordinal":1262304004,"value_ex":303261,"consumed":101},"ram_usage":199629} +DMLOG TRX_OP CREATE onblock 2335e85c0787a36d4a5a89003ffa2ea2b2c1836ea746022ed99141eca5ed78b3 0000000000000000000000000000010000000000ea305500000000221acfa4010000000000ea305500000000a8ed3232b906033b3d4b0000000000ea30550000000000034097ed362ec2a0eecb45779129e26e7b0c11ee9149a27c43f4e71bf1e2f75da256c76c91c8bdeb576ae84924a3056daad0655741ff3b92a1471bdc10503460f43afc0d7510bceac7fceeb31b013cfbb389502cdaf7c9689ef1768b780000000000010000c105161a99a59d87e06e09ec5b028a9cbb7749b4a5ad8819004365d02dc4379a8b7241ef43112c6543b88db2283a2e077278c315ae2c84719a8b25f25cc88565fbea994a90c00d55454dc5b059055ca213579c6ea856967712a56017487886a4d4cc0fe0fb64b1085cc5538970158d05a009c24e276fb94e1a0bf6a528b48fbc4ff52668dcaa34c0517d19666e6b33add67351d8c5f69e999ca1e37931bc410a297428ad9e3d8f650687709fd68f4b90b41f7d825a365b02c23a636cef88ac2ac00c438ba52fe7a3956c5cd3a656a3174b931d3bb2abb45578befc59f283ecd816a4052652f5f96006294109b3dd0bbde63693f55324af452b799ee137a81a905eed25f0af56d2c5a48d60a4a5b5c903edfb7db3a736a94ed589d0b797df33ff9d3e1d4e7bf348da00a945489b2a681749eb56f5de00b900014e137ddae39f48f69d674fca8bd82bbd181e714e283f83e1b45d95ca5af40fb89ad3977b653c448f78c2299dcb6af692324b899b39f16d5a530a33062804e41f09dc97e9f156b4476707c3a6138c5061cf291310887c0b5c71fcaffeab90d5deb50d3b9e687cead450715443fcf88330c586bc0e5f3dee10e7f63c76c00249c87fe4fbf7f38c082006b4bcd2a26394b36614fd4894241d3c451ab0f6fd110958c3423073621a70826e99d528b9f6e9693f45ed277af93474fd473ce7d831dae2180cca35d907bd10cb406bcb40a24e49c26d0a60513b6aeb8551d264e4717f306b81a37a5afb3b47cedc35c2186cc36f7bb4aeaf4487b36e57039ccf45a9136aa856a5d569ecca55ef2b98c4175db53ed27e7911a1b5adf0e7db0fc96c2cae172cf594dfa9a742ca9e88fce57d2331667353a0eac6b4209b67b843a7262a848af0a49a6e2fa9f6584eb409e86cb0accf8d81c9e85d34bea4b925ae936626d00c984e4691186891f5bc168cb6dd1e5607208331eb5983141e159c75a597413887e80e8a9a4b715a507eb7000000 +DMLOG APPLIED_TRANSACTION 5 2335e85c0787a36d4a5a89003ffa2ea2b2c1836ea746022ed99141eca5ed78b305000000043b3d4b010000000579ae543ffc1cc91271d22566e63e107171af1128c3b346345605d03001006400000000000000000000000000000000000000000001010000010000000000ea30554893fc46ecef02f19905c934016bbb1198e8de3ad984fdc9dc20ead97c88abf41e000000000000001e00000000000000010000000000ea30551e0000000000000002020000000000ea30550000000000ea305500000000221acfa4010000000000ea305500000000a8ed3232b906033b3d4b0000000000ea30550000000000034097ed362ec2a0eecb45779129e26e7b0c11ee9149a27c43f4e71bf1e2f75da256c76c91c8bdeb576ae84924a3056daad0655741ff3b92a1471bdc10503460f43afc0d7510bceac7fceeb31b013cfbb389502cdaf7c9689ef1768b780000000000010000c105161a99a59d87e06e09ec5b028a9cbb7749b4a5ad8819004365d02dc4379a8b7241ef43112c6543b88db2283a2e077278c315ae2c84719a8b25f25cc88565fbea994a90c00d55454dc5b059055ca213579c6ea856967712a56017487886a4d4cc0fe0fb64b1085cc5538970158d05a009c24e276fb94e1a0bf6a528b48fbc4ff52668dcaa34c0517d19666e6b33add67351d8c5f69e999ca1e37931bc410a297428ad9e3d8f650687709fd68f4b90b41f7d825a365b02c23a636cef88ac2ac00c438ba52fe7a3956c5cd3a656a3174b931d3bb2abb45578befc59f283ecd816a4052652f5f96006294109b3dd0bbde63693f55324af452b799ee137a81a905eed25f0af56d2c5a48d60a4a5b5c903edfb7db3a736a94ed589d0b797df33ff9d3e1d4e7bf348da00a945489b2a681749eb56f5de00b900014e137ddae39f48f69d674fca8bd82bbd181e714e283f83e1b45d95ca5af40fb89ad3977b653c448f78c2299dcb6af692324b899b39f16d5a530a33062804e41f09dc97e9f156b4476707c3a6138c5061cf291310887c0b5c71fcaffeab90d5deb50d3b9e687cead450715443fcf88330c586bc0e5f3dee10e7f63c76c00249c87fe4fbf7f38c082006b4bcd2a26394b36614fd4894241d3c451ab0f6fd110958c3423073621a70826e99d528b9f6e9693f45ed277af93474fd473ce7d831dae2180cca35d907bd10cb406bcb40a24e49c26d0a60513b6aeb8551d264e4717f306b81a37a5afb3b47cedc35c2186cc36f7bb4aeaf4487b36e57039ccf45a9136aa856a5d569ecca55ef2b98c4175db53ed27e7911a1b5adf0e7db0fc96c2cae172cf594dfa9a742ca9e88fce57d2331667353a0eac6b4209b67b843a7262a848af0a49a6e2fa9f6584eb409e86cb0accf8d81c9e85d34bea4b925ae936626d00c984e4691186891f5bc168cb6dd1e5607208331eb5983141e159c75a597413887e80e8a9a4b715a507eb7000000000000000000002335e85c0787a36d4a5a89003ffa2ea2b2c1836ea746022ed99141eca5ed78b305000000043b3d4b010000000579ae543ffc1cc91271d22566e63e107171af1128c3b346345605d0300000000000000000 DMLOG CREATION_OP ROOT 0 DMLOG PERM_OP INS 0 9 {"usage_id":8,"parent":0,"owner":"alice","name":"owner","last_updated":"2020-01-01T00:00:02.000","auth":{"threshold":1,"keys":[{"key":"EOS6JvuLaCqV8qHbSqUBVRPMo9N7V3vgE8YqHmweG568YmTDJ3opq","weight":1}],"accounts":[{"permission":{"actor":"alice","permission":"eosio.code"},"weight":1}],"waits":[]}} DMLOG PERM_OP INS 0 10 {"usage_id":9,"parent":9,"owner":"alice","name":"active","last_updated":"2020-01-01T00:00:02.000","auth":{"threshold":1,"keys":[{"key":"EOS8d5yGFrYpdXW1SUmaavRZKm5X7Bp9jK634JABCYPciwTkm7Wv2","weight":1}],"accounts":[{"permission":{"actor":"alice","permission":"eosio.code"},"weight":1}],"waits":[]}} DMLOG RLIMIT_OP ACCOUNT_LIMITS INS {"owner":"alice","net_weight":-1,"cpu_weight":-1,"ram_bytes":-1} DMLOG RLIMIT_OP ACCOUNT_USAGE INS {"owner":"alice","net_usage":{"last_ordinal":0,"value_ex":0,"consumed":0},"cpu_usage":{"last_ordinal":0,"value_ex":0,"consumed":0},"ram_usage":0} DMLOG RAM_OP 0 alice account add newaccount alice 2788 2788 -DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304004,"value_ex":103339,"consumed":233},"cpu_usage":{"last_ordinal":1262304004,"value_ex":291686,"consumed":2101},"ram_usage":199629} -DMLOG APPLIED_TRANSACTION 5 357412c850b9a6be6c07837a297845c443c1c8e40f25b87a9750ac297e379dc005000000043b3d4b010000000561f8cbc8bd40df6d1ad8514946e23c3fa752ea31c29ed774509e0d320100d00700001d0000000000000000e8000000000000000001010000010000000000ea30554895e298f1f3e56596649fb49ff53d0f76174ef57ef7c50f28152765cef1f97f1d000000000000001d00000000000000010000000000ea30551d0000000000000002020000000000ea30550000000000ea305500409e9a2264b89a010000000000ea305500000000a8ed32328a010000000000ea30550000000000855c3401000000010002bb30f6894f29bb6fca635b1df728ad77e48fdd6123ce5e4455b0f71e072e7df80100010000000000855c3400804a1401ea305501000001000000010003ebcf44b45a71d4f225768f602d1e2e2b25ef779ee9897fe744bf1a16e85423d50100010000000000855c3400804a1401ea305501000000000000000000000000357412c850b9a6be6c07837a297845c443c1c8e40f25b87a9750ac297e379dc005000000043b3d4b010000000561f8cbc8bd40df6d1ad8514946e23c3fa752ea31c29ed774509e0d32010000000000855c34e40a00000000000000000000000000 +DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304004,"value_ex":104775,"consumed":233},"cpu_usage":{"last_ordinal":1262304004,"value_ex":314836,"consumed":2101},"ram_usage":199629} +DMLOG APPLIED_TRANSACTION 5 c48eaa467ae65e7cb255f0e8a6fd21d7655a59ed2b77722fb6c402a2de9016d305000000043b3d4b010000000579ae543ffc1cc91271d22566e63e107171af1128c3b346345605d0300100d00700001d0000000000000000e8000000000000000001010000010000000000ea30554895e298f1f3e56596649fb49ff53d0f76174ef57ef7c50f28152765cef1f97f1f000000000000001f00000000000000010000000000ea30551f0000000000000002020000000000ea30550000000000ea305500409e9a2264b89a010000000000ea305500000000a8ed32328a010000000000ea30550000000000855c3401000000010002bb30f6894f29bb6fca635b1df728ad77e48fdd6123ce5e4455b0f71e072e7df80100010000000000855c3400804a1401ea305501000001000000010003ebcf44b45a71d4f225768f602d1e2e2b25ef779ee9897fe744bf1a16e85423d50100010000000000855c3400804a1401ea305501000000000000000000000000c48eaa467ae65e7cb255f0e8a6fd21d7655a59ed2b77722fb6c402a2de9016d305000000043b3d4b010000000579ae543ffc1cc91271d22566e63e107171af1128c3b346345605d030010000000000855c34e40a00000000000000000000000000 DMLOG CREATION_OP ROOT 0 DMLOG PERM_OP INS 0 11 {"usage_id":10,"parent":10,"owner":"alice","name":"test1","last_updated":"2020-01-01T00:00:02.000","auth":{"threshold":1,"keys":[],"accounts":[{"permission":{"actor":"eosio","permission":"active"},"weight":1}],"waits":[]}} DMLOG RAM_OP 0 11 auth add updateauth_create alice 3108 320 DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"alice","net_usage":{"last_ordinal":1262304004,"value_ex":834,"consumed":144},"cpu_usage":{"last_ordinal":1262304004,"value_ex":11575,"consumed":2000},"ram_usage":3108} -DMLOG APPLIED_TRANSACTION 5 c2e8f254cf27feb007d7f43ed2cf9f20b4993f425de7b4632997cb7f49de509705000000043b3d4b010000000561f8cbc8bd40df6d1ad8514946e23c3fa752ea31c29ed774509e0d320100d007000012000000000000000090000000000000000001010000010000000000ea3055f3d881d2f7fbf2f7cb6081aff84e7aca1dd3914a0948ef4fc9422e734e8d4d571e000000000000001e00000000000000010000000000855c34010000000000000002020000000000ea30550000000000ea30550040cbdaa86c52d5010000000000855c3400000000a8ed3232310000000000855c34000000008090b1ca00000000a8ed32320100000000010000000000ea305500000000a8ed323201000000000000000000000000c2e8f254cf27feb007d7f43ed2cf9f20b4993f425de7b4632997cb7f49de509705000000043b3d4b010000000561f8cbc8bd40df6d1ad8514946e23c3fa752ea31c29ed774509e0d32010000000000855c34400100000000000000000000000000 -DMLOG RLIMIT_OP STATE UPD {"average_block_net_usage":{"last_ordinal":4,"value_ex":146193333,"consumed":8009},"average_block_cpu_usage":{"last_ordinal":4,"value_ex":399423669,"consumed":4466},"pending_net_usage":376,"pending_cpu_usage":4100,"total_net_weight":0,"total_cpu_weight":0,"total_ram_bytes":0,"virtual_net_limit":1051726,"virtual_cpu_limit":200600} -DMLOG RLIMIT_OP STATE UPD {"average_block_net_usage":{"last_ordinal":5,"value_ex":148108389,"consumed":521},"average_block_cpu_usage":{"last_ordinal":5,"value_ex":430261805,"consumed":4497},"pending_net_usage":0,"pending_cpu_usage":0,"total_net_weight":0,"total_cpu_weight":0,"total_ram_bytes":0,"virtual_net_limit":1052778,"virtual_cpu_limit":200800} -DMLOG ACCEPTED_BLOCK 5 05000000050000000400000000000000010000000000ea3055000100000001000240e54a7b27e042b80a810153bec1dd166eef95fa69f6c9886ae283363bc2add8010000000000013a220582e0cfa7a17f55cebb532b2a1d90d2ef2ae30469faa539ba199e2244a40400000000000000010000000000ea305505000000010000000000ea305504000000000100000001000240e54a7b27e042b80a810153bec1dd166eef95fa69f6c9886ae283363bc2add80100000000000561f8cbc8bd40df6d1ad8514946e23c3fa752ea31c29ed774509e0d32043b3d4b0000000000ea3055000000000004f5b1c8962f98b2d6155f6d21977938d545d83ef187d93aaf83e483e56cbb1751058d6346085c90810b9506a2813958022794c157d0182253441a192032e84b542636e8b3efa7359943ee5c039d3ae19fbeb432871652ecfdc57fb22d000000000000001f78ee459e123dba62f8d8ae4168bec01f85253e5d30cc245bedf803fe712c5680524933231df7361e5d18731b8c0a44f48a696cc74dfd22755d41f031787509330000000029807708239aa7de914d3ed61e9009ab2280bfbc50f1d9769f27f8341ef26198000000000001150ec7e080177b2c02b278d5088611686b49d739925a92d9bfcacd7fc6b74053bd1a99a59d87e06e09ec5b028a9cbb7749b4a5ad8819004365d02dc4379a8b72412652f5f96006294109b3dd0bbde63693f55324af452b799ee137a81a905eed25299dcb6af692324b899b39f16d5a530a33062804e41f09dc97e9f156b447670735c2186cc36f7bb4aeaf4487b36e57039ccf45a9136aa856a5d569ecca55ef2b4a90c00d55454dc5b059055ca213579c6ea856967712a56017487886a4d4cc0f4e7bf348da00a945489b2a681749eb56f5de00b900014e137ddae39f48f69d674fca8bd82bbd181e714e283f83e1b45d95ca5af40fb89ad3977b653c448f78c25443fcf88330c586bc0e5f3dee10e7f63c76c00249c87fe4fbf7f38c082006b468dcaa34c0517d19666e6b33add67351d8c5f69e999ca1e37931bc410a2974286bcb40a24e49c26d0a60513b6aeb8551d264e4717f306b81a37a5afb3b47cedc8ba52fe7a3956c5cd3a656a3174b931d3bb2abb45578befc59f283ecd816a40598c4175db53ed27e7911a1b5adf0e7db0fc96c2cae172cf594dfa9a742ca9e88a9cb566f982145ebccca8dcb6d2fe89b91dbd445c32ecef873cdc5d594279fccad9e3d8f650687709fd68f4b90b41f7d825a365b02c23a636cef88ac2ac00c43bcd2a26394b36614fd4894241d3c451ab0f6fd110958c3423073621a70826e99c3a6138c5061cf291310887c0b5c71fcaffeab90d5deb50d3b9e687cead45071d528b9f6e9693f45ed277af93474fd473ce7d831dae2180cca35d907bd10cb40e0fb64b1085cc5538970158d05a009c24e276fb94e1a0bf6a528b48fbc4ff526ef43112c6543b88db2283a2e077278c315ae2c84719a8b25f25cc88565fbea99f0af56d2c5a48d60a4a5b5c903edfb7db3a736a94ed589d0b797df33ff9d3e1d0001043b3d4b0000000000ea3055000000000004f5b1c8962f98b2d6155f6d21977938d545d83ef187d93aaf83e483e56cbb1751058d6346085c90810b9506a2813958022794c157d0182253441a192032e84b542636e8b3efa7359943ee5c039d3ae19fbeb432871652ecfdc57fb22d000000000000001f78ee459e123dba62f8d8ae4168bec01f85253e5d30cc245bedf803fe712c5680524933231df7361e5d18731b8c0a44f48a696cc74dfd22755d41f031787509330200d00700001d0101002018a75bd433fc0c63bdc343b1b68346656c45b3700cf701b9d12fda5600ba097641950d06262f8e4b03976ebe137be9eb3d186ebf69066e9a7104228ed968d9120000bd0107e10b5e04002f98b2d600000000010000000000ea305500409e9a2264b89a010000000000ea305500000000a8ed32328a010000000000ea30550000000000855c3401000000010002bb30f6894f29bb6fca635b1df728ad77e48fdd6123ce5e4455b0f71e072e7df80100010000000000855c3400804a1401ea305501000001000000010003ebcf44b45a71d4f225768f602d1e2e2b25ef779ee9897fe744bf1a16e85423d50100010000000000855c3400804a1401ea30550100000000d0070000120101001f0de388764e716146ab616ff095376ef69daf2fd6c2f244e0f69ad985857da8772a682aaa81862225fd75f739faf1cdb5879e4bbf2ce6133f7aed2f8d2ff4fe5700006307e10b5e04002f98b2d600000000010000000000ea30550040cbdaa86c52d5010000000000855c3400000000a8ed3232310000000000855c34000000008090b1ca00000000a8ed32320100000000010000000000ea305500000000a8ed3232010000000001 +DMLOG APPLIED_TRANSACTION 5 bfe4827f65b4379470127c12e4e43aa6f6ebe22961aa061925404df282a2af0905000000043b3d4b010000000579ae543ffc1cc91271d22566e63e107171af1128c3b346345605d0300100d007000012000000000000000090000000000000000001010000010000000000ea3055f3d881d2f7fbf2f7cb6081aff84e7aca1dd3914a0948ef4fc9422e734e8d4d5720000000000000002000000000000000010000000000855c34010000000000000002020000000000ea30550000000000ea30550040cbdaa86c52d5010000000000855c3400000000a8ed3232310000000000855c34000000008090b1ca00000000a8ed32320100000000010000000000ea305500000000a8ed323201000000000000000000000000bfe4827f65b4379470127c12e4e43aa6f6ebe22961aa061925404df282a2af0905000000043b3d4b010000000579ae543ffc1cc91271d22566e63e107171af1128c3b346345605d030010000000000855c34400100000000000000000000000000 +DMLOG RLIMIT_OP STATE UPD {"average_block_net_usage":{"last_ordinal":4,"value_ex":148242222,"consumed":8003},"average_block_cpu_usage":{"last_ordinal":4,"value_ex":432479225,"consumed":4499},"pending_net_usage":376,"pending_cpu_usage":4100,"total_net_weight":0,"total_cpu_weight":0,"total_ram_bytes":0,"virtual_net_limit":1051726,"virtual_cpu_limit":200600} +DMLOG RLIMIT_OP STATE UPD {"average_block_net_usage":{"last_ordinal":5,"value_ex":150140204,"consumed":524},"average_block_cpu_usage":{"last_ordinal":5,"value_ex":463041898,"consumed":4529},"pending_net_usage":0,"pending_cpu_usage":0,"total_net_weight":0,"total_cpu_weight":0,"total_ram_bytes":0,"virtual_net_limit":1052778,"virtual_cpu_limit":200800} +DMLOG ACCEPTED_BLOCK 5 05000000050000000400000000000000010000000000ea3055000100000001000240e54a7b27e042b80a810153bec1dd166eef95fa69f6c9886ae283363bc2add801000000000001de8b74494e8ffba1bf591a2989a0fa623cf28bc46e04bd8dc2e2144a59930e0a0400000000000000010000000000ea305505000000010000000000ea305504000000000100000001000240e54a7b27e042b80a810153bec1dd166eef95fa69f6c9886ae283363bc2add80100000000000579ae543ffc1cc91271d22566e63e107171af1128c3b346345605d030043b3d4b0000000000ea305500000000000422c55bcc9df846ced4de43e8b8da9ad8057bcd95e32e31cac7e754682e8c169ede38e1912717b43a1cccb4ce6e53ba09be254b45138885a6a3d99007b27339a61124a4a0f9649755cc0174e703664aa4cb9deffdc8a3ef3b4c15f992000000000000001f3b4b829c2514fa306df32c2069916bd16577269a7a6aee7404307bdce8a0ad2b4d5b491f34f1254c0384543c818c8447271f1bb6e3d5b064425fcda3d72bb1e00000000029807708239aa7de914d3ed61e9009ab2280bfbc50f1d9769f27f8341ef261980000000000011709e86cb0accf8d81c9e85d34bea4b925ae936626d00c984e4691186891f5bc160ec7e080177b2c02b278d5088611686b49d739925a92d9bfcacd7fc6b74053bd1a99a59d87e06e09ec5b028a9cbb7749b4a5ad8819004365d02dc4379a8b72412652f5f96006294109b3dd0bbde63693f55324af452b799ee137a81a905eed25299dcb6af692324b899b39f16d5a530a33062804e41f09dc97e9f156b447670735c2186cc36f7bb4aeaf4487b36e57039ccf45a9136aa856a5d569ecca55ef2b4a90c00d55454dc5b059055ca213579c6ea856967712a56017487886a4d4cc0f4e7bf348da00a945489b2a681749eb56f5de00b900014e137ddae39f48f69d674fca8bd82bbd181e714e283f83e1b45d95ca5af40fb89ad3977b653c448f78c25443fcf88330c586bc0e5f3dee10e7f63c76c00249c87fe4fbf7f38c082006b468dcaa34c0517d19666e6b33add67351d8c5f69e999ca1e37931bc410a2974286bcb40a24e49c26d0a60513b6aeb8551d264e4717f306b81a37a5afb3b47cedc8ba52fe7a3956c5cd3a656a3174b931d3bb2abb45578befc59f283ecd816a4058cb6dd1e5607208331eb5983141e159c75a597413887e80e8a9a4b715a507eb798c4175db53ed27e7911a1b5adf0e7db0fc96c2cae172cf594dfa9a742ca9e88ad9e3d8f650687709fd68f4b90b41f7d825a365b02c23a636cef88ac2ac00c43bcd2a26394b36614fd4894241d3c451ab0f6fd110958c3423073621a70826e99c3a6138c5061cf291310887c0b5c71fcaffeab90d5deb50d3b9e687cead45071d528b9f6e9693f45ed277af93474fd473ce7d831dae2180cca35d907bd10cb40e0fb64b1085cc5538970158d05a009c24e276fb94e1a0bf6a528b48fbc4ff526ef43112c6543b88db2283a2e077278c315ae2c84719a8b25f25cc88565fbea99f0af56d2c5a48d60a4a5b5c903edfb7db3a736a94ed589d0b797df33ff9d3e1dfce57d2331667353a0eac6b4209b67b843a7262a848af0a49a6e2fa9f6584eb40001043b3d4b0000000000ea305500000000000422c55bcc9df846ced4de43e8b8da9ad8057bcd95e32e31cac7e754682e8c169ede38e1912717b43a1cccb4ce6e53ba09be254b45138885a6a3d99007b27339a61124a4a0f9649755cc0174e703664aa4cb9deffdc8a3ef3b4c15f992000000000000001f3b4b829c2514fa306df32c2069916bd16577269a7a6aee7404307bdce8a0ad2b4d5b491f34f1254c0384543c818c8447271f1bb6e3d5b064425fcda3d72bb1e00200d00700001d0101001f1ee8dfc1d9541c04a94ecc7c056776d473f5411122f1cf45d3b1344cf161f5b446d219f9bab8ee78077cd7de911adfaeaa12561637c107a2ec59c7a5812881040000bd0107e10b5e04009df846ce00000000010000000000ea305500409e9a2264b89a010000000000ea305500000000a8ed32328a010000000000ea30550000000000855c3401000000010002bb30f6894f29bb6fca635b1df728ad77e48fdd6123ce5e4455b0f71e072e7df80100010000000000855c3400804a1401ea305501000001000000010003ebcf44b45a71d4f225768f602d1e2e2b25ef779ee9897fe744bf1a16e85423d50100010000000000855c3400804a1401ea30550100000000d007000012010100200963cfae0fccaecff3b4d57bbe2f2bfff0d81df2f368456293508633cc519f125cfe5bd04393743e954389fd38366e661439a203f62ef934eb61921fbbd4897500006307e10b5e04009df846ce00000000010000000000ea30550040cbdaa86c52d5010000000000855c3400000000a8ed3232310000000000855c34000000008090b1ca00000000a8ed32320100000000010000000000ea305500000000a8ed3232010000000001 diff --git a/unittests/deep_mind_tests.cpp b/unittests/deep_mind_tests.cpp index f8019a0ad0..b132be679f 100644 --- a/unittests/deep_mind_tests.cpp +++ b/unittests/deep_mind_tests.cpp @@ -49,7 +49,7 @@ struct deep_mind_log_fixture struct deep_mind_tester : deep_mind_log_fixture, validating_tester { - deep_mind_tester() : validating_tester({}, &deep_mind_logger) {} + deep_mind_tester() : validating_tester({}, &deep_mind_logger, setup_policy::full) {} }; namespace { diff --git a/unittests/delay_tests.cpp b/unittests/delay_tests.cpp index 5b229e48d2..2a98ba3db9 100644 --- a/unittests/delay_tests.cpp +++ b/unittests/delay_tests.cpp @@ -12,37 +12,169 @@ using namespace eosio; using namespace eosio::chain; using namespace eosio::testing; +using mvo = fc::mutable_variant_object; -BOOST_AUTO_TEST_SUITE(delay_tests) +const std::string eosio_token = name("eosio.token"_n).to_string(); -BOOST_FIXTURE_TEST_CASE( delay_create_account, validating_tester) { try { +static void create_accounts(validating_tester& chain) { + chain.produce_blocks(); + chain.create_accounts({"eosio.msig"_n, "eosio.token"_n}); + chain.produce_blocks(10); - produce_blocks(2); - signed_transaction trx; + chain.push_action(config::system_account_name, + "setpriv"_n, + config::system_account_name, + mvo() + ("account", "eosio.msig") + ("is_priv", 1) ); - account_name a = "newco"_n; - account_name creator = config::system_account_name; + chain.set_code("eosio.token"_n, test_contracts::eosio_token_wasm()); + chain.set_abi("eosio.token"_n, test_contracts::eosio_token_abi()); + chain.set_code("eosio.msig"_n, test_contracts::eosio_msig_wasm()); + chain.set_abi("eosio.msig"_n, test_contracts::eosio_msig_abi()); - auto owner_auth = authority( get_public_key( a, "owner" ) ); - trx.actions.emplace_back( vector{{creator,config::active_name}}, - newaccount{ - .creator = creator, - .name = a, - .owner = owner_auth, - .active = authority( get_public_key( a, "active" ) ) - }); - set_transaction_headers(trx); - trx.delay_sec = 3; - trx.sign( get_private_key( creator, "active" ), control->get_chain_id() ); + chain.produce_blocks(); + chain.create_account("tester"_n); + chain.create_account("tester2"_n); + chain.produce_blocks(10); +} - auto trace = push_transaction( trx ); +static void propose_approve_msig_trx(validating_tester& chain, const name& proposal_name, const permission_level& perm, const fc::variant& pretty_trx) { + vector requested_perm = { perm }; + transaction trx; + abi_serializer::from_variant(pretty_trx, trx, chain.get_resolver(), abi_serializer::create_yield_function(chain.abi_serializer_max_time)); - produce_blocks(8); + chain.push_action("eosio.msig"_n, "propose"_n, vector{perm}, + mvo() + ("proposer", "tester") + ("proposal_name", proposal_name) + ("trx", trx) + ("requested", requested_perm) + ); + chain.push_action("eosio.msig"_n, "approve"_n, vector{perm}, + mvo() + ("proposer", "tester") + ("proposal_name", proposal_name) + ("level", perm) + ); +} -} FC_LOG_AND_RETHROW() } +static void propose_approve_msig_token_transfer_trx(validating_tester& chain, const name& proposal_name, const permission_level& perm, uint32_t delay_sec, const std::string& quantity) { + fc::variant pretty_trx = mvo() + ("expiration", "2020-01-01T00:30") + ("ref_block_num", 2) + ("ref_block_prefix", 3) + ("max_net_usage_words", 0) + ("max_cpu_usage_ms", 0) + ("delay_sec", delay_sec) + ("actions", fc::variants({ + mvo() + ("account", name("eosio.token"_n)) + ("name", "transfer") + ("authorization", vector{perm}) + ("data", fc::mutable_variant_object() + ("from", name("tester"_n)) + ("to", name("tester2"_n)) + ("quantity", quantity) + ("memo", "hi" ) + ) + }) + ); + + propose_approve_msig_trx(chain, proposal_name, perm, pretty_trx); +} +static void propose_approve_msig_updateauth_trx(validating_tester& chain, const name& proposal_name, const permission_level& perm, uint32_t delay_sec) { + fc::variant pretty_trx = fc::mutable_variant_object() + ("expiration", "2020-01-01T00:30") + ("ref_block_num", 2) + ("ref_block_prefix", 3) + ("max_net_usage_words", 0) + ("max_cpu_usage_ms", 0) + ("delay_sec", delay_sec) + ("actions", fc::variants({ + mvo() + ("account", config::system_account_name) + ("name", updateauth::get_name()) + ("authorization", vector {{ "tester"_n, config::active_name }}) + ("data", fc::mutable_variant_object() + ("account", "tester") + ("permission", "first") + ("parent", "active") + ("auth", authority(chain.get_public_key("tester"_n, "first"))) + ) + }) + ); + + propose_approve_msig_trx(chain, proposal_name, perm, pretty_trx); +} -BOOST_FIXTURE_TEST_CASE( delay_error_create_account, validating_tester) { try { +static void propose_approve_msig_linkauth_trx(validating_tester& chain, const name& proposal_name, const name& requirement, const permission_level& perm, uint32_t delay_sec) { + fc::variant pretty_trx = fc::mutable_variant_object() + ("expiration", "2020-01-01T00:30") + ("ref_block_num", 2) + ("ref_block_prefix", 3) + ("max_net_usage_words", 0) + ("max_cpu_usage_ms", 0) + ("delay_sec", delay_sec) + ("actions", fc::variants({ + mvo() + ("account", config::system_account_name) + ("name", linkauth::get_name()) + ("authorization", vector{{ "tester"_n, config::active_name }}) + ("data", fc::mutable_variant_object() + ("account", "tester") + ("code", eosio_token) + ("type", "transfer") + ("requirement", requirement) + ) + }) + ); + + propose_approve_msig_trx(chain, proposal_name, perm, pretty_trx); +} + +static void propose_approve_msig_unlinkauth_trx(validating_tester& chain, const name& proposal_name, const permission_level& perm, uint32_t delay_sec) { + fc::variant pretty_trx = mvo() + ("expiration", "2020-01-01T00:30") + ("ref_block_num", 2) + ("ref_block_prefix", 3) + ("max_net_usage_words", 0) + ("max_cpu_usage_ms", 0) + ("delay_sec", delay_sec) + ("actions", fc::variants({ + mvo() + ("account", config::system_account_name) + ("name", unlinkauth::get_name()) + ("authorization", vector{{ "tester"_n, config::active_name}}) + ("data", fc::mutable_variant_object() + ("account", "tester") + ("code", eosio_token) + ("type", "transfer") + ) + }) + ); + + propose_approve_msig_trx(chain, proposal_name, perm, pretty_trx); +} + +static void exec_msig_trx(validating_tester& chain, name proposal_name, const vector& perm) { + chain.push_action("eosio.msig"_n, "exec"_n, perm, + mvo() + ("proposer", "tester") + ("proposal_name", proposal_name) + ("executer", "tester") + ); +} + +static asset get_currency_balance(const validating_tester& chain, account_name account) { + return chain.get_currency_balance("eosio.token"_n, symbol(SY(4,CUR)), account); +} + + +BOOST_AUTO_TEST_SUITE(delay_tests) + +BOOST_FIXTURE_TEST_CASE( delay_error_create_account, validating_tester_no_disable_deferred_trx) { try { produce_blocks(2); signed_transaction trx; @@ -78,49 +210,31 @@ BOOST_FIXTURE_TEST_CASE( delay_error_create_account, validating_tester) { try { } FC_LOG_AND_RETHROW() } - -asset get_currency_balance(const validating_tester& chain, account_name account) { - return chain.get_currency_balance("eosio.token"_n, symbol(SY(4,CUR)), account); -} - -const std::string eosio_token = name("eosio.token"_n).to_string(); - // test link to permission with delay directly on it BOOST_AUTO_TEST_CASE( link_delay_direct_test ) { try { validating_tester chain; - const auto& tester_account = "tester"_n; - chain.produce_blocks(); - chain.create_account("eosio.token"_n); - chain.produce_blocks(10); - - chain.set_code("eosio.token"_n, test_contracts::eosio_token_wasm()); - chain.set_abi("eosio.token"_n, test_contracts::eosio_token_abi()); - - chain.produce_blocks(); - chain.create_account("tester"_n); - chain.create_account("tester2"_n); - chain.produce_blocks(10); + create_accounts(chain); chain.push_action(config::system_account_name, updateauth::get_name(), tester_account, fc::mutable_variant_object() - ("account", "tester") - ("permission", "first") - ("parent", "active") - ("auth", authority(chain.get_public_key(tester_account, "first"))) + ("account", "tester") + ("permission", "first") + ("parent", "active") + ("auth", authority(chain.get_public_key(tester_account, "first"))) ); chain.push_action(config::system_account_name, linkauth::get_name(), tester_account, fc::mutable_variant_object() - ("account", "tester") - ("code", eosio_token) - ("type", "transfer") - ("requirement", "first")); + ("account", "tester") + ("code", eosio_token) + ("type", "transfer") + ("requirement", "first") + ); chain.produce_blocks(); chain.push_action("eosio.token"_n, "create"_n, "eosio.token"_n, mutable_variant_object() - ("issuer", eosio_token) - ("maximum_supply", "9000000.0000 CUR") + ("issuer", eosio_token) + ("maximum_supply", "9000000.0000 CUR") ); - chain.push_action("eosio.token"_n, name("issue"), "eosio.token"_n, fc::mutable_variant_object() ("to", eosio_token) ("quantity", "1000000.0000 CUR") @@ -134,8 +248,6 @@ BOOST_AUTO_TEST_CASE( link_delay_direct_test ) { try { ("memo", "hi" ) ); BOOST_REQUIRE_EQUAL(transaction_receipt::executed, trace->receipt->status); - auto gen_size = chain.control->db().get_index().size(); - BOOST_REQUIRE_EQUAL(0u, gen_size); chain.produce_blocks(); @@ -152,8 +264,6 @@ BOOST_AUTO_TEST_CASE( link_delay_direct_test ) { try { ); BOOST_REQUIRE_EQUAL(transaction_receipt::executed, trace->receipt->status); - gen_size = chain.control->db().get_index().size(); - BOOST_REQUIRE_EQUAL(0u, gen_size); chain.produce_blocks(); @@ -171,27 +281,13 @@ BOOST_AUTO_TEST_CASE( link_delay_direct_test ) { try { ("auth", authority(chain.get_public_key(tester_account, "first"), 10)) ); BOOST_REQUIRE_EQUAL(transaction_receipt::executed, trace->receipt->status); - gen_size = chain.control->db().get_index().size(); - BOOST_REQUIRE_EQUAL(0u, gen_size); chain.produce_blocks(); - trace = chain.push_action("eosio.token"_n, name("transfer"), "tester"_n, fc::mutable_variant_object() - ("from", "tester") - ("to", "tester2") - ("quantity", "3.0000 CUR") - ("memo", "hi" ), - 20, 10 - ); - BOOST_REQUIRE_EQUAL(transaction_receipt::delayed, trace->receipt->status); - gen_size = chain.control->db().get_index().size(); - BOOST_REQUIRE_EQUAL(1u, gen_size); - BOOST_REQUIRE_EQUAL(0u, trace->action_traces.size()); - - liquid_balance = get_currency_balance(chain, "tester"_n); - BOOST_REQUIRE_EQUAL(asset::from_string("99.0000 CUR"), liquid_balance); - liquid_balance = get_currency_balance(chain, "tester2"_n); - BOOST_REQUIRE_EQUAL(asset::from_string("1.0000 CUR"), liquid_balance); + // propose and approve an msig trx that transfers "quantity" tokens + // from tester to tester2 with a delay of "delay_seconds" + constexpr name proposal_name = "prop1"_n; + propose_approve_msig_token_transfer_trx(chain, proposal_name, { "tester"_n, config::active_name }, 10, "3.0000 CUR"); chain.produce_blocks(); @@ -214,141 +310,8 @@ BOOST_AUTO_TEST_CASE( link_delay_direct_test ) { try { liquid_balance = get_currency_balance(chain, "tester2"_n); BOOST_REQUIRE_EQUAL(asset::from_string("1.0000 CUR"), liquid_balance); - chain.produce_blocks(); - - liquid_balance = get_currency_balance(chain, "tester"_n); - BOOST_REQUIRE_EQUAL(asset::from_string("96.0000 CUR"), liquid_balance); - liquid_balance = get_currency_balance(chain, "tester2"_n); - BOOST_REQUIRE_EQUAL(asset::from_string("4.0000 CUR"), liquid_balance); - -} FC_LOG_AND_RETHROW() }/// schedule_test - - -BOOST_AUTO_TEST_CASE(delete_auth_test) { try { - validating_tester chain; - - const auto& tester_account = "tester"_n; - - chain.produce_blocks(); - chain.create_account("eosio.token"_n); - chain.produce_blocks(10); - - chain.set_code("eosio.token"_n, test_contracts::eosio_token_wasm()); - chain.set_abi("eosio.token"_n, test_contracts::eosio_token_abi()); - - chain.produce_blocks(); - chain.create_account("tester"_n); - chain.create_account("tester2"_n); - chain.produce_blocks(10); - - transaction_trace_ptr trace; - - // can't delete auth because it doesn't exist - BOOST_REQUIRE_EXCEPTION( - trace = chain.push_action(config::system_account_name, deleteauth::get_name(), tester_account, fc::mutable_variant_object() - ("account", "tester") - ("permission", "first")), - permission_query_exception, - [] (const permission_query_exception &e)->bool { - expect_assert_message(e, "permission_query_exception: Permission Query Exception\nFailed to retrieve permission"); - return true; - }); - - // update auth - chain.push_action(config::system_account_name, updateauth::get_name(), tester_account, fc::mutable_variant_object() - ("account", "tester") - ("permission", "first") - ("parent", "active") - ("auth", authority(chain.get_public_key(tester_account, "first"))) - ); - - // link auth - chain.push_action(config::system_account_name, linkauth::get_name(), tester_account, fc::mutable_variant_object() - ("account", "tester") - ("code", "eosio.token") - ("type", "transfer") - ("requirement", "first")); - - // create CUR token - chain.produce_blocks(); - chain.push_action("eosio.token"_n, "create"_n, "eosio.token"_n, mutable_variant_object() - ("issuer", "eosio.token" ) - ("maximum_supply", "9000000.0000 CUR" ) - ); - - // issue to account "eosio.token" - chain.push_action("eosio.token"_n, name("issue"), "eosio.token"_n, fc::mutable_variant_object() - ("to", "eosio.token") - ("quantity", "1000000.0000 CUR") - ("memo", "for stuff") - ); - - // transfer from eosio.token to tester - trace = chain.push_action("eosio.token"_n, name("transfer"), "eosio.token"_n, fc::mutable_variant_object() - ("from", "eosio.token") - ("to", "tester") - ("quantity", "100.0000 CUR") - ("memo", "hi" ) - ); - BOOST_REQUIRE_EQUAL(transaction_receipt::executed, trace->receipt->status); - - chain.produce_blocks(); - - auto liquid_balance = get_currency_balance(chain, "eosio.token"_n); - BOOST_REQUIRE_EQUAL(asset::from_string("999900.0000 CUR"), liquid_balance); - liquid_balance = get_currency_balance(chain, "tester"_n); - BOOST_REQUIRE_EQUAL(asset::from_string("100.0000 CUR"), liquid_balance); - - trace = chain.push_action("eosio.token"_n, name("transfer"), "tester"_n, fc::mutable_variant_object() - ("from", "tester") - ("to", "tester2") - ("quantity", "1.0000 CUR") - ("memo", "hi" ) - ); - - BOOST_REQUIRE_EQUAL(transaction_receipt::executed, trace->receipt->status); - - liquid_balance = get_currency_balance(chain, "eosio.token"_n); - BOOST_REQUIRE_EQUAL(asset::from_string("999900.0000 CUR"), liquid_balance); - liquid_balance = get_currency_balance(chain, "tester"_n); - BOOST_REQUIRE_EQUAL(asset::from_string("99.0000 CUR"), liquid_balance); - liquid_balance = get_currency_balance(chain, "tester2"_n); - BOOST_REQUIRE_EQUAL(asset::from_string("1.0000 CUR"), liquid_balance); - - // can't delete auth because it's linked - BOOST_REQUIRE_EXCEPTION( - trace = chain.push_action(config::system_account_name, deleteauth::get_name(), tester_account, fc::mutable_variant_object() - ("account", "tester") - ("permission", "first")), - action_validate_exception, - [] (const action_validate_exception &e)->bool { - expect_assert_message(e, "action_validate_exception: message validation exception\nCannot delete a linked authority"); - return true; - }); - - // unlink auth - trace = chain.push_action(config::system_account_name, unlinkauth::get_name(), tester_account, fc::mutable_variant_object() - ("account", "tester") - ("code", "eosio.token") - ("type", "transfer")); - BOOST_REQUIRE_EQUAL(transaction_receipt::executed, trace->receipt->status); - - // delete auth - trace = chain.push_action(config::system_account_name, deleteauth::get_name(), tester_account, fc::mutable_variant_object() - ("account", "tester") - ("permission", "first")); - - BOOST_REQUIRE_EQUAL(transaction_receipt::executed, trace->receipt->status); - - chain.produce_blocks(1);; - - trace = chain.push_action("eosio.token"_n, name("transfer"), "tester"_n, fc::mutable_variant_object() - ("from", "tester") - ("to", "tester2") - ("quantity", "3.0000 CUR") - ("memo", "hi" ) - ); - BOOST_REQUIRE_EQUAL(transaction_receipt::executed, trace->receipt->status); + // executue after delay of 10 seconds + exec_msig_trx(chain, proposal_name, {{ "tester"_n, config::active_name }}); chain.produce_blocks(); @@ -357,8 +320,7 @@ BOOST_AUTO_TEST_CASE(delete_auth_test) { try { liquid_balance = get_currency_balance(chain, "tester2"_n); BOOST_REQUIRE_EQUAL(asset::from_string("4.0000 CUR"), liquid_balance); -} FC_LOG_AND_RETHROW() }/// delete_auth_test - +} FC_LOG_AND_RETHROW() }/// link_delay_direct_test // test link to permission with delay on permission which is parent of min permission (special logic in permission_object::satisfies) BOOST_AUTO_TEST_CASE( link_delay_direct_parent_permission_test ) { try { @@ -366,17 +328,7 @@ BOOST_AUTO_TEST_CASE( link_delay_direct_parent_permission_test ) { try { const auto& tester_account = "tester"_n; - chain.produce_blocks(); - chain.create_account("eosio.token"_n); - chain.produce_blocks(10); - - chain.set_code("eosio.token"_n, test_contracts::eosio_token_wasm()); - chain.set_abi("eosio.token"_n, test_contracts::eosio_token_abi()); - - chain.produce_blocks(); - chain.create_account("tester"_n); - chain.create_account("tester2"_n); - chain.produce_blocks(10); + create_accounts(chain); chain.push_action(config::system_account_name, updateauth::get_name(), tester_account, fc::mutable_variant_object() ("account", "tester") @@ -409,8 +361,6 @@ BOOST_AUTO_TEST_CASE( link_delay_direct_parent_permission_test ) { try { ("memo", "hi" ) ); BOOST_REQUIRE_EQUAL(transaction_receipt::executed, trace->receipt->status); - auto gen_size = chain.control->db().get_index().size(); - BOOST_REQUIRE_EQUAL(0u, gen_size); chain.produce_blocks(); @@ -427,10 +377,6 @@ BOOST_AUTO_TEST_CASE( link_delay_direct_parent_permission_test ) { try { ); BOOST_REQUIRE_EQUAL(transaction_receipt::executed, trace->receipt->status); - gen_size = chain.control->db().get_index().size(); - BOOST_REQUIRE_EQUAL(0u, gen_size); - - chain.produce_blocks(); liquid_balance = get_currency_balance(chain, "eosio.token"_n); BOOST_REQUIRE_EQUAL(asset::from_string("999900.0000 CUR"), liquid_balance); @@ -446,22 +392,14 @@ BOOST_AUTO_TEST_CASE( link_delay_direct_parent_permission_test ) { try { ("auth", authority(chain.get_public_key(tester_account, "active"), 15)) ); BOOST_REQUIRE_EQUAL(transaction_receipt::executed, trace->receipt->status); - gen_size = chain.control->db().get_index().size(); - BOOST_REQUIRE_EQUAL(0u, gen_size); + chain.produce_blocks(); chain.produce_blocks(); - trace = chain.push_action("eosio.token"_n, name("transfer"), "tester"_n, fc::mutable_variant_object() - ("from", "tester") - ("to", "tester2") - ("quantity", "3.0000 CUR") - ("memo", "hi" ), - 20, 15 - ); - BOOST_REQUIRE_EQUAL(transaction_receipt::delayed, trace->receipt->status); - gen_size = chain.control->db().get_index().size(); - BOOST_REQUIRE_EQUAL(1u, gen_size); - BOOST_REQUIRE_EQUAL(0u, trace->action_traces.size()); + // Propose and approve an msig trx that transfers "quantity" tokens + // from tester to tester2 with a delay of "delay_seconds" + constexpr name proposal_name = "prop1"_n; + propose_approve_msig_token_transfer_trx(chain, proposal_name, { "tester"_n, config::owner_name }, 15, "3.0000 CUR"); liquid_balance = get_currency_balance(chain, "tester"_n); BOOST_REQUIRE_EQUAL(asset::from_string("99.0000 CUR"), liquid_balance); @@ -491,30 +429,22 @@ BOOST_AUTO_TEST_CASE( link_delay_direct_parent_permission_test ) { try { chain.produce_blocks(); + // executue the msig trx + exec_msig_trx(chain, proposal_name, {{ "tester"_n, config::owner_name }}); + liquid_balance = get_currency_balance(chain, "tester"_n); BOOST_REQUIRE_EQUAL(asset::from_string("96.0000 CUR"), liquid_balance); liquid_balance = get_currency_balance(chain, "tester2"_n); BOOST_REQUIRE_EQUAL(asset::from_string("4.0000 CUR"), liquid_balance); -} FC_LOG_AND_RETHROW() }/// schedule_test +} FC_LOG_AND_RETHROW() }/// link_delay_direct_parent_permission_test // test link to permission with delay on permission between min permission and authorizing permission it BOOST_AUTO_TEST_CASE( link_delay_direct_walk_parent_permissions_test ) { try { validating_tester chain; - const auto& tester_account = "tester"_n; - chain.produce_blocks(); - chain.create_account("eosio.token"_n); - chain.produce_blocks(10); - - chain.set_code("eosio.token"_n, test_contracts::eosio_token_wasm()); - chain.set_abi("eosio.token"_n, test_contracts::eosio_token_abi()); - - chain.produce_blocks(); - chain.create_account("tester"_n); - chain.create_account("tester2"_n); - chain.produce_blocks(10); + create_accounts(chain); chain.push_action(config::system_account_name, updateauth::get_name(), tester_account, fc::mutable_variant_object() ("account", "tester") @@ -553,8 +483,6 @@ BOOST_AUTO_TEST_CASE( link_delay_direct_walk_parent_permissions_test ) { try { ("memo", "hi" ) ); BOOST_REQUIRE_EQUAL(transaction_receipt::executed, trace->receipt->status); - auto gen_size = chain.control->db().get_index().size(); - BOOST_REQUIRE_EQUAL(0u, gen_size); chain.produce_blocks(); @@ -571,8 +499,6 @@ BOOST_AUTO_TEST_CASE( link_delay_direct_walk_parent_permissions_test ) { try { ); BOOST_REQUIRE_EQUAL(transaction_receipt::executed, trace->receipt->status); - gen_size = chain.control->db().get_index().size(); - BOOST_REQUIRE_EQUAL(0u, gen_size); chain.produce_blocks(); @@ -590,22 +516,14 @@ BOOST_AUTO_TEST_CASE( link_delay_direct_walk_parent_permissions_test ) { try { ("auth", authority(chain.get_public_key(tester_account, "first"), 20)) ); BOOST_REQUIRE_EQUAL(transaction_receipt::executed, trace->receipt->status); - gen_size = chain.control->db().get_index().size(); - BOOST_REQUIRE_EQUAL(0u, gen_size); chain.produce_blocks(); - trace = chain.push_action("eosio.token"_n, name("transfer"), "tester"_n, fc::mutable_variant_object() - ("from", "tester") - ("to", "tester2") - ("quantity", "3.0000 CUR") - ("memo", "hi" ), - 30, 20 - ); - BOOST_REQUIRE_EQUAL(transaction_receipt::delayed, trace->receipt->status); - gen_size = chain.control->db().get_index().size(); - BOOST_REQUIRE_EQUAL(1u, gen_size); - BOOST_REQUIRE_EQUAL(0u, trace->action_traces.size()); + + // propose and approve an msig trx that transfers "quantity" tokens + // from tester to tester2 with a delay of "delay_seconds" + constexpr name proposal_name = "prop1"_n; + propose_approve_msig_token_transfer_trx(chain, proposal_name, { "tester"_n, config::active_name }, 20, "3.0000 CUR"); liquid_balance = get_currency_balance(chain, "tester"_n); BOOST_REQUIRE_EQUAL(asset::from_string("99.0000 CUR"), liquid_balance); @@ -633,6 +551,9 @@ BOOST_AUTO_TEST_CASE( link_delay_direct_walk_parent_permissions_test ) { try { liquid_balance = get_currency_balance(chain, "tester2"_n); BOOST_REQUIRE_EQUAL(asset::from_string("1.0000 CUR"), liquid_balance); + // executue after delay + exec_msig_trx(chain, proposal_name, {{ "tester"_n, config::active_name }}); + chain.produce_blocks(); liquid_balance = get_currency_balance(chain, "tester"_n); @@ -640,7 +561,7 @@ BOOST_AUTO_TEST_CASE( link_delay_direct_walk_parent_permissions_test ) { try { liquid_balance = get_currency_balance(chain, "tester2"_n); BOOST_REQUIRE_EQUAL(asset::from_string("4.0000 CUR"), liquid_balance); -} FC_LOG_AND_RETHROW() }/// schedule_test +} FC_LOG_AND_RETHROW() }/// link_delay_direct_walk_parent_permissions_test // test removing delay on permission BOOST_AUTO_TEST_CASE( link_delay_permission_change_test ) { try { @@ -648,17 +569,7 @@ BOOST_AUTO_TEST_CASE( link_delay_permission_change_test ) { try { const auto& tester_account = "tester"_n; - chain.produce_blocks(); - chain.create_account("eosio.token"_n); - chain.produce_blocks(10); - - chain.set_code("eosio.token"_n, test_contracts::eosio_token_wasm()); - chain.set_abi("eosio.token"_n, test_contracts::eosio_token_abi()); - - chain.produce_blocks(); - chain.create_account("tester"_n); - chain.create_account("tester2"_n); - chain.produce_blocks(10); + create_accounts(chain); chain.push_action(config::system_account_name, updateauth::get_name(), tester_account, fc::mutable_variant_object() ("account", "tester") @@ -691,8 +602,6 @@ BOOST_AUTO_TEST_CASE( link_delay_permission_change_test ) { try { ("memo", "hi" ) ); BOOST_REQUIRE_EQUAL(transaction_receipt::executed, trace->receipt->status); - auto gen_size = chain.control->db().get_index().size(); - BOOST_REQUIRE_EQUAL(0u, gen_size); chain.produce_blocks(); @@ -702,18 +611,10 @@ BOOST_AUTO_TEST_CASE( link_delay_permission_change_test ) { try { BOOST_REQUIRE_EQUAL(asset::from_string("100.0000 CUR"), liquid_balance); // this transaction will be delayed 20 blocks - trace = chain.push_action("eosio.token"_n, name("transfer"), "tester"_n, fc::mutable_variant_object() - ("from", "tester") - ("to", "tester2") - ("quantity", "1.0000 CUR") - ("memo", "hi" ), - 30, 10 - ); - - BOOST_REQUIRE_EQUAL(transaction_receipt::delayed, trace->receipt->status); - gen_size = chain.control->db().get_index().size(); - BOOST_REQUIRE_EQUAL(1u, gen_size); - BOOST_REQUIRE_EQUAL(0u, trace->action_traces.size()); + constexpr name proposal_1_name = "prop1"_n; + constexpr uint32_t delay_seconds = 10; + constexpr auto quantity = "1.0000 CUR"; + propose_approve_msig_token_transfer_trx(chain, proposal_1_name, { "tester"_n, config::active_name }, delay_seconds, quantity); chain.produce_blocks(); @@ -725,16 +626,9 @@ BOOST_AUTO_TEST_CASE( link_delay_permission_change_test ) { try { BOOST_REQUIRE_EQUAL(asset::from_string("0.0000 CUR"), liquid_balance); // this transaction will be delayed 20 blocks - trace = chain.push_action(config::system_account_name, updateauth::get_name(), tester_account, fc::mutable_variant_object() - ("account", "tester") - ("permission", "first") - ("parent", "active") - ("auth", authority(chain.get_public_key(tester_account, "first"))), - 30, 10); - BOOST_REQUIRE_EQUAL(transaction_receipt::delayed, trace->receipt->status); - gen_size = chain.control->db().get_index().size(); - BOOST_CHECK_EQUAL(2u, gen_size); - BOOST_REQUIRE_EQUAL(0u, trace->action_traces.size()); + constexpr name proposal_2_name = "prop2"_n; + constexpr uint32_t delay_seconds_2 = 10; + propose_approve_msig_updateauth_trx(chain, proposal_2_name, { "tester"_n, config::active_name }, delay_seconds_2); chain.produce_blocks(); @@ -751,17 +645,10 @@ BOOST_AUTO_TEST_CASE( link_delay_permission_change_test ) { try { BOOST_REQUIRE_EQUAL(asset::from_string("0.0000 CUR"), liquid_balance); // this transaction will be delayed 20 blocks - trace = chain.push_action("eosio.token"_n, name("transfer"), "tester"_n, fc::mutable_variant_object() - ("from", "tester") - ("to", "tester2") - ("quantity", "5.0000 CUR") - ("memo", "hi" ), - 30, 10 - ); - BOOST_REQUIRE_EQUAL(transaction_receipt::delayed, trace->receipt->status); - gen_size = chain.control->db().get_index().size(); - BOOST_CHECK_EQUAL(3u, gen_size); - BOOST_REQUIRE_EQUAL(0u, trace->action_traces.size()); + constexpr name proposal_3_name = "prop3"_n; + constexpr uint32_t delay_seconds_3 = 10; + constexpr auto quantity_3 = "5.0000 CUR"; + propose_approve_msig_token_transfer_trx(chain, proposal_3_name, { "tester"_n, config::active_name }, delay_seconds_3, quantity_3); chain.produce_blocks(); @@ -778,22 +665,18 @@ BOOST_AUTO_TEST_CASE( link_delay_permission_change_test ) { try { BOOST_REQUIRE_EQUAL(asset::from_string("0.0000 CUR"), liquid_balance); // first transfer will finally be performed + exec_msig_trx(chain, proposal_1_name, {{ "tester"_n, config::active_name }}); chain.produce_blocks(); - gen_size = chain.control->db().get_index().size(); - BOOST_CHECK_EQUAL(2u, gen_size); - liquid_balance = get_currency_balance(chain, "tester"_n); BOOST_REQUIRE_EQUAL(asset::from_string("99.0000 CUR"), liquid_balance); liquid_balance = get_currency_balance(chain, "tester2"_n); BOOST_REQUIRE_EQUAL(asset::from_string("1.0000 CUR"), liquid_balance); // delayed update auth removing the delay will finally execute + exec_msig_trx(chain, proposal_2_name, {{ "tester"_n, config::active_name }}); chain.produce_blocks(); - gen_size = chain.control->db().get_index().size(); - BOOST_CHECK_EQUAL(1u, gen_size); - // this transfer is performed right away since delay is removed trace = chain.push_action("eosio.token"_n, name("transfer"), "tester"_n, fc::mutable_variant_object() ("from", "tester") @@ -817,21 +700,16 @@ BOOST_AUTO_TEST_CASE( link_delay_permission_change_test ) { try { liquid_balance = get_currency_balance(chain, "tester2"_n); BOOST_REQUIRE_EQUAL(asset::from_string("11.0000 CUR"), liquid_balance); - gen_size = chain.control->db().get_index().size(); - BOOST_CHECK_EQUAL(1u, gen_size); - // second transfer finally is performed + exec_msig_trx(chain, proposal_3_name, {{ "tester"_n, config::active_name }}); chain.produce_blocks(); - gen_size = chain.control->db().get_index().size(); - BOOST_CHECK_EQUAL(0u, gen_size); - liquid_balance = get_currency_balance(chain, "tester"_n); BOOST_REQUIRE_EQUAL(asset::from_string("84.0000 CUR"), liquid_balance); liquid_balance = get_currency_balance(chain, "tester2"_n); BOOST_REQUIRE_EQUAL(asset::from_string("16.0000 CUR"), liquid_balance); -} FC_LOG_AND_RETHROW() }/// schedule_test +} FC_LOG_AND_RETHROW() }/// link_delay_permission_change_test // test removing delay on permission based on heirarchy delay BOOST_AUTO_TEST_CASE( link_delay_permission_change_with_delay_heirarchy_test ) { try { @@ -839,17 +717,7 @@ BOOST_AUTO_TEST_CASE( link_delay_permission_change_with_delay_heirarchy_test ) { const auto& tester_account = "tester"_n; - chain.produce_blocks(); - chain.create_account("eosio.token"_n); - chain.produce_blocks(10); - - chain.set_code("eosio.token"_n, test_contracts::eosio_token_wasm()); - chain.set_abi("eosio.token"_n, test_contracts::eosio_token_abi()); - - chain.produce_blocks(); - chain.create_account("tester"_n); - chain.create_account("tester2"_n); - chain.produce_blocks(10); + create_accounts(chain); chain.push_action(config::system_account_name, updateauth::get_name(), tester_account, fc::mutable_variant_object() ("account", "tester") @@ -888,8 +756,6 @@ BOOST_AUTO_TEST_CASE( link_delay_permission_change_with_delay_heirarchy_test ) { ("memo", "hi" ) ); BOOST_REQUIRE_EQUAL(transaction_receipt::executed, trace->receipt->status); - auto gen_size = chain.control->db().get_index().size(); - BOOST_REQUIRE_EQUAL(0u, gen_size); chain.produce_blocks(); @@ -899,18 +765,10 @@ BOOST_AUTO_TEST_CASE( link_delay_permission_change_with_delay_heirarchy_test ) { BOOST_REQUIRE_EQUAL(asset::from_string("100.0000 CUR"), liquid_balance); // this transaction will be delayed 20 blocks - trace = chain.push_action("eosio.token"_n, name("transfer"), "tester"_n, fc::mutable_variant_object() - ("from", "tester") - ("to", "tester2") - ("quantity", "1.0000 CUR") - ("memo", "hi" ), - 30, 10 - ); - - BOOST_REQUIRE_EQUAL(transaction_receipt::delayed, trace->receipt->status); - gen_size = chain.control->db().get_index().size(); - BOOST_REQUIRE_EQUAL(1u, gen_size); - BOOST_REQUIRE_EQUAL(0u, trace->action_traces.size()); + constexpr name proposal_1_name = "prop1"_n; + constexpr uint32_t delay_seconds = 10; + constexpr auto quantity = "1.0000 CUR"; + propose_approve_msig_token_transfer_trx(chain, proposal_1_name, { "tester"_n, config::active_name }, delay_seconds, quantity); chain.produce_blocks(); @@ -922,18 +780,9 @@ BOOST_AUTO_TEST_CASE( link_delay_permission_change_with_delay_heirarchy_test ) { BOOST_REQUIRE_EQUAL(asset::from_string("0.0000 CUR"), liquid_balance); // this transaction will be delayed 20 blocks - chain.push_action(config::system_account_name, updateauth::get_name(), tester_account, fc::mutable_variant_object() - ("account", "tester") - ("permission", "first") - ("parent", "active") - ("auth", authority(chain.get_public_key(tester_account, "first"))), - 30, 10 - ); - - BOOST_REQUIRE_EQUAL(transaction_receipt::delayed, trace->receipt->status); - gen_size = chain.control->db().get_index().size(); - BOOST_CHECK_EQUAL(2u, gen_size); - BOOST_REQUIRE_EQUAL(0u, trace->action_traces.size()); + constexpr name proposal_2_name = "prop2"_n; + constexpr uint32_t delay_seconds_2 = 10; + propose_approve_msig_updateauth_trx(chain, proposal_2_name, { "tester"_n, config::active_name }, delay_seconds_2); chain.produce_blocks(); @@ -950,18 +799,10 @@ BOOST_AUTO_TEST_CASE( link_delay_permission_change_with_delay_heirarchy_test ) { BOOST_REQUIRE_EQUAL(asset::from_string("0.0000 CUR"), liquid_balance); // this transaction will be delayed 20 blocks - trace = chain.push_action("eosio.token"_n, name("transfer"), "tester"_n, fc::mutable_variant_object() - ("from", "tester") - ("to", "tester2") - ("quantity", "5.0000 CUR") - ("memo", "hi" ), - 30, 10 - ); - - BOOST_REQUIRE_EQUAL(transaction_receipt::delayed, trace->receipt->status); - gen_size = chain.control->db().get_index().size(); - BOOST_CHECK_EQUAL(3u, gen_size); - BOOST_REQUIRE_EQUAL(0u, trace->action_traces.size()); + constexpr name proposal_3_name = "prop3"_n; + constexpr uint32_t delay_seconds_3 = 10; + constexpr auto quantity_3 = "5.0000 CUR"; + propose_approve_msig_token_transfer_trx(chain, proposal_3_name, { "tester"_n, config::active_name }, delay_seconds_3, quantity_3); chain.produce_blocks(); @@ -978,6 +819,7 @@ BOOST_AUTO_TEST_CASE( link_delay_permission_change_with_delay_heirarchy_test ) { BOOST_REQUIRE_EQUAL(asset::from_string("0.0000 CUR"), liquid_balance); // first transfer will finally be performed + exec_msig_trx(chain, proposal_1_name, {{ "tester"_n, config::active_name }}); chain.produce_blocks(); liquid_balance = get_currency_balance(chain, "tester"_n); @@ -985,6 +827,8 @@ BOOST_AUTO_TEST_CASE( link_delay_permission_change_with_delay_heirarchy_test ) { liquid_balance = get_currency_balance(chain, "tester2"_n); BOOST_REQUIRE_EQUAL(asset::from_string("1.0000 CUR"), liquid_balance); + // delayed update auth removing the delay will finally execute + exec_msig_trx(chain, proposal_2_name, {{ "tester"_n, config::active_name }}); chain.produce_blocks(); // this transfer is performed right away since delay is removed @@ -996,8 +840,6 @@ BOOST_AUTO_TEST_CASE( link_delay_permission_change_with_delay_heirarchy_test ) { ); BOOST_REQUIRE_EQUAL(transaction_receipt::executed, trace->receipt->status); - gen_size = chain.control->db().get_index().size(); - BOOST_CHECK_EQUAL(1u, gen_size); chain.produce_blocks(); @@ -1021,6 +863,7 @@ BOOST_AUTO_TEST_CASE( link_delay_permission_change_with_delay_heirarchy_test ) { BOOST_REQUIRE_EQUAL(asset::from_string("11.0000 CUR"), liquid_balance); // second transfer finally is performed + exec_msig_trx(chain, proposal_3_name, {{ "tester"_n, config::active_name }}); chain.produce_blocks(); liquid_balance = get_currency_balance(chain, "tester"_n); @@ -1028,7 +871,7 @@ BOOST_AUTO_TEST_CASE( link_delay_permission_change_with_delay_heirarchy_test ) { liquid_balance = get_currency_balance(chain, "tester2"_n); BOOST_REQUIRE_EQUAL(asset::from_string("16.0000 CUR"), liquid_balance); -} FC_LOG_AND_RETHROW() }/// schedule_test +} FC_LOG_AND_RETHROW() }/// link_delay_permission_change_with_delay_heirarchy_test // test moving link with delay on permission BOOST_AUTO_TEST_CASE( link_delay_link_change_test ) { try { @@ -1036,17 +879,7 @@ BOOST_AUTO_TEST_CASE( link_delay_link_change_test ) { try { const auto& tester_account = "tester"_n; - chain.produce_blocks(); - chain.create_account("eosio.token"_n); - chain.produce_blocks(10); - - chain.set_code("eosio.token"_n, test_contracts::eosio_token_wasm()); - chain.set_abi("eosio.token"_n, test_contracts::eosio_token_abi()); - - chain.produce_blocks(); - chain.create_account("tester"_n); - chain.create_account("tester2"_n); - chain.produce_blocks(10); + create_accounts(chain); chain.push_action(config::system_account_name, updateauth::get_name(), tester_account, fc::mutable_variant_object() ("account", "tester") @@ -1085,8 +918,6 @@ BOOST_AUTO_TEST_CASE( link_delay_link_change_test ) { try { ("memo", "hi" ) ); BOOST_REQUIRE_EQUAL(transaction_receipt::executed, trace->receipt->status); - auto gen_size = chain.control->db().get_index().size(); - BOOST_REQUIRE_EQUAL(0u, gen_size); chain.produce_blocks(); @@ -1096,17 +927,10 @@ BOOST_AUTO_TEST_CASE( link_delay_link_change_test ) { try { BOOST_REQUIRE_EQUAL(asset::from_string("100.0000 CUR"), liquid_balance); // this transaction will be delayed 20 blocks - trace = chain.push_action("eosio.token"_n, name("transfer"), "tester"_n, fc::mutable_variant_object() - ("from", "tester") - ("to", "tester2") - ("quantity", "1.0000 CUR") - ("memo", "hi" ), - 30, 10 - ); - BOOST_REQUIRE_EQUAL(transaction_receipt::delayed, trace->receipt->status); - gen_size = chain.control->db().get_index().size(); - BOOST_REQUIRE_EQUAL(1u, gen_size); - BOOST_REQUIRE_EQUAL(0u, trace->action_traces.size()); + constexpr name proposal_1_name = "prop1"_n; + constexpr uint32_t delay_seconds = 10; + constexpr auto quantity = "1.0000 CUR"; + propose_approve_msig_token_transfer_trx(chain, proposal_1_name, { "tester"_n, config::active_name }, delay_seconds, quantity); chain.produce_blocks(); @@ -1125,25 +949,15 @@ BOOST_AUTO_TEST_CASE( link_delay_link_change_test ) { try { ("code", eosio_token) ("type", "transfer") ("requirement", "second"), - 30, 3), + 30, 0), unsatisfied_authorization, fc_exception_message_starts_with("transaction declares authority") ); // this transaction will be delayed 20 blocks - chain.push_action( config::system_account_name, linkauth::get_name(), - vector{{tester_account, "first"_n}}, - fc::mutable_variant_object() - ("account", "tester") - ("code", eosio_token) - ("type", "transfer") - ("requirement", "second"), - 30, 10 - ); - BOOST_REQUIRE_EQUAL(transaction_receipt::delayed, trace->receipt->status); - gen_size = chain.control->db().get_index().size(); - BOOST_CHECK_EQUAL(2u, gen_size); - BOOST_REQUIRE_EQUAL(0u, trace->action_traces.size()); + constexpr name proposal_2_name = "prop2"_n; + constexpr uint32_t delay_seconds_2 = 10; + propose_approve_msig_linkauth_trx(chain, proposal_2_name, "second"_n, { "tester"_n, config::active_name }, delay_seconds_2); chain.produce_blocks(); @@ -1154,24 +968,17 @@ BOOST_AUTO_TEST_CASE( link_delay_link_change_test ) { try { chain.produce_blocks(16); - liquid_balance = get_currency_balance(chain, "tester"_n); - BOOST_REQUIRE_EQUAL(asset::from_string("100.0000 CUR"), liquid_balance); - liquid_balance = get_currency_balance(chain, "tester2"_n); - BOOST_REQUIRE_EQUAL(asset::from_string("0.0000 CUR"), liquid_balance); - - // this transaction will be delayed 20 blocks - trace = chain.push_action("eosio.token"_n, name("transfer"), "tester"_n, fc::mutable_variant_object() - ("from", "tester") - ("to", "tester2") - ("quantity", "5.0000 CUR") - ("memo", "hi" ), - 30, 10 - ); - BOOST_REQUIRE_EQUAL(transaction_receipt::delayed, trace->receipt->status); - gen_size = chain.control->db().get_index().size(); - BOOST_CHECK_EQUAL(3u, gen_size); - BOOST_CHECK_EQUAL(0u, trace->action_traces.size()); - + liquid_balance = get_currency_balance(chain, "tester"_n); + BOOST_REQUIRE_EQUAL(asset::from_string("100.0000 CUR"), liquid_balance); + liquid_balance = get_currency_balance(chain, "tester2"_n); + BOOST_REQUIRE_EQUAL(asset::from_string("0.0000 CUR"), liquid_balance); + + // this transaction will be delayed 20 blocks + constexpr name proposal_3_name = "prop3"_n; + constexpr uint32_t delay_seconds_3 = 10; + constexpr auto quantity_3 = "5.0000 CUR"; + propose_approve_msig_token_transfer_trx(chain, proposal_3_name, { "tester"_n, config::active_name }, delay_seconds_3, quantity_3); + chain.produce_blocks(); liquid_balance = get_currency_balance(chain, "tester"_n); @@ -1187,6 +994,7 @@ BOOST_AUTO_TEST_CASE( link_delay_link_change_test ) { try { BOOST_REQUIRE_EQUAL(asset::from_string("0.0000 CUR"), liquid_balance); // first transfer will finally be performed + exec_msig_trx(chain, proposal_1_name, {{ "tester"_n, config::active_name }}); chain.produce_blocks(); liquid_balance = get_currency_balance(chain, "tester"_n); @@ -1195,6 +1003,7 @@ BOOST_AUTO_TEST_CASE( link_delay_link_change_test ) { try { BOOST_REQUIRE_EQUAL(asset::from_string("1.0000 CUR"), liquid_balance); // delay on minimum permission of transfer is finally removed + exec_msig_trx(chain, proposal_2_name, {{ "tester"_n, config::active_name }}); chain.produce_blocks(); // this transfer is performed right away since delay is removed @@ -1205,9 +1014,6 @@ BOOST_AUTO_TEST_CASE( link_delay_link_change_test ) { try { ("memo", "hi" ) ); BOOST_REQUIRE_EQUAL(transaction_receipt::executed, trace->receipt->status); - gen_size = chain.control->db().get_index().size(); - BOOST_CHECK_EQUAL(1u, gen_size); - liquid_balance = get_currency_balance(chain, "tester"_n); BOOST_REQUIRE_EQUAL(asset::from_string("89.0000 CUR"), liquid_balance); @@ -1222,6 +1028,7 @@ BOOST_AUTO_TEST_CASE( link_delay_link_change_test ) { try { BOOST_REQUIRE_EQUAL(asset::from_string("11.0000 CUR"), liquid_balance); // second transfer finally is performed + exec_msig_trx(chain, proposal_3_name, {{ "tester"_n, config::active_name }}); chain.produce_blocks(); liquid_balance = get_currency_balance(chain, "tester"_n); @@ -1229,26 +1036,14 @@ BOOST_AUTO_TEST_CASE( link_delay_link_change_test ) { try { liquid_balance = get_currency_balance(chain, "tester2"_n); BOOST_REQUIRE_EQUAL(asset::from_string("16.0000 CUR"), liquid_balance); -} FC_LOG_AND_RETHROW() }/// schedule_test - +} FC_LOG_AND_RETHROW() }/// link_delay_link_change_test // test link with unlink BOOST_AUTO_TEST_CASE( link_delay_unlink_test ) { try { validating_tester chain; - const auto& tester_account = "tester"_n; - chain.produce_blocks(); - chain.create_account("eosio.token"_n); - chain.produce_blocks(10); - - chain.set_code("eosio.token"_n, test_contracts::eosio_token_wasm()); - chain.set_abi("eosio.token"_n, test_contracts::eosio_token_abi()); - - chain.produce_blocks(); - chain.create_account("tester"_n); - chain.create_account("tester2"_n); - chain.produce_blocks(10); + create_accounts(chain); chain.push_action(config::system_account_name, updateauth::get_name(), tester_account, fc::mutable_variant_object() ("account", "tester") @@ -1290,17 +1085,10 @@ BOOST_AUTO_TEST_CASE( link_delay_unlink_test ) { try { BOOST_REQUIRE_EQUAL(asset::from_string("100.0000 CUR"), liquid_balance); // this transaction will be delayed 20 blocks - trace = chain.push_action("eosio.token"_n, name("transfer"), "tester"_n, fc::mutable_variant_object() - ("from", "tester") - ("to", "tester2") - ("quantity", "1.0000 CUR") - ("memo", "hi" ), - 30, 10 - ); - BOOST_REQUIRE_EQUAL(transaction_receipt::delayed, trace->receipt->status); - auto gen_size = chain.control->db().get_index().size(); - BOOST_CHECK_EQUAL(1u, gen_size); - BOOST_REQUIRE_EQUAL(0u, trace->action_traces.size()); + constexpr name first_trnsfr_propsal_name = "prop1"_n; + constexpr uint32_t first_trnsfr_delay_seconds = 10; + constexpr auto first_trnsfr_quantity = "1.0000 CUR"; + propose_approve_msig_token_transfer_trx(chain, first_trnsfr_propsal_name, { "tester"_n, config::active_name }, first_trnsfr_delay_seconds, first_trnsfr_quantity); chain.produce_blocks(); @@ -1318,23 +1106,15 @@ BOOST_AUTO_TEST_CASE( link_delay_unlink_test ) { try { ("account", "tester") ("code", eosio_token) ("type", "transfer"), - 30, 7 + 30, 0 ), unsatisfied_authorization, fc_exception_message_starts_with("transaction declares authority") ); // this transaction will be delayed 20 blocks - chain.push_action(config::system_account_name, unlinkauth::get_name(), tester_account, fc::mutable_variant_object() - ("account", "tester") - ("code", eosio_token) - ("type", "transfer"), - 30, 10 - ); - BOOST_REQUIRE_EQUAL(transaction_receipt::delayed, trace->receipt->status); - gen_size = chain.control->db().get_index().size(); - BOOST_CHECK_EQUAL(2u, gen_size); - BOOST_REQUIRE_EQUAL(0u, trace->action_traces.size()); + constexpr name unlinkauth_proposal_name = "prop2"_n; + propose_approve_msig_unlinkauth_trx(chain, unlinkauth_proposal_name, { "tester"_n, config::active_name }, 10); chain.produce_blocks(); @@ -1351,17 +1131,10 @@ BOOST_AUTO_TEST_CASE( link_delay_unlink_test ) { try { BOOST_REQUIRE_EQUAL(asset::from_string("0.0000 CUR"), liquid_balance); // this transaction will be delayed 20 blocks - trace = chain.push_action("eosio.token"_n, name("transfer"), "tester"_n, fc::mutable_variant_object() - ("from", "tester") - ("to", "tester2") - ("quantity", "5.0000 CUR") - ("memo", "hi" ), - 30, 10 - ); - BOOST_REQUIRE_EQUAL(transaction_receipt::delayed, trace->receipt->status); - gen_size = chain.control->db().get_index().size(); - BOOST_CHECK_EQUAL(3u, gen_size); - BOOST_REQUIRE_EQUAL(0u, trace->action_traces.size()); + constexpr name second_trnfr_propsal_name = "prop3"_n; + constexpr uint32_t second_trnfr_delay_seconds = 10; + constexpr auto second_trnfr_quantity = "5.0000 CUR"; + propose_approve_msig_token_transfer_trx(chain, second_trnfr_propsal_name, { "tester"_n, config::active_name }, second_trnfr_delay_seconds, second_trnfr_quantity); chain.produce_blocks(); @@ -1378,6 +1151,7 @@ BOOST_AUTO_TEST_CASE( link_delay_unlink_test ) { try { BOOST_REQUIRE_EQUAL(asset::from_string("0.0000 CUR"), liquid_balance); // first transfer will finally be performed + exec_msig_trx(chain, first_trnsfr_propsal_name, {{ "tester"_n, config::active_name }}); chain.produce_blocks(); liquid_balance = get_currency_balance(chain, "tester"_n); @@ -1386,6 +1160,7 @@ BOOST_AUTO_TEST_CASE( link_delay_unlink_test ) { try { BOOST_REQUIRE_EQUAL(asset::from_string("1.0000 CUR"), liquid_balance); // the delayed unlinkauth finally occurs + exec_msig_trx(chain, unlinkauth_proposal_name, {{ "tester"_n, config::active_name }}); chain.produce_blocks(); // this transfer is performed right away since delay is removed @@ -1412,6 +1187,7 @@ BOOST_AUTO_TEST_CASE( link_delay_unlink_test ) { try { BOOST_REQUIRE_EQUAL(asset::from_string("11.0000 CUR"), liquid_balance); // second transfer finally is performed + exec_msig_trx(chain, second_trnfr_propsal_name, {{ "tester"_n, config::active_name }}); chain.produce_blocks(); liquid_balance = get_currency_balance(chain, "tester"_n); @@ -1424,20 +1200,9 @@ BOOST_AUTO_TEST_CASE( link_delay_unlink_test ) { try { // test moving link with delay on permission's parent BOOST_AUTO_TEST_CASE( link_delay_link_change_heirarchy_test ) { try { validating_tester chain; - const auto& tester_account = "tester"_n; - chain.produce_blocks(); - chain.create_account("eosio.token"_n); - chain.produce_blocks(10); - - chain.set_code("eosio.token"_n, test_contracts::eosio_token_wasm()); - chain.set_abi("eosio.token"_n, test_contracts::eosio_token_abi()); - - chain.produce_blocks(); - chain.create_account("tester"_n); - chain.create_account("tester2"_n); - chain.produce_blocks(10); + create_accounts(chain); chain.push_action(config::system_account_name, updateauth::get_name(), tester_account, fc::mutable_variant_object() ("account", "tester") @@ -1482,8 +1247,6 @@ BOOST_AUTO_TEST_CASE( link_delay_link_change_heirarchy_test ) { try { ("memo", "hi" ) ); BOOST_REQUIRE_EQUAL(transaction_receipt::executed, trace->receipt->status); - auto gen_size = chain.control->db().get_index().size(); - BOOST_REQUIRE_EQUAL(0u, gen_size); chain.produce_blocks(); @@ -1493,17 +1256,8 @@ BOOST_AUTO_TEST_CASE( link_delay_link_change_heirarchy_test ) { try { BOOST_REQUIRE_EQUAL(asset::from_string("100.0000 CUR"), liquid_balance); // this transaction will be delayed 20 blocks - trace = chain.push_action("eosio.token"_n, name("transfer"), "tester"_n, fc::mutable_variant_object() - ("from", "tester") - ("to", "tester2") - ("quantity", "1.0000 CUR") - ("memo", "hi" ), - 30, 10 - ); - BOOST_REQUIRE_EQUAL(transaction_receipt::delayed, trace->receipt->status); - gen_size = chain.control->db().get_index().size(); - BOOST_REQUIRE_EQUAL(1u, gen_size); - BOOST_REQUIRE_EQUAL(0u, trace->action_traces.size()); + constexpr name first_trnsfr_propsal_name = "prop1"_n; + propose_approve_msig_token_transfer_trx(chain, first_trnsfr_propsal_name, { "tester"_n, config::active_name }, 10, "1.0000 CUR"); chain.produce_blocks(); @@ -1515,17 +1269,8 @@ BOOST_AUTO_TEST_CASE( link_delay_link_change_heirarchy_test ) { try { BOOST_REQUIRE_EQUAL(asset::from_string("0.0000 CUR"), liquid_balance); // this transaction will be delayed 20 blocks - chain.push_action(config::system_account_name, linkauth::get_name(), tester_account, fc::mutable_variant_object() - ("account", "tester") - ("code", eosio_token) - ("type", "transfer") - ("requirement", "third"), - 30, 10 - ); - BOOST_REQUIRE_EQUAL(transaction_receipt::delayed, trace->receipt->status); - gen_size = chain.control->db().get_index().size(); - BOOST_CHECK_EQUAL(2u, gen_size); - BOOST_CHECK_EQUAL(0u, trace->action_traces.size()); + constexpr name linkauth_proposal_name = "prop2"_n; + propose_approve_msig_linkauth_trx(chain, linkauth_proposal_name, "third"_n, { "tester"_n, config::active_name }, 10); chain.produce_blocks(); @@ -1542,17 +1287,8 @@ BOOST_AUTO_TEST_CASE( link_delay_link_change_heirarchy_test ) { try { BOOST_REQUIRE_EQUAL(asset::from_string("0.0000 CUR"), liquid_balance); // this transaction will be delayed 20 blocks - trace = chain.push_action("eosio.token"_n, name("transfer"), "tester"_n, fc::mutable_variant_object() - ("from", "tester") - ("to", "tester2") - ("quantity", "5.0000 CUR") - ("memo", "hi" ), - 30, 10 - ); - BOOST_REQUIRE_EQUAL(transaction_receipt::delayed, trace->receipt->status); - gen_size = chain.control->db().get_index().size(); - BOOST_CHECK_EQUAL(3u, gen_size); - BOOST_CHECK_EQUAL(0u, trace->action_traces.size()); + constexpr name second_trnsfr_propsal_name = "prop3"_n; + propose_approve_msig_token_transfer_trx(chain, second_trnsfr_propsal_name, { "tester"_n, config::active_name }, 10, "5.0000 CUR"); chain.produce_blocks(); @@ -1569,6 +1305,7 @@ BOOST_AUTO_TEST_CASE( link_delay_link_change_heirarchy_test ) { try { BOOST_REQUIRE_EQUAL(asset::from_string("0.0000 CUR"), liquid_balance); // first transfer will finally be performed + exec_msig_trx(chain, first_trnsfr_propsal_name, {{ "tester"_n, config::active_name }}); chain.produce_blocks(); liquid_balance = get_currency_balance(chain, "tester"_n); @@ -1577,6 +1314,7 @@ BOOST_AUTO_TEST_CASE( link_delay_link_change_heirarchy_test ) { try { BOOST_REQUIRE_EQUAL(asset::from_string("1.0000 CUR"), liquid_balance); // delay on minimum permission of transfer is finally removed + exec_msig_trx(chain, linkauth_proposal_name, {{ "tester"_n, config::active_name }}); chain.produce_blocks(); // this transfer is performed right away since delay is removed @@ -1587,8 +1325,6 @@ BOOST_AUTO_TEST_CASE( link_delay_link_change_heirarchy_test ) { try { ("memo", "hi" ) ); BOOST_REQUIRE_EQUAL(transaction_receipt::executed, trace->receipt->status); - gen_size = chain.control->db().get_index().size(); - BOOST_CHECK_EQUAL(1u, gen_size); liquid_balance = get_currency_balance(chain, "tester"_n); BOOST_REQUIRE_EQUAL(asset::from_string("89.0000 CUR"), liquid_balance); @@ -1603,6 +1339,7 @@ BOOST_AUTO_TEST_CASE( link_delay_link_change_heirarchy_test ) { try { BOOST_REQUIRE_EQUAL(asset::from_string("11.0000 CUR"), liquid_balance); // second transfer finally is performed + exec_msig_trx(chain, second_trnsfr_propsal_name, {{ "tester"_n, config::active_name }}); chain.produce_blocks(); liquid_balance = get_currency_balance(chain, "tester"_n); @@ -1612,139 +1349,11 @@ BOOST_AUTO_TEST_CASE( link_delay_link_change_heirarchy_test ) { try { } FC_LOG_AND_RETHROW() } /// link_delay_link_change_heirarchy_test -// test delay_sec field imposing unneeded delay -BOOST_AUTO_TEST_CASE( mindelay_test ) { try { - validating_tester chain; - - chain.produce_blocks(); - chain.create_account("eosio.token"_n); - chain.produce_blocks(10); - - chain.set_code("eosio.token"_n, test_contracts::eosio_token_wasm()); - chain.set_abi("eosio.token"_n, test_contracts::eosio_token_abi()); - - chain.produce_blocks(); - chain.create_account("tester"_n); - chain.create_account("tester2"_n); - chain.produce_blocks(10); - - chain.push_action("eosio.token"_n, "create"_n, "eosio.token"_n, mutable_variant_object() - ("issuer", eosio_token) - ("maximum_supply", "9000000.0000 CUR") - ); - - chain.push_action("eosio.token"_n, name("issue"), "eosio.token"_n, fc::mutable_variant_object() - ("to", eosio_token) - ("quantity", "1000000.0000 CUR") - ("memo", "for stuff") - ); - - auto trace = chain.push_action("eosio.token"_n, name("transfer"), "eosio.token"_n, fc::mutable_variant_object() - ("from", eosio_token) - ("to", "tester") - ("quantity", "100.0000 CUR") - ("memo", "hi" ) - ); - BOOST_REQUIRE_EQUAL(transaction_receipt::executed, trace->receipt->status); - auto gen_size = chain.control->db().get_index().size(); - BOOST_REQUIRE_EQUAL(0u, gen_size); - - chain.produce_blocks(); - - auto liquid_balance = get_currency_balance(chain, "eosio.token"_n); - BOOST_REQUIRE_EQUAL(asset::from_string("999900.0000 CUR"), liquid_balance); - liquid_balance = get_currency_balance(chain, "tester"_n); - BOOST_REQUIRE_EQUAL(asset::from_string("100.0000 CUR"), liquid_balance); - - trace = chain.push_action("eosio.token"_n, name("transfer"), "tester"_n, fc::mutable_variant_object() - ("from", "tester") - ("to", "tester2") - ("quantity", "1.0000 CUR") - ("memo", "hi" ) - ); - - BOOST_REQUIRE_EQUAL(transaction_receipt::executed, trace->receipt->status); - gen_size = chain.control->db().get_index().size(); - BOOST_REQUIRE_EQUAL(0u, gen_size); - - chain.produce_blocks(); - - liquid_balance = get_currency_balance(chain, "eosio.token"_n); - BOOST_REQUIRE_EQUAL(asset::from_string("999900.0000 CUR"), liquid_balance); - liquid_balance = get_currency_balance(chain, "tester"_n); - BOOST_REQUIRE_EQUAL(asset::from_string("99.0000 CUR"), liquid_balance); - liquid_balance = get_currency_balance(chain, "tester2"_n); - BOOST_REQUIRE_EQUAL(asset::from_string("1.0000 CUR"), liquid_balance); - - // send transfer with delay_sec set to 10 - const auto& acnt = chain.control->db().get("eosio.token"_n); - auto abi = acnt.get_abi(); - chain::abi_serializer abis(std::move(abi), abi_serializer::create_yield_function( chain.abi_serializer_max_time )); - const auto a = chain.control->db().get("eosio.token"_n).get_abi(); - - string action_type_name = abis.get_action_type(name("transfer")); - - action act; - act.account = "eosio.token"_n; - act.name = name("transfer"); - act.authorization.push_back(permission_level{"tester"_n, config::active_name}); - act.data = abis.variant_to_binary(action_type_name, fc::mutable_variant_object() - ("from", "tester") - ("to", "tester2") - ("quantity", "3.0000 CUR") - ("memo", "hi" ), - abi_serializer::create_yield_function( chain.abi_serializer_max_time ) - ); - - signed_transaction trx; - trx.actions.push_back(act); - - chain.set_transaction_headers(trx, 30, 10); - trx.sign(chain.get_private_key("tester"_n, "active"), chain.control->get_chain_id()); - trace = chain.push_transaction(trx); - BOOST_REQUIRE_EQUAL(transaction_receipt::delayed, trace->receipt->status); - gen_size = chain.control->db().get_index().size(); - BOOST_REQUIRE_EQUAL(1u, gen_size); - BOOST_REQUIRE_EQUAL(0u, trace->action_traces.size()); - - liquid_balance = get_currency_balance(chain, "tester"_n); - BOOST_REQUIRE_EQUAL(asset::from_string("99.0000 CUR"), liquid_balance); - liquid_balance = get_currency_balance(chain, "tester2"_n); - BOOST_REQUIRE_EQUAL(asset::from_string("1.0000 CUR"), liquid_balance); - - chain.produce_blocks(); - - liquid_balance = get_currency_balance(chain, "tester"_n); - BOOST_REQUIRE_EQUAL(asset::from_string("99.0000 CUR"), liquid_balance); - liquid_balance = get_currency_balance(chain, "tester2"_n); - BOOST_REQUIRE_EQUAL(asset::from_string("1.0000 CUR"), liquid_balance); - - chain.produce_blocks(18); - - liquid_balance = get_currency_balance(chain, "tester"_n); - BOOST_REQUIRE_EQUAL(asset::from_string("99.0000 CUR"), liquid_balance); - liquid_balance = get_currency_balance(chain, "tester2"_n); - BOOST_REQUIRE_EQUAL(asset::from_string("1.0000 CUR"), liquid_balance); - - chain.produce_blocks(); - - liquid_balance = get_currency_balance(chain, "tester"_n); - BOOST_REQUIRE_EQUAL(asset::from_string("99.0000 CUR"), liquid_balance); - liquid_balance = get_currency_balance(chain, "tester2"_n); - BOOST_REQUIRE_EQUAL(asset::from_string("1.0000 CUR"), liquid_balance); - - chain.produce_blocks(); - - liquid_balance = get_currency_balance(chain, "tester"_n); - BOOST_REQUIRE_EQUAL(asset::from_string("96.0000 CUR"), liquid_balance); - liquid_balance = get_currency_balance(chain, "tester2"_n); - BOOST_REQUIRE_EQUAL(asset::from_string("4.0000 CUR"), liquid_balance); - -} FC_LOG_AND_RETHROW() }/// schedule_test - // test canceldelay action cancelling a delayed transaction BOOST_AUTO_TEST_CASE( canceldelay_test ) { try { - validating_tester chain; + validating_tester_no_disable_deferred_trx chain; + chain.produce_block(); + const auto& tester_account = "tester"_n; std::vector ids; @@ -1980,11 +1589,12 @@ BOOST_AUTO_TEST_CASE( canceldelay_test ) { try { BOOST_REQUIRE_EQUAL(asset::from_string("85.0000 CUR"), liquid_balance); liquid_balance = get_currency_balance(chain, "tester2"_n); BOOST_REQUIRE_EQUAL(asset::from_string("15.0000 CUR"), liquid_balance); -} FC_LOG_AND_RETHROW() } +} FC_LOG_AND_RETHROW() } /// canceldelay_test // test canceldelay action under different permission levels BOOST_AUTO_TEST_CASE( canceldelay_test2 ) { try { - validating_tester chain; + validating_tester_no_disable_deferred_trx chain; + chain.produce_block(); const auto& tester_account = "tester"_n; @@ -2246,8 +1856,7 @@ BOOST_AUTO_TEST_CASE( canceldelay_test2 ) { try { liquid_balance = get_currency_balance(chain, "tester2"_n); BOOST_REQUIRE_EQUAL(asset::from_string("0.0000 CUR"), liquid_balance); } -} FC_LOG_AND_RETHROW() } - +} FC_LOG_AND_RETHROW() } /// canceldelay_test2 BOOST_AUTO_TEST_CASE( max_transaction_delay_create ) { try { //assuming max transaction delay is 45 days (default in config.hpp) @@ -2268,23 +1877,16 @@ BOOST_AUTO_TEST_CASE( max_transaction_delay_create ) { try { action_validate_exception, fc_exception_message_starts_with("Cannot set delay longer than max_transacton_delay") ); -} FC_LOG_AND_RETHROW() } +} FC_LOG_AND_RETHROW() } /// max_transaction_delay_create BOOST_AUTO_TEST_CASE( max_transaction_delay_execute ) { try { //assuming max transaction delay is 45 days (default in config.hpp) validating_tester chain; - const auto& tester_account = "tester"_n; - chain.create_account("eosio.token"_n); - chain.set_code("eosio.token"_n, test_contracts::eosio_token_wasm()); - chain.set_abi("eosio.token"_n, test_contracts::eosio_token_abi()); - - chain.produce_blocks(); - chain.create_account("tester"_n); + create_accounts(chain); - chain.produce_blocks(); chain.push_action("eosio.token"_n, "create"_n, "eosio.token"_n, mutable_variant_object() ("issuer", "eosio.token" ) ("maximum_supply", "9000000.0000 CUR" ) @@ -2320,30 +1922,19 @@ BOOST_AUTO_TEST_CASE( max_transaction_delay_execute ) { try { ("params", params) ); chain.produce_blocks(); - //should be able to create transaction with delay 60 sec, despite permission delay being 30 days, because max_transaction_delay is 60 sec - trace = chain.push_action("eosio.token"_n, name("transfer"), "tester"_n, fc::mutable_variant_object() - ("from", "tester") - ("to", "eosio.token") - ("quantity", "9.0000 CUR") - ("memo", "" ), 120, 60); - BOOST_REQUIRE_EQUAL(transaction_receipt::delayed, trace->receipt->status); - - chain.produce_blocks(); - - auto gen_size = chain.control->db().get_index().size(); - BOOST_REQUIRE_EQUAL(1u, gen_size); - BOOST_REQUIRE_EQUAL(0u, trace->action_traces.size()); + //should be able to create a msig transaction with delay 60 sec, despite permission delay being 30 days, because max_transaction_delay is 60 sec + constexpr name proposal_name = "prop1"_n; + propose_approve_msig_token_transfer_trx(chain, proposal_name, { "tester"_n, config::active_name }, 60, "9.0000 CUR"); - //check that the delayed transaction executed after after 60 sec + //check that the delayed msig transaction can be executed after after 60 sec chain.produce_blocks(120); - gen_size = chain.control->db().get_index().size(); - BOOST_CHECK_EQUAL(0u, gen_size); + exec_msig_trx(chain, proposal_name, {{ "tester"_n, config::active_name }}); //check that the transfer really happened auto liquid_balance = get_currency_balance(chain, "tester"_n); BOOST_REQUIRE_EQUAL(asset::from_string("91.0000 CUR"), liquid_balance); -} FC_LOG_AND_RETHROW() } +} FC_LOG_AND_RETHROW() } /// max_transaction_delay_execute BOOST_AUTO_TEST_CASE( test_blockchain_params_enabled ) { try { //since validation_tester activates all features here we will test how setparams works without @@ -2353,55 +1944,15 @@ BOOST_AUTO_TEST_CASE( test_blockchain_params_enabled ) { try { //change max_transaction_delay to 60 sec auto params = chain.control->get_global_properties().configuration; params.max_transaction_delay = 60; - chain.push_action(config::system_account_name, + chain.push_action(config::system_account_name, "setparams"_n, - config::system_account_name, + config::system_account_name, mutable_variant_object()("params", params) ); - + BOOST_CHECK_EQUAL(chain.control->get_global_properties().configuration.max_transaction_delay, 60u); chain.produce_blocks(); } FC_LOG_AND_RETHROW() } -BOOST_FIXTURE_TEST_CASE( delay_expired, validating_tester) { try { - - produce_blocks(2); - signed_transaction trx; - - account_name a = "newco"_n; - account_name creator = config::system_account_name; - - auto owner_auth = authority( get_public_key( a, "owner" ) ); - trx.actions.emplace_back( vector{{creator,config::active_name}}, - newaccount{ - .creator = creator, - .name = a, - .owner = owner_auth, - .active = authority( get_public_key( a, "active" ) ) - }); - set_transaction_headers(trx); - trx.delay_sec = 3; - trx.expiration = fc::time_point_sec{control->head_block_time() + fc::microseconds(1000000)}; - trx.sign( get_private_key( creator, "active" ), control->get_chain_id() ); - - auto trace = push_transaction( trx ); - - BOOST_REQUIRE_EQUAL(transaction_receipt_header::delayed, trace->receipt->status); - - signed_block_ptr sb = produce_block(); - - sb = produce_block(); - - BOOST_REQUIRE_EQUAL(transaction_receipt_header::delayed, trace->receipt->status); - produce_empty_block(fc::milliseconds(610 * 1000)); - sb = produce_block(); - BOOST_REQUIRE_EQUAL(1u, sb->transactions.size()); - BOOST_REQUIRE_EQUAL(transaction_receipt_header::expired, sb->transactions[0].status); - - create_account(a); // account can still be created - -} FC_LOG_AND_RETHROW() } - - BOOST_AUTO_TEST_SUITE_END() diff --git a/unittests/protocol_feature_tests.cpp b/unittests/protocol_feature_tests.cpp index b1cf3f1656..d248e60052 100644 --- a/unittests/protocol_feature_tests.cpp +++ b/unittests/protocol_feature_tests.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -584,16 +585,7 @@ BOOST_AUTO_TEST_CASE( no_duplicate_deferred_id_test ) try { BOOST_REQUIRE_EQUAL(0u, index.size()); - c.push_action( config::system_account_name, "reqauth"_n, "alice"_n, fc::mutable_variant_object() - ("from", "alice"), - 5, 2 - ); - - BOOST_REQUIRE_EQUAL(1u, index.size()); - - c.produce_block(); - - BOOST_REQUIRE_EQUAL(1u, index.size()); + BOOST_REQUIRE_EQUAL(0u, index.size()); const auto& pfm = c.control->get_protocol_feature_manager(); @@ -608,14 +600,14 @@ BOOST_AUTO_TEST_CASE( no_duplicate_deferred_id_test ) try { ("contract", "test") ("payload", 42) ); - BOOST_REQUIRE_EQUAL(2u, index.size()); + BOOST_REQUIRE_EQUAL(1u, index.size()); c.preactivate_protocol_features( {*d1, *d2} ); c.produce_block(); // The deferred transaction with payload 42 that was scheduled prior to the activation of the protocol features should now be retired. BOOST_REQUIRE( trace1 ); - BOOST_REQUIRE_EQUAL(1u, index.size()); + BOOST_REQUIRE_EQUAL(0u, index.size()); trace1 = nullptr; @@ -1929,6 +1921,356 @@ BOOST_AUTO_TEST_CASE( set_parameters_packed_test ) { try { c.error("alice does not have permission to call this API")); } FC_LOG_AND_RETHROW() } +BOOST_AUTO_TEST_CASE( disable_deferred_trxs_stage_1_no_op_test ) { try { + tester_no_disable_deferred_trx c; + + c.produce_block(); + c.create_accounts( {"alice"_n, "bob"_n, "test"_n, "payloadless"_n} ); + c.set_code( "test"_n, test_contracts::deferred_test_wasm() ); + c.set_abi( "test"_n, test_contracts::deferred_test_abi() ); + c.set_code( "payloadless"_n, test_contracts::payloadless_wasm() ); + c.set_abi( "payloadless"_n, test_contracts::payloadless_abi().data() ); + c.produce_block(); + + auto gen_size = c.control->db().get_index().size(); + BOOST_REQUIRE_EQUAL(0u, gen_size); + + // verify send_deferred host function works before disable_deferred_trxs_stage_1 is activated + c.push_action( "test"_n, "delayedcall"_n, "alice"_n, fc::mutable_variant_object() + ("payer", "alice") + ("sender_id", 1) + ("contract", "test") + ("payload", 100) + ("delay_sec", 120) + ("replace_existing", false) + ); + c.produce_block(); + gen_size = c.control->db().get_index().size(); + BOOST_REQUIRE_EQUAL(1u, gen_size); + + // verify cancel_deferred host function works before disable_deferred_trxs_stage_1 is activated + c.push_action( "test"_n, "cancelcall"_n, "alice"_n, fc::mutable_variant_object() + ("sender_id", 1) + ); + c.produce_block(); + gen_size = c.control->db().get_index().size(); + BOOST_REQUIRE_EQUAL(0u, gen_size); + + // generate a deferred trx from contract for cancel_deferred test + c.push_action( "test"_n, "delayedcall"_n, "alice"_n, fc::mutable_variant_object() + ("payer", "alice") + ("sender_id", 1) + ("contract", "test") + ("payload", 100) + ("delay_sec", 120) + ("replace_existing", false) + ); + + // generate a delayed trx for canceldelay test + constexpr uint32_t delay_sec = 10; + c.push_action("payloadless"_n, "doit"_n, "payloadless"_n, mutable_variant_object(), c.DEFAULT_EXPIRATION_DELTA, delay_sec); + + // make sure two trxs were generated + c.produce_block(); + const auto& idx = c.control->db().get_index(); + gen_size = idx.size(); + BOOST_REQUIRE_EQUAL(2u, gen_size); + transaction_id_type alice_trx_id; + transaction_id_type payloadless_trx_id; + for( auto itr = idx.begin(); itr != idx.end(); ++itr ) { + if( itr->payer == "alice"_n) { + alice_trx_id = itr->trx_id; + } else { + payloadless_trx_id = itr->trx_id; + } + } + + // activate disable_deferred_trxs_stage_1 + const auto& pfm = c.control->get_protocol_feature_manager(); + auto d = pfm.get_builtin_digest( builtin_protocol_feature_t::disable_deferred_trxs_stage_1 ); + BOOST_REQUIRE( d ); + c.preactivate_protocol_features( {*d} ); + c.produce_block(); + + // verify send_deferred host function is no-op + c.push_action( "test"_n, "delayedcall"_n, "bob"_n, fc::mutable_variant_object() + ("payer", "bob") + ("sender_id", 2) + ("contract", "test") + ("payload", 100) + ("delay_sec", 120) + ("replace_existing", false) + ); + c.produce_block(); + + // verify bob's deferred trx is not made to generated_transaction_multi_index + gen_size = c.control->db().get_index().size(); + BOOST_REQUIRE_EQUAL(2u, gen_size); + // verify alice's deferred trx is still in generated_transaction_multi_index + auto gto = c.control->db().find(alice_trx_id); + BOOST_REQUIRE(gto != nullptr); + + // verify cancel_deferred host function is no-op + BOOST_REQUIRE_EXCEPTION( + c.push_action( "test"_n, "cancelcall"_n, "alice"_n, fc::mutable_variant_object() + ("sender_id", 1)), + eosio_assert_message_exception, + eosio_assert_message_is( "cancel_deferred failed" ) ); + gen_size = c.control->db().get_index().size(); + BOOST_REQUIRE_EQUAL(2u, gen_size); + // verify alice's deferred trx is not removed + gto = c.control->db().find(alice_trx_id); + BOOST_REQUIRE( gto ); + + // call canceldelay native action + signed_transaction trx; + trx.actions.emplace_back( + vector{{"payloadless"_n, config::active_name}}, + canceldelay{{"payloadless"_n, config::active_name}, payloadless_trx_id} + ); + c.set_transaction_headers(trx); + trx.sign(c.get_private_key("payloadless"_n, "active"), c.control->get_chain_id()); + c.push_transaction(trx); + c.produce_block(); + + // verify canceldelay is no-op + gen_size = c.control->db().get_index().size(); + BOOST_REQUIRE_EQUAL(2u, gen_size); + // verify payloadless' delayed trx is not removed + gto = c.control->db().find(payloadless_trx_id); + BOOST_REQUIRE( gto ); +} FC_LOG_AND_RETHROW() } /// disable_deferred_trxs_stage_1_no_op_test + +// verify a deferred transaction can be retired as expired at any time regardless of +// whether its delay_until or expiration have been reached +BOOST_AUTO_TEST_CASE( disable_deferred_trxs_stage_1_retire_test ) { try { + tester_no_disable_deferred_trx c; + + c.produce_block(); + c.create_accounts( {"alice"_n, "test"_n} ); + c.set_code( "test"_n, test_contracts::deferred_test_wasm() ); + c.set_abi( "test"_n, test_contracts::deferred_test_abi() ); + c.produce_block(); + + // verify number of deferred trxs is 0 + auto gen_size = c.control->db().get_index().size(); + BOOST_REQUIRE_EQUAL( 0u, gen_size ); + auto alice_ram_usage_before = c.control->get_resource_limits_manager().get_account_ram_usage( "alice"_n ); + + // alice schedules a deferred trx + c.push_action( "test"_n, "delayedcall"_n, "alice"_n, fc::mutable_variant_object() + ("payer", "alice") + ("sender_id", 1) + ("contract", "test") + ("payload", 100) + ("delay_sec", 120) + ("replace_existing", false) + ); + c.produce_block(); + + // the deferred trx was added into generated_transaction_multi_index + const auto& idx = c.control->db().get_index(); + gen_size = idx.size(); + BOOST_REQUIRE_EQUAL( 1u, gen_size ); + auto trx_id = idx.begin()->trx_id; + auto delay_until = idx.begin()->delay_until; + // alice's RAM were charged + BOOST_CHECK_GT(c.control->get_resource_limits_manager().get_account_ram_usage( "alice"_n ), alice_ram_usage_before); + + // activate disable_deferred_trxs_stage_1 + const auto& pfm = c.control->get_protocol_feature_manager(); + auto d = pfm.get_builtin_digest( builtin_protocol_feature_t::disable_deferred_trxs_stage_1 ); + BOOST_REQUIRE( d ); + c.preactivate_protocol_features( {*d} ); + c.produce_block(); + + // verify generated_transaction_multi_index still has 1 entry + gen_size = c.control->db().get_index().size(); + BOOST_REQUIRE_EQUAL( 1u, gen_size ); + + // at this time, delay_sec has not reached, + // neither does expiration which is "deferred_trx_expiration_window + delay_sec". + // BOOST_CHECK_LT does not work on time_point. Need to compare explicitly + if ( delay_until <= c.control->pending_block_time() ) { // not reached + BOOST_REQUIRE(false); + } + + // attemp to retire the trx + auto deadline = fc::time_point::now() + fc::milliseconds(10); // 10ms more than enough + auto trace = c.control->push_scheduled_transaction(trx_id, deadline, fc::microseconds::maximum(), 0, false); + + // the trx was retired as "expired" and RAM was refunded even though delay_until not reached + BOOST_REQUIRE_EQUAL( trace->receipt->status, transaction_receipt::expired ); + // all scheduled deferred trxs are removed upon activation of disable_deferred_trxs_stage_2 + gen_size = c.control->db().get_index().size(); + BOOST_REQUIRE_EQUAL( 0u, gen_size ); + // payers' RAM are refunded + BOOST_CHECK_EQUAL( c.control->get_resource_limits_manager().get_account_ram_usage( "alice"_n ), alice_ram_usage_before ); +} FC_LOG_AND_RETHROW() } /// disable_deferred_trxs_stage_1_retire_test + +BOOST_AUTO_TEST_CASE( disable_deferred_trxs_stage_2_test ) { try { + tester_no_disable_deferred_trx c; + + c.produce_block(); + c.create_accounts( {"alice"_n, "bob"_n, "test"_n} ); + c.set_code( "test"_n, test_contracts::deferred_test_wasm() ); + c.set_abi( "test"_n, test_contracts::deferred_test_abi() ); + c.produce_block(); + + // verify number of deferred trxs starts at 0 + auto gen_size = c.control->db().get_index().size(); + BOOST_REQUIRE_EQUAL( 0u, gen_size ); + auto alice_ram_usage_before = c.control->get_resource_limits_manager().get_account_ram_usage( "alice"_n ); + auto bob_ram_usage_before = c.control->get_resource_limits_manager().get_account_ram_usage( "bob"_n ); + + // schedule 2 deferred trxs + c.push_action( "test"_n, "delayedcall"_n, "alice"_n, fc::mutable_variant_object() + ("payer", "alice") + ("sender_id", 1) + ("contract", "test") + ("payload", 100) + ("delay_sec", 120) + ("replace_existing", false) + ); + c.push_action( "test"_n, "delayedcall"_n, "bob"_n, fc::mutable_variant_object() + ("payer", "bob") + ("sender_id", 2) + ("contract", "test") + ("payload", 100) + ("delay_sec", 120) + ("replace_existing", false) + ); + c.produce_block(); + + // trxs were added into generated_transaction_multi_index + const auto& idx = c.control->db().get_index(); + gen_size = idx.size(); + BOOST_REQUIRE_EQUAL( 2u, gen_size ); + + // payers' RAM were charged + BOOST_CHECK_GT(c.control->get_resource_limits_manager().get_account_ram_usage( "alice"_n ), alice_ram_usage_before); + BOOST_CHECK_GT(c.control->get_resource_limits_manager().get_account_ram_usage( "bob"_n ), bob_ram_usage_before); + + const auto& pfm = c.control->get_protocol_feature_manager(); + auto d = pfm.get_builtin_digest( builtin_protocol_feature_t::disable_deferred_trxs_stage_1 ); + BOOST_REQUIRE( d ); + c.preactivate_protocol_features( {*d} ); + + // before disable_deferred_trxs_stage_2 is activated, generated_transaction_multi_index + // should still have 2 entries + gen_size = c.control->db().get_index().size(); + BOOST_REQUIRE_EQUAL( 2u, gen_size ); + + d = pfm.get_builtin_digest( builtin_protocol_feature_t::disable_deferred_trxs_stage_2 ); + BOOST_REQUIRE( d ); + c.preactivate_protocol_features( {*d} ); + c.produce_block(); + + // all scheduled deferred trxs are removed upon activation of disable_deferred_trxs_stage_2 + gen_size = c.control->db().get_index().size(); + BOOST_REQUIRE_EQUAL( 0u, gen_size ); + + // payers' RAM are refunded + BOOST_CHECK_EQUAL( c.control->get_resource_limits_manager().get_account_ram_usage( "alice"_n ), alice_ram_usage_before ); + BOOST_CHECK_EQUAL( c.control->get_resource_limits_manager().get_account_ram_usage( "bob"_n ), bob_ram_usage_before ); +} FC_LOG_AND_RETHROW() } /// disable_deferred_trxs_stage_2_test + +BOOST_AUTO_TEST_CASE( disable_deferred_trxs_stage_2_dependency_test ) { try { + tester_no_disable_deferred_trx c; + + c.produce_block(); + + // disable_deferred_trxs_stage_2 cannot be activated before disable_deferred_trxs_stage_1 + const auto& pfm = c.control->get_protocol_feature_manager(); + auto d = pfm.get_builtin_digest( builtin_protocol_feature_t::disable_deferred_trxs_stage_2 ); + BOOST_REQUIRE( d ); + BOOST_REQUIRE_EXCEPTION( c.preactivate_protocol_features( {*d} ), + protocol_feature_exception, + fc_exception_message_starts_with("not all dependencies of protocol feature with digest")); +} FC_LOG_AND_RETHROW() } /// disable_deferred_trxs_stage_2_dependency_test + +// Verify a block containing delayed transactions is validated +// before DISABLE_DEFERRED_TRXS_STAGE_1 is activated +BOOST_AUTO_TEST_CASE( block_validation_before_stage_1_test ) { try { + tester_no_disable_deferred_trx tester1; + tester_no_disable_deferred_trx tester2; + + tester1.create_accounts( {"payloadless"_n} ); + tester1.set_code( "payloadless"_n, test_contracts::payloadless_wasm() ); + tester1.set_abi( "payloadless"_n, test_contracts::payloadless_abi().data() ); + + // Produce a block containing a delayed trx + constexpr uint32_t delay_sec = 10; + tester1.push_action("payloadless"_n, "doit"_n, "payloadless"_n, mutable_variant_object(), tester1.DEFAULT_EXPIRATION_DELTA, delay_sec); + auto b = tester1.produce_block(); + + // Push the block to another chain. The block should be validated + BOOST_REQUIRE_NO_THROW(tester2.push_block(b)); +} FC_LOG_AND_RETHROW() } /// block_validation_before_stage_1_test + +// Verify a block containing delayed transactions is not validated +// after DISABLE_DEFERRED_TRXS_STAGE_1 is activated +BOOST_AUTO_TEST_CASE( block_validation_after_stage_1_test ) { try { + tester_no_disable_deferred_trx tester1; + + // Activate DISABLE_DEFERRED_TRXS_STAGE_1 such that tester1 + // matches tester2 below + const auto& pfm1 = tester1.control->get_protocol_feature_manager(); + auto d1 = pfm1.get_builtin_digest( builtin_protocol_feature_t::disable_deferred_trxs_stage_1 ); + BOOST_REQUIRE( d1 ); + tester1.preactivate_protocol_features( {*d1} ); + tester1.produce_block(); + + // Create a block with valid transaction + tester1.create_account("newacc"_n); + auto b = tester1.produce_block(); + + // Make a copy of the block + auto copy_b = std::make_shared(std::move(*b)); + // Retrieve the last transaction + auto signed_tx = std::get(copy_b->transactions.back().trx).get_signed_transaction(); + // Make a delayed transaction by forcing delay_sec greater than 0 + signed_tx.delay_sec = 120; + // Re-sign the transaction + signed_tx.signatures.clear(); + signed_tx.sign(tester1.get_private_key(config::system_account_name, "active"), tester1.control->get_chain_id()); + // Replace the original transaction with the delayed transaction + auto delayed_tx = packed_transaction(signed_tx); + copy_b->transactions.back().trx = std::move(delayed_tx); + + // Re-calculate the transaction merkle + deque trx_digests; + const auto& trxs = copy_b->transactions; + for( const auto& a : trxs ) + trx_digests.emplace_back( a.digest() ); + copy_b->transaction_mroot = merkle( std::move(trx_digests) ); + + // Re-sign the block + auto header_bmroot = digest_type::hash( std::make_pair( copy_b->digest(), tester1.control->head_block_state()->blockroot_merkle.get_root() ) ); + auto sig_digest = digest_type::hash( std::make_pair(header_bmroot, tester1.control->head_block_state()->pending_schedule.schedule_hash) ); + copy_b->producer_signature = tester1.get_private_key(config::system_account_name, "active").sign(sig_digest); + + // Create the second chain + tester_no_disable_deferred_trx tester2; + // Activate DISABLE_DEFERRED_TRXS_STAGE_1 on the second chain + const auto& pfm2 = tester2.control->get_protocol_feature_manager(); + auto d2 = pfm2.get_builtin_digest( builtin_protocol_feature_t::disable_deferred_trxs_stage_1 ); + BOOST_REQUIRE( d2 ); + tester2.preactivate_protocol_features( {*d2} ); + tester2.produce_block(); + + // Push the block with delayed transaction to the second chain + auto bsf = tester2.control->create_block_state_future( copy_b->calculate_id(), copy_b ); + tester2.control->abort_block(); + controller::block_report br; + + // The block is invalidated + BOOST_REQUIRE_EXCEPTION(tester2.control->push_block( br, bsf.get(), forked_branch_callback{}, trx_meta_cache_lookup{} ), + fc::exception, + fc_exception_message_starts_with("transaction cannot be delayed") + ); +} FC_LOG_AND_RETHROW() } /// block_validation_after_stage_1_test + static const char import_set_finalizers_wast[] = R"=====( (module (import "env" "set_finalizers" (func $set_finalizers (param i32 i32))) diff --git a/unittests/state_history_tests.cpp b/unittests/state_history_tests.cpp index 8a0e875239..b1089da989 100644 --- a/unittests/state_history_tests.cpp +++ b/unittests/state_history_tests.cpp @@ -571,7 +571,7 @@ BOOST_AUTO_TEST_CASE(test_deltas_resources_history) { } BOOST_AUTO_TEST_CASE(test_trace_log_with_transaction_extensions) { - tester c(setup_policy::full); + tester_no_disable_deferred_trx c; fc::temp_directory state_history_dir; eosio::state_history::trace_converter log; diff --git a/unittests/test-contracts/deferred_test/deferred_test.abi b/unittests/test-contracts/deferred_test/deferred_test.abi index 385f2098d2..a2359666d5 100644 --- a/unittests/test-contracts/deferred_test/deferred_test.abi +++ b/unittests/test-contracts/deferred_test/deferred_test.abi @@ -3,6 +3,16 @@ "version": "eosio::abi/1.2", "types": [], "structs": [ + { + "name": "cancelcall", + "base": "", + "fields": [ + { + "name": "sender_id", + "type": "uint64" + } + ] + }, { "name": "defercall", "base": "", @@ -90,6 +100,11 @@ } ], "actions": [ + { + "name": "cancelcall", + "type": "cancelcall", + "ricardian_contract": "" + }, { "name": "defercall", "type": "defercall", diff --git a/unittests/test-contracts/deferred_test/deferred_test.cpp b/unittests/test-contracts/deferred_test/deferred_test.cpp index d70720b18b..35dae40f31 100644 --- a/unittests/test-contracts/deferred_test/deferred_test.cpp +++ b/unittests/test-contracts/deferred_test/deferred_test.cpp @@ -52,6 +52,11 @@ void deferred_test::delayedcall( name payer, uint64_t sender_id, name contract, trx.send( sender_id, payer, replace_existing ); } +void deferred_test::cancelcall(uint64_t sender_id) { + auto r = eosio::cancel_deferred( sender_id ); + check( (bool)r, "cancel_deferred failed" ); +} + void deferred_test::deferfunc( uint64_t payload ) { print( "deferfunc called on ", get_self(), " with payload = ", payload, "\n" ); check( payload != 13, "value 13 not allowed in payload" ); diff --git a/unittests/test-contracts/deferred_test/deferred_test.hpp b/unittests/test-contracts/deferred_test/deferred_test.hpp index f5a322337e..86d3481bcb 100644 --- a/unittests/test-contracts/deferred_test/deferred_test.hpp +++ b/unittests/test-contracts/deferred_test/deferred_test.hpp @@ -14,6 +14,9 @@ class [[eosio::contract]] deferred_test : public eosio::contract { void delayedcall( eosio::name payer, uint64_t sender_id, eosio::name contract, uint64_t payload, uint32_t delay_sec, bool replace_existing ); + [[eosio::action]] + void cancelcall( uint64_t sender_id ); + [[eosio::action]] void deferfunc( uint64_t payload ); using deferfunc_action = eosio::action_wrapper<"deferfunc"_n, &deferred_test::deferfunc>; diff --git a/unittests/test-contracts/deferred_test/deferred_test.wasm b/unittests/test-contracts/deferred_test/deferred_test.wasm index e0acee03f3..bcdf583236 100755 Binary files a/unittests/test-contracts/deferred_test/deferred_test.wasm and b/unittests/test-contracts/deferred_test/deferred_test.wasm differ diff --git a/unittests/test-contracts/payloadless/payloadless.abi b/unittests/test-contracts/payloadless/payloadless.abi index ad6c695ea6..aafa35c171 100644 --- a/unittests/test-contracts/payloadless/payloadless.abi +++ b/unittests/test-contracts/payloadless/payloadless.abi @@ -7,6 +7,11 @@ "name": "doit", "base": "", "fields": [] + }, + { + "name": "doitslow", + "base": "", + "fields": [] } ], "actions": [ @@ -14,6 +19,11 @@ "name": "doit", "type": "doit", "ricardian_contract": "" + }, + { + "name": "doitslow", + "type": "doitslow", + "ricardian_contract": "" } ], "tables": [], diff --git a/unittests/test-contracts/payloadless/payloadless.cpp b/unittests/test-contracts/payloadless/payloadless.cpp index 16637efa2b..46566c3215 100644 --- a/unittests/test-contracts/payloadless/payloadless.cpp +++ b/unittests/test-contracts/payloadless/payloadless.cpp @@ -5,3 +5,48 @@ using namespace eosio; void payloadless::doit() { print("Im a payloadless action"); } + +constexpr size_t cpu_prime_max = 15375u; + +bool is_prime(int p) { + if (p == 2) { + return true; + } else if (p <= 1 || p % 2 == 0) { + return false; + } + + bool prime = true; + const int to = sqrt(p); + for (int i = 3; i <= to; i += 2) { + if (p % i == 0) { + prime = false; + break; + } + } + return prime; +} + +bool is_mersenne_prime(int p) { + if (p == 2) return true; + + const long long unsigned m_p = (1LLU << p) - 1; + long long unsigned s = 4; + int i; + for (i = 3; i <= p; i++) { + s = (s * s - 2) % m_p; + } + return bool(s == 0); +} + + +void payloadless::doitslow() { + print("Im a payloadless slow action"); + + for (size_t p = 2; p <= cpu_prime_max; p += 1) { + if (is_prime(p) && is_mersenne_prime(p)) { + // We need to keep an eye on this to make sure it doesn't get optimized out. So far so good. + //eosio::print_f(" %u", p); + } + } +} + diff --git a/unittests/test-contracts/payloadless/payloadless.hpp b/unittests/test-contracts/payloadless/payloadless.hpp index 945a0d7417..0fea87a29b 100644 --- a/unittests/test-contracts/payloadless/payloadless.hpp +++ b/unittests/test-contracts/payloadless/payloadless.hpp @@ -8,4 +8,7 @@ class [[eosio::contract]] payloadless : public eosio::contract { [[eosio::action]] void doit(); + + [[eosio::action]] + void doitslow(); }; diff --git a/unittests/test-contracts/payloadless/payloadless.wasm b/unittests/test-contracts/payloadless/payloadless.wasm index 7b0ae32153..dc91259462 100755 Binary files a/unittests/test-contracts/payloadless/payloadless.wasm and b/unittests/test-contracts/payloadless/payloadless.wasm differ diff --git a/unittests/test-contracts/test_api/test_action.cpp b/unittests/test-contracts/test_api/test_action.cpp index c390fb9198..98fc38fd1a 100644 --- a/unittests/test-contracts/test_api/test_action.cpp +++ b/unittests/test-contracts/test_api/test_action.cpp @@ -62,6 +62,12 @@ void test_action::test_dummy_action() { } } +void test_action::read_action() { + print("action size: " + std::to_string(action_data_size())); + void* p = malloc(action_data_size()); + read_action_data(p, action_data_size()); +} + void test_action::read_action_to_0() { read_action_data( (void *)0, action_data_size() ); } diff --git a/unittests/test-contracts/test_api/test_api.cpp b/unittests/test-contracts/test_api/test_api.cpp index d51d3dc71b..e318e63bdb 100644 --- a/unittests/test-contracts/test_api/test_api.cpp +++ b/unittests/test-contracts/test_api/test_api.cpp @@ -49,6 +49,7 @@ extern "C" { //test_action WASM_TEST_HANDLER ( test_action, read_action_normal ); + WASM_TEST_HANDLER ( test_action, read_action ); WASM_TEST_HANDLER ( test_action, read_action_to_0 ); WASM_TEST_HANDLER ( test_action, read_action_to_64k ); WASM_TEST_HANDLER_EX( test_action, require_notice ); @@ -118,6 +119,8 @@ extern "C" { WASM_TEST_HANDLER ( test_transaction, send_action_empty ); WASM_TEST_HANDLER ( test_transaction, send_action_large ); WASM_TEST_HANDLER ( test_transaction, send_action_4k ); + WASM_TEST_HANDLER ( test_transaction, send_action_512k ); + WASM_TEST_HANDLER ( test_transaction, send_many_actions_512k ); WASM_TEST_HANDLER ( test_transaction, send_action_recurse ); WASM_TEST_HANDLER ( test_transaction, test_read_transaction ); WASM_TEST_HANDLER ( test_transaction, test_transaction_size ); diff --git a/unittests/test-contracts/test_api/test_api.hpp b/unittests/test-contracts/test_api/test_api.hpp index cffdc30db8..c6bec87812 100644 --- a/unittests/test-contracts/test_api/test_api.hpp +++ b/unittests/test-contracts/test_api/test_api.hpp @@ -93,6 +93,7 @@ struct test_print { struct test_action { static void read_action_normal(); + static void read_action(); static void read_action_to_0(); static void read_action_to_64k(); static void test_dummy_action(); @@ -202,6 +203,8 @@ struct test_transaction { static void send_action_max(); static void send_action_large(); static void send_action_4k(); + static void send_action_512k(); + static void send_many_actions_512k(); static void send_action_recurse(); static void send_action_inline_fail(); static void test_read_transaction(); diff --git a/unittests/test-contracts/test_api/test_api.wasm b/unittests/test-contracts/test_api/test_api.wasm index 987a355952..e81d415104 100755 Binary files a/unittests/test-contracts/test_api/test_api.wasm and b/unittests/test-contracts/test_api/test_api.wasm differ diff --git a/unittests/test-contracts/test_api/test_transaction.cpp b/unittests/test-contracts/test_api/test_transaction.cpp index f56d435e9c..c311a84a4d 100644 --- a/unittests/test-contracts/test_api/test_transaction.cpp +++ b/unittests/test-contracts/test_api/test_transaction.cpp @@ -84,17 +84,15 @@ void test_transaction::send_action_empty() { } /** - * cause failure due to a large action payload + * cause failure due to a large action payload, larger than max_inline_action_size of 512K */ void test_transaction::send_action_large() { using namespace eosio; - static char large_message[8 * 1024]; - test_action_action<"testapi"_n.value, WASM_TEST_ACTION( "test_action", "read_action_normal" )> test_action; - copy_data( large_message, 8*1024, test_action.data ); + test_action_action<"testapi"_n.value, WASM_TEST_ACTION( "test_action", "read_action" )> test_action; + test_action.data.resize(512*1024+1); std::vector permissions = { {"testapi"_n, "active"_n} }; - action act( permissions, name{"testapi"}, name{WASM_TEST_ACTION("test_action", "read_action_normal")}, test_action ); - + action act( permissions, name{"testapi"}, name{WASM_TEST_ACTION("test_action", "read_action")}, test_action ); act.send(); eosio_assert( false, "send_message_large() should've thrown an error" ); } @@ -104,16 +102,59 @@ void test_transaction::send_action_large() { */ void test_transaction::send_action_4k() { using namespace eosio; - static char large_message[4 * 1024]; - test_action_action<"testapi"_n.value, WASM_TEST_ACTION( "test_action", "test_action_ordinal4" )> test_action; - copy_data( large_message, 4*1024, test_action.data ); + test_action_action<"testapi"_n.value, WASM_TEST_ACTION( "test_action", "read_action" )> test_action; + test_action.data.resize(4*1024); + + std::vector permissions = { {"testapi"_n, "active"_n} }; + action act( permissions, name{"testapi"}, name{WASM_TEST_ACTION("test_action", "read_action")}, test_action ); + + act.send(); +} + +/** + * send an inline action that is 512K (limit is < 512K) + * the limit includes the size of the action + */ +void test_transaction::send_action_512k() { + using namespace eosio; + test_action_action<"testapi"_n.value, WASM_TEST_ACTION( "test_action", "read_action" )> test_action; + test_action.data.resize(1); std::vector permissions = { {"testapi"_n, "active"_n} }; - action act( permissions, name{"testapi"}, name{WASM_TEST_ACTION("test_action", "test_action_ordinal4")}, test_action ); + action temp_act( permissions, name{"testapi"}, name{WASM_TEST_ACTION("test_action", "read_action")}, test_action ); + + size_t action_size = pack_size(temp_act); + test_action.data.resize(512*1024-action_size-2); // check is < 512K + + // send at limit (512K - 1) + action act( permissions, name{"testapi"}, name{WASM_TEST_ACTION("test_action", "read_action")}, test_action ); + + if (pack_size(act) != 512*1024-1) { + std::string err = "send_action_512k action size is: " + std::to_string(action_size) + " not 512K-1"; + eosio_assert(false, err.c_str()); + } act.send(); } +/** + * send many inline actions that are 512K (limit is < 512K) + * the limit includes the size of the action + */ +void test_transaction::send_many_actions_512k() { + using namespace eosio; + test_action_action<"testapi"_n.value, WASM_TEST_ACTION( "test_transaction", "send_action_512k" )> test_action; + + test_action.data.resize(1); + std::vector permissions = { {"testapi"_n, "active"_n} }; + action act( permissions, name{"testapi"}, name{WASM_TEST_ACTION("test_transaction", "send_action_512k")}, test_action ); + + // 65 * 512K > wasm memory limit, which is ok because each gets their own wasm instantiation + for (size_t i = 0; i < 65; ++i) { + act.send(); + } +} + /** * cause failure due recursive loop */ diff --git a/unittests/wasm_tests.cpp b/unittests/wasm_tests.cpp index c0bb9567e5..29d66047a0 100644 --- a/unittests/wasm_tests.cpp +++ b/unittests/wasm_tests.cpp @@ -2184,6 +2184,83 @@ BOOST_FIXTURE_TEST_CASE( negative_memory_grow, validating_tester ) try { } FC_LOG_AND_RETHROW() +// This test is only applicable to Linux +#if defined(__linux__) +// Returns the number of memory mappings of the current process. Only works on Linux +static uint32_t get_num_memory_mappings() { + std::string maps_file = "/proc/" + std::to_string(getpid()) + "/maps"; + std::ifstream maps_ifs(maps_file); + if (!maps_ifs.is_open()) { + return 0; + } + + uint32_t num_mappings = 0; + std::string line; + while (std::getline(maps_ifs, line)) { + num_mappings++; + } + return num_mappings; +} + +BOOST_FIXTURE_TEST_CASE( memory_mapping_test, validating_tester ) try { + static const std::string mem_map_wast_start = R"=====( + (module + (export "apply" (func $apply)) + (global i32 (i32.const + )====="; + static const std::string mem_map_wast_end = R"=====( + )) + (func $apply (param i64) (param i64) (param i64) + ) + ) + )====="; + static const char* mem_map_abi = R"=====( + { + "version": "eosio::abi/1.2", + "types": [], + "structs": [{ "name": "dothedew", "base": "", "fields": [] }], + "actions": [{ "name": "dothedew", "type": "dothedew", "ricardian_contract": ""}], + "tables": [], + "ricardian_clauses": [] + } + )====="; + + produce_block(); + + auto num_mappings_before = get_num_memory_mappings(); + BOOST_CHECK_GT(num_mappings_before, 0U); // must be able to get number of memory mappings + + // number of contracts to deploy + constexpr uint32_t num_contracts = 5000; + + for (uint32_t i = 1; i < num_contracts; ++i) { + std::stringstream ss; + ss << "0x" << std::hex << i << "00000000"; + uint64_t name_value; + ss >> name_value; + auto acct = name(name_value); + create_accounts({acct}); + + std::string contract_wast = mem_map_wast_start + " " + std::to_string(i) + mem_map_wast_end; + set_code(acct, contract_wast.c_str()); + set_abi(acct, mem_map_abi); + + push_action(acct, "dothedew"_n, "eosio"_n, {}); + + // do not put too many transactions in a single block + if (i % 20 == 0 ) { + produce_block(); + } + } + + constexpr uint32_t margin_of_changes = 50; + auto num_mappings_now = get_num_memory_mappings(); + if (num_mappings_now > num_mappings_before) { + BOOST_CHECK_LT(num_mappings_now - num_mappings_before, margin_of_changes); + } +} FC_LOG_AND_RETHROW() +#endif // defined(__linux__) + BOOST_FIXTURE_TEST_CASE(net_usage_tests, tester ) try { int count = 0; auto check = [&](int coderepeat, int max_net_usage)-> bool {